From facedc705c8aaafbca31f5047ba0b877490008b3 Mon Sep 17 00:00:00 2001 From: Siddharth Shrimali Date: Sat, 17 Oct 2026 00:43:44 +0530 Subject: [PATCH] repack: do not rebuild packs on --dry-run "git repack --drop-filtered --dry-run" is documented to list the objects that would be dropped "without rebuilding any pack or deleting anything", but it does both. This is a bug in cmd_repack(): after printing the candidates, the --dry-run block falls through into the regular repack code. repack_promisor_objects() writes a new promisor pack, and with -d, existing_packs_remove_redundant() deletes the old packs. The existing guard only skips the implied "delete_redundant = 1", so it does not stop an explicit -d, and it does not stop the new pack from being written either. This has been broken since --dry-run was introduced in 1e746b00aa (builtin/repack: add --drop-filtered and --dry-run options). The --dry-run block never returned early, so a dry run has always gone on to do a regular repack. It was not broken by a later change. Fix it by returning right after the candidates are listed, and add a test that checks the pack directory is unchanged with and without -d. A dry run can no longer get past that point, so the two "!dry_run" checks that tried to keep it from deleting or dropping anything are now redundant. Reported-by: Coy Geek Helped-by: D. Ben Knoble Helped-by: Patrick Steinhardt Signed-off-by: Siddharth Shrimali Signed-off-by: Junio C Hamano --- builtin/repack.c | 14 ++++++++++---- t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/builtin/repack.c b/builtin/repack.c index c4360382c1..19894804f0 100644 --- a/builtin/repack.c +++ b/builtin/repack.c @@ -351,10 +351,9 @@ int cmd_repack(int argc, /* * Dropping objects means rebuilding the promisor packs * without them and then removing the old packs, so the - * redundant packs must be deleted. Imply -d on a real run. + * redundant packs must be deleted. Imply -d. */ - if (!dry_run) - delete_redundant = 1; + delete_redundant = 1; ret = enumerate_promisor_blobs(repo, &po_args.filter_options, &drop_oids); @@ -391,6 +390,13 @@ int cmd_repack(int argc, oidset_iter_init(&drop_oids, &iter); while ((oid = oidset_iter_next(&iter))) printf("%s\n", oid_to_hex(oid)); + + /* + * Only list the candidates to be dropped; skip + * the actual repack + */ + ret = 0; + goto cleanup; } } @@ -505,7 +511,7 @@ int cmd_repack(int argc, if (pack_everything & ALL_INTO_ONE) { repack_promisor_objects(repo, &po_args, &names, packtmp, - (drop_filtered && !dry_run) ? &drop_oids : NULL); + drop_filtered ? &drop_oids : NULL); if (existing_packs_has_non_kept(&existing) && delete_redundant && diff --git a/t/t7706-repack-drop-filtered.sh b/t/t7706-repack-drop-filtered.sh index cb36115834..a1c475e4ec 100755 --- a/t/t7706-repack-drop-filtered.sh +++ b/t/t7706-repack-drop-filtered.sh @@ -135,6 +135,25 @@ test_expect_success '--dry-run does not remove the filtered objects' ' git -C repo cat-file -e "$BIG" ' +test_expect_success '--dry-run leaves the pack directory untouched' ' + BIG=$(cat big_oid) && + packdir=repo/.git/objects/pack && + + for opt in "" -d + do + ls $packdir >before && + + git -C repo -c repack.writeBitmaps=false \ + repack --drop-filtered --filter=blob:limit=1k \ + --dry-run -a $opt >out && + + ls $packdir >after && + test_cmp before after && + test_grep "$BIG" out && + git -C repo cat-file -e "$BIG" || return 1 + done +' + test_expect_success '--drop-filtered removes the promisor blob locally' ' BIG=$(cat big_oid) && SMALL=$(cat small_oid) &&