Raw
1 #!/bin/sh
2
3 test_description='multi-pack-indexes'
4
5 . ./test-lib.sh
6 . "$TEST_DIRECTORY"/lib-chunk.sh
7 . "$TEST_DIRECTORY"/lib-midx.sh
8
9 GIT_TEST_MULTI_PACK_INDEX=0
10 GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
11 GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
12 objdir=.git/objects
13
14 HASH_LEN=$(test_oid rawsz)
15
16 midx_read_expect () {
17 NUM_PACKS=$1
18 NUM_OBJECTS=$2
19 NUM_CHUNKS=$3
20 OBJECT_DIR=$4
21 EXTRA_CHUNKS="$5"
22 {
23 cat <<-EOF &&
24 header: 4d494458 1 $HASH_LEN $NUM_CHUNKS $NUM_PACKS
25 chunks: pack-names oid-fanout oid-lookup object-offsets$EXTRA_CHUNKS
26 num_objects: $NUM_OBJECTS
27 packs:
28 EOF
29 if test $NUM_PACKS -ge 1
30 then
31 ls "$OBJECT_DIR"/pack/ | grep idx | sort
32 fi &&
33 printf "object-dir: $OBJECT_DIR\n"
34 } >expect &&
35 test-tool read-midx "$OBJECT_DIR" >actual &&
36 test_cmp expect actual
37 }
38
39 test_expect_success 'setup' '
40 test_oid_cache <<-EOF
41 idxoff sha1:2999
42 idxoff sha256:3739
43
44 packnameoff sha1:652
45 packnameoff sha256:940
46
47 fanoutoff sha1:1
48 fanoutoff sha256:3
49 EOF
50 '
51
52 test_expect_success "don't write midx with no packs" '
53 test_must_fail git multi-pack-index --object-dir=. write &&
54 test_path_is_missing pack/multi-pack-index
55 '
56
57 test_expect_success SHA1 'warn if a midx contains no oid' '
58 cp "$TEST_DIRECTORY"/t5319/no-objects.midx $objdir/pack/multi-pack-index &&
59 test_must_fail git multi-pack-index verify &&
60 rm $objdir/pack/multi-pack-index
61 '
62
63 generate_objects () {
64 i=$1
65 iii=$(printf '%03i' $i)
66 {
67 test-tool genrandom "bar" 200 &&
68 test-tool genrandom "baz $iii" 50
69 } >wide_delta_$iii &&
70 {
71 test-tool genrandom "foo"$i 100 &&
72 test-tool genrandom "foo"$(( $i + 1 )) 100 &&
73 test-tool genrandom "foo"$(( $i + 2 )) 100
74 } >deep_delta_$iii &&
75 {
76 echo $iii &&
77 test-tool genrandom "$iii" 8192
78 } >file_$iii &&
79 git update-index --add file_$iii deep_delta_$iii wide_delta_$iii
80 }
81
82 commit_and_list_objects () {
83 {
84 echo 101 &&
85 test-tool genrandom 100 8192;
86 } >file_101 &&
87 git update-index --add file_101 &&
88 tree=$(git write-tree) &&
89 commit=$(git commit-tree $tree -p HEAD</dev/null) &&
90 {
91 echo $tree &&
92 git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\) .*/\\1/"
93 } >obj-list &&
94 git reset --hard $commit
95 }
96
97 test_expect_success 'create objects' '
98 test_commit initial &&
99 for i in $(test_seq 1 5)
100 do
101 generate_objects $i || return 1
102 done &&
103 commit_and_list_objects
104 '
105
106 test_expect_success 'write midx with one v1 pack' '
107 pack=$(git pack-objects --index-version=1 $objdir/pack/test <obj-list) &&
108 test_when_finished rm $objdir/pack/test-$pack.pack \
109 $objdir/pack/test-$pack.idx $objdir/pack/multi-pack-index &&
110 git multi-pack-index --object-dir=$objdir write &&
111 midx_read_expect 1 18 4 $objdir
112 '
113
114 test_expect_success 'write midx with one v2 pack' '
115 git pack-objects --index-version=2,0x40 $objdir/pack/test <obj-list &&
116 git multi-pack-index --object-dir=$objdir write &&
117 midx_read_expect 1 18 4 $objdir
118 '
119
120 compare_results_with_midx "one v2 pack"
121
122 test_expect_success 'corrupt idx reports errors' '
123 idx=$(test-tool read-midx $objdir | grep "\.idx\$") &&
124 mv $objdir/pack/$idx backup-$idx &&
125 test_when_finished "mv backup-\$idx \$objdir/pack/\$idx" &&
126
127 # This is the minimum size for a sha-1 based .idx; this lets
128 # us pass perfunctory tests, but anything that actually opens and reads
129 # the idx file will complain.
130 test_copy_bytes 1064 <backup-$idx >$objdir/pack/$idx &&
131
132 git -c core.multiPackIndex=true rev-list --objects --all 2>err &&
133 grep "index unavailable" err
134 '
135
136 test_expect_success 'add more objects' '
137 for i in $(test_seq 6 10)
138 do
139 generate_objects $i || return 1
140 done &&
141 commit_and_list_objects
142 '
143
144 test_expect_success 'write midx with two packs' '
145 git pack-objects --index-version=1 $objdir/pack/test-2 <obj-list &&
146 git multi-pack-index --object-dir=$objdir write &&
147 midx_read_expect 2 34 4 $objdir
148 '
149
150 compare_results_with_midx "two packs"
151
152 test_expect_success 'write midx with --stdin-packs' '
153 rm -fr $objdir/pack/multi-pack-index &&
154
155 idx="$(find $objdir/pack -name "test-2-*.idx")" &&
156 basename "$idx" >in &&
157
158 git multi-pack-index write --stdin-packs <in &&
159
160 test-tool read-midx $objdir | grep "\.idx$" >packs &&
161
162 test_cmp packs in
163 '
164
165 compare_results_with_midx "mixed mode (one pack + extra)"
166
167 test_expect_success 'write with no objects and preferred pack' '
168 test_when_finished "rm -rf empty" &&
169 git init empty &&
170 test_must_fail git -C empty multi-pack-index write \
171 --stdin-packs --preferred-pack=does-not-exist </dev/null 2>err &&
172 cat >expect <<-EOF &&
173 warning: unknown preferred pack: ${SQ}does-not-exist${SQ}
174 error: no pack files to index.
175 EOF
176 test_cmp expect err
177 '
178
179 test_expect_success 'write progress off for redirected stderr' '
180 git multi-pack-index --object-dir=$objdir write 2>err &&
181 test_line_count = 0 err
182 '
183
184 test_expect_success 'write force progress on for stderr' '
185 GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --progress 2>err &&
186 test_file_not_empty err
187 '
188
189 test_expect_success 'write with the --no-progress option' '
190 GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir write --no-progress 2>err &&
191 test_line_count = 0 err
192 '
193
194 test_expect_success 'add more packs' '
195 for j in $(test_seq 11 20)
196 do
197 generate_objects $j &&
198 commit_and_list_objects &&
199 git pack-objects --index-version=2 $objdir/pack/test-pack <obj-list || return 1
200 done
201 '
202
203 compare_results_with_midx "mixed mode (two packs + extra)"
204
205 test_expect_success 'write midx with twelve packs' '
206 git multi-pack-index --object-dir=$objdir write &&
207 midx_read_expect 12 74 4 $objdir
208 '
209
210 compare_results_with_midx "twelve packs"
211
212 test_expect_success 'multi-pack-index *.rev cleanup with --object-dir' '
213 git init repo &&
214 git clone -s repo alternate &&
215
216 test_when_finished "rm -rf repo alternate" &&
217
218 (
219 cd repo &&
220 test_commit base &&
221 git repack -d
222 ) &&
223
224 ours="alternate/.git/objects/pack/multi-pack-index-123.rev" &&
225 theirs="repo/.git/objects/pack/multi-pack-index-abc.rev" &&
226 touch "$ours" "$theirs" &&
227
228 (
229 cd alternate &&
230 git multi-pack-index --object-dir ../repo/.git/objects write
231 ) &&
232
233 # writing a midx in "repo" should not remove the .rev file in the
234 # alternate
235 test_path_is_file repo/.git/objects/pack/multi-pack-index &&
236 test_path_is_file $ours &&
237 test_path_is_missing $theirs
238 '
239
240 test_expect_success 'warn on improper hash version' '
241 git init --object-format=sha1 sha1 &&
242 (
243 cd sha1 &&
244 git config core.multiPackIndex true &&
245 test_commit 1 &&
246 git repack -a &&
247 git multi-pack-index write &&
248 mv .git/objects/pack/multi-pack-index ../mpi-sha1
249 ) &&
250 git init --object-format=sha256 sha256 &&
251 (
252 cd sha256 &&
253 git config core.multiPackIndex true &&
254 test_commit 1 &&
255 git repack -a &&
256 git multi-pack-index write &&
257 mv .git/objects/pack/multi-pack-index ../mpi-sha256
258 ) &&
259 (
260 cd sha1 &&
261 mv ../mpi-sha256 .git/objects/pack/multi-pack-index &&
262 git log -1 2>err &&
263 test_grep "multi-pack-index hash version 2 does not match version 1" err
264 ) &&
265 (
266 cd sha256 &&
267 mv ../mpi-sha1 .git/objects/pack/multi-pack-index &&
268 git log -1 2>err &&
269 test_grep "multi-pack-index hash version 1 does not match version 2" err
270 )
271 '
272
273 test_expect_success 'midx picks objects from preferred pack' '
274 test_when_finished rm -rf preferred.git &&
275 git init --bare preferred.git &&
276 (
277 cd preferred.git &&
278
279 a=$(echo "a" | git hash-object -w --stdin) &&
280 b=$(echo "b" | git hash-object -w --stdin) &&
281 c=$(echo "c" | git hash-object -w --stdin) &&
282
283 # Set up two packs, duplicating the object "B" at different
284 # offsets.
285 #
286 # Note that the "BC" pack (the one we choose as preferred) sorts
287 # lexically after the "AB" pack, meaning that omitting the
288 # --preferred-pack argument would cause this test to fail (since
289 # the MIDX code would select the copy of "b" in the "AB" pack).
290 git pack-objects objects/pack/test-AB <<-EOF &&
291 $a
292 $b
293 EOF
294 bc=$(git pack-objects objects/pack/test-BC <<-EOF
295 $b
296 $c
297 EOF
298 ) &&
299
300 git multi-pack-index --object-dir=objects \
301 write --preferred-pack=test-BC-$bc.idx 2>err &&
302 test_must_be_empty err &&
303
304 test-tool read-midx --show-objects objects >out &&
305
306 ofs=$(git show-index <objects/pack/test-BC-$bc.idx | grep $b |
307 cut -d" " -f1) &&
308 printf "%s %s\t./objects/pack/test-BC-%s.pack\n" \
309 "$b" "$ofs" "$bc" >expect &&
310 grep ^$b out >actual &&
311
312 test_cmp expect actual
313 )
314 '
315
316 test_expect_success 'preferred packs must be non-empty' '
317 test_when_finished rm -rf preferred.git &&
318 git init preferred.git &&
319 (
320 cd preferred.git &&
321
322 test_commit base &&
323 git repack -ad &&
324
325 empty="$(git pack-objects $objdir/pack/pack </dev/null)" &&
326
327 test_must_fail git multi-pack-index write \
328 --preferred-pack=pack-$empty.pack 2>err &&
329 grep "with no objects" err
330 )
331 '
332
333 test_expect_success 'preferred pack from existing MIDX without bitmaps' '
334 git init preferred-without-bitmaps &&
335 (
336 cd preferred-without-bitmaps &&
337
338 test_commit one &&
339 pack="$(git pack-objects --all $objdir/pack/pack </dev/null)" &&
340
341 git multi-pack-index write &&
342
343 # make another pack so that the subsequent MIDX write
344 # has something to do
345 test_commit two &&
346 git repack -d &&
347
348 # write a new MIDX without bitmaps reusing the singular
349 # pack from the existing MIDX as the preferred pack in
350 # the new MIDX
351 git multi-pack-index write --preferred-pack=pack-$pack.pack
352 )
353 '
354
355 test_expect_success 'preferred pack cannot be determined without bitmap' '
356 test_when_finished "rm -fr preferred-can-be-queried" &&
357 git init preferred-can-be-queried &&
358 (
359 cd preferred-can-be-queried &&
360 test_commit initial &&
361 git repack -Adl --write-midx --no-write-bitmap-index &&
362 test_must_fail test-tool read-midx --preferred-pack .git/objects 2>err &&
363 test_grep "could not determine MIDX preferred pack" err &&
364 git repack -Adl --write-midx --write-bitmap-index &&
365 test-tool read-midx --preferred-pack .git/objects
366 )
367 '
368
369 test_midx_is_retained () {
370 test-tool chmtime =0 .git/objects/pack/multi-pack-index &&
371 ls -l .git/objects/pack/multi-pack-index >expect &&
372 git multi-pack-index write "$@" &&
373 ls -l .git/objects/pack/multi-pack-index >actual &&
374 test_cmp expect actual
375 }
376
377 test_midx_is_rewritten () {
378 test-tool chmtime =0 .git/objects/pack/multi-pack-index &&
379 ls -l .git/objects/pack/multi-pack-index >expect &&
380 git multi-pack-index write "$@" &&
381 ls -l .git/objects/pack/multi-pack-index >actual &&
382 ! test_cmp expect actual
383 }
384
385 test_expect_success 'up-to-date multi-pack-index is retained' '
386 test_when_finished "rm -fr midx-up-to-date" &&
387 git init midx-up-to-date &&
388 (
389 cd midx-up-to-date &&
390
391 # Write the initial pack that contains the most objects.
392 test_commit first &&
393 test_commit second &&
394 git repack -Ad --write-midx &&
395 test_midx_is_retained &&
396
397 # Writing a new bitmap index should cause us to regenerate the MIDX.
398 test_midx_is_rewritten --bitmap &&
399 test_midx_is_retained --bitmap &&
400
401 # Ensure that writing a new packfile causes us to rewrite the index.
402 test_commit incremental &&
403 git repack -d &&
404 test_midx_is_rewritten &&
405 test_midx_is_retained &&
406
407 for pack in .git/objects/pack/*.idx
408 do
409 basename "$pack" || exit 1
410 done >stdin &&
411 test_line_count = 2 stdin &&
412 test_midx_is_retained --stdin-packs <stdin &&
413 head -n1 stdin >stdin.trimmed &&
414 test_midx_is_rewritten --stdin-packs <stdin.trimmed
415 )
416 '
417
418 test_expect_success 'verify multi-pack-index success' '
419 git multi-pack-index verify --object-dir=$objdir
420 '
421
422 test_expect_success 'verify progress off for redirected stderr' '
423 git multi-pack-index verify --object-dir=$objdir 2>err &&
424 test_line_count = 0 err
425 '
426
427 test_expect_success 'verify force progress on for stderr' '
428 git multi-pack-index verify --object-dir=$objdir --progress 2>err &&
429 test_file_not_empty err
430 '
431
432 test_expect_success 'verify with the --no-progress option' '
433 git multi-pack-index verify --object-dir=$objdir --no-progress 2>err &&
434 test_line_count = 0 err
435 '
436
437 # usage: corrupt_midx_and_verify <pos> <data> <objdir> <string>
438 corrupt_midx_and_verify() {
439 POS=$1 &&
440 DATA="${2:-\0}" &&
441 OBJDIR=$3 &&
442 GREPSTR="$4" &&
443 COMMAND="$5" &&
444 if test -z "$COMMAND"
445 then
446 COMMAND="git multi-pack-index verify --object-dir=$OBJDIR"
447 fi &&
448 FILE=$OBJDIR/pack/multi-pack-index &&
449 chmod a+w $FILE &&
450 test_when_finished mv midx-backup $FILE &&
451 cp $FILE midx-backup &&
452 printf "$DATA" | dd of="$FILE" bs=1 seek="$POS" conv=notrunc &&
453 test_must_fail $COMMAND 2>test_err &&
454 grep -v "^+" test_err >err &&
455 test_grep "$GREPSTR" err
456 }
457
458 test_expect_success 'verify bad signature' '
459 corrupt_midx_and_verify 0 "\00" $objdir \
460 "multi-pack-index signature"
461 '
462
463 NUM_OBJECTS=74
464 MIDX_BYTE_VERSION=4
465 MIDX_BYTE_OID_VERSION=5
466 MIDX_BYTE_CHUNK_COUNT=6
467 MIDX_HEADER_SIZE=12
468 MIDX_BYTE_CHUNK_ID=$MIDX_HEADER_SIZE
469 MIDX_BYTE_CHUNK_OFFSET=$(($MIDX_HEADER_SIZE + 4))
470 MIDX_NUM_CHUNKS=5
471 MIDX_CHUNK_LOOKUP_WIDTH=12
472 MIDX_OFFSET_PACKNAMES=$(($MIDX_HEADER_SIZE + \
473 $MIDX_NUM_CHUNKS * $MIDX_CHUNK_LOOKUP_WIDTH))
474 MIDX_BYTE_PACKNAME_ORDER=$(($MIDX_OFFSET_PACKNAMES + 2))
475 MIDX_OFFSET_OID_FANOUT=$(($MIDX_OFFSET_PACKNAMES + $(test_oid packnameoff)))
476 MIDX_OID_FANOUT_WIDTH=4
477 MIDX_BYTE_OID_FANOUT_ORDER=$((MIDX_OFFSET_OID_FANOUT + 250 * $MIDX_OID_FANOUT_WIDTH + $(test_oid fanoutoff)))
478 MIDX_OFFSET_OID_LOOKUP=$(($MIDX_OFFSET_OID_FANOUT + 256 * $MIDX_OID_FANOUT_WIDTH))
479 MIDX_BYTE_OID_LOOKUP=$(($MIDX_OFFSET_OID_LOOKUP + 16 * $HASH_LEN))
480 MIDX_OFFSET_OBJECT_OFFSETS=$(($MIDX_OFFSET_OID_LOOKUP + $NUM_OBJECTS * $HASH_LEN))
481 MIDX_OFFSET_WIDTH=8
482 MIDX_BYTE_PACK_INT_ID=$(($MIDX_OFFSET_OBJECT_OFFSETS + 16 * $MIDX_OFFSET_WIDTH + 2))
483 MIDX_BYTE_OFFSET=$(($MIDX_OFFSET_OBJECT_OFFSETS + 16 * $MIDX_OFFSET_WIDTH + 6))
484
485 test_expect_success 'verify bad version' '
486 corrupt_midx_and_verify $MIDX_BYTE_VERSION "\00" $objdir \
487 "multi-pack-index version"
488 '
489
490 test_expect_success 'verify bad OID version' '
491 corrupt_midx_and_verify $MIDX_BYTE_OID_VERSION "\03" $objdir \
492 "hash version"
493 '
494
495 test_expect_success 'verify truncated chunk count' '
496 corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\01" $objdir \
497 "final chunk has non-zero id"
498 '
499
500 test_expect_success 'verify extended chunk count' '
501 corrupt_midx_and_verify $MIDX_BYTE_CHUNK_COUNT "\07" $objdir \
502 "terminating chunk id appears earlier than expected"
503 '
504
505 test_expect_success 'verify missing required chunk' '
506 corrupt_midx_and_verify $MIDX_BYTE_CHUNK_ID "\01" $objdir \
507 "required pack-name chunk missing"
508 '
509
510 test_expect_success 'verify invalid chunk offset' '
511 corrupt_midx_and_verify $MIDX_BYTE_CHUNK_OFFSET "\01" $objdir \
512 "improper chunk offset(s)"
513 '
514
515 test_expect_success 'verify missing pack' '
516 corrupt_midx_and_verify $MIDX_BYTE_PACKNAME_ORDER "a" $objdir \
517 "failed to load pack"
518 '
519
520 test_expect_success 'verify oid fanout out of order' '
521 corrupt_midx_and_verify $MIDX_BYTE_OID_FANOUT_ORDER "\01" $objdir \
522 "oid fanout out of order"
523 '
524
525 test_expect_success 'verify oid lookup out of order' '
526 corrupt_midx_and_verify $MIDX_BYTE_OID_LOOKUP "\00" $objdir \
527 "oid lookup out of order"
528 '
529
530 test_expect_success 'verify incorrect pack-int-id' '
531 corrupt_midx_and_verify $MIDX_BYTE_PACK_INT_ID "\07" $objdir \
532 "bad pack-int-id"
533 '
534
535 test_expect_success 'verify incorrect offset' '
536 corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
537 "incorrect object offset"
538 '
539
540 test_expect_success 'git-fsck incorrect offset' '
541 corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
542 "incorrect object offset" \
543 "git -c core.multiPackIndex=true fsck" &&
544 test_unconfig core.multiPackIndex &&
545 test_must_fail git fsck &&
546 git -c core.multiPackIndex=false fsck
547 '
548
549 test_expect_success 'git fsck shows MIDX output with --progress' '
550 git fsck --progress 2>err &&
551 grep "Verifying OID order in multi-pack-index" err &&
552 grep "Verifying object offsets" err
553 '
554
555 test_expect_success 'git fsck suppresses MIDX output with --no-progress' '
556 git fsck --no-progress 2>err &&
557 ! grep "Verifying OID order in multi-pack-index" err &&
558 ! grep "Verifying object offsets" err
559 '
560
561 test_expect_success 'corrupt MIDX is not reused' '
562 corrupt_midx_and_verify $MIDX_BYTE_OFFSET "\377" $objdir \
563 "incorrect object offset" &&
564 git multi-pack-index write 2>err &&
565 test_grep checksum.mismatch err &&
566 git multi-pack-index verify
567 '
568
569 test_expect_success 'verify incorrect checksum' '
570 pos=$(($(wc -c <$objdir/pack/multi-pack-index) - 10)) &&
571 corrupt_midx_and_verify $pos \
572 "\377\377\377\377\377\377\377\377\377\377" \
573 $objdir "incorrect checksum"
574 '
575
576 test_expect_success 'setup for v1-specific fsck tests' '
577 git -c midx.version=1 multi-pack-index write
578 '
579
580 test_expect_success 'verify packnames out of order (v1)' '
581 corrupt_midx_and_verify $MIDX_BYTE_PACKNAME_ORDER "z" $objdir \
582 "pack names out of order"
583 '
584
585 test_expect_success 'repack progress off for redirected stderr' '
586 GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack 2>err &&
587 test_line_count = 0 err
588 '
589
590 test_expect_success 'repack force progress on for stderr' '
591 GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --progress 2>err &&
592 test_file_not_empty err
593 '
594
595 test_expect_success 'repack with the --no-progress option' '
596 GIT_PROGRESS_DELAY=0 git multi-pack-index --object-dir=$objdir repack --no-progress 2>err &&
597 test_line_count = 0 err
598 '
599
600 test_expect_success 'repack removes multi-pack-index when deleting packs' '
601 test_path_is_file $objdir/pack/multi-pack-index &&
602 # Set GIT_TEST_MULTI_PACK_INDEX to 0 to avoid writing a new
603 # multi-pack-index after repacking, but set "core.multiPackIndex" to
604 # true so that "git repack" can read the existing MIDX.
605 GIT_TEST_MULTI_PACK_INDEX=0 git -c core.multiPackIndex repack -adf &&
606 test_path_is_missing $objdir/pack/multi-pack-index
607 '
608
609 test_expect_success 'repack preserves multi-pack-index when creating packs' '
610 git init preserve &&
611 test_when_finished "rm -fr preserve" &&
612 (
613 cd preserve &&
614 packdir=.git/objects/pack &&
615 midx=$packdir/multi-pack-index &&
616
617 test_commit 1 &&
618 pack1=$(git pack-objects --all $packdir/pack) &&
619 touch $packdir/pack-$pack1.keep &&
620 test_commit 2 &&
621 pack2=$(git pack-objects --revs $packdir/pack) &&
622 touch $packdir/pack-$pack2.keep &&
623
624 git multi-pack-index write &&
625 cp $midx $midx.bak &&
626
627 cat >pack-input <<-EOF &&
628 HEAD
629 ^HEAD~1
630 EOF
631 test_commit 3 &&
632 pack3=$(git pack-objects --revs $packdir/pack <pack-input) &&
633 test_commit 4 &&
634 pack4=$(git pack-objects --revs $packdir/pack <pack-input) &&
635
636 GIT_TEST_MULTI_PACK_INDEX=0 git -c core.multiPackIndex repack -ad &&
637 ls -la $packdir &&
638 test_path_is_file $packdir/pack-$pack1.pack &&
639 test_path_is_file $packdir/pack-$pack2.pack &&
640 test_path_is_missing $packdir/pack-$pack3.pack &&
641 test_path_is_missing $packdir/pack-$pack4.pack &&
642 test_cmp_bin $midx.bak $midx
643 )
644 '
645
646 compare_results_with_midx "after repack"
647
648 test_expect_success 'multi-pack-index and pack-bitmap' '
649 git -c repack.writeBitmaps=true repack -ad &&
650 git multi-pack-index write &&
651 git rev-list --test-bitmap HEAD
652 '
653
654 test_expect_success 'multi-pack-index and alternates' '
655 git init --bare alt.git &&
656 echo $(pwd)/alt.git/objects >.git/objects/info/alternates &&
657 echo content1 >file1 &&
658 altblob=$(GIT_DIR=alt.git git hash-object -w file1) &&
659 git cat-file blob $altblob &&
660 git rev-list --all
661 '
662
663 compare_results_with_midx "with alternate (local midx)"
664
665 test_expect_success 'multi-pack-index in an alternate' '
666 mv .git/objects/pack/* alt.git/objects/pack &&
667 test_commit add_local_objects &&
668 git repack --local &&
669 git multi-pack-index write &&
670 midx_read_expect 1 3 4 $objdir &&
671 git reset --hard HEAD~1 &&
672 rm -f .git/objects/pack/*
673 '
674
675 compare_results_with_midx "with alternate (remote midx)"
676
677 # usage: corrupt_data <file> <pos> [<data>]
678 corrupt_data () {
679 file=$1
680 pos=$2
681 data="${3:-\0}"
682 printf "$data" | dd of="$file" bs=1 seek="$pos" conv=notrunc
683 }
684
685 # Force 64-bit offsets by manipulating the idx file.
686 # This makes the IDX file _incorrect_ so be careful to clean up after!
687 test_expect_success 'force some 64-bit offsets with pack-objects' '
688 mkdir objects64 &&
689 mkdir objects64/pack &&
690 for i in $(test_seq 1 11)
691 do
692 generate_objects 11 || return 1
693 done &&
694 commit_and_list_objects &&
695 pack64=$(git pack-objects --index-version=2,0x40 objects64/pack/test-64 <obj-list) &&
696 idx64=objects64/pack/test-64-$pack64.idx &&
697 chmod u+w $idx64 &&
698 corrupt_data $idx64 $(test_oid idxoff) "\02" &&
699 # objects64 is not a real repository, but can serve as an alternate
700 # anyway so we can write a MIDX into it
701 git init repo &&
702 test_when_finished "rm -fr repo" &&
703 (
704 cd repo &&
705 ( cd ../objects64 && pwd ) >.git/objects/info/alternates &&
706 midx64=$(git multi-pack-index --object-dir=../objects64 write)
707 ) &&
708 midx_read_expect 1 63 5 "$(pwd)/objects64" " large-offsets"
709 '
710
711 test_expect_success 'verify multi-pack-index with 64-bit offsets' '
712 git multi-pack-index verify --object-dir=objects64
713 '
714
715 NUM_OBJECTS=63
716 MIDX_OFFSET_OID_FANOUT=$((MIDX_OFFSET_PACKNAMES + 54))
717 MIDX_OFFSET_OID_LOOKUP=$((MIDX_OFFSET_OID_FANOUT + 256 * $MIDX_OID_FANOUT_WIDTH))
718 MIDX_OFFSET_OBJECT_OFFSETS=$(($MIDX_OFFSET_OID_LOOKUP + $NUM_OBJECTS * $HASH_LEN))
719 MIDX_OFFSET_LARGE_OFFSETS=$(($MIDX_OFFSET_OBJECT_OFFSETS + $NUM_OBJECTS * $MIDX_OFFSET_WIDTH))
720 MIDX_BYTE_LARGE_OFFSET=$(($MIDX_OFFSET_LARGE_OFFSETS + 3))
721
722 test_expect_success 'verify incorrect 64-bit offset' '
723 corrupt_midx_and_verify $MIDX_BYTE_LARGE_OFFSET "\07" objects64 \
724 "incorrect object offset"
725 '
726
727 test_expect_success 'setup expire tests' '
728 mkdir dup &&
729 (
730 cd dup &&
731 git init &&
732 test-tool genrandom "data" 4096 >large_file.txt &&
733 git update-index --add large_file.txt &&
734 for i in $(test_seq 1 20)
735 do
736 test_commit $i || exit 1
737 done &&
738 git branch A HEAD &&
739 git branch B HEAD~8 &&
740 git branch C HEAD~13 &&
741 git branch D HEAD~16 &&
742 git branch E HEAD~18 &&
743 git pack-objects --revs .git/objects/pack/pack-A <<-EOF &&
744 refs/heads/A
745 ^refs/heads/B
746 EOF
747 git pack-objects --revs .git/objects/pack/pack-B <<-EOF &&
748 refs/heads/B
749 ^refs/heads/C
750 EOF
751 git pack-objects --revs .git/objects/pack/pack-C <<-EOF &&
752 refs/heads/C
753 ^refs/heads/D
754 EOF
755 git pack-objects --revs .git/objects/pack/pack-D <<-EOF &&
756 refs/heads/D
757 ^refs/heads/E
758 EOF
759 git pack-objects --revs .git/objects/pack/pack-E <<-EOF &&
760 refs/heads/E
761 EOF
762 git multi-pack-index write &&
763 cp -r .git/objects/pack .git/objects/pack-backup
764 )
765 '
766
767 test_expect_success 'expire does not remove any packs' '
768 (
769 cd dup &&
770 ls .git/objects/pack >expect &&
771 git multi-pack-index expire &&
772 ls .git/objects/pack >actual &&
773 test_cmp expect actual
774 )
775 '
776
777 test_expect_success 'expire progress off for redirected stderr' '
778 (
779 cd dup &&
780 git multi-pack-index expire 2>err &&
781 test_line_count = 0 err
782 )
783 '
784
785 test_expect_success 'expire force progress on for stderr' '
786 (
787 cd dup &&
788 GIT_PROGRESS_DELAY=0 git multi-pack-index expire --progress 2>err &&
789 test_file_not_empty err
790 )
791 '
792
793 test_expect_success 'expire with the --no-progress option' '
794 (
795 cd dup &&
796 GIT_PROGRESS_DELAY=0 git multi-pack-index expire --no-progress 2>err &&
797 test_line_count = 0 err
798 )
799 '
800
801 test_expect_success 'expire removes unreferenced packs' '
802 (
803 cd dup &&
804 git pack-objects --revs .git/objects/pack/pack-combined <<-EOF &&
805 refs/heads/A
806 ^refs/heads/C
807 EOF
808 git multi-pack-index write &&
809 ls .git/objects/pack | grep -v -e pack-[AB] >expect &&
810 git multi-pack-index expire &&
811 ls .git/objects/pack >actual &&
812 test_cmp expect actual &&
813 ls .git/objects/pack/ | grep idx >expect-idx &&
814 test-tool read-midx .git/objects | grep idx >actual-midx &&
815 test_cmp expect-idx actual-midx &&
816 git multi-pack-index verify &&
817 git fsck
818 )
819 '
820
821 test_expect_success 'repack with minimum size does not alter existing packs' '
822 (
823 cd dup &&
824 rm -rf .git/objects/pack &&
825 mv .git/objects/pack-backup .git/objects/pack &&
826 test-tool chmtime =-5 .git/objects/pack/pack-D* &&
827 test-tool chmtime =-4 .git/objects/pack/pack-C* &&
828 test-tool chmtime =-3 .git/objects/pack/pack-B* &&
829 test-tool chmtime =-2 .git/objects/pack/pack-A* &&
830 ls .git/objects/pack >expect &&
831 MINSIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | head -n 1) &&
832 git multi-pack-index repack --batch-size=$MINSIZE &&
833 ls .git/objects/pack >actual &&
834 test_cmp expect actual
835 )
836 '
837
838 test_expect_success 'repack respects repack.packKeptObjects=false' '
839 test_when_finished rm -f dup/.git/objects/pack/*keep &&
840 (
841 cd dup &&
842 ls .git/objects/pack/*idx >idx-list &&
843 test_line_count = 5 idx-list &&
844 ls .git/objects/pack/*.pack | sed "s/\.pack/.keep/" >keep-list &&
845 test_line_count = 5 keep-list &&
846 for keep in $(cat keep-list)
847 do
848 touch $keep || return 1
849 done &&
850 git multi-pack-index repack --batch-size=0 &&
851 ls .git/objects/pack/*idx >idx-list &&
852 test_line_count = 5 idx-list &&
853 test-tool read-midx .git/objects | grep idx >midx-list &&
854 test_line_count = 5 midx-list &&
855 THIRD_SMALLEST_SIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | sed -n 3p) &&
856 BATCH_SIZE=$((THIRD_SMALLEST_SIZE + 1)) &&
857 git multi-pack-index repack --batch-size=$BATCH_SIZE &&
858 ls .git/objects/pack/*idx >idx-list &&
859 test_line_count = 5 idx-list &&
860 test-tool read-midx .git/objects | grep idx >midx-list &&
861 test_line_count = 5 midx-list
862 )
863 '
864
865 test_expect_success 'repack creates a new pack' '
866 (
867 cd dup &&
868 ls .git/objects/pack/*idx >idx-list &&
869 test_line_count = 5 idx-list &&
870 THIRD_SMALLEST_SIZE=$(test-tool path-utils file-size .git/objects/pack/*pack | sort -n | head -n 3 | tail -n 1) &&
871 BATCH_SIZE=$(($THIRD_SMALLEST_SIZE + 1)) &&
872 git multi-pack-index repack --batch-size=$BATCH_SIZE &&
873 ls .git/objects/pack/*idx >idx-list &&
874 test_line_count = 6 idx-list &&
875 test-tool read-midx .git/objects | grep idx >midx-list &&
876 test_line_count = 6 midx-list
877 )
878 '
879
880 test_expect_success 'repack (all) ignores cruft pack' '
881 git init repo &&
882 test_when_finished "rm -fr repo" &&
883 (
884 cd repo &&
885
886 test_commit base &&
887 test_commit --no-tag unreachable &&
888
889 git reset --hard base &&
890 git reflog expire --all --expire=all &&
891 git repack --cruft -d &&
892
893 git multi-pack-index write &&
894
895 find $objdir/pack | sort >before &&
896 git multi-pack-index repack --batch-size=0 &&
897 find $objdir/pack | sort >after &&
898
899 test_cmp before after
900 )
901 '
902
903 test_expect_success 'repack (--batch-size) ignores cruft pack' '
904 git init repo &&
905 test_when_finished "rm -fr repo" &&
906 (
907 cd repo &&
908
909 test_commit_bulk 5 &&
910 test_commit --no-tag unreachable &&
911
912 git reset --hard HEAD^ &&
913 git reflog expire --all --expire=all &&
914 git repack --cruft -d &&
915
916 test_commit four &&
917
918 find $objdir/pack -type f -name "*.pack" | sort >before &&
919 git repack -d &&
920 find $objdir/pack -type f -name "*.pack" | sort >after &&
921
922 pack="$(comm -13 before after)" &&
923 test_file_size "$pack" >sz &&
924 # Set --batch-size to twice the size of the pack created
925 # in the previous step, since this is enough to
926 # accommodate it and the cruft pack.
927 #
928 # This means that the MIDX machinery *could* combine the
929 # new and cruft packs together.
930 #
931 # We ensure that it does not below.
932 batch="$((($(cat sz) * 2)))" &&
933
934 git multi-pack-index write &&
935
936 find $objdir/pack | sort >before &&
937 git multi-pack-index repack --batch-size=$batch &&
938 find $objdir/pack | sort >after &&
939
940 test_cmp before after
941 )
942 '
943
944 test_expect_success 'expire removes repacked packs' '
945 (
946 cd dup &&
947 ls -al .git/objects/pack/*pack &&
948 ls -S .git/objects/pack/*pack | head -n 4 >expect &&
949 git multi-pack-index expire &&
950 ls -S .git/objects/pack/*pack >actual &&
951 test_cmp expect actual &&
952 test-tool read-midx .git/objects | grep idx >midx-list &&
953 test_line_count = 4 midx-list
954 )
955 '
956
957 test_expect_success 'expire works when adding new packs' '
958 (
959 cd dup &&
960 git pack-objects --revs .git/objects/pack/pack-combined <<-EOF &&
961 refs/heads/A
962 ^refs/heads/B
963 EOF
964 git pack-objects --revs .git/objects/pack/pack-combined <<-EOF &&
965 refs/heads/B
966 ^refs/heads/C
967 EOF
968 git pack-objects --revs .git/objects/pack/pack-combined <<-EOF &&
969 refs/heads/C
970 ^refs/heads/D
971 EOF
972 git multi-pack-index write &&
973 git pack-objects --revs .git/objects/pack/a-pack <<-EOF &&
974 refs/heads/D
975 ^refs/heads/E
976 EOF
977 git multi-pack-index write &&
978 git pack-objects --revs .git/objects/pack/z-pack <<-EOF &&
979 refs/heads/E
980 EOF
981 git multi-pack-index expire &&
982 ls .git/objects/pack/ | grep idx >expect &&
983 test-tool read-midx .git/objects | grep idx >actual &&
984 test_cmp expect actual &&
985 git multi-pack-index verify
986 )
987 '
988
989 test_expect_success 'expire respects .keep files' '
990 (
991 cd dup &&
992 git pack-objects --revs .git/objects/pack/pack-all <<-EOF &&
993 refs/heads/A
994 EOF
995 git multi-pack-index write &&
996 PACKA=$(ls .git/objects/pack/a-pack*\.pack | sed s/\.pack\$//) &&
997 touch $PACKA.keep &&
998 git multi-pack-index expire &&
999 test_path_is_file $PACKA.idx &&
1000 test_path_is_file $PACKA.keep &&
1001 test_path_is_file $PACKA.pack &&
1002 test-tool read-midx .git/objects | grep idx >midx-list &&
1003 test_line_count = 2 midx-list
1004 )
1005 '
1006
1007 test_expect_success 'expiring unreferenced cruft pack retains pack' '
1008 git init repo &&
1009 test_when_finished "rm -fr repo" &&
1010 (
1011 cd repo &&
1012
1013 test_commit base &&
1014 test_commit --no-tag unreachable &&
1015 unreachable=$(git rev-parse HEAD) &&
1016
1017 git reset --hard base &&
1018 git reflog expire --all --expire=all &&
1019 git repack --cruft -d &&
1020 mtimes="$(ls $objdir/pack/pack-*.mtimes)" &&
1021
1022 echo "base..$unreachable" >in &&
1023 pack="$(git pack-objects --revs --delta-base-offset \
1024 $objdir/pack/pack <in)" &&
1025
1026 # Preferring the contents of "$pack" will leave the
1027 # cruft pack unreferenced (ie., none of the objects
1028 # contained in the cruft pack will have their MIDX copy
1029 # selected from the cruft pack).
1030 git multi-pack-index write --preferred-pack="pack-$pack.pack" &&
1031 git multi-pack-index expire &&
1032
1033 test_path_is_file "$mtimes"
1034 )
1035 '
1036
1037 test_expect_success 'repack --batch-size=0 repacks everything' '
1038 cp -r dup dup2 &&
1039 (
1040 cd dup &&
1041 rm .git/objects/pack/*.keep &&
1042 ls .git/objects/pack/*idx >idx-list &&
1043 test_line_count = 2 idx-list &&
1044 git multi-pack-index repack --batch-size=0 &&
1045 ls .git/objects/pack/*idx >idx-list &&
1046 test_line_count = 3 idx-list &&
1047 test-tool read-midx .git/objects | grep idx >midx-list &&
1048 test_line_count = 3 midx-list &&
1049 git multi-pack-index expire &&
1050 ls -al .git/objects/pack/*idx >idx-list &&
1051 test_line_count = 1 idx-list &&
1052 git multi-pack-index repack --batch-size=0 &&
1053 ls -al .git/objects/pack/*idx >new-idx-list &&
1054 test_cmp idx-list new-idx-list
1055 )
1056 '
1057
1058 test_expect_success EXPENSIVE 'repack/expire with many packs' '
1059 cp -r dup many &&
1060 (
1061 cd many &&
1062
1063 for i in $(test_seq 1 100)
1064 do
1065 test_commit extra$i &&
1066 git maintenance run --task=loose-objects || return 1
1067 done &&
1068
1069 git multi-pack-index write &&
1070 git multi-pack-index repack &&
1071 git multi-pack-index expire
1072 )
1073 '
1074
1075 test_expect_success 'repack --batch-size=<large> repacks everything' '
1076 (
1077 cd dup2 &&
1078 rm .git/objects/pack/*.keep &&
1079 ls .git/objects/pack/*idx >idx-list &&
1080 test_line_count = 2 idx-list &&
1081 git multi-pack-index repack --batch-size=2000000 &&
1082 ls .git/objects/pack/*idx >idx-list &&
1083 test_line_count = 3 idx-list &&
1084 test-tool read-midx .git/objects | grep idx >midx-list &&
1085 test_line_count = 3 midx-list &&
1086 git multi-pack-index expire &&
1087 ls -al .git/objects/pack/*idx >idx-list &&
1088 test_line_count = 1 idx-list
1089 )
1090 '
1091
1092 test_expect_success 'repack/expire loop' '
1093 git init repack-expire &&
1094 test_when_finished "rm -fr repack-expire" &&
1095 (
1096 cd repack-expire &&
1097
1098 test_commit_bulk 5 &&
1099
1100 # Create three overlapping pack-files
1101 git rev-list --objects HEAD~3 >in-1 &&
1102 git rev-list --objects HEAD~4..HEAD~2 >in-2 &&
1103 git rev-list --objects HEAD~3..HEAD >in-3 &&
1104
1105 # Create disconnected blobs
1106 obj1=$(git hash-object -w in-1) &&
1107 obj2=$(git hash-object -w in-2) &&
1108 obj3=$(git hash-object -w in-3) &&
1109
1110 echo $obj2 >>in-2 &&
1111 echo $obj3 >>in-3 &&
1112
1113 for i in $(test_seq 3)
1114 do
1115 git pack-objects .git/objects/pack/test-$i <in-$i \
1116 || return 1
1117 done &&
1118
1119 rm -fr .git/objects/pack/pack-* &&
1120 git multi-pack-index write &&
1121
1122 for i in $(test_seq 3)
1123 do
1124 for file in $(ls .git/objects/pack/test-$i*)
1125 do
1126 test-tool chmtime =+$((3600*$i-25000)) $file || return 1
1127 done || return 1
1128 done &&
1129
1130 pack1=$(ls .git/objects/pack/test-1-*.pack) &&
1131 pack2=$(ls .git/objects/pack/test-2-*.pack) &&
1132 pack3=$(ls .git/objects/pack/test-3-*.pack) &&
1133
1134 # Prevent test-1 from being rewritten.
1135 touch "${pack1%.pack}.keep" &&
1136
1137 # This repack-expire loop should repack all non-kept packs
1138 # into a new pack and then delete the old packs.
1139 git multi-pack-index repack &&
1140 git multi-pack-index expire &&
1141
1142 test_path_is_missing $pack3 &&
1143 test_path_is_missing $pack2
1144 )
1145 '
1146
1147 test_expect_success 'load reverse index when missing .idx, .pack' '
1148 git init repo &&
1149 test_when_finished "rm -fr repo" &&
1150 (
1151 cd repo &&
1152
1153 git config core.multiPackIndex true &&
1154
1155 test_commit base &&
1156 git repack -ad &&
1157 git multi-pack-index write &&
1158
1159 git rev-parse HEAD >tip &&
1160 pack=$(ls .git/objects/pack/pack-*.pack) &&
1161 idx=$(ls .git/objects/pack/pack-*.idx) &&
1162
1163 mv $idx $idx.bak &&
1164 git cat-file --batch-check="%(objectsize:disk)" <tip &&
1165
1166 mv $idx.bak $idx &&
1167
1168 mv $pack $pack.bak &&
1169 git cat-file --batch-check="%(objectsize:disk)" <tip &&
1170
1171 test_must_fail git multi-pack-index write 2>err &&
1172 test_grep "could not load pack" err
1173 )
1174 '
1175
1176 test_expect_success 'usage shown without sub-command' '
1177 test_expect_code 129 git multi-pack-index 2>err &&
1178 ! test_grep "unrecognized subcommand" err
1179 '
1180
1181 test_expect_success 'complains when run outside of a repository' '
1182 nongit test_must_fail git multi-pack-index write 2>err &&
1183 grep "not a git repository" err
1184 '
1185
1186 test_expect_success 'repack with delta islands' '
1187 git init repo &&
1188 test_when_finished "rm -fr repo" &&
1189 (
1190 cd repo &&
1191
1192 test_commit first &&
1193 git repack &&
1194 test_commit second &&
1195 git repack &&
1196
1197 git multi-pack-index write &&
1198 git -c repack.useDeltaIslands=true multi-pack-index repack
1199 )
1200 '
1201
1202 corrupt_chunk () {
1203 midx=.git/objects/pack/multi-pack-index &&
1204 test_when_finished "rm -rf $midx" &&
1205 git repack -ad --write-midx &&
1206 corrupt_chunk_file $midx "$@"
1207 }
1208
1209 test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid fanout chunk' '
1210 corrupt_chunk OIDF clear 00000000 &&
1211 test_must_fail git log 2>err &&
1212 cat >expect <<-\EOF &&
1213 error: multi-pack-index OID fanout is of the wrong size
1214 fatal: multi-pack-index required OID fanout chunk missing or corrupted
1215 EOF
1216 test_cmp expect err
1217 '
1218
1219 test_expect_success PERL_TEST_HELPERS 'reader notices too-small oid lookup chunk' '
1220 corrupt_chunk OIDL clear 00000000 &&
1221 test_must_fail git log 2>err &&
1222 cat >expect <<-\EOF &&
1223 error: multi-pack-index OID lookup chunk is the wrong size
1224 fatal: multi-pack-index required OID lookup chunk missing or corrupted
1225 EOF
1226 test_cmp expect err
1227 '
1228
1229 test_expect_success PERL_TEST_HELPERS 'reader notices too-small pack names chunk' '
1230 # There is no NUL to terminate the name here, so the
1231 # chunk is too short.
1232 corrupt_chunk PNAM clear 70656666 &&
1233 test_must_fail git log 2>err &&
1234 cat >expect <<-\EOF &&
1235 fatal: multi-pack-index pack-name chunk is too short
1236 EOF
1237 test_cmp expect err
1238 '
1239
1240 test_expect_success PERL_TEST_HELPERS 'reader handles unaligned chunks' '
1241 # A 9-byte PNAM means all of the subsequent chunks
1242 # will no longer be 4-byte aligned, but it is still
1243 # a valid one-pack chunk on its own (it is "foo.pack\0").
1244 corrupt_chunk PNAM clear 666f6f2e7061636b00 &&
1245 git -c core.multipackindex=false log >expect.out &&
1246 git -c core.multipackindex=true log >out 2>err &&
1247 test_cmp expect.out out &&
1248 cat >expect.err <<-\EOF &&
1249 error: chunk id 4f494446 not 4-byte aligned
1250 EOF
1251 test_cmp expect.err err
1252 '
1253
1254 test_expect_success PERL_TEST_HELPERS 'reader notices too-small object offset chunk' '
1255 corrupt_chunk OOFF clear 00000000 &&
1256 test_must_fail git log 2>err &&
1257 cat >expect <<-\EOF &&
1258 error: multi-pack-index object offset chunk is the wrong size
1259 fatal: multi-pack-index required object offsets chunk missing or corrupted
1260 EOF
1261 test_cmp expect err
1262 '
1263
1264 test_expect_success PERL_TEST_HELPERS 'reader bounds-checks large offset table' '
1265 # re-use the objects64 dir here to cheaply get access to a midx
1266 # with large offsets.
1267 git init repo &&
1268 test_when_finished "rm -rf repo" &&
1269 (
1270 cd repo &&
1271 (cd ../objects64 && pwd) >.git/objects/info/alternates &&
1272 git multi-pack-index --object-dir=../objects64 write &&
1273 midx=../objects64/pack/multi-pack-index &&
1274 corrupt_chunk_file $midx LOFF clear &&
1275 # using only %(objectsize) is important here; see the commit
1276 # message for more details
1277 test_must_fail git cat-file --batch-all-objects \
1278 --batch-check="%(objectsize)" 2>err &&
1279 cat >expect <<-\EOF &&
1280 fatal: multi-pack-index large offset out of bounds
1281 EOF
1282 test_cmp expect err
1283 )
1284 '
1285
1286 test_expect_success PERL_TEST_HELPERS 'reader notices too-small revindex chunk' '
1287 # We only get a revindex with bitmaps (and likewise only
1288 # load it when they are asked for).
1289 test_config repack.writeBitmaps true &&
1290 corrupt_chunk RIDX clear 00000000 &&
1291 git -c core.multipackIndex=false rev-list \
1292 --all --use-bitmap-index >expect.out &&
1293 git -c core.multipackIndex=true rev-list \
1294 --all --use-bitmap-index >out 2>err &&
1295 test_cmp expect.out out &&
1296 cat >expect.err <<-\EOF &&
1297 error: multi-pack-index reverse-index chunk is the wrong size
1298 warning: multi-pack bitmap is missing required reverse index
1299 EOF
1300 test_cmp expect.err err
1301 '
1302
1303 test_expect_success PERL_TEST_HELPERS 'reader notices out-of-bounds fanout' '
1304 # This is similar to the out-of-bounds fanout test in t5318. The values
1305 # in adjacent entries should be large but not identical (they
1306 # are used as hi/lo starts for a binary search, which would then abort
1307 # immediately).
1308 corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
1309 test_must_fail git log 2>err &&
1310 cat >expect <<-\EOF &&
1311 error: oid fanout out of order: fanout[254] = fe000000 > 5c = fanout[255]
1312 fatal: multi-pack-index required OID fanout chunk missing or corrupted
1313 EOF
1314 test_cmp expect err
1315 '
1316
1317 test_expect_success 'bitmapped packs are stored via the BTMP chunk' '
1318 test_when_finished "rm -fr repo" &&
1319 git init repo &&
1320 (
1321 cd repo &&
1322 git config set maintenance.auto false &&
1323
1324 for i in 1 2 3 4 5
1325 do
1326 test_commit "$i" &&
1327 git repack -d || return 1
1328 done &&
1329
1330 find $objdir/pack -type f -name "*.idx" | xargs -n 1 basename |
1331 sort >packs &&
1332
1333 git multi-pack-index write --stdin-packs <packs &&
1334 test_must_fail test-tool read-midx --bitmap $objdir 2>err &&
1335 cat >expect <<-\EOF &&
1336 error: MIDX does not contain the BTMP chunk
1337 EOF
1338 test_cmp expect err &&
1339
1340 git multi-pack-index write --stdin-packs --bitmap \
1341 --preferred-pack="$(head -n1 <packs)" <packs &&
1342 test-tool read-midx --bitmap $objdir >actual &&
1343 for i in $(test_seq $(wc -l <packs))
1344 do
1345 sed -ne "${i}s/\.idx$/\.pack/p" packs &&
1346 echo " bitmap_pos: $((($i - 1) * 3))" &&
1347 echo " bitmap_nr: 3" || return 1
1348 done >expect &&
1349 test_cmp expect actual
1350 )
1351 '
1352
1353 test_expect_success 'pack.preferBitmapTips interprets patterns as hierarchy' '
1354 git init repo &&
1355 test_when_finished "rm -fr repo" &&
1356 (
1357 cd repo &&
1358
1359 # Create enough commits that not all will receive bitmap
1360 # coverage even if they are all at the tip of some reference.
1361 test_commit_bulk --message="%s" 103 &&
1362 git log --format="create refs/tags/%s %H" HEAD >refs &&
1363 git update-ref --stdin <refs &&
1364
1365 # Create the bitmap via the MIDX.
1366 git repack -adb --write-midx &&
1367 test-tool bitmap list-commits | sort >commits-with-bitmap &&
1368
1369 # Verify that we have at least one commit that did not
1370 # receive a bitmap.
1371 git rev-list HEAD >commits.raw &&
1372 sort <commits.raw >commits &&
1373 comm -13 commits-with-bitmap commits >commits-wo-bitmap &&
1374 test_file_not_empty commits-wo-bitmap &&
1375 commit_id=$(head commits-wo-bitmap) &&
1376 ref_without_bitmap=$(git for-each-ref --points-at="$commit_id" --format="%(refname)") &&
1377
1378 # When passing the full refname we do not expect a bitmap to be
1379 # generated, as it should be interpreted as if a slash was
1380 # appended to the pattern.
1381 rm .git/objects/pack/multi-pack-index* &&
1382 git -c pack.preferBitmapTips="$ref_without_bitmap" repack -adb --write-midx &&
1383 test-tool bitmap list-commits >after &&
1384 test_grep ! "$commit_id" after &&
1385
1386 # But if we pass the parent directory of the ref we should see
1387 # a bitmap.
1388 ref_namespace=$(dirname "$ref_without_bitmap") &&
1389 rm .git/objects/pack/multi-pack-index* &&
1390 git -c pack.preferBitmapTips="$ref_namespace" repack -adb --write-midx &&
1391 test-tool bitmap list-commits >after &&
1392 test_grep "$commit_id" after
1393 )
1394 '
1395
1396 test_done