All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] repack: do not rebuild packs on --dry-run
@ 2026-10-08  6:25 Siddharth Shrimali
  2026-10-08 12:56 ` D. Ben Knoble
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-08  6:25 UTC (permalink / raw)
  To: git; +Cc: coygeek, ben.knoble, r.siddharth.shrimali

"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 command
still exits successfully, so the user is not told that the repository
was modified.

The existing guard only skips the implied "delete_redundant = 1", so
it does not stop an explicit -d, nor the new pack from being written.

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>
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
---
Bug report:
https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/

 builtin/repack.c                |  8 ++++++++
 t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/builtin/repack.c b/builtin/repack.c
index c4360382c1..c048053912 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -391,6 +391,14 @@ int cmd_repack(int argc,
 			oidset_iter_init(&drop_oids, &iter);
 			while ((oid = oidset_iter_next(&iter)))
 				printf("%s\n", oid_to_hex(oid));
+
+			/*
+			 * add an exit here, so that dry run does not
+			 * go on to rebuild any pack or delete anything, even
+			 * if the user explicitly asked for -d
+			 */
+			ret = 0;
+			goto cleanup;
 		}
 	}
 
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) &&
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] repack: do not rebuild packs on --dry-run
  2026-10-08  6:25 [PATCH] repack: do not rebuild packs on --dry-run Siddharth Shrimali
@ 2026-10-08 12:56 ` D. Ben Knoble
  2026-10-10 19:53   ` Siddharth Shrimali
  2026-10-08 14:23 ` Junio C Hamano
  2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
  2 siblings, 1 reply; 12+ messages in thread
From: D. Ben Knoble @ 2026-10-08 12:56 UTC (permalink / raw)
  To: Siddharth Shrimali; +Cc: git, coygeek

Hi Siddharth,

On Thu, Oct 8, 2026 at 2:25 AM Siddharth Shrimali
<r.siddharth.shrimali@gmail.com> wrote:
>
> "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 command
> still exits successfully, so the user is not told that the repository
> was modified.
>
> The existing guard only skips the implied "delete_redundant = 1", so
> it does not stop an explicit -d, nor the new pack from being written.
>
> 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.

Makes sense

> Reported-by: Coy Geek <coygeek@gmail.com>
> Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
> ---
> Bug report:
> https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/
>
>  builtin/repack.c                |  8 ++++++++
>  t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
>  2 files changed, 27 insertions(+)
>
> diff --git a/builtin/repack.c b/builtin/repack.c
> index c4360382c1..c048053912 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -391,6 +391,14 @@ int cmd_repack(int argc,
>                         oidset_iter_init(&drop_oids, &iter);
>                         while ((oid = oidset_iter_next(&iter)))
>                                 printf("%s\n", oid_to_hex(oid));

Just outside the patch context is the "if (dry_run)" conditional, so
this is the right place. (In this case, formatting with a larger "-U"
value might help.)

> +
> +                       /*
> +                        * add an exit here, so that dry run does not
> +                        * go on to rebuild any pack or delete anything, even
> +                        * if the user explicitly asked for -d
> +                        */

2 notes:

1. "add an exit" will stop making sense as soon as the patch becomes a
commit; that is, it only makes sense in the context of proposed
changes. Once those changes are part of the code base, the comment and
code are not adding anything. They simply are. So, if we need a
comment (see 2), it might be best phrased as "exit here so that […]",
keeping some of your original wording. Or we could be more terse:
"skip non-dry-run operations" or something.
2. Do we need such a comment, I wonder? git-blame will point folks
towards this commit :)

> +                       ret = 0;
> +                       goto cleanup;

This matches the pattern elsewhere in this procedure, so that looks good.

>                 }
>         }
>
> 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) &&
> --
> 2.56.0

