Git fork
1#!/bin/sh
2
3test_description='pseudo-merge bitmaps'
4
5GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
6
7. ./test-lib.sh
8
9test_pseudo_merges () {
10 test-tool bitmap dump-pseudo-merges
11}
12
13test_pseudo_merge_commits () {
14 test-tool bitmap dump-pseudo-merge-commits "$1"
15}
16
17test_pseudo_merges_satisfied () {
18 test_trace2_data bitmap pseudo_merges_satisfied "$1"
19}
20
21test_pseudo_merges_cascades () {
22 test_trace2_data bitmap pseudo_merges_cascades "$1"
23}
24
25test_pseudo_merges_reused () {
26 test_trace2_data pack-bitmap-write building_bitmaps_pseudo_merge_reused "$1"
27}
28
29tag_everything () {
30 git rev-list --all --no-object-names >in &&
31 sed 's|\(.*\)|create refs/tags/\1 \1|' in |
32 git update-ref --stdin
33}
34
35test_expect_success 'setup' '
36 test_commit_bulk 512 &&
37 tag_everything
38'
39
40test_expect_success 'bitmap traversal without pseudo-merges' '
41 git repack -adb &&
42
43 git rev-list --count --all --objects >expect &&
44
45 : >trace2.txt &&
46 GIT_TRACE2_EVENT=$PWD/trace2.txt \
47 git rev-list --count --all --objects --use-bitmap-index >actual &&
48
49 test_pseudo_merges_satisfied 0 <trace2.txt &&
50 test_pseudo_merges_cascades 0 <trace2.txt &&
51 test_pseudo_merges >merges &&
52 test_must_be_empty merges &&
53 test_cmp expect actual
54'
55
56test_expect_success 'pseudo-merges accurately represent their objects' '
57 test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
58 test_config bitmapPseudoMerge.test.maxMerges 8 &&
59 test_config bitmapPseudoMerge.test.stableThreshold never &&
60
61 git repack -adb &&
62
63 test_pseudo_merges >merges &&
64 test_line_count = 8 merges &&
65
66 for i in $(test_seq 0 $(($(wc -l <merges)-1)))
67 do
68 test-tool bitmap dump-pseudo-merge-commits $i >commits &&
69
70 git rev-list --objects --no-object-names --stdin <commits >expect.raw &&
71 test-tool bitmap dump-pseudo-merge-objects $i >actual.raw &&
72
73 sort -u <expect.raw >expect &&
74 sort -u <actual.raw >actual &&
75
76 test_cmp expect actual || return 1
77 done
78'
79
80test_expect_success 'bitmap traversal with pseudo-merges' '
81 : >trace2.txt &&
82 GIT_TRACE2_EVENT=$PWD/trace2.txt \
83 git rev-list --count --all --objects --use-bitmap-index >actual &&
84 git rev-list --count --all --objects >expect &&
85
86 test_pseudo_merges_satisfied 8 <trace2.txt &&
87 test_pseudo_merges_cascades 1 <trace2.txt &&
88 test_cmp expect actual
89'
90
91test_expect_success 'stale bitmap traversal with pseudo-merges' '
92 test_commit other &&
93
94 : >trace2.txt &&
95 GIT_TRACE2_EVENT=$PWD/trace2.txt \
96 git rev-list --count --all --objects --use-bitmap-index >actual &&
97 git rev-list --count --all --objects >expect &&
98
99 test_pseudo_merges_satisfied 8 <trace2.txt &&
100 test_pseudo_merges_cascades 1 <trace2.txt &&
101 test_cmp expect actual
102'
103
104test_expect_success PERL_TEST_HELPERS 'bitmapPseudoMerge.sampleRate adjusts commit selection rate' '
105 test_config bitmapPseudoMerge.test.pattern "refs/tags/" &&
106 test_config bitmapPseudoMerge.test.maxMerges 1 &&
107 test_config bitmapPseudoMerge.test.stableThreshold never &&
108
109 commits_nr=$(git rev-list --all --count) &&
110
111 for rate in 1.0 0.5 0.25
112 do
113 git -c bitmapPseudoMerge.test.sampleRate=$rate repack -adb &&
114
115 test_pseudo_merges >merges &&
116 test_line_count = 1 merges &&
117 test_pseudo_merge_commits 0 >commits &&
118
119 test-tool bitmap list-commits >bitmaps &&
120 bitmaps_nr="$(wc -l <bitmaps)" &&
121
122 perl -MPOSIX -e "print ceil(\$ARGV[0]*(\$ARGV[1]-\$ARGV[2]))" \
123 "$rate" "$commits_nr" "$bitmaps_nr" >expect &&
124
125 test $(cat expect) -eq $(wc -l <commits) || return 1
126 done
127'
128
129test_expect_success 'bitmapPseudoMerge.threshold excludes newer commits' '
130 git init pseudo-merge-threshold &&
131 (
132 cd pseudo-merge-threshold &&
133
134 new="1672549200" && # 2023-01-01
135 old="1641013200" && # 2022-01-01
136
137 GIT_COMMITTER_DATE="$new +0000" &&
138 export GIT_COMMITTER_DATE &&
139 test_commit_bulk --message="new" --notick 128 &&
140
141 GIT_COMMITTER_DATE="$old +0000" &&
142 export GIT_COMMITTER_DATE &&
143 test_commit_bulk --message="old" --notick 128 &&
144
145 tag_everything &&
146
147 git \
148 -c bitmapPseudoMerge.test.pattern="refs/tags/" \
149 -c bitmapPseudoMerge.test.maxMerges=1 \
150 -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
151 -c bitmapPseudoMerge.test.stableThreshold=never \
152 repack -adb &&
153
154 test_pseudo_merges >merges &&
155 test_line_count = 1 merges &&
156
157 test_pseudo_merge_commits 0 >oids &&
158 git cat-file --batch <oids >commits &&
159
160 test $(wc -l <oids) = $(grep -c "^committer.*$old +0000$" commits)
161 )
162'
163
164test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' '
165 (
166 cd pseudo-merge-threshold &&
167
168 new="1672549200" && # 2023-01-01
169 mid="1654059600" && # 2022-06-01
170 old="1641013200" && # 2022-01-01
171
172 GIT_COMMITTER_DATE="$mid +0000" &&
173 export GIT_COMMITTER_DATE &&
174 test_commit_bulk --message="mid" --notick 128 &&
175
176 git for-each-ref --format="delete %(refname)" refs/tags >in &&
177 git update-ref --stdin <in &&
178
179 tag_everything &&
180
181 git \
182 -c bitmapPseudoMerge.test.pattern="refs/tags/" \
183 -c bitmapPseudoMerge.test.maxMerges=1 \
184 -c bitmapPseudoMerge.test.threshold=$(($new - 1)) \
185 -c bitmapPseudoMerge.test.stableThreshold=$(($mid - 1)) \
186 -c bitmapPseudoMerge.test.stableSize=10 \
187 repack -adb &&
188
189 test_pseudo_merges >merges &&
190 merges_nr="$(wc -l <merges)" &&
191
192 for i in $(test_seq $(($merges_nr - 1)))
193 do
194 test_pseudo_merge_commits 0 >oids &&
195 git cat-file --batch <oids >commits &&
196
197 expect="$(grep -c "^committer.*$old +0000$" commits)" &&
198 actual="$(wc -l <oids)" &&
199
200 test $expect = $actual || return 1
201 done &&
202
203 test_pseudo_merge_commits $(($merges_nr - 1)) >oids &&
204 git cat-file --batch <oids >commits &&
205 test $(wc -l <oids) = $(grep -c "^committer.*$mid +0000$" commits)
206 )
207'
208
209test_expect_success 'out of order thresholds are rejected' '
210 # Disable the test var to remove a stderr message.
211 test_must_fail env GIT_TEST_NAME_HASH_VERSION=1 git \
212 -c bitmapPseudoMerge.test.pattern="refs/*" \
213 -c bitmapPseudoMerge.test.threshold=1.month.ago \
214 -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \
215 repack -adb 2>err &&
216
217 cat >expect <<-EOF &&
218 fatal: pseudo-merge group ${SQ}test${SQ} has unstable threshold before stable one
219 EOF
220
221 test_cmp expect err
222'
223
224test_expect_success 'pseudo-merge pattern with capture groups' '
225 git init pseudo-merge-captures &&
226 (
227 cd pseudo-merge-captures &&
228
229 test_commit_bulk 128 &&
230 tag_everything &&
231
232 for r in $(test_seq 8)
233 do
234 test_commit_bulk 16 &&
235
236 git rev-list HEAD~16.. >in &&
237 sed "s|\(.*\)|create refs/remotes/$r/tags/\1 \1|" in >refs &&
238 git update-ref --stdin <refs || return 1
239 done &&
240
241 git \
242 -c bitmapPseudoMerge.tags.pattern="refs/remotes/([0-9]+)/tags/" \
243 -c bitmapPseudoMerge.tags.maxMerges=1 \
244 repack -adb &&
245
246 git for-each-ref --format="%(objectname) %(refname)" >refs &&
247
248 test_pseudo_merges >merges &&
249 for m in $(test_seq 0 $(($(wc -l <merges) - 1)))
250 do
251 test_pseudo_merge_commits $m >oids &&
252 grep -f oids refs |
253 sed -n "s|refs/remotes/\([0-9][0-9]*\)/|\1|p" &&
254 sort -u || return 1
255 done >remotes &&
256
257 test $(wc -l <remotes) -eq $(sort -u <remotes | wc -l)
258 )
259'
260
261test_expect_success 'pseudo-merge overlap setup' '
262 git init pseudo-merge-overlap &&
263 (
264 cd pseudo-merge-overlap &&
265
266 test_commit_bulk 256 &&
267 tag_everything &&
268
269 git \
270 -c bitmapPseudoMerge.all.pattern="refs/" \
271 -c bitmapPseudoMerge.all.maxMerges=1 \
272 -c bitmapPseudoMerge.all.stableThreshold=never \
273 -c bitmapPseudoMerge.tags.pattern="refs/tags/" \
274 -c bitmapPseudoMerge.tags.maxMerges=1 \
275 -c bitmapPseudoMerge.tags.stableThreshold=never \
276 repack -adb
277 )
278'
279
280test_expect_success 'pseudo-merge overlap generates overlapping groups' '
281 (
282 cd pseudo-merge-overlap &&
283
284 test_pseudo_merges >merges &&
285 test_line_count = 2 merges &&
286
287 test_pseudo_merge_commits 0 >commits-0.raw &&
288 test_pseudo_merge_commits 1 >commits-1.raw &&
289
290 sort commits-0.raw >commits-0 &&
291 sort commits-1.raw >commits-1 &&
292
293 comm -12 commits-0 commits-1 >overlap &&
294
295 test_line_count -gt 0 overlap
296 )
297'
298
299test_expect_success 'pseudo-merge overlap traversal' '
300 (
301 cd pseudo-merge-overlap &&
302
303 : >trace2.txt &&
304 GIT_TRACE2_EVENT=$PWD/trace2.txt \
305 git rev-list --count --all --objects --use-bitmap-index >actual &&
306 git rev-list --count --all --objects >expect &&
307
308 test_pseudo_merges_satisfied 2 <trace2.txt &&
309 test_pseudo_merges_cascades 1 <trace2.txt &&
310 test_cmp expect actual
311 )
312'
313
314test_expect_success 'pseudo-merge overlap stale traversal' '
315 (
316 cd pseudo-merge-overlap &&
317
318 test_commit other &&
319
320 : >trace2.txt &&
321 GIT_TRACE2_EVENT=$PWD/trace2.txt \
322 git rev-list --count --all --objects --use-bitmap-index >actual &&
323 git rev-list --count --all --objects >expect &&
324
325 test_pseudo_merges_satisfied 2 <trace2.txt &&
326 test_pseudo_merges_cascades 1 <trace2.txt &&
327 test_cmp expect actual
328 )
329'
330
331test_expect_success 'pseudo-merge reuse' '
332 git init pseudo-merge-reuse &&
333 (
334 cd pseudo-merge-reuse &&
335
336 stable="1641013200" && # 2022-01-01
337 unstable="1672549200" && # 2023-01-01
338
339 GIT_COMMITTER_DATE="$stable +0000" &&
340 export GIT_COMMITTER_DATE &&
341 test_commit_bulk --notick 128 &&
342 GIT_COMMITTER_DATE="$unstable +0000" &&
343 export GIT_COMMITTER_DATE &&
344 test_commit_bulk --notick 128 &&
345
346 tag_everything &&
347
348 git \
349 -c bitmapPseudoMerge.test.pattern="refs/tags/" \
350 -c bitmapPseudoMerge.test.maxMerges=1 \
351 -c bitmapPseudoMerge.test.threshold=now \
352 -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \
353 -c bitmapPseudoMerge.test.stableSize=512 \
354 repack -adb &&
355
356 test_pseudo_merges >merges &&
357 test_line_count = 2 merges &&
358
359 test_pseudo_merge_commits 0 >stable-oids.before &&
360 test_pseudo_merge_commits 1 >unstable-oids.before &&
361
362 : >trace2.txt &&
363 GIT_TRACE2_EVENT=$PWD/trace2.txt git \
364 -c bitmapPseudoMerge.test.pattern="refs/tags/" \
365 -c bitmapPseudoMerge.test.maxMerges=2 \
366 -c bitmapPseudoMerge.test.threshold=now \
367 -c bitmapPseudoMerge.test.stableThreshold=$(($unstable - 1)) \
368 -c bitmapPseudoMerge.test.stableSize=512 \
369 repack -adb &&
370
371 test_pseudo_merges_reused 1 <trace2.txt &&
372
373 test_pseudo_merges >merges &&
374 test_line_count = 3 merges &&
375
376 test_pseudo_merge_commits 0 >stable-oids.after &&
377 for i in 1 2
378 do
379 test_pseudo_merge_commits $i || return 1
380 done >unstable-oids.after &&
381
382 sort -u <stable-oids.before >expect &&
383 sort -u <stable-oids.after >actual &&
384 test_cmp expect actual &&
385
386 sort -u <unstable-oids.before >expect &&
387 sort -u <unstable-oids.after >actual &&
388 test_cmp expect actual
389 )
390'
391
392test_expect_success 'empty pseudo-merge group' '
393 git init pseudo-merge-empty-group &&
394 (
395 cd pseudo-merge-empty-group &&
396
397 # Ensure that a pseudo-merge group with no unstable
398 # commits does not generate an empty pseudo-merge
399 # bitmap.
400 git config bitmapPseudoMerge.empty.pattern refs/ &&
401
402 test_commit base &&
403 git repack -adb &&
404
405 test-tool bitmap dump-pseudo-merges >merges &&
406 test_line_count = 1 merges &&
407
408 test 0 -eq "$(grep -c commits=0 <merges)"
409 )
410'
411
412test_expect_success 'pseudo-merge closure' '
413 git init pseudo-merge-closure &&
414 (
415 cd pseudo-merge-closure &&
416
417 test_commit A &&
418 git repack -d &&
419
420 test_commit B &&
421
422 # Note that the contents of A is packed, but B is not. A
423 # (and the objects reachable from it) are thus visible
424 # to the MIDX, but the same is not true for B and its
425 # objects.
426 #
427 # Ensure that we do not attempt to create a pseudo-merge
428 # for B, depsite it matching the below pseudo-merge
429 # group pattern, as doing so would result in a failure
430 # to write a non-closed bitmap.
431 git config bitmapPseudoMerge.test.pattern refs/ &&
432 git config bitmapPseudoMerge.test.threshold now &&
433
434 git multi-pack-index write --bitmap &&
435
436 test-tool bitmap dump-pseudo-merges >pseudo-merges &&
437 test_line_count = 1 pseudo-merges &&
438
439 git rev-parse A >expect &&
440
441 test-tool bitmap list-commits >actual &&
442 test_cmp expect actual &&
443 test-tool bitmap dump-pseudo-merge-commits 0 >actual &&
444 test_cmp expect actual
445 )
446'
447
448test_expect_success 'use pseudo-merge in boundary traversal' '
449 git init pseudo-merge-boundary-traversal &&
450 (
451 cd pseudo-merge-boundary-traversal &&
452
453 git config bitmapPseudoMerge.test.pattern refs/ &&
454 git config pack.useBitmapBoundaryTraversal true &&
455
456 test_commit A &&
457 git repack -adb &&
458 test_commit B &&
459
460 nr=$(git rev-list --count --use-bitmap-index HEAD~1..HEAD) &&
461 test 1 -eq "$nr"
462 )
463'
464
465test_done