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/pack-bitmap.c b/pack-bitmap.c index 2f5cb34009..1c93871484 100644 --- a/pack-bitmap.c +++ b/pack-bitmap.c @@ -3328,15 +3328,26 @@ void for_each_preferred_bitmap_tip(struct repository *repo, { 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), - item->string, cb, cb_data); + pattern, cb, cb_data); } + + strbuf_release(&buf); } int bitmap_is_preferred_refname(struct repository *r, const char *refname) 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 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 && + 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 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 && + 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