Thanks for adding a test to cover this. It looks reasonable to me, but
I didn't study the surrounding tests to think very critically about
it.

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] repack: do not rebuild packs on --dry-run
  2026-10-08  6:25 [PATCH] repack: do not rebuild packs on --dry-run Siddharth Shrimali
  2026-10-08 12:56 ` D. Ben Knoble
@ 2026-10-08 14:23 ` Junio C Hamano
  2026-10-10 20:05   ` Siddharth Shrimali
  2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
  2 siblings, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2026-10-08 14:23 UTC (permalink / raw)
  To: Siddharth Shrimali; +Cc: git, coygeek, ben.knoble

Siddharth Shrimali <r.siddharth.shrimali@gmail.com> writes:

> "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 command
> still exits successfully, so the user is not told that the repository
> was modified.

Very interesting finding.  I am curious if this was the case from
the beginning, or we broke --dry-run unknowingly as a side effect of
some unrelated changes.  If it is not too much, can you bisect and
document where we broke it in the log message?

> The existing guard only skips the implied "delete_redundant = 1", so
> it does not stop an explicit -d, nor the new pack from being written.
>
> 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>
> Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
> ---
> Bug report:
> https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/
>
>  builtin/repack.c                |  8 ++++++++
>  t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
>  2 files changed, 27 insertions(+)
>
> diff --git a/builtin/repack.c b/builtin/repack.c
> index c4360382c1..c048053912 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -391,6 +391,14 @@ int cmd_repack(int argc,
>  			oidset_iter_init(&drop_oids, &iter);
>  			while ((oid = oidset_iter_next(&iter)))
>  				printf("%s\n", oid_to_hex(oid));
> +
> +			/*
> +			 * add an exit here, so that dry run does not
> +			 * go on to rebuild any pack or delete anything, even
> +			 * if the user explicitly asked for -d
> +			 */
> +			ret = 0;
> +			goto cleanup;
>  		}
>  	}
>  
> 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) &&

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] repack: do not rebuild packs on --dry-run
  2026-10-08 12:56 ` D. Ben Knoble
@ 2026-10-10 19:53   ` Siddharth Shrimali
  0 siblings, 0 replies; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-10 19:53 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: git, coygeek, Junio C Hamano

Hi Ben,

On Thu, 8 Oct 2026 at 18:26, D. Ben Knoble <ben.knoble@gmail.com> wrote:
> Just outside the patch context is the "if (dry_run)" conditional, so
> this is the right place. (In this case, formatting with a larger "-U"
> value might help.)
Thanks, Ben! I will do that in v2

> > +
> > +                       /*
> > +                        * add an exit here, so that dry run does not
> > +                        * go on to rebuild any pack or delete anything, even
> > +                        * if the user explicitly asked for -d
> > +                        */
>
> 2 notes:
>
> 1. "add an exit" will stop making sense as soon as the patch becomes a
> commit; that is, it only makes sense in the context of proposed
> changes. Once those changes are part of the code base, the comment and
> code are not adding anything. They simply are. So, if we need a
> comment (see 2), it might be best phrased as "exit here so that […]",
> keeping some of your original wording. Or we could be more terse:
> "skip non-dry-run operations" or something.
> 2. Do we need such a comment, I wonder? git-blame will point folks
> towards this commit :)
>
Oh yeah right, it will stop making sense without any context.
Yeah git blame does the thing, but I feel like adding a short comment for that

Will send a v2 soon

Thanks,
Siddharth

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] repack: do not rebuild packs on --dry-run
  2026-10-08 14:23 ` Junio C Hamano
@ 2026-10-10 20:05   ` Siddharth Shrimali
  0 siblings, 0 replies; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-10 20:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, coygeek, ben.knoble

Hi Junio,

On Thu, 8 Oct 2026 at 19:53, Junio C Hamano <gitster@pobox.com> wrote:
> Very interesting finding.  I am curious if this was the case from
> the beginning, or we broke --dry-run unknowingly as a side effect of
> some unrelated changes.  If it is not too much, can you bisect and
> document where we broke it in the log message?

unfortunately, this was a mistake on my end and it has been broken
since --dry-run was introduced in 1e746b00aa. the --dry-run
block never returned early, so it always went on to do a regular
repack, including the deletion when -d is given explicitly.

I will document this in the log message in v2

Thanks,
Siddharth

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2] repack: do not rebuild packs on --dry-run
  2026-10-08  6:25 [PATCH] repack: do not rebuild packs on --dry-run Siddharth Shrimali
  2026-10-08 12:56 ` D. Ben Knoble
  2026-10-08 14:23 ` Junio C Hamano
@ 2026-10-10 21:00 ` Siddharth Shrimali
  2026-10-10 21:06   ` Ben Knoble
                     ` (2 more replies)
  2 siblings, 3 replies; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-10 21:00 UTC (permalink / raw)
  To: git; +Cc: coygeek, ben.knoble, gitster, r.siddharth.shrimali

