t5308: test reverse indexes with duplicate objects

A non-strict .idx has one entry for each object in the pack, even when multiple entries have the same object ID. Thus a pack ordered A, B, A, C has two .idx entries for A at distinct offsets. The corresponding per-pack reverse index must represent both entries and map them back to physical pack order. Existing reverse-index tests do not cover packs with duplicate objects. Add one and check that %(objectsize:disk) for B stops at the second A, rather than extending through it to C. Exercise both the on-disk and in-memory reverse-index implementations. As part of validating Git's handling of packs containing duplicate objects, cover their per-pack reverse indexes. Signed-off-by: Taylor Blau <ttaylorr@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Taylor Blau committed Jul 24, 2026 at 16:05 UTC 82114627614c22b05c7c0919ad59ac8f225fe7d5
1 file changed +39
t/t5308-pack-detect-duplicates.sh
+39
@@ -27,6 +27,11 @@ HI_SHA1=$EMPTY_BLOB
27 # duplicate runs).
28 MISSING_SHA1=$(test_oid missing_oid)
29
30 +# Three distinct objects for tests where physical pack order matters.
31 +A=$(test_oid packlib_7_0)
32 +B=$LO_SHA1
33 +C=$HI_SHA1
34 +
35 # git will never intentionally create packfiles with
36 # duplicate objects, so we have to construct them by hand.
37 #
@@ -72,6 +77,40 @@ test_expect_success 'lookup in duplicated pack' '
77 test_cmp expect actual
78 '
79
80 +test_expect_success 'duplicate entries remain in pack reverse index' '
81 + clear_packs &&
82 + {
83 + pack_header 4 &&
84 + pack_obj $A &&
85 + pack_obj $B &&
86 + pack_obj $A &&
87 + pack_obj $C
88 + } >physical-order.pack &&
89 + pack_trailer physical-order.pack &&
90 +
91 + test_must_fail git index-pack --rev-index --stdin --strict \
92 + <physical-order.pack 2>err &&
93 + test_grep "appears twice in the pack" err &&
94 +
95 + git index-pack --rev-index --stdin <physical-order.pack &&
96 + git show-index <"$(ls .git/objects/pack/pack-*.idx)" >offsets.raw &&
97 +
98 + sort -n offsets.raw | grep -A1 "$B" | cut -d" " -f1 >adjacent &&
99 + echo $(($(tail -n1 adjacent) - $(head -n1 adjacent))) >expect &&
100 + echo "$B" >in &&
101 +
102 + GIT_TEST_REV_INDEX_DIE_IN_MEMORY=1 \
103 + git cat-file --batch-check="%(objectsize:disk)" \
104 + <in >actual.disk &&
105 + GIT_TEST_REV_INDEX_DIE_ON_DISK=1 \
106 + git -c pack.readReverseIndex=false \
107 + cat-file --batch-check="%(objectsize:disk)" \
108 + <in >actual.mem &&
109 +
110 + test_cmp expect actual.disk &&
111 + test_cmp expect actual.mem
112 +'
113 +
114 test_expect_success 'index-pack can reject packs with duplicates' '
115 clear_packs &&
116 create_pack dups.pack 2 &&