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