From: Siddharth Shrimali Date: Thu, 16 Jul 2026 13:28:46 GMT Subject: [RFC PATCH 5/7] t7706: test --drop-filtered enumeration and validation Message-ID: <20260716132848.95982-6-r.siddharth.shrimali@gmail.com> In-Reply-To: <20260716132848.95982-1-r.siddharth.shrimali@gmail.com> Add tests for the --drop-filtered option. * Validation: --drop-filtered requires --filter and -a, is incompatible with --filter-to and --write-bitmap-index, --dry-run only takes effect with --drop-filtered, and --drop-filtered requires a promisor remote. * Enumeration: in a repository with a promisor remote, --dry-run lists promisor blobs above the filter threshold and excludes smaller ones. Promisor blobs are created with a synthetic promisor pack, following the helper pattern used in t0410. * Safety: a locally created large blob, which is not a promisor object and therefore not recoverable from the remote, is never listed as a drop candidate. * Non-destructiveness: --dry-run leaves the filtered objects intact in the repository. Mentored-by: Christian Couder Mentored-by: Siddharth Asthana Signed-off-by: Siddharth Shrimali --- t/meson.build | 1 + t/t7706-repack-drop-filtered.sh | 139 ++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100755 t/t7706-repack-drop-filtered.sh diff --git a/t/meson.build b/t/meson.build index 8ae6ab6c5f..37f272d7f4 100644 --- a/t/meson.build +++ b/t/meson.build @@ -962,6 +962,7 @@ integration_tests = [ 't7703-repack-geometric.sh', 't7704-repack-cruft.sh', 't7705-repack-incremental-midx.sh', + 't7706-repack-drop-filtered.sh', 't7800-difftool.sh', 't7810-grep.sh', 't7811-grep-open.sh', diff --git a/t/t7706-repack-drop-filtered.sh b/t/t7706-repack-drop-filtered.sh new file mode 100755 index 0000000000..b558807847 --- /dev/null +++ b/t/t7706-repack-drop-filtered.sh @@ -0,0 +1,139 @@ +#!/bin/sh + +test_description='git repack --drop-filtered enumerates +filtered promisor blobs' + +. ./test-lib.sh + +delete_object () { + local repo="$1" && + local obj="$2" && + local path="$repo/.git/objects/$(test_oid_to_path "$obj")" && + rm "$path" +} + +# pack the objects into a promisor pack inside "repo", +# it is a pack accompanied by an empty ".promisor" marker file. objects +# in such a pack are treated as recoverable from the promisor remote. +pack_as_from_promisor () { + HASH=$(git -C repo pack-objects .git/objects/pack/pack) && + >repo/.git/objects/pack/pack-$HASH.promisor && + echo $HASH +} + +# write a blob of $1 bytes into "repo", record it as coming from the +# promisor remote (promisor pack), and remove the loose copy so the +# object is only present in the promisor pack. +promisor_blob () { + test-tool genrandom "$1" "$2" >blob_content && + OID=$(git -C repo hash-object -w --stdin /dev/null && + delete_object repo "$OID" && + echo "$OID" +} + +# checks for options validations before any promisor walk +test_expect_success 'setup plain repo for validation' ' + git init plain && + test_commit -C plain initial && + git clone --bare plain plain.git && + git -C plain.git repack -a -d +' + +test_expect_success '--drop-filtered requires --filter' ' + test_must_fail git -C plain.git repack --drop-filtered --dry-run -a 2>err && + test_grep "drop-filtered requires --filter" err +' + +test_expect_success '--drop-filtered cannot be used with --filter-to' ' + test_must_fail git -C plain.git repack --drop-filtered \ + --filter=blob:limit=1k --filter-to=./filter-out 2>err && + test_grep "options .--drop-filtered. and .--filter-to. cannot be used together" err +' + +test_expect_success '--dry-run only takes effect with --drop-filtered' ' + test_must_fail git -C plain.git repack --dry-run 2>err && + test_grep "dry-run only takes effect with --drop-filtered" err +' + +test_expect_success '--drop-filtered without --dry-run is rejected' ' + test_must_fail git -C plain.git repack --drop-filtered \ + --filter=blob:limit=1k -a 2>err && + test_grep "drop-filtered doesn.t work without --dry-run yet" err +' + +test_expect_success '--drop-filtered requires -a' ' + test_must_fail git -C plain.git repack --drop-filtered \ + --filter=blob:limit=1k --dry-run 2>err && + test_grep "drop-filtered requires -a" err +' + +test_expect_success '--drop-filtered fails with --write-bitmap-index' ' + test_must_fail git -C plain.git repack --drop-filtered \ + --filter=blob:limit=1k --dry-run -a -b 2>err && + test_grep "options .--drop-filtered. and .--write-bitmap-index. cannot be used together" err +' + +test_expect_success '--drop-filtered fails without a promisor remote' ' + test_must_fail git -C plain.git repack --drop-filtered \ + --filter=blob:limit=1k --dry-run -a 2>err && + test_grep "drop-filtered requires a promisor remote" err +' + +# enumeration and safety tests using promisor packs +test_expect_success 'setup repo with a promisor remote' ' + rm -rf repo && + test_create_repo repo && + test_commit -C repo base && + + # mark the repo as a partial clone with a promisor remote so the + # promisor walk and the safety guard are satisfied. + git -C repo config core.repositoryformatversion 1 && + git -C repo config extensions.partialclone origin && + git -C repo config remote.origin.promisor true && + git -C repo config remote.origin.url "." && + + BIG=$(promisor_blob big 3072) && + SMALL=$(promisor_blob small 512) && + echo "$BIG" >big_oid && + echo "$SMALL" >small_oid +' + +test_expect_success 'promisor blob over the threshold is listed' ' + BIG=$(cat big_oid) && + SMALL=$(cat small_oid) && + + git -C repo -c repack.writeBitmaps=false \ + repack --drop-filtered --filter=blob:limit=1k --dry-run -a >out && + + test_grep "$BIG" out && + test_grep ! "$SMALL" out +' + +test_expect_success 'locally created blob is never listed' ' + BIG=$(cat big_oid) && + + # large blob that exists only locally (no promisor pack) must + # never be a drop candidate: dropping it would be unrecoverable + # data loss. + test-tool genrandom local 4096 >local_content && + LOCAL=$(git -C repo hash-object -w --stdin out && + + test_grep "$BIG" out && + test_grep ! "$LOCAL" out +' + +test_expect_success '--dry-run does not remove the filtered objects' ' + BIG=$(cat big_oid) && + + git -C repo -c repack.writeBitmaps=false \ + repack --drop-filtered --filter=blob:limit=1k --dry-run -a >out && + + # candidate blob must still be present after a dry run. + git -C repo cat-file -e "$BIG" +' + +test_done -- 2.54.0