From 8d0a01e9d83b4d806477733c2d6874eaf5f4eb38 Mon Sep 17 00:00:00 2001 From: Pia Park Date: Tue, 8 Sep 2026 00:10:16 -0700 Subject: [PATCH] midx-write: skip writes with no object entries A MIDX write can find packs without finding any objects, either because the packs are empty or because an incremental write finds only objects already indexed by an earlier layer. The existing early exit checks only the number of packs, so these cases publish a zero-object MIDX without a reverse index. Empty MIDXs were already published by 662148c435 (midx: write object offsets, 2018-07-12); the failure mode appeared in 27afc272c4 (midx: implement writing incremental MIDX bitmaps, 2025-03-20), when incremental bitmap writes began loading reverse indexes from prior layers. Reproducible on master as of b8242b093d (The 23rd batch, 2026-09-07), starting with a non-incremental write: git init --bare --object-format=sha1 empty.git && ( cd empty.git && git pack-objects objects/pack/pack Signed-off-by: Junio C Hamano --- midx-write.c | 5 +- t/t5319-multi-pack-index.sh | 35 ++++++++++++ t/t5326-multi-pack-bitmaps.sh | 13 +++-- t/t5334-incremental-multi-pack-index.sh | 75 +++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 9 deletions(-) diff --git a/midx-write.c b/midx-write.c index 8537102254..3038bbfad2 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1617,9 +1617,8 @@ static int write_midx_internal(struct write_midx_opts *opts) } if (!ctx.entries_nr) { - if (opts->flags & MIDX_WRITE_BITMAP) - warning(_("refusing to write multi-pack .bitmap without any objects")); - opts->flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP); + result = 0; + goto cleanup; } if (ctx.incremental) { diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh index 2b8ff6f3ed..931182ba2c 100755 --- a/t/t5319-multi-pack-index.sh +++ b/t/t5319-multi-pack-index.sh @@ -54,6 +54,41 @@ test_expect_success "don't write midx with no packs" ' test_path_is_missing pack/multi-pack-index ' +test_expect_success 'skip non-incremental MIDX with no objects' ' + git init --bare empty.git && + ( + cd empty.git && + git pack-objects objects/pack/pack files.expect && + + for bitmap in "" --bitmap + do + git multi-pack-index write $bitmap >out 2>&1 && + test_must_be_empty out && + test_path_is_missing objects/pack/multi-pack-index && + ls objects/pack >files.actual && + test_cmp files.expect files.actual || return 1 + done && + + git multi-pack-index write --incremental --bitmap && + test_dir_is_empty objects/pack/multi-pack-index.d && + + echo blob | git hash-object -w --stdin >in && + git pack-objects objects/pack/pack in && + git pack-objects objects/pack/pack files.expect && git multi-pack-index write --bitmap --stdin-packs \ - err && + out 2>&1 && - test_grep "bitmap without any objects" err && - - test_path_is_file $midx && - test_path_is_missing $midx-$(midx_checksum $objdir).bitmap + test_must_be_empty out && + test_path_is_missing $midx && + ls $objdir/pack >files.actual && + test_cmp files.expect files.actual ) ' diff --git a/t/t5334-incremental-multi-pack-index.sh b/t/t5334-incremental-multi-pack-index.sh index f0b82b5f65..fbcc19feeb 100755 --- a/t/t5334-incremental-multi-pack-index.sh +++ b/t/t5334-incremental-multi-pack-index.sh @@ -195,4 +195,79 @@ test_expect_success 'non-incremental write with existing incremental chain' ' ) ' +test_expect_success 'skip initial MIDX layer with no objects' ' + git init empty && + ( + cd empty && + git config maintenance.auto false && + git pack-objects $packdir/pack out 2>&1 && + test_must_be_empty out && + test_dir_is_empty "$midxdir" || return 1 + done && + + write_midx_layer && + test_line_count = 1 "$midx_chain" && + git multi-pack-index verify + ) +' + +test_expect_success 'skip MIDX layer with empty pack' ' + git init empty-pack && + ( + cd empty-pack && + git config maintenance.auto false && + write_midx_layer && + + git pack-objects $packdir/pack files.expect && + + for bitmap in --bitmap --no-bitmap + do + git multi-pack-index write --incremental "$bitmap" >out 2>&1 && + test_must_be_empty out && + test_cmp chain.expect "$midx_chain" && + ls "$packdir" "$midxdir" >files.actual && + test_cmp files.expect files.actual || return 1 + done && + + write_midx_layer && + test_line_count = 2 "$midx_chain" && + git multi-pack-index verify && + git rev-list --test-bitmap 2.2 + ) +' + +test_expect_success 'skip MIDX layer with duplicate pack' ' + git init duplicate-pack && + ( + cd duplicate-pack && + git config maintenance.auto false && + write_midx_layer && + + git rev-parse HEAD^{tree} >in && + git pack-objects $packdir/pack files.expect && + + for bitmap in --bitmap --no-bitmap + do + git multi-pack-index write --incremental "$bitmap" >out 2>&1 && + test_must_be_empty out && + test_cmp chain.expect "$midx_chain" && + ls "$packdir" "$midxdir" >files.actual && + test_cmp files.expect files.actual || return 1 + done && + + write_midx_layer && + test_line_count = 2 "$midx_chain" && + git multi-pack-index verify && + git rev-list --test-bitmap 2.2 + ) +' + test_done