Merge branch 'js/range-diff-wo-dotdot'
[git/debian.git] / t / t5310-pack-bitmaps.sh
blob5ba76031090ef3fb27b6e861e5766dfa7ae3c427
1 #!/bin/sh
3 test_description='exercise basic bitmap functionality'
4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7 . ./test-lib.sh
9 objpath () {
10 echo ".git/objects/$(echo "$1" | sed -e 's|\(..\)|\1/|')"
13 # show objects present in pack ($1 should be associated *.idx)
14 list_packed_objects () {
15 git show-index <"$1" >object-list &&
16 cut -d' ' -f2 object-list
19 # has_any pattern-file content-file
20 # tests whether content-file has any entry from pattern-file with entries being
21 # whole lines.
22 has_any () {
23 grep -Ff "$1" "$2"
26 # To ensure the logic for "maximal commits" is exercised, make
27 # the repository a bit more complicated.
29 # other second
30 # * *
31 # (99 commits) (99 commits)
32 # * *
33 # |\ /|
34 # | * octo-other octo-second * |
35 # |/|\_________ ____________/|\|
36 # | \ \/ __________/ |
37 # | | ________/\ / |
38 # * |/ * merge-right *
39 # | _|__________/ \____________ |
40 # |/ | \|
41 # (l1) * * merge-left * (r1)
42 # | / \________________________ |
43 # |/ \|
44 # (l2) * * (r2)
45 # \___________________________ |
46 # \|
47 # * (base)
49 # We only push bits down the first-parent history, which
50 # makes some of these commits unimportant!
52 # The important part for the maximal commit algorithm is how
53 # the bitmasks are extended. Assuming starting bit positions
54 # for second (bit 0) and other (bit 1), the bitmasks at the
55 # end should be:
57 # second: 1 (maximal, selected)
58 # other: 01 (maximal, selected)
59 # (base): 11 (maximal)
61 # This complicated history was important for a previous
62 # version of the walk that guarantees never walking a
63 # commit multiple times. That goal might be important
64 # again, so preserve this complicated case. For now, this
65 # test will guarantee that the bitmaps are computed
66 # correctly, even with the repeat calculations.
68 test_expect_success 'setup repo with moderate-sized history' '
69 test_commit_bulk --id=file 10 &&
70 git branch -M second &&
71 git checkout -b other HEAD~5 &&
72 test_commit_bulk --id=side 10 &&
74 # add complicated history setup, including merges and
75 # ambiguous merge-bases
77 git checkout -b merge-left other~2 &&
78 git merge second~2 -m "merge-left" &&
80 git checkout -b merge-right second~1 &&
81 git merge other~1 -m "merge-right" &&
83 git checkout -b octo-second second &&
84 git merge merge-left merge-right -m "octopus-second" &&
86 git checkout -b octo-other other &&
87 git merge merge-left merge-right -m "octopus-other" &&
89 git checkout other &&
90 git merge octo-other -m "pull octopus" &&
92 git checkout second &&
93 git merge octo-second -m "pull octopus" &&
95 # Remove these branches so they are not selected
96 # as bitmap tips
97 git branch -D merge-left &&
98 git branch -D merge-right &&
99 git branch -D octo-other &&
100 git branch -D octo-second &&
102 # add padding to make these merges less interesting
103 # and avoid having them selected for bitmaps
104 test_commit_bulk --id=file 100 &&
105 git checkout other &&
106 test_commit_bulk --id=side 100 &&
107 git checkout second &&
109 bitmaptip=$(git rev-parse second) &&
110 blob=$(echo tagged-blob | git hash-object -w --stdin) &&
111 git tag tagged-blob $blob &&
112 git config repack.writebitmaps true
115 test_expect_success 'full repack creates bitmaps' '
116 GIT_TRACE2_EVENT_NESTING=4 GIT_TRACE2_EVENT="$(pwd)/trace" \
117 git repack -ad &&
118 ls .git/objects/pack/ | grep bitmap >output &&
119 test_line_count = 1 output &&
120 grep "\"key\":\"num_selected_commits\",\"value\":\"106\"" trace &&
121 grep "\"key\":\"num_maximal_commits\",\"value\":\"107\"" trace
124 test_expect_success 'rev-list --test-bitmap verifies bitmaps' '
125 git rev-list --test-bitmap HEAD
128 rev_list_tests_head () {
129 test_expect_success "counting commits via bitmap ($state, $branch)" '
130 git rev-list --count $branch >expect &&
131 git rev-list --use-bitmap-index --count $branch >actual &&
132 test_cmp expect actual
135 test_expect_success "counting partial commits via bitmap ($state, $branch)" '
136 git rev-list --count $branch~5..$branch >expect &&
137 git rev-list --use-bitmap-index --count $branch~5..$branch >actual &&
138 test_cmp expect actual
141 test_expect_success "counting commits with limit ($state, $branch)" '
142 git rev-list --count -n 1 $branch >expect &&
143 git rev-list --use-bitmap-index --count -n 1 $branch >actual &&
144 test_cmp expect actual
147 test_expect_success "counting non-linear history ($state, $branch)" '
148 git rev-list --count other...second >expect &&
149 git rev-list --use-bitmap-index --count other...second >actual &&
150 test_cmp expect actual
153 test_expect_success "counting commits with limiting ($state, $branch)" '
154 git rev-list --count $branch -- 1.t >expect &&
155 git rev-list --use-bitmap-index --count $branch -- 1.t >actual &&
156 test_cmp expect actual
159 test_expect_success "counting objects via bitmap ($state, $branch)" '
160 git rev-list --count --objects $branch >expect &&
161 git rev-list --use-bitmap-index --count --objects $branch >actual &&
162 test_cmp expect actual
165 test_expect_success "enumerate commits ($state, $branch)" '
166 git rev-list --use-bitmap-index $branch >actual &&
167 git rev-list $branch >expect &&
168 test_bitmap_traversal --no-confirm-bitmaps expect actual
171 test_expect_success "enumerate --objects ($state, $branch)" '
172 git rev-list --objects --use-bitmap-index $branch >actual &&
173 git rev-list --objects $branch >expect &&
174 test_bitmap_traversal expect actual
177 test_expect_success "bitmap --objects handles non-commit objects ($state, $branch)" '
178 git rev-list --objects --use-bitmap-index $branch tagged-blob >actual &&
179 grep $blob actual
183 rev_list_tests () {
184 state=$1
186 for branch in "second" "other"
188 rev_list_tests_head
189 done
192 rev_list_tests 'full bitmap'
194 test_expect_success 'clone from bitmapped repository' '
195 git clone --no-local --bare . clone.git &&
196 git rev-parse HEAD >expect &&
197 git --git-dir=clone.git rev-parse HEAD >actual &&
198 test_cmp expect actual
201 test_expect_success 'partial clone from bitmapped repository' '
202 test_config uploadpack.allowfilter true &&
203 git clone --no-local --bare --filter=blob:none . partial-clone.git &&
205 cd partial-clone.git &&
206 pack=$(echo objects/pack/*.pack) &&
207 git verify-pack -v "$pack" >have &&
208 awk "/blob/ { print \$1 }" <have >blobs &&
209 # we expect this single blob because of the direct ref
210 git rev-parse refs/tags/tagged-blob >expect &&
211 test_cmp expect blobs
215 test_expect_success 'setup further non-bitmapped commits' '
216 test_commit_bulk --id=further 10
219 rev_list_tests 'partial bitmap'
221 test_expect_success 'fetch (partial bitmap)' '
222 git --git-dir=clone.git fetch origin second:second &&
223 git rev-parse HEAD >expect &&
224 git --git-dir=clone.git rev-parse HEAD >actual &&
225 test_cmp expect actual
228 test_expect_success 'incremental repack fails when bitmaps are requested' '
229 test_commit more-1 &&
230 test_must_fail git repack -d 2>err &&
231 test_i18ngrep "Incremental repacks are incompatible with bitmap" err
234 test_expect_success 'incremental repack can disable bitmaps' '
235 test_commit more-2 &&
236 git repack -d --no-write-bitmap-index
239 test_expect_success 'pack-objects respects --local (non-local loose)' '
240 git init --bare alt.git &&
241 echo $(pwd)/alt.git/objects >.git/objects/info/alternates &&
242 echo content1 >file1 &&
243 # non-local loose object which is not present in bitmapped pack
244 altblob=$(GIT_DIR=alt.git git hash-object -w file1) &&
245 # non-local loose object which is also present in bitmapped pack
246 git cat-file blob $blob | GIT_DIR=alt.git git hash-object -w --stdin &&
247 git add file1 &&
248 test_tick &&
249 git commit -m commit_file1 &&
250 echo HEAD | git pack-objects --local --stdout --revs >1.pack &&
251 git index-pack 1.pack &&
252 list_packed_objects 1.idx >1.objects &&
253 printf "%s\n" "$altblob" "$blob" >nonlocal-loose &&
254 ! has_any nonlocal-loose 1.objects
257 test_expect_success 'pack-objects respects --honor-pack-keep (local non-bitmapped pack)' '
258 echo content2 >file2 &&
259 blob2=$(git hash-object -w file2) &&
260 git add file2 &&
261 test_tick &&
262 git commit -m commit_file2 &&
263 printf "%s\n" "$blob2" "$bitmaptip" >keepobjects &&
264 pack2=$(git pack-objects pack2 <keepobjects) &&
265 mv pack2-$pack2.* .git/objects/pack/ &&
266 >.git/objects/pack/pack2-$pack2.keep &&
267 rm $(objpath $blob2) &&
268 echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >2a.pack &&
269 git index-pack 2a.pack &&
270 list_packed_objects 2a.idx >2a.objects &&
271 ! has_any keepobjects 2a.objects
274 test_expect_success 'pack-objects respects --local (non-local pack)' '
275 mv .git/objects/pack/pack2-$pack2.* alt.git/objects/pack/ &&
276 echo HEAD | git pack-objects --local --stdout --revs >2b.pack &&
277 git index-pack 2b.pack &&
278 list_packed_objects 2b.idx >2b.objects &&
279 ! has_any keepobjects 2b.objects
282 test_expect_success 'pack-objects respects --honor-pack-keep (local bitmapped pack)' '
283 ls .git/objects/pack/ | grep bitmap >output &&
284 test_line_count = 1 output &&
285 packbitmap=$(basename $(cat output) .bitmap) &&
286 list_packed_objects .git/objects/pack/$packbitmap.idx >packbitmap.objects &&
287 test_when_finished "rm -f .git/objects/pack/$packbitmap.keep" &&
288 >.git/objects/pack/$packbitmap.keep &&
289 echo HEAD | git pack-objects --honor-pack-keep --stdout --revs >3a.pack &&
290 git index-pack 3a.pack &&
291 list_packed_objects 3a.idx >3a.objects &&
292 ! has_any packbitmap.objects 3a.objects
295 test_expect_success 'pack-objects respects --local (non-local bitmapped pack)' '
296 mv .git/objects/pack/$packbitmap.* alt.git/objects/pack/ &&
297 rm -f .git/objects/pack/multi-pack-index &&
298 test_when_finished "mv alt.git/objects/pack/$packbitmap.* .git/objects/pack/" &&
299 echo HEAD | git pack-objects --local --stdout --revs >3b.pack &&
300 git index-pack 3b.pack &&
301 list_packed_objects 3b.idx >3b.objects &&
302 ! has_any packbitmap.objects 3b.objects
305 test_expect_success 'pack-objects to file can use bitmap' '
306 # make sure we still have 1 bitmap index from previous tests
307 ls .git/objects/pack/ | grep bitmap >output &&
308 test_line_count = 1 output &&
309 # verify equivalent packs are generated with/without using bitmap index
310 packasha1=$(git pack-objects --no-use-bitmap-index --all packa </dev/null) &&
311 packbsha1=$(git pack-objects --use-bitmap-index --all packb </dev/null) &&
312 list_packed_objects packa-$packasha1.idx >packa.objects &&
313 list_packed_objects packb-$packbsha1.idx >packb.objects &&
314 test_cmp packa.objects packb.objects
317 test_expect_success 'full repack, reusing previous bitmaps' '
318 git repack -ad &&
319 ls .git/objects/pack/ | grep bitmap >output &&
320 test_line_count = 1 output
323 test_expect_success 'fetch (full bitmap)' '
324 git --git-dir=clone.git fetch origin second:second &&
325 git rev-parse HEAD >expect &&
326 git --git-dir=clone.git rev-parse HEAD >actual &&
327 test_cmp expect actual
330 test_expect_success 'create objects for missing-HAVE tests' '
331 blob=$(echo "missing have" | git hash-object -w --stdin) &&
332 tree=$(printf "100644 blob $blob\tfile\n" | git mktree) &&
333 parent=$(echo parent | git commit-tree $tree) &&
334 commit=$(echo commit | git commit-tree $tree -p $parent) &&
335 cat >revs <<-EOF
336 HEAD
337 ^HEAD^
338 ^$commit
342 test_expect_success 'pack-objects respects --incremental' '
343 cat >revs2 <<-EOF &&
344 HEAD
345 $commit
347 git pack-objects --incremental --stdout --revs <revs2 >4.pack &&
348 git index-pack 4.pack &&
349 list_packed_objects 4.idx >4.objects &&
350 test_line_count = 4 4.objects &&
351 git rev-list --objects $commit >revlist &&
352 cut -d" " -f1 revlist |sort >objects &&
353 test_cmp 4.objects objects
356 test_expect_success 'pack with missing blob' '
357 rm $(objpath $blob) &&
358 git pack-objects --stdout --revs <revs >/dev/null
361 test_expect_success 'pack with missing tree' '
362 rm $(objpath $tree) &&
363 git pack-objects --stdout --revs <revs >/dev/null
366 test_expect_success 'pack with missing parent' '
367 rm $(objpath $parent) &&
368 git pack-objects --stdout --revs <revs >/dev/null
371 test_expect_success JGIT,SHA1 'we can read jgit bitmaps' '
372 git clone --bare . compat-jgit.git &&
374 cd compat-jgit.git &&
375 rm -f objects/pack/*.bitmap &&
376 jgit gc &&
377 git rev-list --test-bitmap HEAD
381 test_expect_success JGIT,SHA1 'jgit can read our bitmaps' '
382 git clone --bare . compat-us.git &&
384 cd compat-us.git &&
385 git repack -adb &&
386 # jgit gc will barf if it does not like our bitmaps
387 jgit gc
391 test_expect_success 'splitting packs does not generate bogus bitmaps' '
392 test-tool genrandom foo $((1024 * 1024)) >rand &&
393 git add rand &&
394 git commit -m "commit with big file" &&
395 git -c pack.packSizeLimit=500k repack -adb &&
396 git init --bare no-bitmaps.git &&
397 git -C no-bitmaps.git fetch .. HEAD
400 test_expect_success 'set up reusable pack' '
401 rm -f .git/objects/pack/*.keep &&
402 git repack -adb &&
403 reusable_pack () {
404 git for-each-ref --format="%(objectname)" |
405 git pack-objects --delta-base-offset --revs --stdout "$@"
409 test_expect_success 'pack reuse respects --honor-pack-keep' '
410 test_when_finished "rm -f .git/objects/pack/*.keep" &&
411 for i in .git/objects/pack/*.pack
413 >${i%.pack}.keep
414 done &&
415 reusable_pack --honor-pack-keep >empty.pack &&
416 git index-pack empty.pack &&
417 git show-index <empty.idx >actual &&
418 test_must_be_empty actual
421 test_expect_success 'pack reuse respects --local' '
422 mv .git/objects/pack/* alt.git/objects/pack/ &&
423 test_when_finished "mv alt.git/objects/pack/* .git/objects/pack/" &&
424 reusable_pack --local >empty.pack &&
425 git index-pack empty.pack &&
426 git show-index <empty.idx >actual &&
427 test_must_be_empty actual
430 test_expect_success 'pack reuse respects --incremental' '
431 reusable_pack --incremental >empty.pack &&
432 git index-pack empty.pack &&
433 git show-index <empty.idx >actual &&
434 test_must_be_empty actual
437 test_expect_success 'truncated bitmap fails gracefully (ewah)' '
438 test_config pack.writebitmaphashcache false &&
439 git repack -ad &&
440 git rev-list --use-bitmap-index --count --all >expect &&
441 bitmap=$(ls .git/objects/pack/*.bitmap) &&
442 test_when_finished "rm -f $bitmap" &&
443 test_copy_bytes 256 <$bitmap >$bitmap.tmp &&
444 mv -f $bitmap.tmp $bitmap &&
445 git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
446 test_cmp expect actual &&
447 test_i18ngrep corrupt.ewah.bitmap stderr
450 test_expect_success 'truncated bitmap fails gracefully (cache)' '
451 git repack -ad &&
452 git rev-list --use-bitmap-index --count --all >expect &&
453 bitmap=$(ls .git/objects/pack/*.bitmap) &&
454 test_when_finished "rm -f $bitmap" &&
455 test_copy_bytes 512 <$bitmap >$bitmap.tmp &&
456 mv -f $bitmap.tmp $bitmap &&
457 git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
458 test_cmp expect actual &&
459 test_i18ngrep corrupted.bitmap.index stderr
462 # have_delta <obj> <expected_base>
464 # Note that because this relies on cat-file, it might find _any_ copy of an
465 # object in the repository. The caller is responsible for making sure
466 # there's only one (e.g., via "repack -ad", or having just fetched a copy).
467 have_delta () {
468 echo $2 >expect &&
469 echo $1 | git cat-file --batch-check="%(deltabase)" >actual &&
470 test_cmp expect actual
473 # Create a state of history with these properties:
475 # - refs that allow a client to fetch some new history, while sharing some old
476 # history with the server; we use branches delta-reuse-old and
477 # delta-reuse-new here
479 # - the new history contains an object that is stored on the server as a delta
480 # against a base that is in the old history
482 # - the base object is not immediately reachable from the tip of the old
483 # history; finding it would involve digging down through history we know the
484 # other side has
486 # This should result in a state where fetching from old->new would not
487 # traditionally reuse the on-disk delta (because we'd have to dig to realize
488 # that the client has it), but we will do so if bitmaps can tell us cheaply
489 # that the other side has it.
490 test_expect_success 'set up thin delta-reuse parent' '
491 # This first commit contains the buried base object.
492 test-tool genrandom delta 16384 >file &&
493 git add file &&
494 git commit -m "delta base" &&
495 base=$(git rev-parse --verify HEAD:file) &&
497 # These intermediate commits bury the base back in history.
498 # This becomes the "old" state.
499 for i in 1 2 3 4 5
501 echo $i >file &&
502 git commit -am "intermediate $i" || return 1
503 done &&
504 git branch delta-reuse-old &&
506 # And now our new history has a delta against the buried base. Note
507 # that this must be smaller than the original file, since pack-objects
508 # prefers to create deltas from smaller objects to larger.
509 test-tool genrandom delta 16300 >file &&
510 git commit -am "delta result" &&
511 delta=$(git rev-parse --verify HEAD:file) &&
512 git branch delta-reuse-new &&
514 # Repack with bitmaps and double check that we have the expected delta
515 # relationship.
516 git repack -adb &&
517 have_delta $delta $base
520 # Now we can sanity-check the non-bitmap behavior (that the server is not able
521 # to reuse the delta). This isn't strictly something we care about, so this
522 # test could be scrapped in the future. But it makes sure that the next test is
523 # actually triggering the feature we want.
525 # Note that our tools for working with on-the-wire "thin" packs are limited. So
526 # we actually perform the fetch, retain the resulting pack, and inspect the
527 # result.
528 test_expect_success 'fetch without bitmaps ignores delta against old base' '
529 test_config pack.usebitmaps false &&
530 test_when_finished "rm -rf client.git" &&
531 git init --bare client.git &&
533 cd client.git &&
534 git config transfer.unpackLimit 1 &&
535 git fetch .. delta-reuse-old:delta-reuse-old &&
536 git fetch .. delta-reuse-new:delta-reuse-new &&
537 have_delta $delta $ZERO_OID
541 # And do the same for the bitmap case, where we do expect to find the delta.
542 test_expect_success 'fetch with bitmaps can reuse old base' '
543 test_config pack.usebitmaps true &&
544 test_when_finished "rm -rf client.git" &&
545 git init --bare client.git &&
547 cd client.git &&
548 git config transfer.unpackLimit 1 &&
549 git fetch .. delta-reuse-old:delta-reuse-old &&
550 git fetch .. delta-reuse-new:delta-reuse-new &&
551 have_delta $delta $base
555 test_done