Git 2.26.1
[git] / t / t5324-split-commit-graph.sh
1 #!/bin/sh
2
3 test_description='split commit graph'
4 . ./test-lib.sh
5
6 GIT_TEST_COMMIT_GRAPH=0
7
8 test_expect_success 'setup repo' '
9         git init &&
10         git config core.commitGraph true &&
11         git config gc.writeCommitGraph false &&
12         infodir=".git/objects/info" &&
13         graphdir="$infodir/commit-graphs" &&
14         test_oid_init &&
15         test_oid_cache <<-EOM
16         shallow sha1:1760
17         shallow sha256:2064
18
19         base sha1:1376
20         base sha256:1496
21         EOM
22 '
23
24 graph_read_expect() {
25         NUM_BASE=0
26         if test ! -z $2
27         then
28                 NUM_BASE=$2
29         fi
30         cat >expect <<- EOF
31         header: 43475048 1 1 3 $NUM_BASE
32         num_commits: $1
33         chunks: oid_fanout oid_lookup commit_metadata
34         EOF
35         test-tool read-graph >output &&
36         test_cmp expect output
37 }
38
39 test_expect_success 'create commits and write commit-graph' '
40         for i in $(test_seq 3)
41         do
42                 test_commit $i &&
43                 git branch commits/$i || return 1
44         done &&
45         git commit-graph write --reachable &&
46         test_path_is_file $infodir/commit-graph &&
47         graph_read_expect 3
48 '
49
50 graph_git_two_modes() {
51         git -c core.commitGraph=true $1 >output
52         git -c core.commitGraph=false $1 >expect
53         test_cmp expect output
54 }
55
56 graph_git_behavior() {
57         MSG=$1
58         BRANCH=$2
59         COMPARE=$3
60         test_expect_success "check normal git operations: $MSG" '
61                 graph_git_two_modes "log --oneline $BRANCH" &&
62                 graph_git_two_modes "log --topo-order $BRANCH" &&
63                 graph_git_two_modes "log --graph $COMPARE..$BRANCH" &&
64                 graph_git_two_modes "branch -vv" &&
65                 graph_git_two_modes "merge-base -a $BRANCH $COMPARE"
66         '
67 }
68
69 graph_git_behavior 'graph exists' commits/3 commits/1
70
71 verify_chain_files_exist() {
72         for hash in $(cat $1/commit-graph-chain)
73         do
74                 test_path_is_file $1/graph-$hash.graph || return 1
75         done
76 }
77
78 test_expect_success 'add more commits, and write a new base graph' '
79         git reset --hard commits/1 &&
80         for i in $(test_seq 4 5)
81         do
82                 test_commit $i &&
83                 git branch commits/$i || return 1
84         done &&
85         git reset --hard commits/2 &&
86         for i in $(test_seq 6 10)
87         do
88                 test_commit $i &&
89                 git branch commits/$i || return 1
90         done &&
91         git reset --hard commits/2 &&
92         git merge commits/4 &&
93         git branch merge/1 &&
94         git reset --hard commits/4 &&
95         git merge commits/6 &&
96         git branch merge/2 &&
97         git commit-graph write --reachable &&
98         graph_read_expect 12
99 '
100
101 test_expect_success 'fork and fail to base a chain on a commit-graph file' '
102         test_when_finished rm -rf fork &&
103         git clone . fork &&
104         (
105                 cd fork &&
106                 rm .git/objects/info/commit-graph &&
107                 echo "$(pwd)/../.git/objects" >.git/objects/info/alternates &&
108                 test_commit new-commit &&
109                 git commit-graph write --reachable --split &&
110                 test_path_is_file $graphdir/commit-graph-chain &&
111                 test_line_count = 1 $graphdir/commit-graph-chain &&
112                 verify_chain_files_exist $graphdir
113         )
114 '
115
116 test_expect_success 'add three more commits, write a tip graph' '
117         git reset --hard commits/3 &&
118         git merge merge/1 &&
119         git merge commits/5 &&
120         git merge merge/2 &&
121         git branch merge/3 &&
122         git commit-graph write --reachable --split &&
123         test_path_is_missing $infodir/commit-graph &&
124         test_path_is_file $graphdir/commit-graph-chain &&
125         ls $graphdir/graph-*.graph >graph-files &&
126         test_line_count = 2 graph-files &&
127         verify_chain_files_exist $graphdir
128 '
129
130 graph_git_behavior 'split commit-graph: merge 3 vs 2' merge/3 merge/2
131
132 test_expect_success 'add one commit, write a tip graph' '
133         test_commit 11 &&
134         git branch commits/11 &&
135         git commit-graph write --reachable --split &&
136         test_path_is_missing $infodir/commit-graph &&
137         test_path_is_file $graphdir/commit-graph-chain &&
138         ls $graphdir/graph-*.graph >graph-files &&
139         test_line_count = 3 graph-files &&
140         verify_chain_files_exist $graphdir
141 '
142
143 graph_git_behavior 'three-layer commit-graph: commit 11 vs 6' commits/11 commits/6
144
145 test_expect_success 'add one commit, write a merged graph' '
146         test_commit 12 &&
147         git branch commits/12 &&
148         git commit-graph write --reachable --split &&
149         test_path_is_file $graphdir/commit-graph-chain &&
150         test_line_count = 2 $graphdir/commit-graph-chain &&
151         ls $graphdir/graph-*.graph >graph-files &&
152         test_line_count = 2 graph-files &&
153         verify_chain_files_exist $graphdir
154 '
155
156 graph_git_behavior 'merged commit-graph: commit 12 vs 6' commits/12 commits/6
157
158 test_expect_success 'create fork and chain across alternate' '
159         git clone . fork &&
160         (
161                 cd fork &&
162                 git config core.commitGraph true &&
163                 rm -rf $graphdir &&
164                 echo "$(pwd)/../.git/objects" >.git/objects/info/alternates &&
165                 test_commit 13 &&
166                 git branch commits/13 &&
167                 git commit-graph write --reachable --split &&
168                 test_path_is_file $graphdir/commit-graph-chain &&
169                 test_line_count = 3 $graphdir/commit-graph-chain &&
170                 ls $graphdir/graph-*.graph >graph-files &&
171                 test_line_count = 1 graph-files &&
172                 git -c core.commitGraph=true  rev-list HEAD >expect &&
173                 git -c core.commitGraph=false rev-list HEAD >actual &&
174                 test_cmp expect actual &&
175                 test_commit 14 &&
176                 git commit-graph write --reachable --split --object-dir=.git/objects/ &&
177                 test_line_count = 3 $graphdir/commit-graph-chain &&
178                 ls $graphdir/graph-*.graph >graph-files &&
179                 test_line_count = 1 graph-files
180         )
181 '
182
183 graph_git_behavior 'alternate: commit 13 vs 6' commits/13 commits/6
184
185 test_expect_success 'test merge stragety constants' '
186         git clone . merge-2 &&
187         (
188                 cd merge-2 &&
189                 git config core.commitGraph true &&
190                 test_line_count = 2 $graphdir/commit-graph-chain &&
191                 test_commit 14 &&
192                 git commit-graph write --reachable --split --size-multiple=2 &&
193                 test_line_count = 3 $graphdir/commit-graph-chain
194
195         ) &&
196         git clone . merge-10 &&
197         (
198                 cd merge-10 &&
199                 git config core.commitGraph true &&
200                 test_line_count = 2 $graphdir/commit-graph-chain &&
201                 test_commit 14 &&
202                 git commit-graph write --reachable --split --size-multiple=10 &&
203                 test_line_count = 1 $graphdir/commit-graph-chain &&
204                 ls $graphdir/graph-*.graph >graph-files &&
205                 test_line_count = 1 graph-files
206         ) &&
207         git clone . merge-10-expire &&
208         (
209                 cd merge-10-expire &&
210                 git config core.commitGraph true &&
211                 test_line_count = 2 $graphdir/commit-graph-chain &&
212                 test_commit 15 &&
213                 git commit-graph write --reachable --split --size-multiple=10 --expire-time=1980-01-01 &&
214                 test_line_count = 1 $graphdir/commit-graph-chain &&
215                 ls $graphdir/graph-*.graph >graph-files &&
216                 test_line_count = 3 graph-files
217         ) &&
218         git clone --no-hardlinks . max-commits &&
219         (
220                 cd max-commits &&
221                 git config core.commitGraph true &&
222                 test_line_count = 2 $graphdir/commit-graph-chain &&
223                 test_commit 16 &&
224                 test_commit 17 &&
225                 git commit-graph write --reachable --split --max-commits=1 &&
226                 test_line_count = 1 $graphdir/commit-graph-chain &&
227                 ls $graphdir/graph-*.graph >graph-files &&
228                 test_line_count = 1 graph-files
229         )
230 '
231
232 test_expect_success 'remove commit-graph-chain file after flattening' '
233         git clone . flatten &&
234         (
235                 cd flatten &&
236                 test_line_count = 2 $graphdir/commit-graph-chain &&
237                 git commit-graph write --reachable &&
238                 test_path_is_missing $graphdir/commit-graph-chain &&
239                 ls $graphdir >graph-files &&
240                 test_line_count = 0 graph-files
241         )
242 '
243
244 corrupt_file() {
245         file=$1
246         pos=$2
247         data="${3:-\0}"
248         chmod a+w "$file" &&
249         printf "$data" | dd of="$file" bs=1 seek="$pos" conv=notrunc
250 }
251
252 test_expect_success 'verify hashes along chain, even in shallow' '
253         git clone --no-hardlinks . verify &&
254         (
255                 cd verify &&
256                 git commit-graph verify &&
257                 base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
258                 corrupt_file "$base_file" $(test_oid shallow) "\01" &&
259                 test_must_fail git commit-graph verify --shallow 2>test_err &&
260                 grep -v "^+" test_err >err &&
261                 test_i18ngrep "incorrect checksum" err
262         )
263 '
264
265 test_expect_success 'verify --shallow does not check base contents' '
266         git clone --no-hardlinks . verify-shallow &&
267         (
268                 cd verify-shallow &&
269                 git commit-graph verify &&
270                 base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
271                 corrupt_file "$base_file" 1000 "\01" &&
272                 git commit-graph verify --shallow &&
273                 test_must_fail git commit-graph verify 2>test_err &&
274                 grep -v "^+" test_err >err &&
275                 test_i18ngrep "incorrect checksum" err
276         )
277 '
278
279 test_expect_success 'warn on base graph chunk incorrect' '
280         git clone --no-hardlinks . base-chunk &&
281         (
282                 cd base-chunk &&
283                 git commit-graph verify &&
284                 base_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
285                 corrupt_file "$base_file" $(test_oid base) "\01" &&
286                 git commit-graph verify --shallow 2>test_err &&
287                 grep -v "^+" test_err >err &&
288                 test_i18ngrep "commit-graph chain does not match" err
289         )
290 '
291
292 test_expect_success 'verify after commit-graph-chain corruption' '
293         git clone --no-hardlinks . verify-chain &&
294         (
295                 cd verify-chain &&
296                 corrupt_file "$graphdir/commit-graph-chain" 60 "G" &&
297                 git commit-graph verify 2>test_err &&
298                 grep -v "^+" test_err >err &&
299                 test_i18ngrep "invalid commit-graph chain" err &&
300                 corrupt_file "$graphdir/commit-graph-chain" 60 "A" &&
301                 git commit-graph verify 2>test_err &&
302                 grep -v "^+" test_err >err &&
303                 test_i18ngrep "unable to find all commit-graph files" err
304         )
305 '
306
307 test_expect_success 'verify across alternates' '
308         git clone --no-hardlinks . verify-alt &&
309         (
310                 cd verify-alt &&
311                 rm -rf $graphdir &&
312                 altdir="$(pwd)/../.git/objects" &&
313                 echo "$altdir" >.git/objects/info/alternates &&
314                 git commit-graph verify --object-dir="$altdir/" &&
315                 test_commit extra &&
316                 git commit-graph write --reachable --split &&
317                 tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
318                 corrupt_file "$tip_file" 100 "\01" &&
319                 test_must_fail git commit-graph verify --shallow 2>test_err &&
320                 grep -v "^+" test_err >err &&
321                 test_i18ngrep "commit-graph has incorrect fanout value" err
322         )
323 '
324
325 test_expect_success 'add octopus merge' '
326         git reset --hard commits/10 &&
327         git merge commits/3 commits/4 &&
328         git branch merge/octopus &&
329         git commit-graph write --reachable --split &&
330         git commit-graph verify --progress 2>err &&
331         test_line_count = 3 err &&
332         test_i18ngrep ! warning err &&
333         test_line_count = 3 $graphdir/commit-graph-chain
334 '
335
336 graph_git_behavior 'graph exists' merge/octopus commits/12
337
338 test_expect_success 'split across alternate where alternate is not split' '
339         git commit-graph write --reachable &&
340         test_path_is_file .git/objects/info/commit-graph &&
341         cp .git/objects/info/commit-graph . &&
342         git clone --no-hardlinks . alt-split &&
343         (
344                 cd alt-split &&
345                 rm -f .git/objects/info/commit-graph &&
346                 echo "$(pwd)"/../.git/objects >.git/objects/info/alternates &&
347                 test_commit 18 &&
348                 git commit-graph write --reachable --split &&
349                 test_line_count = 1 $graphdir/commit-graph-chain
350         ) &&
351         test_cmp commit-graph .git/objects/info/commit-graph
352 '
353
354 test_done