]>
Commit | Line | Data |
---|---|---|
1 | #!/bin/sh | |
2 | ||
3 | test_description='commit graph' | |
4 | . ./test-lib.sh | |
5 | ||
6 | GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0 | |
7 | ||
8 | test_expect_success 'usage' ' | |
9 | test_expect_code 129 git commit-graph write blah 2>err && | |
10 | test_expect_code 129 git commit-graph write verify | |
11 | ' | |
12 | ||
13 | test_expect_success 'usage shown without sub-command' ' | |
14 | test_expect_code 129 git commit-graph 2>err && | |
15 | grep usage: err | |
16 | ' | |
17 | ||
18 | test_expect_success 'usage shown with an error on unknown sub-command' ' | |
19 | cat >expect <<-\EOF && | |
20 | error: unknown subcommand: `unknown'\'' | |
21 | EOF | |
22 | test_expect_code 129 git commit-graph unknown 2>stderr && | |
23 | grep error stderr >actual && | |
24 | test_cmp expect actual | |
25 | ' | |
26 | ||
27 | objdir=".git/objects" | |
28 | ||
29 | test_expect_success 'setup full repo' ' | |
30 | git init full | |
31 | ' | |
32 | ||
33 | test_expect_success POSIXPERM 'tweak umask for modebit tests' ' | |
34 | umask 022 | |
35 | ' | |
36 | ||
37 | test_expect_success 'verify graph with no graph file' ' | |
38 | git -C full commit-graph verify | |
39 | ' | |
40 | ||
41 | test_expect_success 'write graph with no packs' ' | |
42 | git -C full commit-graph write --object-dir $objdir && | |
43 | test_path_is_missing full/$objdir/info/commit-graph | |
44 | ' | |
45 | ||
46 | test_expect_success 'exit with correct error on bad input to --stdin-packs' ' | |
47 | echo doesnotexist >in && | |
48 | test_expect_code 1 git -C full commit-graph write --stdin-packs \ | |
49 | <in 2>stderr && | |
50 | test_i18ngrep "error adding pack" stderr | |
51 | ' | |
52 | ||
53 | test_expect_success 'create commits and repack' ' | |
54 | for i in $(test_seq 3) | |
55 | do | |
56 | test_commit -C full $i && | |
57 | git -C full branch commits/$i || return 1 | |
58 | done && | |
59 | git -C full repack | |
60 | ' | |
61 | ||
62 | . "$TEST_DIRECTORY"/lib-commit-graph.sh | |
63 | ||
64 | graph_git_behavior 'no graph' full commits/3 commits/1 | |
65 | ||
66 | test_expect_success 'exit with correct error on bad input to --stdin-commits' ' | |
67 | # invalid, non-hex OID | |
68 | echo HEAD | test_expect_code 1 git -C full commit-graph write \ | |
69 | --stdin-commits 2>stderr && | |
70 | test_i18ngrep "unexpected non-hex object ID: HEAD" stderr && | |
71 | # non-existent OID | |
72 | echo $ZERO_OID | test_expect_code 1 git -C full commit-graph write \ | |
73 | --stdin-commits 2>stderr && | |
74 | test_i18ngrep "invalid object" stderr && | |
75 | # valid commit and tree OID | |
76 | git -C full rev-parse HEAD HEAD^{tree} >in && | |
77 | git -C full commit-graph write --stdin-commits <in && | |
78 | graph_read_expect -C full 3 generation_data | |
79 | ' | |
80 | ||
81 | test_expect_success 'write graph' ' | |
82 | git -C full commit-graph write && | |
83 | test_path_is_file full/$objdir/info/commit-graph && | |
84 | graph_read_expect -C full 3 generation_data | |
85 | ' | |
86 | ||
87 | test_expect_success POSIXPERM 'write graph has correct permissions' ' | |
88 | test_path_is_file full/$objdir/info/commit-graph && | |
89 | echo "-r--r--r--" >expect && | |
90 | test_modebits full/$objdir/info/commit-graph >actual && | |
91 | test_cmp expect actual | |
92 | ' | |
93 | ||
94 | graph_git_behavior 'graph exists' full commits/3 commits/1 | |
95 | ||
96 | test_expect_success 'Add more commits' ' | |
97 | git -C full reset --hard commits/1 && | |
98 | for i in $(test_seq 4 5) | |
99 | do | |
100 | test_commit -C full $i && | |
101 | git -C full branch commits/$i || return 1 | |
102 | done && | |
103 | git -C full reset --hard commits/2 && | |
104 | for i in $(test_seq 6 7) | |
105 | do | |
106 | test_commit -C full $i && | |
107 | git -C full branch commits/$i || return 1 | |
108 | done && | |
109 | git -C full reset --hard commits/2 && | |
110 | git -C full merge commits/4 && | |
111 | git -C full branch merge/1 && | |
112 | git -C full reset --hard commits/4 && | |
113 | git -C full merge commits/6 && | |
114 | git -C full branch merge/2 && | |
115 | git -C full reset --hard commits/3 && | |
116 | git -C full merge commits/5 commits/7 && | |
117 | git -C full branch merge/3 && | |
118 | git -C full repack | |
119 | ' | |
120 | ||
121 | test_expect_success 'commit-graph write progress off for redirected stderr' ' | |
122 | git -C full commit-graph write 2>err && | |
123 | test_must_be_empty err | |
124 | ' | |
125 | ||
126 | test_expect_success 'commit-graph write force progress on for stderr' ' | |
127 | GIT_PROGRESS_DELAY=0 git -C full commit-graph write --progress 2>err && | |
128 | test_file_not_empty err | |
129 | ' | |
130 | ||
131 | test_expect_success 'commit-graph write with the --no-progress option' ' | |
132 | git -C full commit-graph write --no-progress 2>err && | |
133 | test_must_be_empty err | |
134 | ' | |
135 | ||
136 | test_expect_success 'commit-graph write --stdin-commits progress off for redirected stderr' ' | |
137 | git -C full rev-parse commits/5 >in && | |
138 | git -C full commit-graph write --stdin-commits <in 2>err && | |
139 | test_must_be_empty err | |
140 | ' | |
141 | ||
142 | test_expect_success 'commit-graph write --stdin-commits force progress on for stderr' ' | |
143 | git -C full rev-parse commits/5 >in && | |
144 | GIT_PROGRESS_DELAY=0 git -C full commit-graph write --stdin-commits \ | |
145 | --progress <in 2>err && | |
146 | test_i18ngrep "Collecting commits from input" err | |
147 | ' | |
148 | ||
149 | test_expect_success 'commit-graph write --stdin-commits with the --no-progress option' ' | |
150 | git -C full rev-parse commits/5 >in && | |
151 | git -C full commit-graph write --stdin-commits --no-progress <in 2>err && | |
152 | test_must_be_empty err | |
153 | ' | |
154 | ||
155 | test_expect_success 'commit-graph verify progress off for redirected stderr' ' | |
156 | git -C full commit-graph verify 2>err && | |
157 | test_must_be_empty err | |
158 | ' | |
159 | ||
160 | test_expect_success 'commit-graph verify force progress on for stderr' ' | |
161 | GIT_PROGRESS_DELAY=0 git -C full commit-graph verify --progress 2>err && | |
162 | test_file_not_empty err | |
163 | ' | |
164 | ||
165 | test_expect_success 'commit-graph verify with the --no-progress option' ' | |
166 | git -C full commit-graph verify --no-progress 2>err && | |
167 | test_must_be_empty err | |
168 | ' | |
169 | ||
170 | # Current graph structure: | |
171 | # | |
172 | # __M3___ | |
173 | # / | \ | |
174 | # 3 M1 5 M2 7 | |
175 | # |/ \|/ \| | |
176 | # 2 4 6 | |
177 | # |___/____/ | |
178 | # 1 | |
179 | ||
180 | test_expect_success 'write graph with merges' ' | |
181 | git -C full commit-graph write && | |
182 | test_path_is_file full/$objdir/info/commit-graph && | |
183 | graph_read_expect -C full 10 "generation_data extra_edges" | |
184 | ' | |
185 | ||
186 | graph_git_behavior 'merge 1 vs 2' full merge/1 merge/2 | |
187 | graph_git_behavior 'merge 1 vs 3' full merge/1 merge/3 | |
188 | graph_git_behavior 'merge 2 vs 3' full merge/2 merge/3 | |
189 | ||
190 | test_expect_success 'Add one more commit' ' | |
191 | test_commit -C full 8 && | |
192 | git -C full branch commits/8 && | |
193 | ls full/$objdir/pack | grep idx >existing-idx && | |
194 | git -C full repack && | |
195 | ls full/$objdir/pack| grep idx | grep -v -f existing-idx >new-idx | |
196 | ' | |
197 | ||
198 | # Current graph structure: | |
199 | # | |
200 | # 8 | |
201 | # | | |
202 | # __M3___ | |
203 | # / | \ | |
204 | # 3 M1 5 M2 7 | |
205 | # |/ \|/ \| | |
206 | # 2 4 6 | |
207 | # |___/____/ | |
208 | # 1 | |
209 | ||
210 | graph_git_behavior 'mixed mode, commit 8 vs merge 1' full commits/8 merge/1 | |
211 | graph_git_behavior 'mixed mode, commit 8 vs merge 2' full commits/8 merge/2 | |
212 | ||
213 | test_expect_success 'write graph with new commit' ' | |
214 | git -C full commit-graph write && | |
215 | test_path_is_file full/$objdir/info/commit-graph && | |
216 | graph_read_expect -C full 11 "generation_data extra_edges" | |
217 | ' | |
218 | ||
219 | graph_git_behavior 'full graph, commit 8 vs merge 1' full commits/8 merge/1 | |
220 | graph_git_behavior 'full graph, commit 8 vs merge 2' full commits/8 merge/2 | |
221 | ||
222 | test_expect_success 'write graph with nothing new' ' | |
223 | git -C full commit-graph write && | |
224 | test_path_is_file full/$objdir/info/commit-graph && | |
225 | graph_read_expect -C full 11 "generation_data extra_edges" | |
226 | ' | |
227 | ||
228 | graph_git_behavior 'cleared graph, commit 8 vs merge 1' full commits/8 merge/1 | |
229 | graph_git_behavior 'cleared graph, commit 8 vs merge 2' full commits/8 merge/2 | |
230 | ||
231 | test_expect_success 'build graph from latest pack with closure' ' | |
232 | git -C full commit-graph write --stdin-packs <new-idx && | |
233 | test_path_is_file full/$objdir/info/commit-graph && | |
234 | graph_read_expect -C full 9 "generation_data extra_edges" | |
235 | ' | |
236 | ||
237 | graph_git_behavior 'graph from pack, commit 8 vs merge 1' full commits/8 merge/1 | |
238 | graph_git_behavior 'graph from pack, commit 8 vs merge 2' full commits/8 merge/2 | |
239 | ||
240 | test_expect_success 'build graph from commits with closure' ' | |
241 | git -C full tag -a -m "merge" tag/merge merge/2 && | |
242 | git -C full rev-parse tag/merge >commits-in && | |
243 | git -C full rev-parse merge/1 >>commits-in && | |
244 | git -C full commit-graph write --stdin-commits <commits-in && | |
245 | test_path_is_file full/$objdir/info/commit-graph && | |
246 | graph_read_expect -C full 6 "generation_data" | |
247 | ' | |
248 | ||
249 | graph_git_behavior 'graph from commits, commit 8 vs merge 1' full commits/8 merge/1 | |
250 | graph_git_behavior 'graph from commits, commit 8 vs merge 2' full commits/8 merge/2 | |
251 | ||
252 | test_expect_success 'build graph from commits with append' ' | |
253 | git -C full rev-parse merge/3 >in && | |
254 | git -C full commit-graph write --stdin-commits --append <in && | |
255 | test_path_is_file full/$objdir/info/commit-graph && | |
256 | graph_read_expect -C full 10 "generation_data extra_edges" | |
257 | ' | |
258 | ||
259 | graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 | |
260 | graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 | |
261 | ||
262 | test_expect_success 'build graph using --reachable' ' | |
263 | git -C full commit-graph write --reachable && | |
264 | test_path_is_file full/$objdir/info/commit-graph && | |
265 | graph_read_expect -C full 11 "generation_data extra_edges" | |
266 | ' | |
267 | ||
268 | graph_git_behavior 'append graph, commit 8 vs merge 1' full commits/8 merge/1 | |
269 | graph_git_behavior 'append graph, commit 8 vs merge 2' full commits/8 merge/2 | |
270 | ||
271 | test_expect_success 'setup bare repo' ' | |
272 | git clone --bare --no-local full bare | |
273 | ' | |
274 | ||
275 | graph_git_behavior 'bare repo, commit 8 vs merge 1' bare commits/8 merge/1 | |
276 | graph_git_behavior 'bare repo, commit 8 vs merge 2' bare commits/8 merge/2 | |
277 | ||
278 | test_expect_success 'write graph in bare repo' ' | |
279 | git -C bare commit-graph write && | |
280 | test_path_is_file bare/objects/info/commit-graph && | |
281 | graph_read_expect -C bare 11 "generation_data extra_edges" | |
282 | ' | |
283 | ||
284 | graph_git_behavior 'bare repo with graph, commit 8 vs merge 1' bare commits/8 merge/1 | |
285 | graph_git_behavior 'bare repo with graph, commit 8 vs merge 2' bare commits/8 merge/2 | |
286 | ||
287 | test_expect_success 'perform fast-forward merge in full repo' ' | |
288 | git -C full checkout -b merge-5-to-8 commits/5 && | |
289 | git -C full merge commits/8 && | |
290 | git -C full show-ref -s merge-5-to-8 >output && | |
291 | git -C full show-ref -s commits/8 >expect && | |
292 | test_cmp expect output | |
293 | ' | |
294 | ||
295 | test_expect_success 'check that gc computes commit-graph' ' | |
296 | test_commit -C full --no-tag blank && | |
297 | git -C full commit-graph write --reachable && | |
298 | cp full/$objdir/info/commit-graph commit-graph-before-gc && | |
299 | git -C full reset --hard HEAD~1 && | |
300 | test_config -C full gc.writeCommitGraph true && | |
301 | git -C full gc && | |
302 | cp full/$objdir/info/commit-graph commit-graph-after-gc && | |
303 | ! test_cmp_bin commit-graph-before-gc commit-graph-after-gc && | |
304 | git -C full commit-graph write --reachable && | |
305 | test_cmp_bin commit-graph-after-gc full/$objdir/info/commit-graph | |
306 | ' | |
307 | ||
308 | test_expect_success 'replace-objects invalidates commit-graph' ' | |
309 | test_when_finished rm -rf replace && | |
310 | git clone full replace && | |
311 | ( | |
312 | cd replace && | |
313 | git commit-graph write --reachable && | |
314 | test_path_is_file .git/objects/info/commit-graph && | |
315 | git replace HEAD~1 HEAD~2 && | |
316 | graph_git_two_modes "commit-graph verify" && | |
317 | git -c core.commitGraph=false log >expect && | |
318 | git -c core.commitGraph=true log >actual && | |
319 | test_cmp expect actual && | |
320 | git commit-graph write --reachable && | |
321 | git -c core.commitGraph=false --no-replace-objects log >expect && | |
322 | git -c core.commitGraph=true --no-replace-objects log >actual && | |
323 | test_cmp expect actual && | |
324 | rm -rf .git/objects/info/commit-graph && | |
325 | git commit-graph write --reachable && | |
326 | test_path_is_file .git/objects/info/commit-graph | |
327 | ) | |
328 | ' | |
329 | ||
330 | test_expect_success 'commit grafts invalidate commit-graph' ' | |
331 | test_when_finished rm -rf graft && | |
332 | git clone --template= full graft && | |
333 | ( | |
334 | cd graft && | |
335 | git commit-graph write --reachable && | |
336 | test_path_is_file .git/objects/info/commit-graph && | |
337 | H1=$(git rev-parse --verify HEAD~1) && | |
338 | H3=$(git rev-parse --verify HEAD~3) && | |
339 | mkdir .git/info && | |
340 | echo "$H1 $H3" >.git/info/grafts && | |
341 | git -c core.commitGraph=false log >expect && | |
342 | git -c core.commitGraph=true log >actual && | |
343 | test_cmp expect actual && | |
344 | git commit-graph write --reachable && | |
345 | git -c core.commitGraph=false --no-replace-objects log >expect && | |
346 | git -c core.commitGraph=true --no-replace-objects log >actual && | |
347 | test_cmp expect actual && | |
348 | rm -rf .git/objects/info/commit-graph && | |
349 | git commit-graph write --reachable && | |
350 | test_path_is_missing .git/objects/info/commit-graph | |
351 | ) | |
352 | ' | |
353 | ||
354 | test_expect_success 'replace-objects invalidates commit-graph' ' | |
355 | test_when_finished rm -rf shallow && | |
356 | git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow && | |
357 | ( | |
358 | cd shallow && | |
359 | git commit-graph write --reachable && | |
360 | test_path_is_missing .git/objects/info/commit-graph && | |
361 | git fetch origin --unshallow && | |
362 | git commit-graph write --reachable && | |
363 | test_path_is_file .git/objects/info/commit-graph | |
364 | ) | |
365 | ' | |
366 | ||
367 | test_expect_success 'warn on improper hash version' ' | |
368 | git init --object-format=sha1 sha1 && | |
369 | ( | |
370 | cd sha1 && | |
371 | test_commit 1 && | |
372 | git commit-graph write --reachable && | |
373 | mv .git/objects/info/commit-graph ../cg-sha1 | |
374 | ) && | |
375 | git init --object-format=sha256 sha256 && | |
376 | ( | |
377 | cd sha256 && | |
378 | test_commit 1 && | |
379 | git commit-graph write --reachable && | |
380 | mv .git/objects/info/commit-graph ../cg-sha256 | |
381 | ) && | |
382 | ( | |
383 | cd sha1 && | |
384 | mv ../cg-sha256 .git/objects/info/commit-graph && | |
385 | git log -1 2>err && | |
386 | test_i18ngrep "commit-graph hash version 2 does not match version 1" err | |
387 | ) && | |
388 | ( | |
389 | cd sha256 && | |
390 | mv ../cg-sha1 .git/objects/info/commit-graph && | |
391 | git log -1 2>err && | |
392 | test_i18ngrep "commit-graph hash version 1 does not match version 2" err | |
393 | ) | |
394 | ' | |
395 | ||
396 | test_expect_success TIME_IS_64BIT,TIME_T_IS_64BIT 'lower layers have overflow chunk' ' | |
397 | UNIX_EPOCH_ZERO="@0 +0000" && | |
398 | FUTURE_DATE="@4147483646 +0000" && | |
399 | rm -f full/.git/objects/info/commit-graph && | |
400 | test_commit -C full --date "$FUTURE_DATE" future-1 && | |
401 | test_commit -C full --date "$UNIX_EPOCH_ZERO" old-1 && | |
402 | git -C full commit-graph write --reachable && | |
403 | test_commit -C full --date "$FUTURE_DATE" future-2 && | |
404 | test_commit -C full --date "$UNIX_EPOCH_ZERO" old-2 && | |
405 | git -C full commit-graph write --reachable --split=no-merge && | |
406 | test_commit -C full extra && | |
407 | git -C full commit-graph write --reachable --split=no-merge && | |
408 | git -C full commit-graph write --reachable && | |
409 | graph_read_expect -C full 16 \ | |
410 | "generation_data generation_data_overflow extra_edges" && | |
411 | mv full/.git/objects/info/commit-graph commit-graph-upgraded && | |
412 | git -C full commit-graph write --reachable && | |
413 | graph_read_expect -C full 16 \ | |
414 | "generation_data generation_data_overflow extra_edges" && | |
415 | test_cmp full/.git/objects/info/commit-graph commit-graph-upgraded | |
416 | ' | |
417 | ||
418 | # the verify tests below expect the commit-graph to contain | |
419 | # exactly the commits reachable from the commits/8 branch. | |
420 | # If the file changes the set of commits in the list, then the | |
421 | # offsets into the binary file will result in different edits | |
422 | # and the tests will likely break. | |
423 | ||
424 | test_expect_success 'git commit-graph verify' ' | |
425 | git -C full rev-parse commits/8 >in && | |
426 | git -C full -c commitGraph.generationVersion=1 commit-graph write \ | |
427 | --stdin-commits <in && | |
428 | git -C full commit-graph verify >output && | |
429 | graph_read_expect -C full 9 extra_edges 1 | |
430 | ' | |
431 | ||
432 | NUM_COMMITS=9 | |
433 | NUM_OCTOPUS_EDGES=2 | |
434 | HASH_LEN="$(test_oid rawsz)" | |
435 | GRAPH_BYTE_VERSION=4 | |
436 | GRAPH_BYTE_HASH=5 | |
437 | GRAPH_BYTE_CHUNK_COUNT=6 | |
438 | GRAPH_CHUNK_LOOKUP_OFFSET=8 | |
439 | GRAPH_CHUNK_LOOKUP_WIDTH=12 | |
440 | GRAPH_CHUNK_LOOKUP_ROWS=5 | |
441 | GRAPH_BYTE_OID_FANOUT_ID=$GRAPH_CHUNK_LOOKUP_OFFSET | |
442 | GRAPH_BYTE_OID_LOOKUP_ID=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ | |
443 | 1 * $GRAPH_CHUNK_LOOKUP_WIDTH)) | |
444 | GRAPH_BYTE_COMMIT_DATA_ID=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ | |
445 | 2 * $GRAPH_CHUNK_LOOKUP_WIDTH)) | |
446 | GRAPH_FANOUT_OFFSET=$(($GRAPH_CHUNK_LOOKUP_OFFSET + \ | |
447 | $GRAPH_CHUNK_LOOKUP_WIDTH * $GRAPH_CHUNK_LOOKUP_ROWS)) | |
448 | GRAPH_BYTE_FANOUT1=$(($GRAPH_FANOUT_OFFSET + 4 * 4)) | |
449 | GRAPH_BYTE_FANOUT2=$(($GRAPH_FANOUT_OFFSET + 4 * 255)) | |
450 | GRAPH_OID_LOOKUP_OFFSET=$(($GRAPH_FANOUT_OFFSET + 4 * 256)) | |
451 | GRAPH_BYTE_OID_LOOKUP_ORDER=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 8)) | |
452 | GRAPH_BYTE_OID_LOOKUP_MISSING=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * 4 + 10)) | |
453 | GRAPH_COMMIT_DATA_OFFSET=$(($GRAPH_OID_LOOKUP_OFFSET + $HASH_LEN * $NUM_COMMITS)) | |
454 | GRAPH_BYTE_COMMIT_TREE=$GRAPH_COMMIT_DATA_OFFSET | |
455 | GRAPH_BYTE_COMMIT_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN)) | |
456 | GRAPH_BYTE_COMMIT_EXTRA_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 4)) | |
457 | GRAPH_BYTE_COMMIT_WRONG_PARENT=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 3)) | |
458 | GRAPH_BYTE_COMMIT_GENERATION=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 11)) | |
459 | GRAPH_BYTE_COMMIT_DATE=$(($GRAPH_COMMIT_DATA_OFFSET + $HASH_LEN + 12)) | |
460 | GRAPH_COMMIT_DATA_WIDTH=$(($HASH_LEN + 16)) | |
461 | GRAPH_OCTOPUS_DATA_OFFSET=$(($GRAPH_COMMIT_DATA_OFFSET + \ | |
462 | $GRAPH_COMMIT_DATA_WIDTH * $NUM_COMMITS)) | |
463 | GRAPH_BYTE_OCTOPUS=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4)) | |
464 | GRAPH_BYTE_FOOTER=$(($GRAPH_OCTOPUS_DATA_OFFSET + 4 * $NUM_OCTOPUS_EDGES)) | |
465 | ||
466 | corrupt_graph_setup() { | |
467 | test_when_finished mv commit-graph-backup full/$objdir/info/commit-graph && | |
468 | cp full/$objdir/info/commit-graph commit-graph-backup && | |
469 | chmod u+w full/$objdir/info/commit-graph | |
470 | } | |
471 | ||
472 | corrupt_graph_verify() { | |
473 | grepstr=$1 | |
474 | test_must_fail git -C full commit-graph verify 2>test_err && | |
475 | grep -v "^+" test_err >err && | |
476 | test_i18ngrep "$grepstr" err && | |
477 | if test "$2" != "no-copy" | |
478 | then | |
479 | cp full/$objdir/info/commit-graph commit-graph-pre-write-test | |
480 | fi && | |
481 | git -C full status --short && | |
482 | GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE=true git -C full commit-graph write && | |
483 | chmod u+w full/$objdir/info/commit-graph && | |
484 | git -C full commit-graph verify | |
485 | } | |
486 | ||
487 | # usage: corrupt_graph_and_verify <position> <data> <string> [<zero_pos>] | |
488 | # Manipulates the commit-graph file at the position | |
489 | # by inserting the data, optionally zeroing the file | |
490 | # starting at <zero_pos>, then runs 'git commit-graph verify' | |
491 | # and places the output in the file 'err'. Test 'err' for | |
492 | # the given string. | |
493 | corrupt_graph_and_verify() { | |
494 | pos=$1 | |
495 | data="${2:-\0}" | |
496 | grepstr=$3 | |
497 | corrupt_graph_setup && | |
498 | orig_size=$(wc -c <full/$objdir/info/commit-graph) && | |
499 | zero_pos=${4:-${orig_size}} && | |
500 | printf "$data" | dd of="full/$objdir/info/commit-graph" bs=1 seek="$pos" conv=notrunc && | |
501 | dd of="full/$objdir/info/commit-graph" bs=1 seek="$zero_pos" if=/dev/null && | |
502 | test-tool genzeros $(($orig_size - $zero_pos)) >>"full/$objdir/info/commit-graph" && | |
503 | corrupt_graph_verify "$grepstr" | |
504 | ||
505 | } | |
506 | ||
507 | test_expect_success POSIXPERM,SANITY 'detect permission problem' ' | |
508 | corrupt_graph_setup && | |
509 | chmod 000 full/$objdir/info/commit-graph && | |
510 | corrupt_graph_verify "Could not open" "no-copy" | |
511 | ' | |
512 | ||
513 | test_expect_success 'detect too small' ' | |
514 | corrupt_graph_setup && | |
515 | echo "a small graph" >full/$objdir/info/commit-graph && | |
516 | corrupt_graph_verify "too small" | |
517 | ' | |
518 | ||
519 | test_expect_success 'detect bad signature' ' | |
520 | corrupt_graph_and_verify 0 "\0" \ | |
521 | "graph signature" | |
522 | ' | |
523 | ||
524 | test_expect_success 'detect bad version' ' | |
525 | corrupt_graph_and_verify $GRAPH_BYTE_VERSION "\02" \ | |
526 | "graph version" | |
527 | ' | |
528 | ||
529 | test_expect_success 'detect bad hash version' ' | |
530 | corrupt_graph_and_verify $GRAPH_BYTE_HASH "\03" \ | |
531 | "hash version" | |
532 | ' | |
533 | ||
534 | test_expect_success 'detect low chunk count' ' | |
535 | corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\01" \ | |
536 | "final chunk has non-zero id" | |
537 | ' | |
538 | ||
539 | test_expect_success 'detect missing OID fanout chunk' ' | |
540 | corrupt_graph_and_verify $GRAPH_BYTE_OID_FANOUT_ID "\0" \ | |
541 | "missing the OID Fanout chunk" | |
542 | ' | |
543 | ||
544 | test_expect_success 'detect missing OID lookup chunk' ' | |
545 | corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_ID "\0" \ | |
546 | "missing the OID Lookup chunk" | |
547 | ' | |
548 | ||
549 | test_expect_success 'detect missing commit data chunk' ' | |
550 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATA_ID "\0" \ | |
551 | "missing the Commit Data chunk" | |
552 | ' | |
553 | ||
554 | test_expect_success 'detect incorrect fanout' ' | |
555 | corrupt_graph_and_verify $GRAPH_BYTE_FANOUT1 "\01" \ | |
556 | "fanout value" | |
557 | ' | |
558 | ||
559 | test_expect_success 'detect incorrect fanout final value' ' | |
560 | corrupt_graph_and_verify $GRAPH_BYTE_FANOUT2 "\01" \ | |
561 | "fanout value" | |
562 | ' | |
563 | ||
564 | test_expect_success 'detect incorrect OID order' ' | |
565 | corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_ORDER "\01" \ | |
566 | "incorrect OID order" | |
567 | ' | |
568 | ||
569 | test_expect_success 'detect OID not in object database' ' | |
570 | corrupt_graph_and_verify $GRAPH_BYTE_OID_LOOKUP_MISSING "\01" \ | |
571 | "from object database" | |
572 | ' | |
573 | ||
574 | test_expect_success 'detect incorrect tree OID' ' | |
575 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_TREE "\01" \ | |
576 | "root tree OID for commit" | |
577 | ' | |
578 | ||
579 | test_expect_success 'detect incorrect parent int-id' ' | |
580 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_PARENT "\01" \ | |
581 | "invalid parent" | |
582 | ' | |
583 | ||
584 | test_expect_success 'detect extra parent int-id' ' | |
585 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_EXTRA_PARENT "\00" \ | |
586 | "is too long" | |
587 | ' | |
588 | ||
589 | test_expect_success 'detect wrong parent' ' | |
590 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_WRONG_PARENT "\01" \ | |
591 | "commit-graph parent for" | |
592 | ' | |
593 | ||
594 | test_expect_success 'detect incorrect generation number' ' | |
595 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\070" \ | |
596 | "generation for commit" | |
597 | ' | |
598 | ||
599 | test_expect_success 'detect incorrect generation number' ' | |
600 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_GENERATION "\01" \ | |
601 | "but zero elsewhere" | |
602 | ' | |
603 | ||
604 | test_expect_success 'detect incorrect commit date' ' | |
605 | corrupt_graph_and_verify $GRAPH_BYTE_COMMIT_DATE "\01" \ | |
606 | "commit date" | |
607 | ' | |
608 | ||
609 | test_expect_success 'detect incorrect parent for octopus merge' ' | |
610 | corrupt_graph_and_verify $GRAPH_BYTE_OCTOPUS "\01" \ | |
611 | "invalid parent" | |
612 | ' | |
613 | ||
614 | test_expect_success 'detect invalid checksum hash' ' | |
615 | corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ | |
616 | "incorrect checksum" | |
617 | ' | |
618 | ||
619 | test_expect_success 'detect incorrect chunk count' ' | |
620 | corrupt_graph_and_verify $GRAPH_BYTE_CHUNK_COUNT "\377" \ | |
621 | "commit-graph file is too small to hold [0-9]* chunks" \ | |
622 | $GRAPH_CHUNK_LOOKUP_OFFSET | |
623 | ' | |
624 | ||
625 | test_expect_success 'git fsck (checks commit-graph when config set to true)' ' | |
626 | git -C full fsck && | |
627 | corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ | |
628 | "incorrect checksum" && | |
629 | cp commit-graph-pre-write-test full/$objdir/info/commit-graph && | |
630 | test_must_fail git -C full -c core.commitGraph=true fsck | |
631 | ' | |
632 | ||
633 | test_expect_success 'git fsck (ignores commit-graph when config set to false)' ' | |
634 | git -C full fsck && | |
635 | corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ | |
636 | "incorrect checksum" && | |
637 | cp commit-graph-pre-write-test full/$objdir/info/commit-graph && | |
638 | git -C full -c core.commitGraph=false fsck | |
639 | ' | |
640 | ||
641 | test_expect_success 'git fsck (checks commit-graph when config unset)' ' | |
642 | test_when_finished "git -C full config core.commitGraph true" && | |
643 | ||
644 | git -C full fsck && | |
645 | corrupt_graph_and_verify $GRAPH_BYTE_FOOTER "\00" \ | |
646 | "incorrect checksum" && | |
647 | test_unconfig -C full core.commitGraph && | |
648 | cp commit-graph-pre-write-test full/$objdir/info/commit-graph && | |
649 | test_must_fail git -C full fsck | |
650 | ' | |
651 | ||
652 | test_expect_success 'git fsck shows commit-graph output with --progress' ' | |
653 | git -C "$TRASH_DIRECTORY/full" fsck --progress 2>err && | |
654 | grep "Verifying commits in commit graph" err | |
655 | ' | |
656 | ||
657 | test_expect_success 'git fsck suppresses commit-graph output with --no-progress' ' | |
658 | git -C "$TRASH_DIRECTORY/full" fsck --no-progress 2>err && | |
659 | ! grep "Verifying commits in commit graph" err | |
660 | ' | |
661 | ||
662 | test_expect_success 'setup non-the_repository tests' ' | |
663 | rm -rf repo && | |
664 | git init repo && | |
665 | test_commit -C repo one && | |
666 | test_commit -C repo two && | |
667 | git -C repo config core.commitGraph true && | |
668 | git -C repo rev-parse two | \ | |
669 | git -C repo commit-graph write --stdin-commits | |
670 | ' | |
671 | ||
672 | test_expect_success 'parse_commit_in_graph works for non-the_repository' ' | |
673 | test-tool repository parse_commit_in_graph \ | |
674 | repo/.git repo "$(git -C repo rev-parse two)" >actual && | |
675 | { | |
676 | git -C repo log --pretty=format:"%ct " -1 && | |
677 | git -C repo rev-parse one | |
678 | } >expect && | |
679 | test_cmp expect actual && | |
680 | ||
681 | test-tool repository parse_commit_in_graph \ | |
682 | repo/.git repo "$(git -C repo rev-parse one)" >actual && | |
683 | git -C repo log --pretty="%ct" -1 one >expect && | |
684 | test_cmp expect actual | |
685 | ' | |
686 | ||
687 | test_expect_success 'get_commit_tree_in_graph works for non-the_repository' ' | |
688 | test-tool repository get_commit_tree_in_graph \ | |
689 | repo/.git repo "$(git -C repo rev-parse two)" >actual && | |
690 | git -C repo rev-parse two^{tree} >expect && | |
691 | test_cmp expect actual && | |
692 | ||
693 | test-tool repository get_commit_tree_in_graph \ | |
694 | repo/.git repo "$(git -C repo rev-parse one)" >actual && | |
695 | git -C repo rev-parse one^{tree} >expect && | |
696 | test_cmp expect actual | |
697 | ' | |
698 | ||
699 | test_expect_success 'corrupt commit-graph write (broken parent)' ' | |
700 | rm -rf repo && | |
701 | git init repo && | |
702 | ( | |
703 | cd repo && | |
704 | empty="$(git mktree </dev/null)" && | |
705 | cat >broken <<-EOF && | |
706 | tree $empty | |
707 | parent $ZERO_OID | |
708 | author whatever <whatever@example.com> 1234 -0000 | |
709 | committer whatever <whatever@example.com> 1234 -0000 | |
710 | ||
711 | broken commit | |
712 | EOF | |
713 | broken="$(git hash-object -w -t commit --literally broken)" && | |
714 | git commit-tree -p "$broken" -m "good commit" "$empty" >good && | |
715 | test_must_fail git commit-graph write --stdin-commits \ | |
716 | <good 2>test_err && | |
717 | test_i18ngrep "unable to parse commit" test_err | |
718 | ) | |
719 | ' | |
720 | ||
721 | test_expect_success 'corrupt commit-graph write (missing tree)' ' | |
722 | rm -rf repo && | |
723 | git init repo && | |
724 | ( | |
725 | cd repo && | |
726 | tree="$(git mktree </dev/null)" && | |
727 | cat >broken <<-EOF && | |
728 | parent $ZERO_OID | |
729 | author whatever <whatever@example.com> 1234 -0000 | |
730 | committer whatever <whatever@example.com> 1234 -0000 | |
731 | ||
732 | broken commit | |
733 | EOF | |
734 | broken="$(git hash-object -w -t commit --literally broken)" && | |
735 | git commit-tree -p "$broken" -m "good" "$tree" >good && | |
736 | test_must_fail git commit-graph write --stdin-commits \ | |
737 | <good 2>test_err && | |
738 | test_i18ngrep "unable to parse commit" test_err | |
739 | ) | |
740 | ' | |
741 | ||
742 | # We test the overflow-related code with the following repo history: | |
743 | # | |
744 | # 4:F - 5:N - 6:U | |
745 | # / \ | |
746 | # 1:U - 2:N - 3:U M:N | |
747 | # \ / | |
748 | # 7:N - 8:F - 9:N | |
749 | # | |
750 | # Here the commits denoted by U have committer date of zero seconds | |
751 | # since Unix epoch, the commits denoted by N have committer date | |
752 | # starting from 1112354055 seconds since Unix epoch (default committer | |
753 | # date for the test suite), and the commits denoted by F have committer | |
754 | # date of (2 ^ 31 - 2) seconds since Unix epoch. | |
755 | # | |
756 | # The largest offset observed is 2 ^ 31, just large enough to overflow. | |
757 | # | |
758 | ||
759 | test_expect_success 'set up and verify repo with generation data overflow chunk' ' | |
760 | UNIX_EPOCH_ZERO="@0 +0000" && | |
761 | FUTURE_DATE="@2147483646 +0000" && | |
762 | ||
763 | git init repo && | |
764 | ( | |
765 | cd repo && | |
766 | ||
767 | test_commit --date "$UNIX_EPOCH_ZERO" 1 && | |
768 | test_commit 2 && | |
769 | test_commit --date "$UNIX_EPOCH_ZERO" 3 && | |
770 | git commit-graph write --reachable && | |
771 | graph_read_expect 3 generation_data && | |
772 | test_commit --date "$FUTURE_DATE" 4 && | |
773 | test_commit 5 && | |
774 | test_commit --date "$UNIX_EPOCH_ZERO" 6 && | |
775 | git branch left && | |
776 | git reset --hard 3 && | |
777 | test_commit 7 && | |
778 | test_commit --date "$FUTURE_DATE" 8 && | |
779 | test_commit 9 && | |
780 | git branch right && | |
781 | git reset --hard 3 && | |
782 | test_merge M left right && | |
783 | git commit-graph write --reachable && | |
784 | graph_read_expect 10 "generation_data generation_data_overflow" && | |
785 | git commit-graph verify | |
786 | ) | |
787 | ' | |
788 | ||
789 | graph_git_behavior 'generation data overflow chunk repo' repo left right | |
790 | ||
791 | test_expect_success 'overflow during generation version upgrade' ' | |
792 | git init overflow-v2-upgrade && | |
793 | ( | |
794 | cd overflow-v2-upgrade && | |
795 | ||
796 | # This commit will have a date at two seconds past the Epoch, | |
797 | # and a (v1) generation number of 1, since it is a root commit. | |
798 | # | |
799 | # The offset will then be computed as 1-2, which will underflow | |
800 | # to 2^31, which is greater than the v2 offset small limit of | |
801 | # 2^31-1. | |
802 | # | |
803 | # This is sufficient to need a large offset table for the v2 | |
804 | # generation numbers. | |
805 | test_commit --date "@2 +0000" base && | |
806 | git repack -d && | |
807 | ||
808 | # Test that upgrading from generation v1 to v2 correctly | |
809 | # produces the overflow table. | |
810 | git -c commitGraph.generationVersion=1 commit-graph write && | |
811 | git -c commitGraph.generationVersion=2 commit-graph write \ | |
812 | --changed-paths && | |
813 | ||
814 | git rev-list --all | |
815 | ) | |
816 | ' | |
817 | ||
818 | test_done |