"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.

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>
---
Bug report:
https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/

Changes since v1:
 - reworded the comment
 - documented the bug in the log message

 builtin/repack.c                |  7 +++++++
 t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/builtin/repack.c b/builtin/repack.c
index c4360382c1..7797972642 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -387,14 +387,21 @@ int cmd_repack(int argc,
 		if (dry_run) {
 			struct oidset_iter iter;
 			const struct object_id *oid;
 
 			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;
 		}
 	}
 
 	if (delete_redundant && repo->repository_format_precious_objects)
 		die(_("cannot delete packs in a precious-objects repo"));
 
 	die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
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
@@ -131,14 +131,33 @@ test_expect_success '--dry-run does not remove the filtered objects' '
 	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_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) &&
 
 	git -C repo -c repack.writeBitmaps=false \
 		repack --drop-filtered --filter=blob:limit=1k -a &&
 
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] repack: do not rebuild packs on --dry-run
  2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
@ 2026-10-10 21:06   ` Ben Knoble
  2026-10-11  5:57     ` Junio C Hamano
  2026-10-13 11:30   ` Patrick Steinhardt
  2026-10-16 19:13   ` [PATCH v3] " Siddharth Shrimali
  2 siblings, 1 reply; 12+ messages in thread
From: Ben Knoble @ 2026-10-10 21:06 UTC (permalink / raw)
  To: Siddharth Shrimali; +Cc: git, coygeek, gitster, r.siddharth.shrimali


> Le 10 oct. 2026 à 17:01, Siddharth Shrimali <r.siddharth.shrimali@gmail.com> a écrit :
> 
> "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.
> 
> 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>
> ---
> Bug report:
> https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/
> 
> Changes since v1:
> - reworded the comment
> - documented the bug in the log message

Thanks, I’m happy with this version. You may add my Reviewed-by, if you like

> builtin/repack.c                |  7 +++++++
> t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
> 2 files changed, 26 insertions(+)
> 
> diff --git a/builtin/repack.c b/builtin/repack.c
> index c4360382c1..7797972642 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -387,14 +387,21 @@ int cmd_repack(int argc,
>        if (dry_run) {
>            struct oidset_iter iter;
>            const struct object_id *oid;
> 
>            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;
>        }
>    }
> 
>    if (delete_redundant && repo->repository_format_precious_objects)
>        die(_("cannot delete packs in a precious-objects repo"));
> 
>    die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
> 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
> @@ -131,14 +131,33 @@ test_expect_success '--dry-run does not remove the filtered objects' '
>    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_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) &&
> 
>    git -C repo -c repack.writeBitmaps=false \
>        repack --drop-filtered --filter=blob:limit=1k -a &&
> 
> --
> 2.56.0
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] repack: do not rebuild packs on --dry-run
  2026-10-10 21:06   ` Ben Knoble
@ 2026-10-11  5:57     ` Junio C Hamano
  0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-10-11  5:57 UTC (permalink / raw)
  To: Ben Knoble; +Cc: Siddharth Shrimali, git, coygeek

Ben Knoble <ben.knoble@gmail.com> writes:

>>  ...
>> 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>
>> ---
>> Bug report:
>> https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/
>> 
>> Changes since v1:
>> - reworded the comment
>> - documented the bug in the log message
>
> Thanks, I’m happy with this version. You may add my Reviewed-by, if you like

Thanks for writing and reviewing.  Let me mark the topic for 'next'.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] repack: do not rebuild packs on --dry-run
  2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
  2026-10-10 21:06   ` Ben Knoble
@ 2026-10-13 11:30   ` Patrick Steinhardt
  2026-10-16 18:15     ` Siddharth Shrimali
  2026-10-16 19:13   ` [PATCH v3] " Siddharth Shrimali
  2 siblings, 1 reply; 12+ messages in thread
