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