[PATCH 1/2] maintenance: account for promisor pack geometry

Taylor Blau <[email protected]> Tue, 4 Aug 2026 20:57:40 -0700
Newsgroups org.kernel.vger.git
Message-ID <a9de123b43efb58c53c99c71eb7e34f29e075071.1785902237.git.ttaylorr@openai.com>
Commit 9bc151850c (builtin/maintenance: introduce
"geometric-repack" task, 2025-10-24) added a new maintenance task to
perform either a geometric repack, or an all-into-one repack if the
geometric repack would itself produce a single pack.

Some time later, commit dcc9c7ef47 (builtin/repack: handle promisor
packs with geometric repacking, 2026-01-05) taught the geometric
repacking machinery to separate promisor packs from ordinary ones, but
did not update the maintenance task accordingly.

As a consequence, the geometric-repack maintenance task only considers
the non-promisor pack progression. It falls back to all-into-one
whenever a geometric repack would roll up all non-promisor packs into a
single pack, even if the promisor progression would keep a large pack
and roll up only smaller ones.

Check both progressions before choosing the repack mode. If either
leaves a pack above its split, geometric repack still avoids rewriting
that pack, whereas the all-into-one fallback would rewrite it. Use the
fallback only when neither progression leaves a pack behind. That
preserves the reason for the fallback: let the all-into-one repack
handle unreachable objects when it is not rewriting more packs than the
geometric repack.

Signed-off-by: Taylor Blau <[email protected]>
---
 builtin/gc.c           |  3 ++-
 t/t7900-maintenance.sh | 45 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/builtin/gc.c b/builtin/gc.c
index 49c8474fad..ed75c12c43 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -1593,7 +1593,8 @@ static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts,
 	child.odb_to_close = the_repository->objects;
 
 	strvec_pushl(&child.args, "repack", "-d", "-l", NULL);
-	if (geometry.split < geometry.pack_nr)
+	if (geometry.split < geometry.pack_nr ||
+	    geometry.promisor_split < geometry.promisor_pack_nr)
 		strvec_pushf(&child.args, "--geometric=%d",
 			     geometry.split_factor);
 	else
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index a8d691719d..ba5b359e77 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -659,6 +659,51 @@ test_expect_success 'geometric repacking task' '
 	)
 '
 
+objdir=.git/objects
+packdir=$objdir/pack
+
+pack_promisor () {
+	p="$(echo "$@" | git pack-objects --revs $packdir/pack)" &&
+	touch "$packdir/pack-$p.promisor" &&
+	echo "$p"
+}
+
+test_expect_success 'geometric repacking task handles promisor packs' '
+	test_when_finished "rm -rf repo" &&
+	git init repo &&
+	(
+		cd repo &&
+		git config set maintenance.auto false &&
+		git remote add promisor garbage &&
+		git config set remote.promisor.promisor true &&
+
+		for n in $(test_seq 6)
+		do
+			test_commit $n || return 1
+		done &&
+
+		A="$(pack_promisor 1)" &&
+		B="$(pack_promisor 1..2)" &&
+		C="$(pack_promisor 2..6)" &&
+		git prune-packed &&
+
+		ls $packdir/pack-*.promisor | sort >promisors.before &&
+		GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
+			git maintenance run --quiet --task=geometric-repack &&
+		ls $packdir/pack-*.promisor | sort >promisors.after &&
+
+		test_subcommand git repack -d -l --geometric=2 \
+			--quiet --write-midx <trace2.txt &&
+
+		test_line_count = 2 promisors.after &&
+
+		printf "$packdir/pack-%s.promisor\n" "$A" "$B" | sort >expect &&
+		comm -23 promisors.before promisors.after >actual &&
+
+		test_cmp expect actual
+	)
+'
+
 test_geometric_repack_needed () {
 	NEEDED="$1"
 	GEOMETRIC_CONFIG="$2" &&
-- 
2.55.0.483.gdc2fffc37c