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