repack: teach MIDX retention about geometric rollups

When writing an incremental MIDX, existing_packs_retain_midx_packs() marks packs in the existing MIDX chain as retained. This keeps them from being deleted by the later existing_packs deletion pass, since retained MIDX layers may still refer to those packs. Geometric repacks need a narrower rule. Packs below the split are rolled up into the newly-written pack, and should remain eligible for deletion even if the old MIDX chain mentions them. Packs above the split were marked as retained by the previous commit. Teach existing_packs_retain_midx_packs() to skip packs which are part of the geometric rollup. This does not change the current caller's behavior, since geometric repacks do not yet use the existing_packs deletion path. Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Jun 26, 2026 at 15:02 UTC 5ff781e9fa3cfea4ac008c7e0e06a5f720b78060
3 files changed +44 -4
builtin/repack.c
+1 -1
@@ -576,7 +576,7 @@ int cmd_repack(int argc,
576
577 if (delete_redundant && pack_everything & ALL_INTO_ONE) {
578 if (write_midx == REPACK_WRITE_MIDX_INCREMENTAL)
579 - existing_packs_retain_midx_packs(&existing);
579 + existing_packs_retain_midx_packs(&existing, &geometry);
580 existing_packs_mark_for_deletion(&existing, &names);
581 }
582
repack.c
+41 -2
@@ -292,6 +292,39 @@ void existing_packs_mark_for_deletion(struct existing_packs *existing,
292 &existing->cruft_packs);
293 }
294
295 +static int pack_geometry_contains_pack(struct packed_git **packs,
296 + uint32_t packs_nr,
297 + const char *base)
298 +{
299 + struct strbuf buf = STRBUF_INIT;
300 + uint32_t i;
301 +
302 + for (i = 0; i < packs_nr; i++) {
303 + strbuf_reset(&buf);
304 + strbuf_addstr(&buf, pack_basename(packs[i]));
305 + strbuf_strip_suffix(&buf, ".pack");
306 +
307 + if (!strcmp(buf.buf, base)) {
308 + strbuf_release(&buf);
309 + return 1;
310 + }
311 + }
312 +
313 + strbuf_release(&buf);
314 + return 0;
315 +}
316 +
317 +static int pack_geometry_contains_rollup(const struct pack_geometry *geometry,
318 + const char *base)
319 +{
320 + if (!geometry || !geometry->split_factor)
321 + return 0;
322 +
323 + return pack_geometry_contains_pack(geometry->pack, geometry->split, base) ||
324 + pack_geometry_contains_pack(geometry->promisor_pack,
325 + geometry->promisor_split, base);
326 +}
327 +
328 /*
329 * Mark every pack that is referenced by the existing MIDX chain as
330 * retained, so that a subsequent call to
@@ -300,9 +333,12 @@ void existing_packs_mark_for_deletion(struct existing_packs *existing,
333 * This is used when writing an incremental MIDX layer on top of an
334 * existing chain: retained layers continue to reference the same
335 * packs on disk, so those packs must not be unlinked even if the
303 - * freshly-written pack supersedes them.
336 + * freshly-written pack supersedes them. When doing a geometric repack,
337 + * packs below the split are rewritten into the new MIDX tip and should
338 + * remain eligible for deletion.
339 */
305 -void existing_packs_retain_midx_packs(struct existing_packs *existing)
340 +void existing_packs_retain_midx_packs(struct existing_packs *existing,
341 + const struct pack_geometry *geometry)
342 {
343 struct string_list_item *item;
344 struct strbuf buf = STRBUF_INIT;
@@ -315,6 +351,9 @@ void existing_packs_retain_midx_packs(struct existing_packs *existing)
351 strbuf_strip_suffix(&buf, ".pack");
352 strbuf_strip_suffix(&buf, ".idx");
353
354 + if (pack_geometry_contains_rollup(geometry, buf.buf))
355 + continue;
356 +
357 found = string_list_lookup(&existing->non_kept_packs, buf.buf);
358 if (found)
359 existing_packs_mark_retained(found);
repack.h
+2 -1
@@ -87,7 +87,8 @@ void existing_packs_retain_from_geometry(struct existing_packs *existing,
87 const struct pack_geometry *geometry);
88 void existing_packs_mark_for_deletion(struct existing_packs *existing,
89 struct string_list *names);
90 -void existing_packs_retain_midx_packs(struct existing_packs *existing);
90 +void existing_packs_retain_midx_packs(struct existing_packs *existing,
91 + const struct pack_geometry *geometry);
92 void existing_packs_remove_redundant(struct existing_packs *existing,
93 const char *packdir,
94 bool wrote_incremental_midx);