aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-02-20 10:09:32 -0800
committerJunio C Hamano <gitster@pobox.com>2026-02-20 10:09:32 -0800
commit4fa8cfd68ab9ed6fb273a354ff1b5e240cbabc1d (patch)
tree727bb838a214bbdda297fbe6125b270edc4169c5
parent73fd77805fc6406f31c36212846d9e2541d19321 (diff)
parent6375a00ef16071eadbb383bd9915e277ef304bfe (diff)
downloadgit-4fa8cfd68ab9ed6fb273a354ff1b5e240cbabc1d.tar.xz
Merge branch 'ps/for-each-ref-in-fixes' into ps/refs-for-each
* ps/for-each-ref-in-fixes: bisect: simplify string_list memory handling bisect: fix misuse of `refs_for_each_ref_in()` pack-bitmap: fix bug with exact ref match in "pack.preferBitmapTips" pack-bitmap: deduplicate logic to iterate over preferred bitmap tips
-rw-r--r--Documentation/config/pack.adoc9
-rw-r--r--bisect.c16
-rw-r--r--builtin/pack-objects.c19
-rw-r--r--pack-bitmap.c29
-rw-r--r--pack-bitmap.h9
-rw-r--r--repack-midx.c14
-rwxr-xr-xt/t5310-pack-bitmaps.sh41
-rwxr-xr-xt/t5319-multi-pack-index.sh43
8 files changed, 137 insertions, 43 deletions
diff --git a/Documentation/config/pack.adoc b/Documentation/config/pack.adoc
index 75402d5579..fa997c8597 100644
--- a/Documentation/config/pack.adoc
+++ b/Documentation/config/pack.adoc
@@ -160,12 +160,13 @@ pack.usePathWalk::
processes. See linkgit:git-pack-objects[1] for full details.
pack.preferBitmapTips::
+ Specifies a ref hierarchy (e.g., "refs/heads/"); can be
+ given multiple times to specify more than one hierarchies.
When selecting which commits will receive bitmaps, prefer a
- commit at the tip of any reference that is a suffix of any value
- of this configuration over any other commits in the "selection
- window".
+ commit at the tip of a reference that is contained in any of
+ the configured hierarchies.
+
-Note that setting this configuration to `refs/foo` does not mean that
+Note that setting this configuration to `refs/foo/` does not mean that
the commits at the tips of `refs/foo/bar` and `refs/foo/baz` will
necessarily be selected. This is because commits are selected for
bitmaps from within a series of windows of variable length.
diff --git a/bisect.c b/bisect.c
index b313f13240..2bdad4ee42 100644
--- a/bisect.c
+++ b/bisect.c
@@ -1180,8 +1180,7 @@ int estimate_bisect_steps(int all)
static int mark_for_removal(const struct reference *ref, void *cb_data)
{
struct string_list *refs = cb_data;
- char *bisect_ref = xstrfmt("refs/bisect%s", ref->name);
- string_list_append(refs, bisect_ref);
+ string_list_append(refs, ref->name);
return 0;
}
@@ -1190,16 +1189,15 @@ int bisect_clean_state(void)
int result = 0;
/* There may be some refs packed during bisection */
- struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
- refs_for_each_ref_in(get_main_ref_store(the_repository),
- "refs/bisect", mark_for_removal,
- (void *) &refs_for_removal);
- string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
- string_list_append(&refs_for_removal, xstrdup("BISECT_EXPECTED_REV"));
+ struct string_list refs_for_removal = STRING_LIST_INIT_DUP;
+ refs_for_each_fullref_in(get_main_ref_store(the_repository),
+ "refs/bisect/", NULL, mark_for_removal,
+ &refs_for_removal);
+ string_list_append(&refs_for_removal, "BISECT_HEAD");
+ string_list_append(&refs_for_removal, "BISECT_EXPECTED_REV");
result = refs_delete_refs(get_main_ref_store(the_repository),
"bisect: remove", &refs_for_removal,
REF_NO_DEREF);
- refs_for_removal.strdup_strings = 1;
string_list_clear(&refs_for_removal, 0);
unlink_or_warn(git_path_bisect_ancestors_ok());
unlink_or_warn(git_path_bisect_log());
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index e6c8f896ab..c2ce70db04 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4551,22 +4551,6 @@ static int mark_bitmap_preferred_tip(const struct reference *ref, void *data UNU
return 0;
}
-static void mark_bitmap_preferred_tips(void)
-{
- struct string_list_item *item;
- const struct string_list *preferred_tips;
-
- preferred_tips = bitmap_preferred_tips(the_repository);
- if (!preferred_tips)
- return;
-
- for_each_string_list_item(item, preferred_tips) {
- refs_for_each_ref_in(get_main_ref_store(the_repository),
- item->string, mark_bitmap_preferred_tip,
- NULL);
- }
-}
-
static inline int is_oid_uninteresting(struct repository *repo,
struct object_id *oid)
{
@@ -4707,7 +4691,8 @@ static void get_object_list(struct rev_info *revs, struct strvec *argv)
load_delta_islands(the_repository, progress);
if (write_bitmap_index)
- mark_bitmap_preferred_tips();
+ for_each_preferred_bitmap_tip(the_repository, mark_bitmap_preferred_tip,
+ NULL);
if (!fn_show_object)
fn_show_object = show_object;
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 972203f12b..1c93871484 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -3314,7 +3314,7 @@ int bitmap_is_midx(struct bitmap_index *bitmap_git)
return !!bitmap_git->midx;
}
-const struct string_list *bitmap_preferred_tips(struct repository *r)
+static const struct string_list *bitmap_preferred_tips(struct repository *r)
{
const struct string_list *dest;
@@ -3323,6 +3323,33 @@ const struct string_list *bitmap_preferred_tips(struct repository *r)
return NULL;
}
+void for_each_preferred_bitmap_tip(struct repository *repo,
+ each_ref_fn cb, void *cb_data)
+{
+ struct string_list_item *item;
+ const struct string_list *preferred_tips;
+ struct strbuf buf = STRBUF_INIT;
+
+ preferred_tips = bitmap_preferred_tips(repo);
+ if (!preferred_tips)
+ return;
+
+ for_each_string_list_item(item, preferred_tips) {
+ const char *pattern = item->string;
+
+ if (!ends_with(pattern, "/")) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s/", pattern);
+ pattern = buf.buf;
+ }
+
+ refs_for_each_ref_in(get_main_ref_store(repo),
+ pattern, cb, cb_data);
+ }
+
+ strbuf_release(&buf);
+}
+
int bitmap_is_preferred_refname(struct repository *r, const char *refname)
{
const struct string_list *preferred_tips = bitmap_preferred_tips(r);
diff --git a/pack-bitmap.h b/pack-bitmap.h
index 1bd7a791e2..d0611d0481 100644
--- a/pack-bitmap.h
+++ b/pack-bitmap.h
@@ -5,6 +5,7 @@
#include "khash.h"
#include "pack.h"
#include "pack-objects.h"
+#include "refs.h"
#include "string-list.h"
struct commit;
@@ -99,6 +100,13 @@ int for_each_bitmapped_object(struct bitmap_index *bitmap_git,
show_reachable_fn show_reach,
void *payload);
+/*
+ * Iterate over all references that are configured as preferred bitmap tips via
+ * "pack.preferBitmapTips" and invoke the callback on each function.
+ */
+void for_each_preferred_bitmap_tip(struct repository *repo,
+ each_ref_fn cb, void *cb_data);
+
#define GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL \
"GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL"
@@ -182,7 +190,6 @@ char *pack_bitmap_filename(struct packed_git *p);
int bitmap_is_midx(struct bitmap_index *bitmap_git);
-const struct string_list *bitmap_preferred_tips(struct repository *r);
int bitmap_is_preferred_refname(struct repository *r, const char *refname);
int verify_bitmap_files(struct repository *r);
diff --git a/repack-midx.c b/repack-midx.c
index 74bdfa3a6e..0682b80c42 100644
--- a/repack-midx.c
+++ b/repack-midx.c
@@ -40,7 +40,6 @@ static int midx_snapshot_ref_one(const struct reference *ref, void *_data)
void midx_snapshot_refs(struct repository *repo, struct tempfile *f)
{
struct midx_snapshot_ref_data data;
- const struct string_list *preferred = bitmap_preferred_tips(repo);
data.repo = repo;
data.f = f;
@@ -51,16 +50,9 @@ void midx_snapshot_refs(struct repository *repo, struct tempfile *f)
die(_("could not open tempfile %s for writing"),
get_tempfile_path(f));
- if (preferred) {
- struct string_list_item *item;
-
- data.preferred = 1;
- for_each_string_list_item(item, preferred)
- refs_for_each_ref_in(get_main_ref_store(repo),
- item->string,
- midx_snapshot_ref_one, &data);
- data.preferred = 0;
- }
+ data.preferred = 1;
+ for_each_preferred_bitmap_tip(repo, midx_snapshot_ref_one, &data);
+ data.preferred = 0;
refs_for_each_ref(get_main_ref_store(repo),
midx_snapshot_ref_one, &data);
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 6718fb98c0..310b708c5c 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -466,6 +466,47 @@ test_bitmap_cases () {
)
'
+ test_expect_success 'pack.preferBitmapTips interprets patterns as hierarchy' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ # Create enough commits that not all will receive bitmap
+ # coverage even if they are all at the tip of some reference.
+ test_commit_bulk --message="%s" 103 &&
+ git log --format="create refs/tags/%s/tag %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ # Create the bitmap.
+ git repack -adb &&
+ test-tool bitmap list-commits | sort >commits-with-bitmap &&
+
+ # Verify that we have at least one commit that did not
+ # receive a bitmap.
+ git rev-list HEAD >commits.raw &&
+ sort <commits.raw >commits &&
+ comm -13 commits-with-bitmap commits >commits-wo-bitmap &&
+ test_file_not_empty commits-wo-bitmap &&
+ commit_id=$(head commits-wo-bitmap) &&
+ ref_without_bitmap=$(git for-each-ref --points-at="$commit_id" --format="%(refname)") &&
+
+ # When passing the full refname we do not expect a
+ # bitmap to be generated, as it should be interpreted
+ # as if a slash was appended to the pattern.
+ git -c pack.preferBitmapTips="$ref_without_bitmap" repack -adb &&
+ test-tool bitmap list-commits >after &&
+ test_grep ! "$commit_id" after &&
+
+ # But if we pass the parent directory of the ref we
+ # should see a bitmap.
+ ref_namespace=$(dirname "$ref_without_bitmap") &&
+ git -c pack.preferBitmapTips="$ref_namespace" repack -adb &&
+ test-tool bitmap list-commits >after &&
+ test_grep "$commit_id" after
+ )
+ '
+
test_expect_success 'complains about multiple pack bitmaps' '
rm -fr repo &&
git init repo &&
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index faae98c7e7..449353416f 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1345,4 +1345,47 @@ test_expect_success 'bitmapped packs are stored via the BTMP chunk' '
)
'
+test_expect_success 'pack.preferBitmapTips interprets patterns as hierarchy' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ # Create enough commits that not all will receive bitmap
+ # coverage even if they are all at the tip of some reference.
+ test_commit_bulk --message="%s" 103 &&
+ git log --format="create refs/tags/%s %H" HEAD >refs &&
+ git update-ref --stdin <refs &&
+
+ # Create the bitmap via the MIDX.
+ git repack -adb --write-midx &&
+ test-tool bitmap list-commits | sort >commits-with-bitmap &&
+
+ # Verify that we have at least one commit that did not
+ # receive a bitmap.
+ git rev-list HEAD >commits.raw &&
+ sort <commits.raw >commits &&
+ comm -13 commits-with-bitmap commits >commits-wo-bitmap &&
+ test_file_not_empty commits-wo-bitmap &&
+ commit_id=$(head commits-wo-bitmap) &&
+ ref_without_bitmap=$(git for-each-ref --points-at="$commit_id" --format="%(refname)") &&
+
+ # When passing the full refname we do not expect a bitmap to be
+ # generated, as it should be interpreted as if a slash was
+ # appended to the pattern.
+ rm .git/objects/pack/multi-pack-index* &&
+ git -c pack.preferBitmapTips="$ref_without_bitmap" repack -adb --write-midx &&
+ test-tool bitmap list-commits >after &&
+ test_grep ! "$commit_id" after &&
+
+ # But if we pass the parent directory of the ref we should see
+ # a bitmap.
+ ref_namespace=$(dirname "$ref_without_bitmap") &&
+ rm .git/objects/pack/multi-pack-index* &&
+ git -c pack.preferBitmapTips="$ref_namespace" repack -adb --write-midx &&
+ test-tool bitmap list-commits >after &&
+ test_grep "$commit_id" after
+ )
+'
+
test_done