From: Patrick Steinhardt @ 2026-10-13 11:30 UTC (permalink / raw)
  To: Siddharth Shrimali; +Cc: git, coygeek, ben.knoble, gitster

On Sun, Oct 11, 2026 at 02:30:50AM +0530, Siddharth Shrimali wrote:
>  builtin/repack.c                |  7 +++++++
>  t/t7706-repack-drop-filtered.sh | 19 +++++++++++++++++++
>  2 files changed, 26 insertions(+)
> 
> diff --git a/builtin/repack.c b/builtin/repack.c
> index c4360382c1..7797972642 100644
> --- a/builtin/repack.c
> +++ b/builtin/repack.c
> @@ -387,14 +387,21 @@ int cmd_repack(int argc,
>  		if (dry_run) {
>  			struct oidset_iter iter;
>  			const struct object_id *oid;
>  
>  			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;
>  		}
>  	}

Okay, makes sense. I wonder though, we later have a check like this:

	if (pack_everything & ALL_INTO_ONE) {
		repack_promisor_objects(repo, &po_args, &names, packtmp,
			(drop_filtered && !dry_run) ? &drop_oids : NULL);

Is the `!dry_run` check redundant now because of the above early exit?

Patrick

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2] repack: do not rebuild packs on --dry-run
  2026-10-13 11:30   ` Patrick Steinhardt
@ 2026-10-16 18:15     ` Siddharth Shrimali
  0 siblings, 0 replies; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-16 18:15 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: git, coygeek, ben.knoble, gitster

Hi Patrick,
Sorry for the late reply, I was a bit occupied with my university work.

On Tue, 13 Oct 2026 at 17:00, Patrick Steinhardt <ps@pks.im> wrote:
> Okay, makes sense. I wonder though, we later have a check like this:
>
>         if (pack_everything & ALL_INTO_ONE) {
>                 repack_promisor_objects(repo, &po_args, &names, packtmp,
>                         (drop_filtered && !dry_run) ? &drop_oids : NULL);
>
> Is the `!dry_run` check redundant now because of the above early exit?

oh yes, now that we have an early exit, a dry run never gets past
the candidate listing, so dry_run is always false by the time we
reach repack_promisor_objects(). the same applies to the earlier

    if (!dry_run)
        delete_redundant = 1;

since nothing reads delete_redundant before the early exit

I will drop both checks in v3.

Thanks,
Siddharth

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3] repack: do not rebuild packs on --dry-run
  2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
  2026-10-10 21:06   ` Ben Knoble
  2026-10-13 11:30   ` Patrick Steinhardt
@ 2026-10-16 19:13   ` Siddharth Shrimali
  2026-10-16 20:47     ` Junio C Hamano
  2 siblings, 1 reply; 12+ messages in thread
From: Siddharth Shrimali @ 2026-10-16 19:13 UTC (permalink / raw)
  To: git; +Cc: coygeek, ben.knoble, gitster, ps, r.siddharth.shrimali

"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 <coygeek@gmail.com>
Helped-by: D. Ben Knoble <ben.knoble@gmail.com>
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
---
Bug report:
https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/

Changes since v2:
 - dropped the "!dry_run" checks around the implied -d and the
   repack_promisor_objects() call, which the early return made
   redundant

 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
