Merge branch 'jt/avoid-prefetch-when-able-in-diff'
[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                 touch $graphdir/to-delete.graph $graphdir/to-keep.graph &&
214                 test-tool chmtime =1546362000 $graphdir/to-delete.graph &&
215                 test-tool chmtime =1546362001 $graphdir/to-keep.graph &&
216                 git commit-graph write --reachable --split --size-multiple=10 \
217                         --expire-time="2019-01-01 12:00 -05:00" &&
218                 test_line_count = 1 $graphdir/commit-graph-chain &&
219                 test_path_is_missing $graphdir/to-delete.graph &&
220                 test_path_is_file $graphdir/to-keep.graph &&
221                 ls $graphdir/graph-*.graph >graph-files &&
222                 test_line_count = 3 graph-files
223         ) &&
224         git clone --no-hardlinks . max-commits &&
225         (
226                 cd max-commits &&
227                 git config core.commitGraph true &&
228                 test_line_count = 2 $graphdir/commit-graph-chain &&
229                 test_commit 16 &&
230                 test_commit 17 &&
231                 git commit-graph write --reachable --split --max-commits=1 &&
232                 test_line_count = 1 $graphdir/commit-graph-chain &&
233                 ls $graphdir/graph-*.graph >graph-files &&
234                 test_line_count = 1 graph-files
235         )
236 '
237
238 test_expect_success 'remove commit-graph-chain file after flattening' '
239         git clone . flatten &&
240         (
241                 cd flatten &&
242                 test_line_count = 2 $graphdir/commit-graph-chain &&
243                 git commit-graph write --reachable &&
244                 test_path_is_missing $graphdir/commit-graph-chain &&
245                 ls $graphdir >graph-files &&
246                 test_line_count = 0 graph-files
247         )
248 '
249
250 corrupt_file() {
251         file=$1
252         pos=$2
253         data="${3:-\0}"
254         chmod a+w "$file" &&
255         printf "$data" | dd of="$file" bs=1 seek="$pos" conv=notrunc
256 }
257
258 test_expect_success 'verify hashes along chain, even in shallow' '
259         git clone --no-hardlinks . verify &&
260         (
261                 cd verify &&
262                 git commit-graph verify &&
263                 base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
264                 corrupt_file "$base_file" $(test_oid shallow) "\01" &&
265                 test_must_fail git commit-graph verify --shallow 2>test_err &&
266                 grep -v "^+" test_err >err &&
267                 test_i18ngrep "incorrect checksum" err
268         )
269 '
270
271 test_expect_success 'verify --shallow does not check base contents' '
272         git clone --no-hardlinks . verify-shallow &&
273         (
274                 cd verify-shallow &&
275                 git commit-graph verify &&
276                 base_file=$graphdir/graph-$(head -n 1 $graphdir/commit-graph-chain).graph &&
277                 corrupt_file "$base_file" 1000 "\01" &&
278                 git commit-graph verify --shallow &&
279                 test_must_fail git commit-graph verify 2>test_err &&
280                 grep -v "^+" test_err >err &&
281                 test_i18ngrep "incorrect checksum" err
282         )
283 '
284
285 test_expect_success 'warn on base graph chunk incorrect' '
286         git clone --no-hardlinks . base-chunk &&
287         (
288                 cd base-chunk &&
289                 git commit-graph verify &&
290                 base_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
291                 corrupt_file "$base_file" $(test_oid base) "\01" &&
292                 git commit-graph verify --shallow 2>test_err &&
293                 grep -v "^+" test_err >err &&
294                 test_i18ngrep "commit-graph chain does not match" err
295         )
296 '
297
298 test_expect_success 'verify after commit-graph-chain corruption' '
299         git clone --no-hardlinks . verify-chain &&
300         (
301                 cd verify-chain &&
302                 corrupt_file "$graphdir/commit-graph-chain" 60 "G" &&
303                 git commit-graph verify 2>test_err &&
304                 grep -v "^+" test_err >err &&
305                 test_i18ngrep "invalid commit-graph chain" err &&
306                 corrupt_file "$graphdir/commit-graph-chain" 60 "A" &&
307                 git commit-graph verify 2>test_err &&
308                 grep -v "^+" test_err >err &&
309                 test_i18ngrep "unable to find all commit-graph files" err
310         )
311 '
312
313 test_expect_success 'verify across alternates' '
314         git clone --no-hardlinks . verify-alt &&
315         (
316                 cd verify-alt &&
317                 rm -rf $graphdir &&
318                 altdir="$(pwd)/../.git/objects" &&
319                 echo "$altdir" >.git/objects/info/alternates &&
320                 git commit-graph verify --object-dir="$altdir/" &&
321                 test_commit extra &&
322                 git commit-graph write --reachable --split &&
323                 tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
324                 corrupt_file "$tip_file" 100 "\01" &&
325                 test_must_fail git commit-graph verify --shallow 2>test_err &&
326                 grep -v "^+" test_err >err &&
327                 test_i18ngrep "commit-graph has incorrect fanout value" err
328         )
329 '
330
331 test_expect_success 'add octopus merge' '
332         git reset --hard commits/10 &&
333         git merge commits/3 commits/4 &&
334         git branch merge/octopus &&
335         git commit-graph write --reachable --split &&
336         git commit-graph verify --progress 2>err &&
337         test_line_count = 3 err &&
338         test_i18ngrep ! warning err &&
339         test_line_count = 3 $graphdir/commit-graph-chain
340 '
341
342 graph_git_behavior 'graph exists' merge/octopus commits/12
343
344 test_expect_success 'split across alternate where alternate is not split' '
345         git commit-graph write --reachable &&
346         test_path_is_file .git/objects/info/commit-graph &&
347         cp .git/objects/info/commit-graph . &&
348         git clone --no-hardlinks . alt-split &&
349         (
350                 cd alt-split &&
351                 rm -f .git/objects/info/commit-graph &&
352                 echo "$(pwd)"/../.git/objects >.git/objects/info/alternates &&
353                 test_commit 18 &&
354                 git commit-graph write --reachable --split &&
355                 test_line_count = 1 $graphdir/commit-graph-chain
356         ) &&
357         test_cmp commit-graph .git/objects/info/commit-graph
358 '
359
360 test_done