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
9 GIT_TEST_COMMIT_GRAPH
=0
10 GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS
=0
12 test_expect_success
'setup test - repo, commits, commit graph, log outputs' '
15 test_commit c1 A/file1 &&
16 test_commit c2 A/B/file2 &&
17 test_commit c3 A/B/C/file3 &&
18 test_commit c4 A/file1 &&
19 test_commit c5 A/B/file2 &&
20 test_commit c6 A/B/C/file3 &&
21 test_commit c7 A/file1 &&
22 test_commit c8 A/B/file2 &&
23 test_commit c9 A/B/C/file3 &&
24 test_commit c10 file_to_be_deleted &&
25 git checkout -b side HEAD~4 &&
26 test_commit side-1 file4 &&
29 test_commit c11 file5 &&
30 mv file5 file5_renamed &&
31 git add file5_renamed &&
32 git commit -m "rename" &&
33 rm file_to_be_deleted &&
35 git commit -m "file removed" &&
36 git commit --allow-empty -m "empty" &&
37 git commit-graph write --reachable --changed-paths &&
45 graph_read_expect
() {
48 header: 43475048 1 $(test_oid oid_version) $NUM_CHUNKS 0
50 chunks: oid_fanout oid_lookup commit_metadata generation_data bloom_indexes bloom_data
52 test-tool read-graph
>actual
&&
53 test_cmp expect actual
56 test_expect_success
'commit-graph write wrote out the bloom chunks' '
60 # Turn off any inherited trace2 settings for this test.
61 sane_unset GIT_TRACE2 GIT_TRACE2_PERF GIT_TRACE2_EVENT
62 sane_unset GIT_TRACE2_PERF_BRIEF
63 sane_unset GIT_TRACE2_CONFIG_PARAMS
66 rm -f "$TRASH_DIRECTORY/trace.perf" &&
67 git
-c core.commitGraph
=false log
--pretty="format:%s" $1 >log_wo_bloom
&&
68 GIT_TRACE2_PERF
="$TRASH_DIRECTORY/trace.perf" git
-c core.commitGraph
=true log
--pretty="format:%s" $1 >log_w_bloom
71 test_bloom_filters_used
() {
73 bloom_trace_prefix
="statistics:{\"filter_not_present\":${2:-0},\"maybe\""
75 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
76 test_cmp log_wo_bloom log_w_bloom
&&
77 test_path_is_file
"$TRASH_DIRECTORY/trace.perf"
80 test_bloom_filters_not_used
() {
83 ! grep -q "statistics:{\"filter_not_present\":" "$TRASH_DIRECTORY/trace.perf" &&
84 test_cmp log_wo_bloom log_w_bloom
87 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
92 "--full-history --simplify-merges" \
94 "--simplify-by-decoration" \
99 "--author-date-order" \
100 "--ancestry-path side..main"
102 test_expect_success
"git log option: $option for path: $path" '
103 test_bloom_filters_used "$option -- $path" &&
104 test_config commitgraph.readChangedPaths false &&
105 test_bloom_filters_not_used "$option -- $path"
110 test_expect_success
'git log -- folder works with and without the trailing slash' '
111 test_bloom_filters_used "-- A" &&
112 test_bloom_filters_used "-- A/"
115 test_expect_success
'git log for path that does not exist. ' '
116 test_bloom_filters_used "-- path_does_not_exist"
119 test_expect_success
'git log with --walk-reflogs does not use Bloom filters' '
120 test_bloom_filters_not_used "--walk-reflogs -- A"
123 test_expect_success
'git log -- multiple path specs does not use Bloom filters' '
124 test_bloom_filters_not_used "-- file4 A/file1"
127 test_expect_success
'git log -- "." pathspec at root does not use Bloom filters' '
128 test_bloom_filters_not_used "-- ."
131 test_expect_success
'git log with wildcard that resolves to a single path uses Bloom filters' '
132 test_bloom_filters_used "-- *4" &&
133 test_bloom_filters_used "-- *renamed"
136 test_expect_success
'git log with wildcard that resolves to a multiple paths does not uses Bloom filters' '
137 test_bloom_filters_not_used "-- *" &&
138 test_bloom_filters_not_used "-- file*"
141 test_expect_success
'setup - add commit-graph to the chain without Bloom filters' '
142 test_commit c14 A/anotherFile2 &&
143 test_commit c15 A/B/anotherFile2 &&
144 test_commit c16 A/B/C/anotherFile2 &&
145 git commit-graph write --reachable --split --no-changed-paths &&
146 test_line_count = 2 .git/objects/info/commit-graphs/commit-graph-chain
149 test_expect_success
'use Bloom filters even if the latest graph does not have Bloom filters' '
150 # Ensure that the number of empty filters is equal to the number of
151 # filters in the latest graph layer to prove that they are loaded (and
153 test_bloom_filters_used "-- A/B" 3
156 test_expect_success
'setup - add commit-graph to the chain with Bloom filters' '
157 test_commit c17 A/anotherFile3 &&
158 git commit-graph write --reachable --changed-paths --split &&
159 test_line_count = 3 .git/objects/info/commit-graphs/commit-graph-chain
162 test_bloom_filters_used_when_some_filters_are_missing
() {
164 bloom_trace_prefix
="statistics:{\"filter_not_present\":3,\"maybe\":6,\"definitely_not\":9"
166 grep -q "$bloom_trace_prefix" "$TRASH_DIRECTORY/trace.perf" &&
167 test_cmp log_wo_bloom log_w_bloom
170 test_expect_success
'Use Bloom filters if they exist in the latest but not all commit graphs in the chain.' '
171 test_bloom_filters_used_when_some_filters_are_missing "-- A/B"
174 test_expect_success
'persist filter settings' '
175 test_when_finished rm -rf .git/objects/info/commit-graph* &&
176 rm -rf .git/objects/info/commit-graph* &&
177 GIT_TRACE2_EVENT="$(pwd)/trace2.txt" \
178 GIT_TEST_BLOOM_SETTINGS_NUM_HASHES=9 \
179 GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY=15 \
180 git commit-graph write --reachable --changed-paths &&
181 grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2.txt &&
182 GIT_TRACE2_EVENT="$(pwd)/trace2-auto.txt" \
183 git commit-graph write --reachable --changed-paths &&
184 grep "{\"hash_version\":1,\"num_hashes\":9,\"bits_per_entry\":15,\"max_changed_paths\":512" trace2-auto.txt
187 test_max_changed_paths
() {
188 grep "\"max_changed_paths\":$1" $2
191 test_filter_not_computed
() {
192 grep "\"key\":\"filter-not-computed\",\"value\":\"$1\"" $2
195 test_filter_computed
() {
196 grep "\"key\":\"filter-computed\",\"value\":\"$1\"" $2
199 test_filter_trunc_empty
() {
200 grep "\"key\":\"filter-trunc-empty\",\"value\":\"$1\"" $2
203 test_filter_trunc_large
() {
204 grep "\"key\":\"filter-trunc-large\",\"value\":\"$1\"" $2
207 test_expect_success
'correctly report changes over limit' '
214 for i in $(test_seq 1 2)
216 printf $i >d/file$i.txt &&
217 printf $i >d/e/file$i.txt || return 1
221 printf bash >mode/script.sh &&
227 git add d foo foo.txt mode &&
228 git commit -m "files" &&
230 # Commit has 7 file and 4 directory adds
231 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
232 GIT_TRACE2_EVENT="$(pwd)/trace" \
233 git commit-graph write --reachable --changed-paths &&
234 test_max_changed_paths 10 trace &&
235 test_filter_computed 1 trace &&
236 test_filter_trunc_large 1 trace &&
238 for path in $(git ls-tree -r --name-only HEAD)
240 git -c commitGraph.readChangedPaths=false log \
242 git log -- $path >actual &&
243 test_cmp expect actual || return 1
246 # Make a variety of path changes
247 printf new1 >d/e/file1.txt &&
248 printf new2 >d/file2.txt &&
253 printf new1 >f/file1.txt &&
255 # including a mode-only change (counts as modified)
256 git update-index --chmod=+x mode/script.sh &&
259 git commit -m "complicated" &&
261 # start from scratch and rebuild
262 rm -f .git/objects/info/commit-graph &&
263 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=10 \
264 GIT_TRACE2_EVENT="$(pwd)/trace-edit" \
265 git commit-graph write --reachable --changed-paths &&
266 test_max_changed_paths 10 trace-edit &&
267 test_filter_computed 2 trace-edit &&
268 test_filter_trunc_large 2 trace-edit &&
270 for path in $(git ls-tree -r --name-only HEAD)
272 git -c commitGraph.readChangedPaths=false log \
274 git log -- $path >actual &&
275 test_cmp expect actual || return 1
278 # start from scratch and rebuild
279 rm -f .git/objects/info/commit-graph &&
280 GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS=11 \
281 GIT_TRACE2_EVENT="$(pwd)/trace-update" \
282 git commit-graph write --reachable --changed-paths &&
283 test_max_changed_paths 11 trace-update &&
284 test_filter_computed 2 trace-update &&
285 test_filter_trunc_large 0 trace-update &&
287 for path in $(git ls-tree -r --name-only HEAD)
289 git -c commitGraph.readChangedPaths=false log \
291 git log -- $path >actual &&
292 test_cmp expect actual || return 1
297 test_expect_success
'correctly report commits with no changed paths' '
299 test_when_finished "rm -fr empty" &&
303 git commit --allow-empty -m "initial commit" &&
305 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
306 git commit-graph write --reachable --changed-paths &&
307 test_filter_computed 1 trace.event &&
308 test_filter_not_computed 0 trace.event &&
309 test_filter_trunc_empty 1 trace.event &&
310 test_filter_trunc_large 0 trace.event
314 test_expect_success
'Bloom generation is limited by --max-new-filters' '
317 test_commit c2 filter &&
318 test_commit c3 filter &&
319 test_commit c4 no-filter &&
322 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
323 git commit-graph write --reachable --split=replace \
324 --changed-paths --max-new-filters=2 &&
326 test_filter_computed 2 trace.event &&
327 test_filter_not_computed 3 trace.event &&
328 test_filter_trunc_empty 0 trace.event &&
329 test_filter_trunc_large 0 trace.event
333 test_expect_success
'Bloom generation backfills previously-skipped filters' '
334 # Check specifying commitGraph.maxNewFilters over "git config" works.
335 test_config -C limits commitGraph.maxNewFilters 1 &&
340 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
341 git commit-graph write --reachable --changed-paths \
343 test_filter_computed 1 trace.event &&
344 test_filter_not_computed 4 trace.event &&
345 test_filter_trunc_empty 0 trace.event &&
346 test_filter_trunc_large 0 trace.event
350 test_expect_success
'--max-new-filters overrides configuration' '
352 test_when_finished "rm -fr override" &&
353 test_config -C override commitGraph.maxNewFilters 2 &&
360 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
361 git commit-graph write --reachable --changed-paths \
362 --max-new-filters=1 &&
363 test_filter_computed 1 trace.event &&
364 test_filter_not_computed 1 trace.event &&
365 test_filter_trunc_empty 0 trace.event &&
366 test_filter_trunc_large 0 trace.event
370 test_expect_success
'Bloom generation backfills empty commits' '
372 test_when_finished "rm -fr empty" &&
375 for i in $(test_seq 1 6)
377 git commit --allow-empty -m "$i" || return 1
380 # Generate Bloom filters for empty commits 1-6, two at a time.
381 for i in $(test_seq 1 3)
384 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
385 git commit-graph write --reachable \
386 --changed-paths --max-new-filters=2 &&
387 test_filter_computed 2 trace.event &&
388 test_filter_not_computed 4 trace.event &&
389 test_filter_trunc_empty 2 trace.event &&
390 test_filter_trunc_large 0 trace.event || return 1
393 # Finally, make sure that once all commits have filters, that
394 # none are subsequently recomputed.
396 GIT_TRACE2_EVENT="$(pwd)/trace.event" \
397 git commit-graph write --reachable \
398 --changed-paths --max-new-filters=2 &&
399 test_filter_computed 0 trace.event &&
400 test_filter_not_computed 6 trace.event &&
401 test_filter_trunc_empty 0 trace.event &&
402 test_filter_trunc_large 0 trace.event