Raw
1 #!/bin/sh
2
3 test_description='git log for a path with Bloom filters'
4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
7 . ./test-lib.sh
8 . "$TEST_DIRECTORY"/lib-chunk.sh
9
10 GIT_TEST_COMMIT_GRAPH=0
11 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
12
13 test_expect_success 'setup test - repo, commits, commit graph, log outputs' '
14 git init &&
15 mkdir A A/B A/B/C &&
16 test_commit c1 A/file1 &&
17 test_commit c2 A/B/file2 &&
18 test_commit c3 A/B/C/file3 &&
19 test_commit c4 A/file1 &&
20 test_commit c5 A/B/file2 &&
21 test_commit c6 A/B/C/file3 &&
22 test_commit c7 A/file1 &&
23 test_commit c8 A/B/file2 &&
24 test_commit c9 A/B/C/file3 &&
25 test_commit c10 file_to_be_deleted &&
26 git checkout -b side HEAD~4 &&
27 test_commit side-1 file4 &&
28 git checkout main &&
29 git merge side &&
30 test_commit c11 file5 &&
31 mv file5 file5_renamed &&
32 git add file5_renamed &&
33 git commit -m "rename" &&
34 rm file_to_be_deleted &&
35 git add . &&
36 git commit -m "file removed" &&
37 git commit --allow-empty -m "empty" &&
38 git commit-graph write --reachable --changed-paths &&
39
40 test_oid_cache <<-EOF
41 oid_version sha1:1
42 oid_version sha256:2
43 EOF
44 '
45
46 graph_read_expect () {
47 NUM_CHUNKS=6
48 cat >expect <<- EOF
49 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
50 num_commits: $1
51 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
52 options: bloom(1,10,7) read_generation_data
53 EOF
54 test-tool read-graph >actual &&
55 test_cmp expect actual
56 }
57
58 test_expect_success 'commit-graph write wrote out the bloom chunks' '
59 graph_read_expect 16
60 '
61
62 # Turn off any inherited trace2 settings for this test.
63 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
64 sane_unset GIT_TRACE2_PERF_BRIEF
65 sane_unset GIT_TRACE2_CONFIG_PARAMS
66
67 setup () {
68 rm -f "$TRASH_DIRECTORY/trace.perf" &&
69 eval git -c core.commitGraph=false log --pretty="format:%s" "$1" >log_wo_bloom &&
70 eval "GIT_TRACE2_PERF=\"$TRASH_DIRECTORY/trace.perf\"" \
71 git -c core.commitGraph=true log --pretty="format:%s" "$1" >log_w_bloom
72 }
73
74 test_bloom_filters_used () {
75 log_args=$1
76 bloom_trace_prefix="statistics:{\"filter_not_present\":${2:-0},\"maybe\""
77 setup "$log_args" &&
78 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
79 test_cmp log_wo_bloom log_w_bloom &&
80 test_path_is_file "$TRASH_DIRECTORY/trace.perf"
81 }
82
83 test_bloom_filters_not_used () {
84 log_args=$1
85 setup "$log_args" &&
86
87 if grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf"
88 then
89 # if the Bloom filter system is initialized, ensure that no
90 # filters were used
91 data="statistics:{"
92 # unusable filters (e.g., those computed with a
93 # different value of commitGraph.changedPathsVersion)
94 # are counted in the filter_not_present bucket, so any
95 # value is OK there.
96 data="$data\"filter_not_present\":[0-9][0-9]*,"
97 data="$data\"maybe\":0,"
98 data="$data\"definitely_not\":0,"
99 data="$data\"false_positive\":0}"
100
101 grep -q "$data" "$TRASH_DIRECTORY/trace.perf"
102 fi &&
103 test_cmp log_wo_bloom log_w_bloom
104 }
105
106 for path in A A/B A/B/C A/file1 A/B/file2 A/B/C/file3 file4 file5 file5_renamed file_to_be_deleted
107 do
108 for option in "" \
109 "--all" \
110 "--full-history" \
111 "--full-history --simplify-merges" \
112 "--simplify-merges" \
113 "--simplify-by-decoration" \
114 "--follow" \
115 "--first-parent" \
116 "--topo-order" \
117 "--date-order" \
118 "--author-date-order" \
119 "--ancestry-path side..main"
120 do
121 test_expect_success "git log option: $option for path: $path" '
122 test_bloom_filters_used "$option -- $path" &&
123 test_config commitgraph.readChangedPaths false &&
124 test_bloom_filters_not_used "$option -- $path"
125 '
126 done
127 done
128
129 test_expect_success 'git log -- folder works with and without the trailing slash' '
130 test_bloom_filters_used "-- A" &&
131 test_bloom_filters_used "-- A/"
132 '
133
134 test_expect_success 'git log for path that does not exist. ' '
135 test_bloom_filters_used "-- path_does_not_exist"
136 '
137
138 test_expect_success 'git log with --walk-reflogs does not use Bloom filters' '
139 test_bloom_filters_not_used "--walk-reflogs -- A"
140 '
141
142 test_expect_success 'git log -- "." pathspec at root does not use Bloom filters' '
143 test_bloom_filters_not_used "-- ."
144 '
145
146 test_expect_success 'git log with wildcard that resolves to a single path uses Bloom filters' '
147 test_bloom_filters_used "-- *4" &&
148 test_bloom_filters_used "-- *renamed"
149 '
150
151 test_expect_success 'git log with multiple literal paths uses Bloom filter' '
152 test_bloom_filters_used "-- file4 A/file1" &&
153 test_bloom_filters_used "-- *" &&
154 test_bloom_filters_used "-- file*"
155 '
156
157 test_expect_success 'git log with paths all contain non-wildcard part uses Bloom filter' '
158 test_bloom_filters_used "-- A/\* file4" &&
159 test_bloom_filters_used "-- A/file\*" &&
160 test_bloom_filters_used "-- * A/\*"
161 '
162
163 test_expect_success 'git log with path only contains wildcard part does not use Bloom filter' '
164 test_bloom_filters_not_used "-- file\*" &&
165 test_bloom_filters_not_used "-- file\* A/\*" &&
166 test_bloom_filters_not_used "-- file\* *" &&
167 test_bloom_filters_not_used "-- \*"
168 '
169
170 test_expect_success 'git log with path contains various magic signatures' '
171 cd A &&
172 test_bloom_filters_used "-- \:\(top\)B" &&
173 cd .. &&
174
175 test_bloom_filters_used "-- \:\(glob\)A/\*\*/C" &&
176 test_bloom_filters_not_used "-- \:\(icase\)FILE4" &&
177 test_bloom_filters_not_used "-- \:\(exclude\)A/B/C" &&
178
179 test_when_finished "rm -f .gitattributes" &&
180 cat >.gitattributes <<-EOF &&
181 A/file1 text
182 A/B/file2 -text
183 EOF
184 test_bloom_filters_used "-- \:\(attr\:text\)A"
185 '
186
187 test_expect_success 'setup - add commit-graph to the chain without Bloom filters' '
188 test_commit c14 A/anotherFile2 &&
189 test_commit c15 A/B/anotherFile2 &&
190 test_commit c16 A/B/C/anotherFile2 &&
191 git commit-graph write --reachable --split --no-changed-paths &&
192 test_line_count = 2 .git/objects/info/commit-graphs/commit-graph-chain
193 '
194
195 test_expect_success 'use Bloom filters even if the latest graph does not have Bloom filters' '
196 # Ensure that the number of empty filters is equal to the number of
197 # filters in the latest graph layer to prove that they are loaded (and
198 # ignored).
199 test_bloom_filters_used "-- A/B" 3
200 '
201
202 test_expect_success 'setup - add commit-graph to the chain with Bloom filters' '
203 test_commit c17 A/anotherFile3 &&
204 git commit-graph write --reachable --changed-paths --split &&
205 test_line_count = 3 .git/objects/info/commit-graphs/commit-graph-chain
206 '
207
208 test_bloom_filters_used_when_some_filters_are_missing () {
209 log_args=$1
210 bloom_trace_prefix="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":10"
211 setup "$log_args" &&
212 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
213 test_cmp log_wo_bloom log_w_bloom
214 }
215
216 test_expect_success 'Use Bloom filters if they exist in the latest but not all commit graphs in the chain.' '
217 test_bloom_filters_used_when_some_filters_are_missing "-- A/B"
218 '
219
220 test_expect_success 'persist filter settings' '
221 test_when_finished rm -rf .git/objects/info/commit-graph* &&
222 rm -rf .git/objects/info/commit-graph* &&
223 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
224 GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=9 \
225 GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY=15 \
226 git commit-graph write --reachable --changed-paths &&
227 test_grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2.txt &&
228 GIT_TRACE2_EVENT="$(pwd)/trace2-auto.txt" \
229 git commit-graph write --reachable --changed-paths &&
230 test_grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2-auto.txt
231 '
232
233 test_max_changed_paths () {
234 grep "\"max_changed_paths\":$1" $2
235 }
236
237 test_filter_not_computed () {
238 grep "\"key\":\"filter-not-computed\",\"value\":\"$1\"" $2
239 }
240
241 test_filter_computed () {
242 grep "\"key\":\"filter-computed\",\"value\":\"$1\"" $2
243 }
244
245 test_filter_trunc_empty () {
246 grep "\"key\":\"filter-trunc-empty\",\"value\":\"$1\"" $2
247 }
248
249 test_filter_trunc_large () {
250 grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2
251 }
252
253 test_filter_upgraded () {
254 grep "\"key\":\"filter-upgraded\",\"value\":\"$1\"" $2
255 }
256
257 test_expect_success 'correctly report changes over limit' '
258 git init limits &&
259 (
260 cd limits &&
261 mkdir d &&
262 mkdir d/e &&
263
264 for i in $(test_seq 1 2)
265 do
266 printf $i >d/file$i.txt &&
267 printf $i >d/e/file$i.txt || return 1
268 done &&
269
270 mkdir mode &&
271 printf bash >mode/script.sh &&
272
273 mkdir foo &&
274 touch foo/bar &&
275 touch foo.txt &&
276
277 git add d foo foo.txt mode &&
278 git commit -m "files" &&
279
280 # Commit has 7 file and 4 directory adds
281 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
282 GIT_TRACE2_EVENT="$(pwd)/trace" \
283 git commit-graph write --reachable --changed-paths &&
284 test_max_changed_paths 10 trace &&
285 test_filter_computed 1 trace &&
286 test_filter_trunc_large 1 trace &&
287
288 for path in $(git ls-tree -r --name-only HEAD)
289 do
290 git -c commitGraph.readChangedPaths=false log \
291 -- $path >expect &&
292 git log -- $path >actual &&
293 test_cmp expect actual || return 1
294 done &&
295
296 # Make a variety of path changes
297 printf new1 >d/e/file1.txt &&
298 printf new2 >d/file2.txt &&
299 rm d/e/file2.txt &&
300 rm -r foo &&
301 printf text >foo &&
302 mkdir f &&
303 printf new1 >f/file1.txt &&
304
305 # including a mode-only change (counts as modified)
306 git update-index --chmod=+x mode/script.sh &&
307
308 git add foo d f &&
309 git commit -m "complicated" &&
310
311 # start from scratch and rebuild
312 rm -f .git/objects/info/commit-graph &&
313 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
314 GIT_TRACE2_EVENT="$(pwd)/trace-edit" \
315 git commit-graph write --reachable --changed-paths &&
316 test_max_changed_paths 10 trace-edit &&
317 test_filter_computed 2 trace-edit &&
318 test_filter_trunc_large 2 trace-edit &&
319
320 for path in $(git ls-tree -r --name-only HEAD)
321 do
322 git -c commitGraph.readChangedPaths=false log \
323 -- $path >expect &&
324 git log -- $path >actual &&
325 test_cmp expect actual || return 1
326 done &&
327
328 # start from scratch and rebuild
329 rm -f .git/objects/info/commit-graph &&
330 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=11 \
331 GIT_TRACE2_EVENT="$(pwd)/trace-update" \
332 git commit-graph write --reachable --changed-paths &&
333 test_max_changed_paths 11 trace-update &&
334 test_filter_computed 2 trace-update &&
335 test_filter_trunc_large 0 trace-update &&
336
337 for path in $(git ls-tree -r --name-only HEAD)
338 do
339 git -c commitGraph.readChangedPaths=false log \
340 -- $path >expect &&
341 git log -- $path >actual &&
342 test_cmp expect actual || return 1
343 done
344 )
345 '
346
347 test_expect_success 'correctly report commits with no changed paths' '
348 git init empty &&
349 test_when_finished "rm -fr empty" &&
350 (
351 cd empty &&
352
353 git commit --allow-empty -m "initial commit" &&
354
355 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
356 git commit-graph write --reachable --changed-paths &&
357 test_filter_computed 1 trace.event &&
358 test_filter_not_computed 0 trace.event &&
359 test_filter_trunc_empty 1 trace.event &&
360 test_filter_trunc_large 0 trace.event
361 )
362 '
363
364 test_expect_success 'Bloom generation is limited by --max-new-filters' '
365 (
366 cd limits &&
367 test_commit c2 filter &&
368 test_commit c3 filter &&
369 test_commit c4 no-filter &&
370
371 rm -f trace.event &&
372 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
373 git commit-graph write --reachable --split=replace \
374 --changed-paths --max-new-filters=2 &&
375
376 test_filter_computed 2 trace.event &&
377 test_filter_not_computed 3 trace.event &&
378 test_filter_trunc_empty 0 trace.event &&
379 test_filter_trunc_large 0 trace.event
380 )
381 '
382
383 test_expect_success 'Bloom generation backfills previously-skipped filters' '
384 # Check specifying commitGraph.maxNewFilters over "git config" works.
385 test_config -C limits commitGraph.maxNewFilters 1 &&
386 (
387 cd limits &&
388
389 rm -f trace.event &&
390 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
391 git commit-graph write --reachable --changed-paths \
392 --split=replace &&
393 test_filter_computed 1 trace.event &&
394 test_filter_not_computed 4 trace.event &&
395 test_filter_trunc_empty 0 trace.event &&
396 test_filter_trunc_large 0 trace.event
397 )
398 '
399
400 test_expect_success '--max-new-filters overrides configuration' '
401 git init override &&
402 test_when_finished "rm -fr override" &&
403 test_config -C override commitGraph.maxNewFilters 2 &&
404 (
405 cd override &&
406 test_commit one &&
407 test_commit two &&
408
409 rm -f trace.event &&
410 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
411 git commit-graph write --reachable --changed-paths \
412 --max-new-filters=1 &&
413 test_filter_computed 1 trace.event &&
414 test_filter_not_computed 1 trace.event &&
415 test_filter_trunc_empty 0 trace.event &&
416 test_filter_trunc_large 0 trace.event
417 )
418 '
419
420 test_expect_success 'Bloom generation backfills empty commits' '
421 git init empty &&
422 test_when_finished "rm -fr empty" &&
423 (
424 cd empty &&
425 for i in $(test_seq 1 6)
426 do
427 git commit --allow-empty -m "$i" || return 1
428 done &&
429
430 # Generate Bloom filters for empty commits 1-6, two at a time.
431 for i in $(test_seq 1 3)
432 do
433 rm -f trace.event &&
434 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
435 git commit-graph write --reachable \
436 --changed-paths --max-new-filters=2 &&
437 test_filter_computed 2 trace.event &&
438 test_filter_not_computed 4 trace.event &&
439 test_filter_trunc_empty 2 trace.event &&
440 test_filter_trunc_large 0 trace.event || return 1
441 done &&
442
443 # Finally, make sure that once all commits have filters, that
444 # none are subsequently recomputed.
445 rm -f trace.event &&
446 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
447 git commit-graph write --reachable \
448 --changed-paths --max-new-filters=2 &&
449 test_filter_computed 0 trace.event &&
450 test_filter_not_computed 6 trace.event &&
451 test_filter_trunc_empty 0 trace.event &&
452 test_filter_trunc_large 0 trace.event
453 )
454 '
455
456 graph=.git/objects/info/commit-graph
457 graphdir=.git/objects/info/commit-graphs
458 chain=$graphdir/commit-graph-chain
459
460 test_expect_success 'setup for mixed Bloom setting tests' '
461 repo=mixed-bloom-settings &&
462
463 git init $repo &&
464 for i in one two three
465 do
466 test_commit -C $repo $i file || return 1
467 done
468 '
469
470 test_expect_success 'ensure Bloom filters with incompatible settings are ignored' '
471 # Compute Bloom filters with "unusual" settings.
472 git -C $repo rev-parse one >in &&
473 GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=3 git -C $repo commit-graph write \
474 --stdin-commits --changed-paths --split <in &&
475 layer=$(head -n 1 $repo/$chain) &&
476
477 # A commit-graph layer without Bloom filters "hides" the layers
478 # below ...
479 git -C $repo rev-parse two >in &&
480 git -C $repo commit-graph write --stdin-commits --no-changed-paths \
481 --split=no-merge <in &&
482
483 # Another commit-graph layer that has Bloom filters, but with
484 # standard settings, and is thus incompatible with the base
485 # layer written above.
486 git -C $repo rev-parse HEAD >in &&
487 git -C $repo commit-graph write --stdin-commits --changed-paths \
488 --split=no-merge <in &&
489
490 test_line_count = 3 $repo/$chain &&
491
492 # Ensure that incompatible Bloom filters are ignored.
493 git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- file \
494 >expect 2>err &&
495 git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
496 test_cmp expect actual &&
497 test_grep "disabling Bloom filters for commit-graph layer .$layer." err
498 '
499
500 test_expect_success 'merge graph layers with incompatible Bloom settings' '
501 # Ensure that incompatible Bloom filters are ignored when
502 # merging existing layers.
503 >trace2.txt &&
504 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
505 git -C $repo commit-graph write --reachable --changed-paths 2>err &&
506 test_grep "disabling Bloom filters for commit-graph layer .$layer." err &&
507 test_grep "{\"hash_version\":1,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt &&
508
509 test_path_is_file $repo/$graph &&
510 test_dir_is_empty $repo/$graphdir &&
511
512 git -C $repo -c core.commitGraph=false log --oneline --no-decorate -- \
513 file >expect &&
514 trace_out="$(pwd)/trace.perf" &&
515 GIT_TRACE2_PERF="$trace_out" \
516 git -C $repo log --oneline --no-decorate -- file >actual 2>err &&
517
518 test_cmp expect actual &&
519 test_grep "statistics:{\"filter_not_present\":0," trace.perf &&
520 test_must_be_empty err
521 '
522
523 # chosen to be the same under all Unicode normalization forms
524 CENT=$(printf "\302\242")
525
526 test_expect_success 'ensure Bloom filter with incompatible versions are ignored' '
527 rm "$repo/$graph" &&
528
529 git -C $repo log --oneline --no-decorate -- $CENT >expect &&
530
531 # Compute v1 Bloom filters for commits at the bottom.
532 git -C $repo rev-parse HEAD^ >in &&
533 git -C $repo commit-graph write --stdin-commits --changed-paths \
534 --split <in &&
535
536 # Compute v2 Bloomfilters for the rest of the commits at the top.
537 git -C $repo rev-parse HEAD >in &&
538 git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write \
539 --stdin-commits --changed-paths --split=no-merge <in &&
540
541 test_line_count = 2 $repo/$chain &&
542
543 git -C $repo log --oneline --no-decorate -- $CENT >actual 2>err &&
544 test_cmp expect actual &&
545
546 layer="$(head -n 1 $repo/$chain)" &&
547 cat >expect.err <<-EOF &&
548 warning: disabling Bloom filters for commit-graph layer $SQ$layer$SQ due to incompatible settings
549 EOF
550 test_cmp expect.err err &&
551
552 # Merge the two layers with incompatible bloom filter versions,
553 # ensuring that the v2 filters are used.
554 >trace2.txt &&
555 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
556 git -C $repo -c commitGraph.changedPathsVersion=2 commit-graph write --reachable --changed-paths 2>err &&
557 test_grep "disabling Bloom filters for commit-graph layer .$layer." err &&
558 test_grep "{\"hash_version\":2,\"num_hashes\":7,\"bits_per_entry\":10,\"max_changed_paths\":512" trace2.txt
559 '
560
561 get_first_changed_path_filter () {
562 test-tool read-graph bloom-filters >filters.dat &&
563 head -n 1 filters.dat
564 }
565
566 test_expect_success 'set up repo with high bit path, version 1 changed-path' '
567 git init highbit1 &&
568 test_commit -C highbit1 c1 "$CENT" &&
569 git -C highbit1 commit-graph write --reachable --changed-paths
570 '
571
572 test_expect_success 'setup make another commit' '
573 # "git log" does not use Bloom filters for root commits - see how, in
574 # revision.c, rev_compare_tree() (the only code path that eventually calls
575 # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
576 # has one parent. Therefore, make another commit so that we perform the tests on
577 # a non-root commit.
578 test_commit -C highbit1 anotherc1 "another$CENT"
579 '
580
581 test_expect_success 'version 1 changed-path used when version 1 requested' '
582 (
583 cd highbit1 &&
584 test_bloom_filters_used "-- another$CENT"
585 )
586 '
587
588 test_expect_success 'version 1 changed-path not used when version 2 requested' '
589 (
590 cd highbit1 &&
591 git config --add commitGraph.changedPathsVersion 2 &&
592 test_bloom_filters_not_used "-- another$CENT"
593 )
594 '
595
596 test_expect_success 'version 1 changed-path used when autodetect requested' '
597 (
598 cd highbit1 &&
599 git config --add commitGraph.changedPathsVersion -1 &&
600 test_bloom_filters_used "-- another$CENT"
601 )
602 '
603
604 test_expect_success 'when writing another commit graph, preserve existing version 1 of changed-path' '
605 test_commit -C highbit1 c1double "$CENT$CENT" &&
606 git -C highbit1 commit-graph write --reachable --changed-paths &&
607 (
608 cd highbit1 &&
609 git config --add commitGraph.changedPathsVersion -1 &&
610 echo "options: bloom(1,10,7) read_generation_data" >expect &&
611 test-tool read-graph >full &&
612 grep options full >actual &&
613 test_cmp expect actual
614 )
615 '
616
617 test_expect_success 'set up repo with high bit path, version 2 changed-path' '
618 git init highbit2 &&
619 git -C highbit2 config --add commitGraph.changedPathsVersion 2 &&
620 test_commit -C highbit2 c2 "$CENT" &&
621 git -C highbit2 commit-graph write --reachable --changed-paths
622 '
623
624 test_expect_success 'check value of version 2 changed-path' '
625 (
626 cd highbit2 &&
627 echo "c01f" >expect &&
628 get_first_changed_path_filter >actual &&
629 test_cmp expect actual
630 )
631 '
632
633 test_expect_success 'setup make another commit' '
634 # "git log" does not use Bloom filters for root commits - see how, in
635 # revision.c, rev_compare_tree() (the only code path that eventually calls
636 # get_bloom_filter()) is only called by try_to_simplify_commit() when the commit
637 # has one parent. Therefore, make another commit so that we perform the tests on
638 # a non-root commit.
639 test_commit -C highbit2 anotherc2 "another$CENT"
640 '
641
642 test_expect_success 'version 2 changed-path used when version 2 requested' '
643 (
644 cd highbit2 &&
645 test_bloom_filters_used "-- another$CENT"
646 )
647 '
648
649 test_expect_success 'version 2 changed-path not used when version 1 requested' '
650 (
651 cd highbit2 &&
652 git config --add commitGraph.changedPathsVersion 1 &&
653 test_bloom_filters_not_used "-- another$CENT"
654 )
655 '
656
657 test_expect_success 'version 2 changed-path used when autodetect requested' '
658 (
659 cd highbit2 &&
660 git config --add commitGraph.changedPathsVersion -1 &&
661 test_bloom_filters_used "-- another$CENT"
662 )
663 '
664
665 test_expect_success 'when writing another commit graph, preserve existing version 2 of changed-path' '
666 test_commit -C highbit2 c2double "$CENT$CENT" &&
667 git -C highbit2 commit-graph write --reachable --changed-paths &&
668 (
669 cd highbit2 &&
670 git config --add commitGraph.changedPathsVersion -1 &&
671 echo "options: bloom(2,10,7) read_generation_data" >expect &&
672 test-tool read-graph >full &&
673 grep options full >actual &&
674 test_cmp expect actual
675 )
676 '
677
678 test_expect_success 'when writing commit graph, do not reuse changed-path of another version' '
679 git init doublewrite &&
680 test_commit -C doublewrite c "$CENT" &&
681
682 git -C doublewrite config --add commitGraph.changedPathsVersion 1 &&
683 >trace2.txt &&
684 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
685 git -C doublewrite commit-graph write --reachable --changed-paths &&
686 test_filter_computed 1 trace2.txt &&
687 test_filter_upgraded 0 trace2.txt &&
688
689 git -C doublewrite commit-graph write --reachable --changed-paths &&
690 for v in -2 3
691 do
692 git -C doublewrite config --add commitGraph.changedPathsVersion $v &&
693 git -C doublewrite commit-graph write --reachable --changed-paths 2>err &&
694 cat >expect <<-EOF &&
695 warning: attempting to write a commit-graph, but ${SQ}commitGraph.changedPathsVersion${SQ} ($v) is not supported
696 EOF
697 test_cmp expect err || return 1
698 done &&
699
700 git -C doublewrite config --add commitGraph.changedPathsVersion 2 &&
701 >trace2.txt &&
702 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
703 git -C doublewrite commit-graph write --reachable --changed-paths &&
704 test_filter_computed 1 trace2.txt &&
705 test_filter_upgraded 0 trace2.txt &&
706
707 (
708 cd doublewrite &&
709 echo "c01f" >expect &&
710 get_first_changed_path_filter >actual &&
711 test_cmp expect actual
712 )
713 '
714
715 test_expect_success 'when writing commit graph, reuse changed-path of another version where possible' '
716 git init upgrade &&
717
718 test_commit -C upgrade base no-high-bits &&
719
720 git -C upgrade config --add commitGraph.changedPathsVersion 1 &&
721 >trace2.txt &&
722 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
723 git -C upgrade commit-graph write --reachable --changed-paths &&
724 test_filter_computed 1 trace2.txt &&
725 test_filter_upgraded 0 trace2.txt &&
726
727 git -C upgrade config --add commitGraph.changedPathsVersion 2 &&
728 >trace2.txt &&
729 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
730 git -C upgrade commit-graph write --reachable --changed-paths &&
731 test_filter_computed 0 trace2.txt &&
732 test_filter_upgraded 1 trace2.txt
733 '
734
735 corrupt_graph () {
736 test_when_finished "rm -rf $graph" &&
737 git commit-graph write --reachable --changed-paths &&
738 corrupt_chunk_file $graph "$@"
739 }
740
741 check_corrupt_graph () {
742 corrupt_graph "$@" &&
743 git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
744 git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
745 test_cmp expect.out out
746 }
747
748 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small data chunk' '
749 check_corrupt_graph BDAT clear 00000000 &&
750 echo "warning: ignoring too-small changed-path chunk" \
751 "(4 < 12) in commit-graph file" >expect.err &&
752 test_cmp expect.err err
753 '
754
755 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-bounds filter offsets' '
756 check_corrupt_graph BIDX 12 FFFFFFFF &&
757 # use grep to avoid depending on exact chunk size
758 test_grep "warning: ignoring out-of-range offset (4294967295) for changed-path filter at pos 3 of .git/objects/info/commit-graph" err
759 '
760
761 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices too-small index chunk' '
762 # replace the index with a single entry, making most
763 # lookups out-of-bounds
764 check_corrupt_graph BIDX clear 00000000 &&
765 echo "warning: commit-graph changed-path index chunk" \
766 "is too small" >expect.err &&
767 test_cmp expect.err err
768 '
769
770 test_expect_success PERL_TEST_HELPERS 'Bloom reader notices out-of-order index offsets' '
771 # we do not know any real offsets, but we can pick
772 # something plausible; we should not get to the point of
773 # actually reading from the bogus offsets anyway.
774 corrupt_graph BIDX 4 0000000c00000005 &&
775 echo "warning: ignoring decreasing changed-path index offsets" \
776 "(12 > 5) for positions 1 and 2 of .git/objects/info/commit-graph" >expect.err &&
777 git -c core.commitGraph=false log -- A/B/file2 >expect.out &&
778 git -c core.commitGraph=true log -- A/B/file2 >out 2>err &&
779 test_cmp expect.out out &&
780 test_cmp expect.err err
781 '
782
783 test_done