t6022: Add tests for reversing order of merges when D/F conflicts present
[git] / t / t6022-merge-rename.sh
1 #!/bin/sh
2
3 test_description='Merge-recursive merging renames'
4 . ./test-lib.sh
5
6 modify () {
7         sed -e "$1" <"$2" >"$2.x" &&
8         mv "$2.x" "$2"
9 }
10
11 test_expect_success setup \
12 '
13 cat >A <<\EOF &&
14 a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15 b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
16 c cccccccccccccccccccccccccccccccccccccccccccccccc
17 d dddddddddddddddddddddddddddddddddddddddddddddddd
18 e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
19 f ffffffffffffffffffffffffffffffffffffffffffffffff
20 g gggggggggggggggggggggggggggggggggggggggggggggggg
21 h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
22 i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
23 j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
24 k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
25 l llllllllllllllllllllllllllllllllllllllllllllllll
26 m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
27 n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
28 o oooooooooooooooooooooooooooooooooooooooooooooooo
29 EOF
30
31 cat >M <<\EOF &&
32 A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
33 B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
34 C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
35 D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
36 E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
37 F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
38 G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
39 H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
40 I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
41 J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
42 K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
43 L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
44 M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
45 N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
46 O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
47 EOF
48
49 git add A M &&
50 git commit -m "initial has A and M" &&
51 git branch white &&
52 git branch red &&
53 git branch blue &&
54 git branch yellow &&
55 git branch change &&
56 git branch change+rename &&
57
58 sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
59 mv A+ A &&
60 git commit -a -m "master updates A" &&
61
62 git checkout yellow &&
63 rm -f M &&
64 git commit -a -m "yellow removes M" &&
65
66 git checkout white &&
67 sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
68 sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
69 rm -f A M &&
70 git update-index --add --remove A B M N &&
71 git commit -m "white renames A->B, M->N" &&
72
73 git checkout red &&
74 sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
75 sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
76 rm -f A M &&
77 git update-index --add --remove A B M N &&
78 git commit -m "red renames A->B, M->N" &&
79
80 git checkout blue &&
81 sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
82 sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
83 rm -f A M &&
84 git update-index --add --remove A C M N &&
85 git commit -m "blue renames A->C, M->N" &&
86
87 git checkout change &&
88 sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
89 mv A+ A &&
90 git commit -q -a -m "changed" &&
91
92 git checkout change+rename &&
93 sed -e "/^g /s/.*/g : changed line/" <A >B &&
94 rm A &&
95 git update-index --add B &&
96 git commit -q -a -m "changed and renamed" &&
97
98 git checkout master'
99
100 test_expect_success 'pull renaming branch into unrenaming one' \
101 '
102         git show-branch
103         git pull . white && {
104                 echo "BAD: should have conflicted"
105                 return 1
106         }
107         git ls-files -s
108         test "$(git ls-files -u B | wc -l)" -eq 3 || {
109                 echo "BAD: should have left stages for B"
110                 return 1
111         }
112         test "$(git ls-files -s N | wc -l)" -eq 1 || {
113                 echo "BAD: should have merged N"
114                 return 1
115         }
116         sed -ne "/^g/{
117         p
118         q
119         }" B | grep master || {
120                 echo "BAD: should have listed our change first"
121                 return 1
122         }
123         test "$(git diff white N | wc -l)" -eq 0 || {
124                 echo "BAD: should have taken colored branch"
125                 return 1
126         }
127 '
128
129 test_expect_success 'pull renaming branch into another renaming one' \
130 '
131         rm -f B
132         git reset --hard
133         git checkout red
134         git pull . white && {
135                 echo "BAD: should have conflicted"
136                 return 1
137         }
138         test "$(git ls-files -u B | wc -l)" -eq 3 || {
139                 echo "BAD: should have left stages"
140                 return 1
141         }
142         test "$(git ls-files -s N | wc -l)" -eq 1 || {
143                 echo "BAD: should have merged N"
144                 return 1
145         }
146         sed -ne "/^g/{
147         p
148         q
149         }" B | grep red || {
150                 echo "BAD: should have listed our change first"
151                 return 1
152         }
153         test "$(git diff white N | wc -l)" -eq 0 || {
154                 echo "BAD: should have taken colored branch"
155                 return 1
156         }
157 '
158
159 test_expect_success 'pull unrenaming branch into renaming one' \
160 '
161         git reset --hard
162         git show-branch
163         git pull . master && {
164                 echo "BAD: should have conflicted"
165                 return 1
166         }
167         test "$(git ls-files -u B | wc -l)" -eq 3 || {
168                 echo "BAD: should have left stages"
169                 return 1
170         }
171         test "$(git ls-files -s N | wc -l)" -eq 1 || {
172                 echo "BAD: should have merged N"
173                 return 1
174         }
175         sed -ne "/^g/{
176         p
177         q
178         }" B | grep red || {
179                 echo "BAD: should have listed our change first"
180                 return 1
181         }
182         test "$(git diff white N | wc -l)" -eq 0 || {
183                 echo "BAD: should have taken colored branch"
184                 return 1
185         }
186 '
187
188 test_expect_success 'pull conflicting renames' \
189 '
190         git reset --hard
191         git show-branch
192         git pull . blue && {
193                 echo "BAD: should have conflicted"
194                 return 1
195         }
196         test "$(git ls-files -u A | wc -l)" -eq 1 || {
197                 echo "BAD: should have left a stage"
198                 return 1
199         }
200         test "$(git ls-files -u B | wc -l)" -eq 1 || {
201                 echo "BAD: should have left a stage"
202                 return 1
203         }
204         test "$(git ls-files -u C | wc -l)" -eq 1 || {
205                 echo "BAD: should have left a stage"
206                 return 1
207         }
208         test "$(git ls-files -s N | wc -l)" -eq 1 || {
209                 echo "BAD: should have merged N"
210                 return 1
211         }
212         sed -ne "/^g/{
213         p
214         q
215         }" B | grep red || {
216                 echo "BAD: should have listed our change first"
217                 return 1
218         }
219         test "$(git diff white N | wc -l)" -eq 0 || {
220                 echo "BAD: should have taken colored branch"
221                 return 1
222         }
223 '
224
225 test_expect_success 'interference with untracked working tree file' '
226
227         git reset --hard
228         git show-branch
229         echo >A this file should not matter
230         git pull . white && {
231                 echo "BAD: should have conflicted"
232                 return 1
233         }
234         test -f A || {
235                 echo "BAD: should have left A intact"
236                 return 1
237         }
238 '
239
240 test_expect_success 'interference with untracked working tree file' '
241
242         git reset --hard
243         git checkout white
244         git show-branch
245         rm -f A
246         echo >A this file should not matter
247         git pull . red && {
248                 echo "BAD: should have conflicted"
249                 return 1
250         }
251         test -f A || {
252                 echo "BAD: should have left A intact"
253                 return 1
254         }
255 '
256
257 test_expect_success 'interference with untracked working tree file' '
258
259         git reset --hard
260         rm -f A M
261         git checkout -f master
262         git tag -f anchor
263         git show-branch
264         git pull . yellow || {
265                 echo "BAD: should have cleanly merged"
266                 return 1
267         }
268         test -f M && {
269                 echo "BAD: should have removed M"
270                 return 1
271         }
272         git reset --hard anchor
273 '
274
275 test_expect_success 'updated working tree file should prevent the merge' '
276
277         git reset --hard
278         rm -f A M
279         git checkout -f master
280         git tag -f anchor
281         git show-branch
282         echo >>M one line addition
283         cat M >M.saved
284         git pull . yellow && {
285                 echo "BAD: should have complained"
286                 return 1
287         }
288         test_cmp M M.saved || {
289                 echo "BAD: should have left M intact"
290                 return 1
291         }
292         rm -f M.saved
293 '
294
295 test_expect_success 'updated working tree file should prevent the merge' '
296
297         git reset --hard
298         rm -f A M
299         git checkout -f master
300         git tag -f anchor
301         git show-branch
302         echo >>M one line addition
303         cat M >M.saved
304         git update-index M
305         git pull . yellow && {
306                 echo "BAD: should have complained"
307                 return 1
308         }
309         test_cmp M M.saved || {
310                 echo "BAD: should have left M intact"
311                 return 1
312         }
313         rm -f M.saved
314 '
315
316 test_expect_success 'interference with untracked working tree file' '
317
318         git reset --hard
319         rm -f A M
320         git checkout -f yellow
321         git tag -f anchor
322         git show-branch
323         echo >M this file should not matter
324         git pull . master || {
325                 echo "BAD: should have cleanly merged"
326                 return 1
327         }
328         test -f M || {
329                 echo "BAD: should have left M intact"
330                 return 1
331         }
332         git ls-files -s | grep M && {
333                 echo "BAD: M must be untracked in the result"
334                 return 1
335         }
336         git reset --hard anchor
337 '
338
339 test_expect_success 'merge of identical changes in a renamed file' '
340         rm -f A M N
341         git reset --hard &&
342         git checkout change+rename &&
343         GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" &&
344         git reset --hard HEAD^ &&
345         git checkout change &&
346         GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B"
347 '
348
349 test_expect_success 'setup for rename + d/f conflicts' '
350         git reset --hard &&
351         git checkout --orphan dir-in-way &&
352         git rm -rf . &&
353
354         mkdir sub &&
355         mkdir dir &&
356         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
357         echo foo >dir/file-in-the-way &&
358         git add -A &&
359         git commit -m "Common commmit" &&
360
361         echo 11 >>sub/file &&
362         echo more >>dir/file-in-the-way &&
363         git add -u &&
364         git commit -m "Commit to merge, with dir in the way" &&
365
366         git checkout -b dir-not-in-way &&
367         git reset --soft HEAD^ &&
368         git rm -rf dir &&
369         git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
370
371         git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
372         git rm -rf dir &&
373         git rm sub/file &&
374         printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
375         git add dir &&
376         git commit -m "Independent change" &&
377
378         git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
379         git rm -rf dir &&
380         git mv sub/file dir &&
381         echo 12 >>dir &&
382         git add dir &&
383         git commit -m "Conflicting change"
384 '
385
386 printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
387
388 test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
389         git reset --hard &&
390         git checkout -q renamed-file-has-no-conflicts^0 &&
391         git merge --strategy=recursive dir-not-in-way &&
392         git diff --quiet &&
393         test -f dir &&
394         test_cmp expected dir
395 '
396
397 test_expect_failure 'Rename+D/F conflict; renamed file merges but dir in way' '
398         git reset --hard &&
399         rm -rf dir~* &&
400         git checkout -q renamed-file-has-no-conflicts^0 &&
401         test_must_fail git merge --strategy=recursive dir-in-way >output &&
402
403         grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
404         grep "Auto-merging dir" output &&
405         grep "Adding as dir~HEAD instead" output &&
406
407         test 2 = "$(git ls-files -u | wc -l)" &&
408         test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
409
410         test_must_fail git diff --quiet &&
411         test_must_fail git diff --cached --quiet &&
412
413         test -f dir/file-in-the-way &&
414         test -f dir~HEAD &&
415         test_cmp expected dir~HEAD
416 '
417
418 test_expect_failure 'Same as previous, but merged other way' '
419         git reset --hard &&
420         rm -rf dir~* &&
421         git checkout -q dir-in-way^0 &&
422         test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
423
424         ! grep "error: refusing to lose untracked file at" errors &&
425         grep "CONFLICT (delete/modify): dir/file-in-the-way" output &&
426         grep "Auto-merging dir" output &&
427         grep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
428
429         test 2 = "$(git ls-files -u | wc -l)" &&
430         test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
431
432         test_must_fail git diff --quiet &&
433         test_must_fail git diff --cached --quiet &&
434
435         test -f dir/file-in-the-way &&
436         test -f dir~renamed-file-has-no-conflicts &&
437         test_cmp expected dir~renamed-file-has-no-conflicts
438 '
439
440 cat >expected <<\EOF &&
441 1
442 2
443 3
444 4
445 5
446 6
447 7
448 8
449 9
450 10
451 <<<<<<< HEAD
452 12
453 =======
454 11
455 >>>>>>> dir-not-in-way
456 EOF
457
458 test_expect_failure 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
459         git reset --hard &&
460         rm -rf dir~* &&
461         git checkout -q renamed-file-has-conflicts^0 &&
462         test_must_fail git merge --strategy=recursive dir-not-in-way &&
463
464         test 3 = "$(git ls-files -u | wc -l)" &&
465         test 3 = "$(git ls-files -u dir | wc -l)" &&
466
467         test_must_fail git diff --quiet &&
468         test_must_fail git diff --cached --quiet &&
469
470         test -f dir &&
471         test_cmp expected dir
472 '
473
474 test_expect_failure 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
475         modify s/dir-not-in-way/dir-in-way/ expected &&
476
477         git reset --hard &&
478         rm -rf dir~* &&
479         git checkout -q renamed-file-has-conflicts^0 &&
480         test_must_fail git merge --strategy=recursive dir-in-way &&
481
482         test 5 = "$(git ls-files -u | wc -l)" &&
483         test 3 = "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
484         test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
485
486         test_must_fail git diff --quiet &&
487         test_must_fail git diff --cached --quiet &&
488
489         test -f dir/file-in-the-way &&
490         test -f dir~HEAD &&
491         test_cmp expected dir~HEAD
492 '
493
494 cat >expected <<\EOF &&
495 1
496 2
497 3
498 4
499 5
500 6
501 7
502 8
503 9
504 10
505 <<<<<<< HEAD
506 11
507 =======
508 12
509 >>>>>>> renamed-file-has-conflicts
510 EOF
511
512 test_expect_failure 'Same as previous, but merged other way' '
513         git reset --hard &&
514         rm -rf dir~* &&
515         git checkout -q dir-in-way^0 &&
516         test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
517
518         test 5 = "$(git ls-files -u | wc -l)" &&
519         test 3 = "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
520         test 2 = "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
521
522         test_must_fail git diff --quiet &&
523         test_must_fail git diff --cached --quiet &&
524
525         test -f dir/file-in-the-way &&
526         test -f dir~renamed-file-has-conflicts &&
527         test_cmp expected dir~renamed-file-has-conflicts
528 '
529
530 test_done