]> git.ipfire.org Git - thirdparty/git.git/blob - t/t6437-submodule-merge.sh
c9a86f2e947e4a2943438cc5adcaaeab39a465d9
[thirdparty/git.git] / t / t6437-submodule-merge.sh
1 #!/bin/sh
2
3 test_description='merging with submodules'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
9 export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
10
11 . ./test-lib.sh
12 . "$TEST_DIRECTORY"/lib-merge.sh
13
14 #
15 # history
16 #
17 # a --- c
18 # / \ /
19 # root X
20 # \ / \
21 # b --- d
22 #
23
24 test_expect_success setup '
25
26 mkdir sub &&
27 (cd sub &&
28 git init &&
29 echo original > file &&
30 git add file &&
31 test_tick &&
32 git commit -m sub-root) &&
33 git add sub &&
34 test_tick &&
35 git commit -m root &&
36
37 git checkout -b a main &&
38 (cd sub &&
39 echo A > file &&
40 git add file &&
41 test_tick &&
42 git commit -m sub-a) &&
43 git add sub &&
44 test_tick &&
45 git commit -m a &&
46
47 git checkout -b b main &&
48 (cd sub &&
49 echo B > file &&
50 git add file &&
51 test_tick &&
52 git commit -m sub-b) &&
53 git add sub &&
54 test_tick &&
55 git commit -m b &&
56
57 git checkout -b c a &&
58 git merge -s ours b &&
59
60 git checkout -b d b &&
61 git merge -s ours a
62 '
63
64 # History setup
65 #
66 # b
67 # / \
68 # init -- a d
69 # \ \ /
70 # g c
71 #
72 # a in the main repository records to sub-a in the submodule and
73 # analogous b and c. d should be automatically found by merging c into
74 # b in the main repository.
75 test_expect_success 'setup for merge search' '
76 mkdir merge-search &&
77 (cd merge-search &&
78 git init &&
79 mkdir sub &&
80 (cd sub &&
81 git init &&
82 echo "file-a" > file-a &&
83 git add file-a &&
84 git commit -m "sub-a" &&
85 git branch sub-a) &&
86 git commit --allow-empty -m init &&
87 git branch init &&
88 git add sub &&
89 git commit -m "a" &&
90 git branch a &&
91
92 git checkout -b b &&
93 (cd sub &&
94 git checkout -b sub-b &&
95 echo "file-b" > file-b &&
96 git add file-b &&
97 git commit -m "sub-b") &&
98 git commit -a -m "b" &&
99
100 git checkout -b c a &&
101 (cd sub &&
102 git checkout -b sub-c sub-a &&
103 echo "file-c" > file-c &&
104 git add file-c &&
105 git commit -m "sub-c") &&
106 git commit -a -m "c")
107 '
108
109 test_expect_success 'merging should conflict for non fast-forward' '
110 test_when_finished "git -C merge-search reset --hard" &&
111 (cd merge-search &&
112 git checkout -b test-nonforward-a b &&
113 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
114 then
115 test_must_fail git merge c >actual &&
116 sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
117 grep "$sub_expect" actual
118 else
119 test_must_fail git merge c 2> actual
120 fi)
121 '
122
123 test_expect_success 'finish setup for merge-search' '
124 (cd merge-search &&
125 git checkout -b d a &&
126 (cd sub &&
127 git checkout -b sub-d sub-b &&
128 git merge sub-c) &&
129 git commit -a -m "d" &&
130 git branch test b &&
131
132 git checkout -b g init &&
133 (cd sub &&
134 git checkout -b sub-g sub-c) &&
135 git add sub &&
136 git commit -a -m "g")
137 '
138
139 test_expect_success 'merge with one side as a fast-forward of the other' '
140 (cd merge-search &&
141 git checkout -b test-forward b &&
142 git merge d &&
143 git ls-tree test-forward sub | cut -f1 | cut -f3 -d" " > actual &&
144 (cd sub &&
145 git rev-parse sub-d > ../expect) &&
146 test_cmp expect actual)
147 '
148
149 test_expect_success 'merging should conflict for non fast-forward (resolution exists)' '
150 (cd merge-search &&
151 git checkout -b test-nonforward-b b &&
152 (cd sub &&
153 git rev-parse --short sub-d > ../expect) &&
154 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
155 then
156 test_must_fail git merge c >actual &&
157 sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
158 grep "$sub_expect" actual
159 else
160 test_must_fail git merge c 2> actual
161 fi &&
162 grep $(cat expect) actual > /dev/null &&
163 git reset --hard)
164 '
165
166 test_expect_success 'merging should fail for ambiguous common parent' '
167 (cd merge-search &&
168 git checkout -b test-ambiguous b &&
169 (cd sub &&
170 git checkout -b ambiguous sub-b &&
171 git merge sub-c &&
172 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
173 then
174 git rev-parse --short sub-d >../expect1 &&
175 git rev-parse --short ambiguous >../expect2
176 else
177 git rev-parse sub-d > ../expect1 &&
178 git rev-parse ambiguous > ../expect2
179 fi
180 ) &&
181 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
182 then
183 test_must_fail git merge c >actual &&
184 sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-c)" &&
185 grep "$sub_expect" actual
186 else
187 test_must_fail git merge c 2> actual
188 fi &&
189 grep $(cat expect1) actual > /dev/null &&
190 grep $(cat expect2) actual > /dev/null &&
191 git reset --hard)
192 '
193
194 # in a situation like this
195 #
196 # submodule tree:
197 #
198 # sub-a --- sub-b --- sub-d
199 #
200 # main tree:
201 #
202 # e (sub-a)
203 # /
204 # bb (sub-b)
205 # \
206 # f (sub-d)
207 #
208 # A merge between e and f should fail because one of the submodule
209 # commits (sub-a) does not descend from the submodule merge-base (sub-b).
210 #
211 test_expect_success 'merging should fail for changes that are backwards' '
212 (cd merge-search &&
213 git checkout -b bb a &&
214 (cd sub &&
215 git checkout sub-b) &&
216 git commit -a -m "bb" &&
217
218 git checkout -b e bb &&
219 (cd sub &&
220 git checkout sub-a) &&
221 git commit -a -m "e" &&
222
223 git checkout -b f bb &&
224 (cd sub &&
225 git checkout sub-d) &&
226 git commit -a -m "f" &&
227
228 git checkout -b test-backward e &&
229 test_must_fail git merge f >actual &&
230 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
231 then
232 sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short sub-d)" &&
233 grep "$sub_expect" actual
234 fi)
235 '
236
237
238 # Check that the conflicting submodule is detected when it is
239 # in the common ancestor. status should be 'U00...00"
240 test_expect_success 'git submodule status should display the merge conflict properly with merge base' '
241 (cd merge-search &&
242 cat >.gitmodules <<EOF &&
243 [submodule "sub"]
244 path = sub
245 url = $TRASH_DIRECTORY/sub
246 EOF
247 cat >expect <<EOF &&
248 U$ZERO_OID sub
249 EOF
250 git submodule status > actual &&
251 test_cmp expect actual &&
252 git reset --hard)
253 '
254
255 # Check that the conflicting submodule is detected when it is
256 # not in the common ancestor. status should be 'U00...00"
257 test_expect_success 'git submodule status should display the merge conflict properly without merge-base' '
258 (cd merge-search &&
259 git checkout -b test-no-merge-base g &&
260 test_must_fail git merge b &&
261 cat >.gitmodules <<EOF &&
262 [submodule "sub"]
263 path = sub
264 url = $TRASH_DIRECTORY/sub
265 EOF
266 cat >expect <<EOF &&
267 U$ZERO_OID sub
268 EOF
269 git submodule status > actual &&
270 test_cmp expect actual &&
271 git reset --hard)
272 '
273
274
275 test_expect_success 'merging with a modify/modify conflict between merge bases' '
276 git reset --hard HEAD &&
277 git checkout -b test2 c &&
278 git merge d
279 '
280
281 # canonical criss-cross history in top and submodule
282 test_expect_success 'setup for recursive merge with submodule' '
283 mkdir merge-recursive &&
284 (cd merge-recursive &&
285 git init &&
286 mkdir sub &&
287 (cd sub &&
288 git init &&
289 test_commit a &&
290 git checkout -b sub-b main &&
291 test_commit b &&
292 git checkout -b sub-c main &&
293 test_commit c &&
294 git checkout -b sub-bc sub-b &&
295 git merge sub-c &&
296 git checkout -b sub-cb sub-c &&
297 git merge sub-b &&
298 git checkout main) &&
299 git add sub &&
300 git commit -m a &&
301 git checkout -b top-b main &&
302 (cd sub && git checkout sub-b) &&
303 git add sub &&
304 git commit -m b &&
305 git checkout -b top-c main &&
306 (cd sub && git checkout sub-c) &&
307 git add sub &&
308 git commit -m c &&
309 git checkout -b top-bc top-b &&
310 git merge -s ours --no-commit top-c &&
311 (cd sub && git checkout sub-bc) &&
312 git add sub &&
313 git commit -m bc &&
314 git checkout -b top-cb top-c &&
315 git merge -s ours --no-commit top-b &&
316 (cd sub && git checkout sub-cb) &&
317 git add sub &&
318 git commit -m cb)
319 '
320
321 # merge should leave submodule unmerged in index
322 test_expect_success 'recursive merge with submodule' '
323 (cd merge-recursive &&
324 test_must_fail git merge top-bc &&
325 echo "160000 $(git rev-parse top-cb:sub) 2 sub" > expect2 &&
326 echo "160000 $(git rev-parse top-bc:sub) 3 sub" > expect3 &&
327 git ls-files -u > actual &&
328 grep "$(cat expect2)" actual > /dev/null &&
329 grep "$(cat expect3)" actual > /dev/null)
330 '
331
332 # File/submodule conflict
333 # Commit O: <empty>
334 # Commit A: path (submodule)
335 # Commit B: path
336 # Expected: path/ is submodule and file contents for B's path are somewhere
337
338 test_expect_success 'setup file/submodule conflict' '
339 git init file-submodule &&
340 (
341 cd file-submodule &&
342
343 git commit --allow-empty -m O &&
344
345 git branch A &&
346 git branch B &&
347
348 git checkout B &&
349 echo content >path &&
350 git add path &&
351 git commit -m B &&
352
353 git checkout A &&
354 git init path &&
355 test_commit -C path world &&
356 git submodule add ./path &&
357 git commit -m A
358 )
359 '
360
361 test_expect_merge_algorithm failure success 'file/submodule conflict' '
362 test_when_finished "git -C file-submodule reset --hard" &&
363 (
364 cd file-submodule &&
365
366 git checkout A^0 &&
367 test_must_fail git merge B^0 &&
368
369 git ls-files -s >out &&
370 test_line_count = 3 out &&
371 git ls-files -u >out &&
372 test_line_count = 2 out &&
373
374 # path/ is still a submodule
375 test_path_is_dir path/.git &&
376
377 # There is a submodule at "path", so B:path cannot be written
378 # there. We expect it to be written somewhere in the same
379 # directory, though, so just grep for its content in all
380 # files, and ignore "grep: path: Is a directory" message
381 echo Checking if contents from B:path showed up anywhere &&
382 grep -q content * 2>/dev/null
383 )
384 '
385
386 test_expect_success 'file/submodule conflict; merge --abort works afterward' '
387 test_when_finished "git -C file-submodule reset --hard" &&
388 (
389 cd file-submodule &&
390
391 git checkout A^0 &&
392 test_must_fail git merge B^0 >out 2>err &&
393
394 test_path_is_file .git/MERGE_HEAD &&
395 git merge --abort
396 )
397 '
398
399 # Directory/submodule conflict
400 # Commit O: <empty>
401 # Commit A: path (submodule), with sole tracked file named 'world'
402 # Commit B1: path/file
403 # Commit B2: path/world
404 #
405 # Expected from merge of A & B1:
406 # Contents under path/ from commit B1 are renamed elsewhere; we do not
407 # want to write files from one of our tracked directories into a submodule
408 #
409 # Expected from merge of A & B2:
410 # Similar to last merge, but with a slight twist: we don't want paths
411 # under the submodule to be treated as untracked or in the way.
412
413 test_expect_success 'setup directory/submodule conflict' '
414 git init directory-submodule &&
415 (
416 cd directory-submodule &&
417
418 git commit --allow-empty -m O &&
419
420 git branch A &&
421 git branch B1 &&
422 git branch B2 &&
423
424 git checkout B1 &&
425 mkdir path &&
426 echo contents >path/file &&
427 git add path/file &&
428 git commit -m B1 &&
429
430 git checkout B2 &&
431 mkdir path &&
432 echo contents >path/world &&
433 git add path/world &&
434 git commit -m B2 &&
435
436 git checkout A &&
437 git init path &&
438 test_commit -C path hello world &&
439 git submodule add ./path &&
440 git commit -m A
441 )
442 '
443
444 test_expect_failure 'directory/submodule conflict; keep submodule clean' '
445 test_when_finished "git -C directory-submodule reset --hard" &&
446 (
447 cd directory-submodule &&
448
449 git checkout A^0 &&
450 test_must_fail git merge B1^0 &&
451
452 git ls-files -s >out &&
453 test_line_count = 3 out &&
454 git ls-files -u >out &&
455 test_line_count = 1 out &&
456
457 # path/ is still a submodule
458 test_path_is_dir path/.git &&
459
460 echo Checking if contents from B1:path/file showed up &&
461 # Would rather use grep -r, but that is GNU extension...
462 git ls-files -co | xargs grep -q contents 2>/dev/null &&
463
464 # However, B1:path/file should NOT have shown up at path/file,
465 # because we should not write into the submodule
466 test_path_is_missing path/file
467 )
468 '
469
470 test_expect_merge_algorithm failure success !FAIL_PREREQS 'directory/submodule conflict; should not treat submodule files as untracked or in the way' '
471 test_when_finished "git -C directory-submodule/path reset --hard" &&
472 test_when_finished "git -C directory-submodule reset --hard" &&
473 (
474 cd directory-submodule &&
475
476 git checkout A^0 &&
477 test_must_fail git merge B2^0 >out 2>err &&
478
479 # We do not want files within the submodule to prevent the
480 # merge from starting; we should not be writing to such paths
481 # anyway.
482 test_i18ngrep ! "refusing to lose untracked file at" err
483 )
484 '
485
486 test_expect_failure 'directory/submodule conflict; merge --abort works afterward' '
487 test_when_finished "git -C directory-submodule/path reset --hard" &&
488 test_when_finished "git -C directory-submodule reset --hard" &&
489 (
490 cd directory-submodule &&
491
492 git checkout A^0 &&
493 test_must_fail git merge B2^0 &&
494 test_path_is_file .git/MERGE_HEAD &&
495
496 # merge --abort should succeed, should clear .git/MERGE_HEAD,
497 # and should not leave behind any conflicted files
498 git merge --abort &&
499 test_path_is_missing .git/MERGE_HEAD &&
500 git ls-files -u >conflicts &&
501 test_must_be_empty conflicts
502 )
503 '
504
505 # Setup:
506 # - Submodule has 2 commits: a and b
507 # - Superproject branch 'a' adds and commits submodule pointing to 'commit a'
508 # - Superproject branch 'b' adds and commits submodule pointing to 'commit b'
509 # If these two branches are now merged, there is no merge base
510 test_expect_success 'setup for null merge base' '
511 mkdir no-merge-base &&
512 (cd no-merge-base &&
513 git init &&
514 mkdir sub &&
515 (cd sub &&
516 git init &&
517 echo "file-a" > file-a &&
518 git add file-a &&
519 git commit -m "commit a") &&
520 git commit --allow-empty -m init &&
521 git branch init &&
522 git checkout -b a init &&
523 git add sub &&
524 git commit -m "a" &&
525 git switch main &&
526 (cd sub &&
527 echo "file-b" > file-b &&
528 git add file-b &&
529 git commit -m "commit b"))
530 '
531
532 test_expect_success 'merging should fail with no merge base' '
533 (cd no-merge-base &&
534 git checkout -b b init &&
535 git add sub &&
536 git commit -m "b" &&
537 test_must_fail git merge a >actual &&
538 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
539 then
540 sub_expect="go to submodule (sub), and either merge commit $(git -C sub rev-parse --short HEAD^1)" &&
541 grep "$sub_expect" actual
542 fi)
543 '
544
545 test_done