merge tests: expect improved directory/file conflict handling in ort
[git] / t / t6402-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         cat >A <<-\EOF &&
13         a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
14         b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
15         c cccccccccccccccccccccccccccccccccccccccccccccccc
16         d dddddddddddddddddddddddddddddddddddddddddddddddd
17         e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
18         f ffffffffffffffffffffffffffffffffffffffffffffffff
19         g gggggggggggggggggggggggggggggggggggggggggggggggg
20         h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
21         i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
22         j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
23         k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
24         l llllllllllllllllllllllllllllllllllllllllllllllll
25         m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
26         n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
27         o oooooooooooooooooooooooooooooooooooooooooooooooo
28         EOF
29
30         cat >M <<-\EOF &&
31         A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
32         B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
33         C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
34         D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
35         E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
36         F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
37         G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
38         H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
39         I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
40         J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
41         K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
42         L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
43         M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
44         N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
45         O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
46         EOF
47
48         git add A M &&
49         git commit -m "initial has A and M" &&
50         git branch white &&
51         git branch red &&
52         git branch blue &&
53         git branch yellow &&
54         git branch change &&
55         git branch change+rename &&
56
57         sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
58         mv A+ A &&
59         git commit -a -m "master updates A" &&
60
61         git checkout yellow &&
62         rm -f M &&
63         git commit -a -m "yellow removes M" &&
64
65         git checkout white &&
66         sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
67         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
68         rm -f A M &&
69         git update-index --add --remove A B M N &&
70         git commit -m "white renames A->B, M->N" &&
71
72         git checkout red &&
73         sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
74         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
75         rm -f A M &&
76         git update-index --add --remove A B M N &&
77         git commit -m "red renames A->B, M->N" &&
78
79         git checkout blue &&
80         sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
81         sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
82         rm -f A M &&
83         git update-index --add --remove A C M N &&
84         git commit -m "blue renames A->C, M->N" &&
85
86         git checkout change &&
87         sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
88         mv A+ A &&
89         git commit -q -a -m "changed" &&
90
91         git checkout change+rename &&
92         sed -e "/^g /s/.*/g : changed line/" <A >B &&
93         rm A &&
94         git update-index --add B &&
95         git commit -q -a -m "changed and renamed" &&
96
97         git checkout master
98 '
99
100 test_expect_success 'pull renaming branch into unrenaming one' \
101 '
102         git show-branch &&
103         test_expect_code 1 git pull . white &&
104         git ls-files -s &&
105         git ls-files -u B >b.stages &&
106         test_line_count = 3 b.stages &&
107         git ls-files -s N >n.stages &&
108         test_line_count = 1 n.stages &&
109         sed -ne "/^g/{
110         p
111         q
112         }" B | grep master &&
113         git diff --exit-code white N
114 '
115
116 test_expect_success 'pull renaming branch into another renaming one' \
117 '
118         rm -f B &&
119         git reset --hard &&
120         git checkout red &&
121         test_expect_code 1 git pull . white &&
122         git ls-files -u B >b.stages &&
123         test_line_count = 3 b.stages &&
124         git ls-files -s N >n.stages &&
125         test_line_count = 1 n.stages &&
126         sed -ne "/^g/{
127         p
128         q
129         }" B | grep red &&
130         git diff --exit-code white N
131 '
132
133 test_expect_success 'pull unrenaming branch into renaming one' \
134 '
135         git reset --hard &&
136         git show-branch &&
137         test_expect_code 1 git pull . master &&
138         git ls-files -u B >b.stages &&
139         test_line_count = 3 b.stages &&
140         git ls-files -s N >n.stages &&
141         test_line_count = 1 n.stages &&
142         sed -ne "/^g/{
143         p
144         q
145         }" B | grep red &&
146         git diff --exit-code white N
147 '
148
149 test_expect_success 'pull conflicting renames' \
150 '
151         git reset --hard &&
152         git show-branch &&
153         test_expect_code 1 git pull . blue &&
154         git ls-files -u A >a.stages &&
155         test_line_count = 1 a.stages &&
156         git ls-files -u B >b.stages &&
157         test_line_count = 1 b.stages &&
158         git ls-files -u C >c.stages &&
159         test_line_count = 1 c.stages &&
160         git ls-files -s N >n.stages &&
161         test_line_count = 1 n.stages &&
162         sed -ne "/^g/{
163         p
164         q
165         }" B | grep red &&
166         git diff --exit-code white N
167 '
168
169 test_expect_success 'interference with untracked working tree file' '
170         git reset --hard &&
171         git show-branch &&
172         echo >A this file should not matter &&
173         test_expect_code 1 git pull . white &&
174         test_path_is_file A
175 '
176
177 test_expect_success 'interference with untracked working tree file' '
178         git reset --hard &&
179         git checkout white &&
180         git show-branch &&
181         rm -f A &&
182         echo >A this file should not matter &&
183         test_expect_code 1 git pull . red &&
184         test_path_is_file A
185 '
186
187 test_expect_success 'interference with untracked working tree file' '
188         git reset --hard &&
189         rm -f A M &&
190         git checkout -f master &&
191         git tag -f anchor &&
192         git show-branch &&
193         git pull . yellow &&
194         test_path_is_missing M &&
195         git reset --hard anchor
196 '
197
198 test_expect_success 'updated working tree file should prevent the merge' '
199         git reset --hard &&
200         rm -f A M &&
201         git checkout -f master &&
202         git tag -f anchor &&
203         git show-branch &&
204         echo >>M one line addition &&
205         cat M >M.saved &&
206         test_expect_code 128 git pull . yellow &&
207         test_cmp M M.saved &&
208         rm -f M.saved
209 '
210
211 test_expect_success 'updated working tree file should prevent the merge' '
212         git reset --hard &&
213         rm -f A M &&
214         git checkout -f master &&
215         git tag -f anchor &&
216         git show-branch &&
217         echo >>M one line addition &&
218         cat M >M.saved &&
219         git update-index M &&
220         test_expect_code 128 git pull . yellow &&
221         test_cmp M M.saved &&
222         rm -f M.saved
223 '
224
225 test_expect_success 'interference with untracked working tree file' '
226         git reset --hard &&
227         rm -f A M &&
228         git checkout -f yellow &&
229         git tag -f anchor &&
230         git show-branch &&
231         echo >M this file should not matter &&
232         git pull . master &&
233         test_path_is_file M &&
234         ! {
235                 git ls-files -s |
236                 grep M
237         } &&
238         git reset --hard anchor
239 '
240
241 test_expect_success 'merge of identical changes in a renamed file' '
242         rm -f A M N &&
243         git reset --hard &&
244         git checkout change+rename &&
245
246         test-tool chmtime --get -3600 B >old-mtime &&
247         GIT_MERGE_VERBOSITY=3 git merge change >out &&
248
249         test-tool chmtime --get B >new-mtime &&
250         test_cmp old-mtime new-mtime &&
251
252         git reset --hard HEAD^ &&
253         git checkout change &&
254
255         # A will be renamed to B; we check mtimes and file presence
256         test_path_is_missing B &&
257         test-tool chmtime --get -3600 A >old-mtime &&
258         GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
259
260         test_path_is_missing A &&
261         test-tool chmtime --get B >new-mtime &&
262         test $(cat old-mtime) -lt $(cat new-mtime)
263 '
264
265 test_expect_success 'setup for rename + d/f conflicts' '
266         git reset --hard &&
267         git checkout --orphan dir-in-way &&
268         git rm -rf . &&
269         git clean -fdqx &&
270
271         mkdir sub &&
272         mkdir dir &&
273         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
274         echo foo >dir/file-in-the-way &&
275         git add -A &&
276         git commit -m "Common commit" &&
277
278         echo 11 >>sub/file &&
279         echo more >>dir/file-in-the-way &&
280         git add -u &&
281         git commit -m "Commit to merge, with dir in the way" &&
282
283         git checkout -b dir-not-in-way &&
284         git reset --soft HEAD^ &&
285         git rm -rf dir &&
286         git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
287
288         git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
289         git rm -rf dir &&
290         git rm sub/file &&
291         printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
292         git add dir &&
293         git commit -m "Independent change" &&
294
295         git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
296         git rm -rf dir &&
297         git mv sub/file dir &&
298         echo 12 >>dir &&
299         git add dir &&
300         git commit -m "Conflicting change"
301 '
302
303 test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
304         git reset --hard &&
305         git checkout -q renamed-file-has-no-conflicts^0 &&
306
307         git merge --strategy=recursive dir-not-in-way &&
308
309         git diff --quiet &&
310         test_path_is_file dir &&
311         test_write_lines 1 2 3 4 5555 6 7 8 9 10 11 >expected &&
312         test_cmp expected dir
313 '
314
315 test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
316         git reset --hard &&
317         rm -rf dir~* &&
318         git checkout -q renamed-file-has-no-conflicts^0 &&
319         test_must_fail git merge --strategy=recursive dir-in-way >output &&
320
321         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
322         test_i18ngrep "Auto-merging dir" output &&
323         test_i18ngrep "Adding as dir~HEAD instead" output &&
324
325         test 3 -eq "$(git ls-files -u | wc -l)" &&
326         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
327
328         test_must_fail git diff --quiet &&
329         test_must_fail git diff --cached --quiet &&
330
331         test_path_is_file dir/file-in-the-way &&
332         test_path_is_file dir~HEAD &&
333         test_cmp expected dir~HEAD
334 '
335
336 test_expect_success 'Same as previous, but merged other way' '
337         git reset --hard &&
338         rm -rf dir~* &&
339         git checkout -q dir-in-way^0 &&
340         test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
341
342         ! grep "error: refusing to lose untracked file at" errors &&
343         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
344         test_i18ngrep "Auto-merging dir" output &&
345         test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
346
347         test 3 -eq "$(git ls-files -u | wc -l)" &&
348         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
349
350         test_must_fail git diff --quiet &&
351         test_must_fail git diff --cached --quiet &&
352
353         test_path_is_file dir/file-in-the-way &&
354         test_path_is_file dir~renamed-file-has-no-conflicts &&
355         test_cmp expected dir~renamed-file-has-no-conflicts
356 '
357
358 test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
359         git reset --hard &&
360         rm -rf dir~* &&
361         git checkout -q renamed-file-has-conflicts^0 &&
362         test_must_fail git merge --strategy=recursive dir-not-in-way &&
363
364         test 3 -eq "$(git ls-files -u | wc -l)" &&
365         test 3 -eq "$(git ls-files -u dir | wc -l)" &&
366
367         test_must_fail git diff --quiet &&
368         test_must_fail git diff --cached --quiet &&
369
370         test_path_is_file dir &&
371         cat >expected <<-\EOF &&
372         1
373         2
374         3
375         4
376         5
377         6
378         7
379         8
380         9
381         10
382         <<<<<<< HEAD:dir
383         12
384         =======
385         11
386         >>>>>>> dir-not-in-way:sub/file
387         EOF
388         test_cmp expected dir
389 '
390
391 test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
392         modify s/dir-not-in-way/dir-in-way/ expected &&
393
394         git reset --hard &&
395         rm -rf dir~* &&
396         git checkout -q renamed-file-has-conflicts^0 &&
397         test_must_fail git merge --strategy=recursive dir-in-way &&
398
399         test 5 -eq "$(git ls-files -u | wc -l)" &&
400         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
401         then
402                 test 3 -eq "$(git ls-files -u dir~HEAD | wc -l)"
403         else
404                 test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
405         fi &&
406         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
407
408         test_must_fail git diff --quiet &&
409         test_must_fail git diff --cached --quiet &&
410
411         test_path_is_file dir/file-in-the-way &&
412         test_path_is_file dir~HEAD &&
413         test_cmp expected dir~HEAD
414 '
415
416 test_expect_success 'Same as previous, but merged other way' '
417         git reset --hard &&
418         rm -rf dir~* &&
419         git checkout -q dir-in-way^0 &&
420         test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
421
422         test 5 -eq "$(git ls-files -u | wc -l)" &&
423         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
424         then
425                 test 3 -eq "$(git ls-files -u dir~renamed-file-has-conflicts | wc -l)"
426         else
427                 test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)"
428         fi &&
429         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
430
431         test_must_fail git diff --quiet &&
432         test_must_fail git diff --cached --quiet &&
433
434         test_path_is_file dir/file-in-the-way &&
435         test_path_is_file dir~renamed-file-has-conflicts &&
436         cat >expected <<-\EOF &&
437         1
438         2
439         3
440         4
441         5
442         6
443         7
444         8
445         9
446         10
447         <<<<<<< HEAD:sub/file
448         11
449         =======
450         12
451         >>>>>>> renamed-file-has-conflicts:dir
452         EOF
453         test_cmp expected dir~renamed-file-has-conflicts
454 '
455
456 test_expect_success 'setup both rename source and destination involved in D/F conflict' '
457         git reset --hard &&
458         git checkout --orphan rename-dest &&
459         git rm -rf . &&
460         git clean -fdqx &&
461
462         mkdir one &&
463         echo stuff >one/file &&
464         git add -A &&
465         git commit -m "Common commit" &&
466
467         git mv one/file destdir &&
468         git commit -m "Renamed to destdir" &&
469
470         git checkout -b source-conflict HEAD~1 &&
471         git rm -rf one &&
472         mkdir destdir &&
473         touch one destdir/foo &&
474         git add -A &&
475         git commit -m "Conflicts in the way"
476 '
477
478 test_expect_success 'both rename source and destination involved in D/F conflict' '
479         git reset --hard &&
480         rm -rf dir~* &&
481         git checkout -q rename-dest^0 &&
482         test_must_fail git merge --strategy=recursive source-conflict &&
483
484         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
485         then
486                 test 2 -eq "$(git ls-files -u | wc -l)"
487         else
488                 test 1 -eq "$(git ls-files -u | wc -l)"
489         fi &&
490
491         test_must_fail git diff --quiet &&
492
493         test_path_is_file destdir/foo &&
494         test_path_is_file one &&
495         test_path_is_file destdir~HEAD &&
496         test "stuff" = "$(cat destdir~HEAD)"
497 '
498
499 test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
500         git reset --hard &&
501         git checkout --orphan rename-two &&
502         git rm -rf . &&
503         git clean -fdqx &&
504
505         mkdir one &&
506         mkdir two &&
507         echo stuff >one/file &&
508         echo other >two/file &&
509         git add -A &&
510         git commit -m "Common commit" &&
511
512         git rm -rf one &&
513         git mv two/file one &&
514         git commit -m "Rename two/file -> one" &&
515
516         git checkout -b rename-one HEAD~1 &&
517         git rm -rf two &&
518         git mv one/file two &&
519         rm -r one &&
520         git commit -m "Rename one/file -> two"
521 '
522
523 if test "$GIT_TEST_MERGE_ALGORITHM" = ort
524 then
525         test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
526                 git checkout -q rename-one^0 &&
527                 mkdir one &&
528                 test_must_fail git merge --strategy=recursive rename-two &&
529
530                 test 4 -eq "$(git ls-files -u | wc -l)" &&
531                 test 2 -eq "$(git ls-files -u one | wc -l)" &&
532                 test 2 -eq "$(git ls-files -u two | wc -l)" &&
533
534                 test_must_fail git diff --quiet &&
535
536                 test 3 -eq $(find . | grep -v .git | wc -l) &&
537
538                 test_path_is_file one &&
539                 test_path_is_file two &&
540                 test "other" = $(cat one) &&
541                 test "stuff" = $(cat two)
542         '
543 else
544         test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
545                 git checkout -q rename-one^0 &&
546                 mkdir one &&
547                 test_must_fail git merge --strategy=recursive rename-two &&
548
549                 test 2 -eq "$(git ls-files -u | wc -l)" &&
550                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
551                 test 1 -eq "$(git ls-files -u two | wc -l)" &&
552
553                 test_must_fail git diff --quiet &&
554
555                 test 4 -eq $(find . | grep -v .git | wc -l) &&
556
557                 test_path_is_dir one &&
558                 test_path_is_file one~rename-two &&
559                 test_path_is_file two &&
560                 test "other" = $(cat one~rename-two) &&
561                 test "stuff" = $(cat two)
562         '
563 fi
564
565 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
566         git reset --hard &&
567         git clean -fdqx &&
568         test_must_fail git merge --strategy=recursive rename-two &&
569
570         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
571         then
572                 test 4 -eq "$(git ls-files -u | wc -l)" &&
573                 test 2 -eq "$(git ls-files -u one | wc -l)" &&
574                 test 2 -eq "$(git ls-files -u two | wc -l)"
575         else
576                 test 2 -eq "$(git ls-files -u | wc -l)" &&
577                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
578                 test 1 -eq "$(git ls-files -u two | wc -l)"
579         fi &&
580
581         test_must_fail git diff --quiet &&
582
583         test 3 -eq $(find . | grep -v .git | wc -l) &&
584
585         test_path_is_file one &&
586         test_path_is_file two &&
587         test "other" = $(cat one) &&
588         test "stuff" = $(cat two)
589 '
590
591 test_expect_success 'setup rename of one file to two, with directories in the way' '
592         git reset --hard &&
593         git checkout --orphan first-rename &&
594         git rm -rf . &&
595         git clean -fdqx &&
596
597         echo stuff >original &&
598         git add -A &&
599         git commit -m "Common commit" &&
600
601         mkdir two &&
602         >two/file &&
603         git add two/file &&
604         git mv original one &&
605         git commit -m "Put two/file in the way, rename to one" &&
606
607         git checkout -b second-rename HEAD~1 &&
608         mkdir one &&
609         >one/file &&
610         git add one/file &&
611         git mv original two &&
612         git commit -m "Put one/file in the way, rename to two"
613 '
614
615 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
616         git checkout -q first-rename^0 &&
617         test_must_fail git merge --strategy=recursive second-rename &&
618
619         if test "$GIT_TEST_MERGE_ALGORITHM" = ort
620         then
621                 test 5 -eq "$(git ls-files -s | wc -l)" &&
622                 test 3 -eq "$(git ls-files -u | wc -l)" &&
623                 test 1 -eq "$(git ls-files -u one~HEAD | wc -l)" &&
624                 test 1 -eq "$(git ls-files -u two~second-rename | wc -l)" &&
625                 test 1 -eq "$(git ls-files -u original | wc -l)" &&
626                 test 0 -eq "$(git ls-files -o | wc -l)"
627         else
628                 test 5 -eq "$(git ls-files -s | wc -l)" &&
629                 test 3 -eq "$(git ls-files -u | wc -l)" &&
630                 test 1 -eq "$(git ls-files -u one | wc -l)" &&
631                 test 1 -eq "$(git ls-files -u two | wc -l)" &&
632                 test 1 -eq "$(git ls-files -u original | wc -l)" &&
633                 test 2 -eq "$(git ls-files -o | wc -l)"
634         fi &&
635
636         test_path_is_file one/file &&
637         test_path_is_file two/file &&
638         test_path_is_file one~HEAD &&
639         test_path_is_file two~second-rename &&
640         test_path_is_missing original
641 '
642
643 test_expect_success 'setup rename one file to two; directories moving out of the way' '
644         git reset --hard &&
645         git checkout --orphan first-rename-redo &&
646         git rm -rf . &&
647         git clean -fdqx &&
648
649         echo stuff >original &&
650         mkdir one two &&
651         touch one/file two/file &&
652         git add -A &&
653         git commit -m "Common commit" &&
654
655         git rm -rf one &&
656         git mv original one &&
657         git commit -m "Rename to one" &&
658
659         git checkout -b second-rename-redo HEAD~1 &&
660         git rm -rf two &&
661         git mv original two &&
662         git commit -m "Rename to two"
663 '
664
665 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
666         git checkout -q first-rename-redo^0 &&
667         test_must_fail git merge --strategy=recursive second-rename-redo &&
668
669         test 3 -eq "$(git ls-files -u | wc -l)" &&
670         test 1 -eq "$(git ls-files -u one | wc -l)" &&
671         test 1 -eq "$(git ls-files -u two | wc -l)" &&
672         test 1 -eq "$(git ls-files -u original | wc -l)" &&
673         test 0 -eq "$(git ls-files -o | wc -l)" &&
674
675         test_path_is_file one &&
676         test_path_is_file two &&
677         test_path_is_missing original
678 '
679
680 test_expect_success 'setup avoid unnecessary update, normal rename' '
681         git reset --hard &&
682         git checkout --orphan avoid-unnecessary-update-1 &&
683         git rm -rf . &&
684         git clean -fdqx &&
685
686         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
687         git add -A &&
688         git commit -m "Common commit" &&
689
690         git mv original rename &&
691         echo 11 >>rename &&
692         git add -u &&
693         git commit -m "Renamed and modified" &&
694
695         git checkout -b merge-branch-1 HEAD~1 &&
696         echo "random content" >random-file &&
697         git add -A &&
698         git commit -m "Random, unrelated changes"
699 '
700
701 test_expect_success 'avoid unnecessary update, normal rename' '
702         git checkout -q avoid-unnecessary-update-1^0 &&
703         test-tool chmtime --get -3600 rename >expect &&
704         git merge merge-branch-1 &&
705         test-tool chmtime --get rename >actual &&
706         test_cmp expect actual # "rename" should have stayed intact
707 '
708
709 test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
710         git reset --hard &&
711         git checkout --orphan avoid-unnecessary-update-2 &&
712         git rm -rf . &&
713         git clean -fdqx &&
714
715         mkdir df &&
716         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
717         git add -A &&
718         git commit -m "Common commit" &&
719
720         git mv df/file temp &&
721         rm -rf df &&
722         git mv temp df &&
723         echo 11 >>df &&
724         git add -u &&
725         git commit -m "Renamed and modified" &&
726
727         git checkout -b merge-branch-2 HEAD~1 &&
728         >unrelated-change &&
729         git add unrelated-change &&
730         git commit -m "Only unrelated changes"
731 '
732
733 test_expect_success 'avoid unnecessary update, with D/F conflict' '
734         git checkout -q avoid-unnecessary-update-2^0 &&
735         test-tool chmtime --get -3600 df >expect &&
736         git merge merge-branch-2 &&
737         test-tool chmtime --get df >actual &&
738         test_cmp expect actual # "df" should have stayed intact
739 '
740
741 test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
742         git rm -rf . &&
743         git clean -fdqx &&
744         rm -rf .git &&
745         git init &&
746
747         >irrelevant &&
748         mkdir df &&
749         >df/file &&
750         git add -A &&
751         git commit -mA &&
752
753         git checkout -b side &&
754         git rm -rf df &&
755         git commit -mB &&
756
757         git checkout master &&
758         git rm -rf df &&
759         echo bla >df &&
760         git add -A &&
761         git commit -m "Add a newfile"
762 '
763
764 test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
765         git checkout -q master^0 &&
766         test-tool chmtime --get -3600 df >expect &&
767         git merge side &&
768         test-tool chmtime --get df >actual &&
769         test_cmp expect actual # "df" should have stayed intact
770 '
771
772 test_expect_success 'setup avoid unnecessary update, modify/delete' '
773         git rm -rf . &&
774         git clean -fdqx &&
775         rm -rf .git &&
776         git init &&
777
778         >irrelevant &&
779         >file &&
780         git add -A &&
781         git commit -mA &&
782
783         git checkout -b side &&
784         git rm -f file &&
785         git commit -m "Delete file" &&
786
787         git checkout master &&
788         echo bla >file &&
789         git add -A &&
790         git commit -m "Modify file"
791 '
792
793 test_expect_success 'avoid unnecessary update, modify/delete' '
794         git checkout -q master^0 &&
795         test-tool chmtime --get -3600 file >expect &&
796         test_must_fail git merge side &&
797         test-tool chmtime --get file >actual &&
798         test_cmp expect actual # "file" should have stayed intact
799 '
800
801 test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
802         git rm -rf . &&
803         git clean -fdqx &&
804         rm -rf .git &&
805         git init &&
806
807         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
808         git add -A &&
809         git commit -mA &&
810
811         git checkout -b side &&
812         cp file newfile &&
813         git add -A &&
814         git commit -m "Add file copy" &&
815
816         git checkout master &&
817         git mv file newfile &&
818         git commit -m "Rename file"
819 '
820
821 test_expect_success 'avoid unnecessary update, rename/add-dest' '
822         git checkout -q master^0 &&
823         test-tool chmtime --get -3600 newfile >expect &&
824         git merge side &&
825         test-tool chmtime --get newfile >actual &&
826         test_cmp expect actual # "file" should have stayed intact
827 '
828
829 test_expect_success 'setup merge of rename + small change' '
830         git reset --hard &&
831         git checkout --orphan rename-plus-small-change &&
832         git rm -rf . &&
833         git clean -fdqx &&
834
835         echo ORIGINAL >file &&
836         git add file &&
837
838         test_tick &&
839         git commit -m Initial &&
840         git checkout -b rename_branch &&
841         git mv file renamed_file &&
842         git commit -m Rename &&
843         git checkout rename-plus-small-change &&
844         echo NEW-VERSION >file &&
845         git commit -a -m Reformat
846 '
847
848 test_expect_success 'merge rename + small change' '
849         git merge rename_branch &&
850
851         test 1 -eq $(git ls-files -s | wc -l) &&
852         test 0 -eq $(git ls-files -o | wc -l) &&
853         test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
854 '
855
856 test_expect_success 'setup for use of extended merge markers' '
857         git rm -rf . &&
858         git clean -fdqx &&
859         rm -rf .git &&
860         git init &&
861
862         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
863         git add original_file &&
864         git commit -mA &&
865
866         git checkout -b rename &&
867         echo 9 >>original_file &&
868         git add original_file &&
869         git mv original_file renamed_file &&
870         git commit -mB &&
871
872         git checkout master &&
873         echo 8.5 >>original_file &&
874         git add original_file &&
875         git commit -mC
876 '
877
878 test_expect_success 'merge master into rename has correct extended markers' '
879         git checkout rename^0 &&
880         test_must_fail git merge -s recursive master^0 &&
881
882         cat >expected <<-\EOF &&
883         1
884         2
885         3
886         4
887         5
888         6
889         7
890         8
891         <<<<<<< HEAD:renamed_file
892         9
893         =======
894         8.5
895         >>>>>>> master^0:original_file
896         EOF
897         test_cmp expected renamed_file
898 '
899
900 test_expect_success 'merge rename into master has correct extended markers' '
901         git reset --hard &&
902         git checkout master^0 &&
903         test_must_fail git merge -s recursive rename^0 &&
904
905         cat >expected <<-\EOF &&
906         1
907         2
908         3
909         4
910         5
911         6
912         7
913         8
914         <<<<<<< HEAD:original_file
915         8.5
916         =======
917         9
918         >>>>>>> rename^0:renamed_file
919         EOF
920         test_cmp expected renamed_file
921 '
922
923 test_expect_success 'setup spurious "refusing to lose untracked" message' '
924         git rm -rf . &&
925         git clean -fdqx &&
926         rm -rf .git &&
927         git init &&
928
929         > irrelevant_file &&
930         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
931         git add irrelevant_file original_file &&
932         git commit -mA &&
933
934         git checkout -b rename &&
935         git mv original_file renamed_file &&
936         git commit -mB &&
937
938         git checkout master &&
939         git rm original_file &&
940         git commit -mC
941 '
942
943 test_expect_success 'no spurious "refusing to lose untracked" message' '
944         git checkout master^0 &&
945         test_must_fail git merge rename^0 2>errors.txt &&
946         ! grep "refusing to lose untracked file" errors.txt
947 '
948
949 test_expect_success 'do not follow renames for empty files' '
950         git checkout -f -b empty-base &&
951         >empty1 &&
952         git add empty1 &&
953         git commit -m base &&
954         echo content >empty1 &&
955         git add empty1 &&
956         git commit -m fill &&
957         git checkout -b empty-topic HEAD^ &&
958         git mv empty1 empty2 &&
959         git commit -m rename &&
960         test_must_fail git merge empty-base &&
961         test_must_be_empty empty2
962 '
963
964 test_done