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,
2026-08-14).  The --dry-run block never returned early, so a dry run
has always gone on to do a regular repack.

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.

Reported-by: Coy Geek <coygeek@gmail.com>
Helped-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
jch
Siddharth Shrimali 2026-10-11 02:30:50 +05:30 committed by Junio C Hamano
parent a018953688
commit e33f507164
2 changed files with 26 additions and 0 deletions

View File

@ -391,6 +391,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;
}
}


View File

@ -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) &&