@@ -347,18 +347,17 @@ int cmd_repack(int argc,
 		}
 
 		write_bitmaps = 0;
 
 		/*
 		 * 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);
 
 		if (ret)
 			goto cleanup;
 
 		/*
@@ -387,14 +386,21 @@ int cmd_repack(int argc,
 		if (dry_run) {
 			struct oidset_iter iter;
 			const struct object_id *oid;
 
 			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;
 		}
 	}
 
 	if (delete_redundant && repo->repository_format_precious_objects)
 		die(_("cannot delete packs in a precious-objects repo"));
 
 	die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
@@ -501,15 +507,15 @@ int cmd_repack(int argc,
 			strvec_push(&cmd.args, "--write-bitmap-index-quiet");
 	}
 	if (use_delta_islands)
 		strvec_push(&cmd.args, "--delta-islands");
 
 	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 &&
 		    !(pack_everything & PACK_CRUFT)) {
 			for_each_string_list_item(item, &names) {
 				strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
 					     packtmp_name, item->string);
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
@@ -131,14 +131,33 @@ test_expect_success '--dry-run does not remove the filtered objects' '
 	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_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) &&
 
 	git -C repo -c repack.writeBitmaps=false \
 		repack --drop-filtered --filter=blob:limit=1k -a &&
 
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3] repack: do not rebuild packs on --dry-run
  2026-10-16 19:13   ` [PATCH v3] " Siddharth Shrimali
@ 2026-10-16 20:47     ` Junio C Hamano
  0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2026-10-16 20:47 UTC (permalink / raw)
  To: Siddharth Shrimali; +Cc: git, coygeek, ben.knoble, ps

Siddharth Shrimali <r.siddharth.shrimali@gmail.com> writes:

> "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.

As a part of an answer to a question "was this broken from the
beginning, or is it a regression?", the last sentence may have
value, but as part of a standalone proposed log message, it sounds
weird, don't you think?  You already clearly said this was broken
since the beginning.

> 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.

Makes sense.

> 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.

This makes sense as an explanation on the differences between v2 and
v3, but for those who are reading v3 standalone (which are our
primary target audience, i.e., those who read "git log -p" in the
future), it is on the borderline redundant, as it is a natural part
of what you already described, i.e., return right after giving a
list without doing anything.

Will queue as-is.  I think it is good enough, even though I did
nitpick a couple of points in the above.

Thanks.

> Reported-by: Coy Geek <coygeek@gmail.com>
> Helped-by: D. Ben Knoble <ben.knoble@gmail.com>
> Helped-by: Patrick Steinhardt <ps@pks.im>
> Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
> ---
> Bug report:
> https://lore.kernel.org/git/CACgTecOm+=vbf50tZNXhcYvRi1ZTsQwbjVoJAbQqs2CmXdJCxg@mail.gmail.com/
>
> Changes since v2:
>  - dropped the "!dry_run" checks around the implied -d and the
>    repack_promisor_objects() call, which the early return made
>    redundant

>  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
> @@ -347,18 +347,17 @@ int cmd_repack(int argc,
>  		}
>  
>  		write_bitmaps = 0;
>  
>  		/*
>  		 * 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);
>  
>  		if (ret)
>  			goto cleanup;
>  
>  		/*
> @@ -387,14 +386,21 @@ int cmd_repack(int argc,
>  		if (dry_run) {
>  			struct oidset_iter iter;
>  			const struct object_id *oid;
>  
>  			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;
>  		}
>  	}
>  
>  	if (delete_redundant && repo->repository_format_precious_objects)
>  		die(_("cannot delete packs in a precious-objects repo"));
>  
>  	die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
> @@ -501,15 +507,15 @@ int cmd_repack(int argc,
>  			strvec_push(&cmd.args, "--write-bitmap-index-quiet");
>  	}
>  	if (use_delta_islands)
>  		strvec_push(&cmd.args, "--delta-islands");
>  
>  	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 &&
>  		    !(pack_everything & PACK_CRUFT)) {
>  			for_each_string_list_item(item, &names) {
>  				strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
>  					     packtmp_name, item->string);
> 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
> @@ -131,14 +131,33 @@ test_expect_success '--dry-run does not remove the filtered objects' '
>  	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_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) &&
>  
>  	git -C repo -c repack.writeBitmaps=false \
>  		repack --drop-filtered --filter=blob:limit=1k -a &&

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-10-16 20:47 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-08  6:25 [PATCH] repack: do not rebuild packs on --dry-run Siddharth Shrimali
2026-10-08 12:56 ` D. Ben Knoble
2026-10-10 19:53   ` Siddharth Shrimali
2026-10-08 14:23 ` Junio C Hamano
2026-10-10 20:05   ` Siddharth Shrimali
2026-10-10 21:00 ` [PATCH v2] " Siddharth Shrimali
2026-10-10 21:06   ` Ben Knoble
2026-10-11  5:57     ` Junio C Hamano
2026-10-13 11:30   ` Patrick Steinhardt
2026-10-16 18:15     ` Siddharth Shrimali
2026-10-16 19:13   ` [PATCH v3] " Siddharth Shrimali
2026-10-16 20:47     ` Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.