git stash: avoid data loss when "git stash save" kills a directory
[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         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         GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" &&
246         git reset --hard HEAD^ &&
247         git checkout change &&
248         GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B"
249 '
250
251 test_expect_success 'setup for rename + d/f conflicts' '
252         git reset --hard &&
253         git checkout --orphan dir-in-way &&
254         git rm -rf . &&
255         git clean -fdqx &&
256
257         mkdir sub &&
258         mkdir dir &&
259         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
260         echo foo >dir/file-in-the-way &&
261         git add -A &&
262         git commit -m "Common commmit" &&
263
264         echo 11 >>sub/file &&
265         echo more >>dir/file-in-the-way &&
266         git add -u &&
267         git commit -m "Commit to merge, with dir in the way" &&
268
269         git checkout -b dir-not-in-way &&
270         git reset --soft HEAD^ &&
271         git rm -rf dir &&
272         git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
273
274         git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
275         git rm -rf dir &&
276         git rm sub/file &&
277         printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
278         git add dir &&
279         git commit -m "Independent change" &&
280
281         git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
282         git rm -rf dir &&
283         git mv sub/file dir &&
284         echo 12 >>dir &&
285         git add dir &&
286         git commit -m "Conflicting change"
287 '
288
289 printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
290
291 test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
292         git reset --hard &&
293         git checkout -q renamed-file-has-no-conflicts^0 &&
294         git merge --strategy=recursive dir-not-in-way &&
295         git diff --quiet &&
296         test -f dir &&
297         test_cmp expected dir
298 '
299
300 test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
301         git reset --hard &&
302         rm -rf dir~* &&
303         git checkout -q renamed-file-has-no-conflicts^0 &&
304         test_must_fail git merge --strategy=recursive dir-in-way >output &&
305
306         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
307         test_i18ngrep "Auto-merging dir" output &&
308         test_i18ngrep "Adding as dir~HEAD instead" output &&
309
310         test 3 -eq "$(git ls-files -u | wc -l)" &&
311         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
312
313         test_must_fail git diff --quiet &&
314         test_must_fail git diff --cached --quiet &&
315
316         test -f dir/file-in-the-way &&
317         test -f dir~HEAD &&
318         test_cmp expected dir~HEAD
319 '
320
321 test_expect_success 'Same as previous, but merged other way' '
322         git reset --hard &&
323         rm -rf dir~* &&
324         git checkout -q dir-in-way^0 &&
325         test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
326
327         ! grep "error: refusing to lose untracked file at" errors &&
328         test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
329         test_i18ngrep "Auto-merging dir" output &&
330         test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
331
332         test 3 -eq "$(git ls-files -u | wc -l)" &&
333         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
334
335         test_must_fail git diff --quiet &&
336         test_must_fail git diff --cached --quiet &&
337
338         test -f dir/file-in-the-way &&
339         test -f dir~renamed-file-has-no-conflicts &&
340         test_cmp expected dir~renamed-file-has-no-conflicts
341 '
342
343 cat >expected <<\EOF &&
344 1
345 2
346 3
347 4
348 5
349 6
350 7
351 8
352 9
353 10
354 <<<<<<< HEAD:dir
355 12
356 =======
357 11
358 >>>>>>> dir-not-in-way:sub/file
359 EOF
360
361 test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
362         git reset --hard &&
363         rm -rf dir~* &&
364         git checkout -q renamed-file-has-conflicts^0 &&
365         test_must_fail git merge --strategy=recursive dir-not-in-way &&
366
367         test 3 -eq "$(git ls-files -u | wc -l)" &&
368         test 3 -eq "$(git ls-files -u dir | wc -l)" &&
369
370         test_must_fail git diff --quiet &&
371         test_must_fail git diff --cached --quiet &&
372
373         test -f dir &&
374         test_cmp expected dir
375 '
376
377 test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
378         modify s/dir-not-in-way/dir-in-way/ expected &&
379
380         git reset --hard &&
381         rm -rf dir~* &&
382         git checkout -q renamed-file-has-conflicts^0 &&
383         test_must_fail git merge --strategy=recursive dir-in-way &&
384
385         test 5 -eq "$(git ls-files -u | wc -l)" &&
386         test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
387         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
388
389         test_must_fail git diff --quiet &&
390         test_must_fail git diff --cached --quiet &&
391
392         test -f dir/file-in-the-way &&
393         test -f dir~HEAD &&
394         test_cmp expected dir~HEAD
395 '
396
397 cat >expected <<\EOF &&
398 1
399 2
400 3
401 4
402 5
403 6
404 7
405 8
406 9
407 10
408 <<<<<<< HEAD:sub/file
409 11
410 =======
411 12
412 >>>>>>> renamed-file-has-conflicts:dir
413 EOF
414
415 test_expect_success 'Same as previous, but merged other way' '
416         git reset --hard &&
417         rm -rf dir~* &&
418         git checkout -q dir-in-way^0 &&
419         test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
420
421         test 5 -eq "$(git ls-files -u | wc -l)" &&
422         test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
423         test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
424
425         test_must_fail git diff --quiet &&
426         test_must_fail git diff --cached --quiet &&
427
428         test -f dir/file-in-the-way &&
429         test -f dir~renamed-file-has-conflicts &&
430         test_cmp expected dir~renamed-file-has-conflicts
431 '
432
433 test_expect_success 'setup both rename source and destination involved in D/F conflict' '
434         git reset --hard &&
435         git checkout --orphan rename-dest &&
436         git rm -rf . &&
437         git clean -fdqx &&
438
439         mkdir one &&
440         echo stuff >one/file &&
441         git add -A &&
442         git commit -m "Common commmit" &&
443
444         git mv one/file destdir &&
445         git commit -m "Renamed to destdir" &&
446
447         git checkout -b source-conflict HEAD~1 &&
448         git rm -rf one &&
449         mkdir destdir &&
450         touch one destdir/foo &&
451         git add -A &&
452         git commit -m "Conflicts in the way"
453 '
454
455 test_expect_success 'both rename source and destination involved in D/F conflict' '
456         git reset --hard &&
457         rm -rf dir~* &&
458         git checkout -q rename-dest^0 &&
459         test_must_fail git merge --strategy=recursive source-conflict &&
460
461         test 1 -eq "$(git ls-files -u | wc -l)" &&
462
463         test_must_fail git diff --quiet &&
464
465         test -f destdir/foo &&
466         test -f one &&
467         test -f destdir~HEAD &&
468         test "stuff" = "$(cat destdir~HEAD)"
469 '
470
471 test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
472         git reset --hard &&
473         git checkout --orphan rename-two &&
474         git rm -rf . &&
475         git clean -fdqx &&
476
477         mkdir one &&
478         mkdir two &&
479         echo stuff >one/file &&
480         echo other >two/file &&
481         git add -A &&
482         git commit -m "Common commmit" &&
483
484         git rm -rf one &&
485         git mv two/file one &&
486         git commit -m "Rename two/file -> one" &&
487
488         git checkout -b rename-one HEAD~1 &&
489         git rm -rf two &&
490         git mv one/file two &&
491         rm -r one &&
492         git commit -m "Rename one/file -> two"
493 '
494
495 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
496         git checkout -q rename-one^0 &&
497         mkdir one &&
498         test_must_fail git merge --strategy=recursive rename-two &&
499
500         test 2 -eq "$(git ls-files -u | wc -l)" &&
501         test 1 -eq "$(git ls-files -u one | wc -l)" &&
502         test 1 -eq "$(git ls-files -u two | wc -l)" &&
503
504         test_must_fail git diff --quiet &&
505
506         test 4 -eq $(find . | grep -v .git | wc -l) &&
507
508         test -d one &&
509         test -f one~rename-two &&
510         test -f two &&
511         test "other" = $(cat one~rename-two) &&
512         test "stuff" = $(cat two)
513 '
514
515 test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
516         git reset --hard &&
517         git clean -fdqx &&
518         test_must_fail git merge --strategy=recursive rename-two &&
519
520         test 2 -eq "$(git ls-files -u | wc -l)" &&
521         test 1 -eq "$(git ls-files -u one | wc -l)" &&
522         test 1 -eq "$(git ls-files -u two | wc -l)" &&
523
524         test_must_fail git diff --quiet &&
525
526         test 3 -eq $(find . | grep -v .git | wc -l) &&
527
528         test -f one &&
529         test -f two &&
530         test "other" = $(cat one) &&
531         test "stuff" = $(cat two)
532 '
533
534 test_expect_success 'setup rename of one file to two, with directories in the way' '
535         git reset --hard &&
536         git checkout --orphan first-rename &&
537         git rm -rf . &&
538         git clean -fdqx &&
539
540         echo stuff >original &&
541         git add -A &&
542         git commit -m "Common commmit" &&
543
544         mkdir two &&
545         >two/file &&
546         git add two/file &&
547         git mv original one &&
548         git commit -m "Put two/file in the way, rename to one" &&
549
550         git checkout -b second-rename HEAD~1 &&
551         mkdir one &&
552         >one/file &&
553         git add one/file &&
554         git mv original two &&
555         git commit -m "Put one/file in the way, rename to two"
556 '
557
558 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
559         git checkout -q first-rename^0 &&
560         test_must_fail git merge --strategy=recursive second-rename &&
561
562         test 5 -eq "$(git ls-files -s | wc -l)" &&
563         test 3 -eq "$(git ls-files -u | wc -l)" &&
564         test 1 -eq "$(git ls-files -u one | wc -l)" &&
565         test 1 -eq "$(git ls-files -u two | wc -l)" &&
566         test 1 -eq "$(git ls-files -u original | wc -l)" &&
567         test 2 -eq "$(git ls-files -o | wc -l)" &&
568
569         test -f one/file &&
570         test -f two/file &&
571         test -f one~HEAD &&
572         test -f two~second-rename &&
573         ! test -f original
574 '
575
576 test_expect_success 'setup rename one file to two; directories moving out of the way' '
577         git reset --hard &&
578         git checkout --orphan first-rename-redo &&
579         git rm -rf . &&
580         git clean -fdqx &&
581
582         echo stuff >original &&
583         mkdir one two &&
584         touch one/file two/file &&
585         git add -A &&
586         git commit -m "Common commmit" &&
587
588         git rm -rf one &&
589         git mv original one &&
590         git commit -m "Rename to one" &&
591
592         git checkout -b second-rename-redo HEAD~1 &&
593         git rm -rf two &&
594         git mv original two &&
595         git commit -m "Rename to two"
596 '
597
598 test_expect_success 'check handling of differently renamed file with D/F conflicts' '
599         git checkout -q first-rename-redo^0 &&
600         test_must_fail git merge --strategy=recursive second-rename-redo &&
601
602         test 3 -eq "$(git ls-files -u | wc -l)" &&
603         test 1 -eq "$(git ls-files -u one | wc -l)" &&
604         test 1 -eq "$(git ls-files -u two | wc -l)" &&
605         test 1 -eq "$(git ls-files -u original | wc -l)" &&
606         test 0 -eq "$(git ls-files -o | wc -l)" &&
607
608         test -f one &&
609         test -f two &&
610         ! test -f original
611 '
612
613 test_expect_success 'setup avoid unnecessary update, normal rename' '
614         git reset --hard &&
615         git checkout --orphan avoid-unnecessary-update-1 &&
616         git rm -rf . &&
617         git clean -fdqx &&
618
619         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
620         git add -A &&
621         git commit -m "Common commmit" &&
622
623         git mv original rename &&
624         echo 11 >>rename &&
625         git add -u &&
626         git commit -m "Renamed and modified" &&
627
628         git checkout -b merge-branch-1 HEAD~1 &&
629         echo "random content" >random-file &&
630         git add -A &&
631         git commit -m "Random, unrelated changes"
632 '
633
634 test_expect_success 'avoid unnecessary update, normal rename' '
635         git checkout -q avoid-unnecessary-update-1^0 &&
636         test-chmtime =1000000000 rename &&
637         test-chmtime -v +0 rename >expect &&
638         git merge merge-branch-1 &&
639         test-chmtime -v +0 rename >actual &&
640         test_cmp expect actual # "rename" should have stayed intact
641 '
642
643 test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
644         git reset --hard &&
645         git checkout --orphan avoid-unnecessary-update-2 &&
646         git rm -rf . &&
647         git clean -fdqx &&
648
649         mkdir df &&
650         printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
651         git add -A &&
652         git commit -m "Common commmit" &&
653
654         git mv df/file temp &&
655         rm -rf df &&
656         git mv temp df &&
657         echo 11 >>df &&
658         git add -u &&
659         git commit -m "Renamed and modified" &&
660
661         git checkout -b merge-branch-2 HEAD~1 &&
662         >unrelated-change &&
663         git add unrelated-change &&
664         git commit -m "Only unrelated changes"
665 '
666
667 test_expect_success 'avoid unnecessary update, with D/F conflict' '
668         git checkout -q avoid-unnecessary-update-2^0 &&
669         test-chmtime =1000000000 df &&
670         test-chmtime -v +0 df >expect &&
671         git merge merge-branch-2 &&
672         test-chmtime -v +0 df >actual &&
673         test_cmp expect actual # "df" should have stayed intact
674 '
675
676 test_expect_success 'setup avoid unnecessary update, dir->(file,nothing)' '
677         git rm -rf . &&
678         git clean -fdqx &&
679         rm -rf .git &&
680         git init &&
681
682         >irrelevant &&
683         mkdir df &&
684         >df/file &&
685         git add -A &&
686         git commit -mA &&
687
688         git checkout -b side
689         git rm -rf df &&
690         git commit -mB &&
691
692         git checkout master &&
693         git rm -rf df &&
694         echo bla >df &&
695         git add -A &&
696         git commit -m "Add a newfile"
697 '
698
699 test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
700         git checkout -q master^0 &&
701         test-chmtime =1000000000 df &&
702         test-chmtime -v +0 df >expect &&
703         git merge side &&
704         test-chmtime -v +0 df >actual &&
705         test_cmp expect actual # "df" should have stayed intact
706 '
707
708 test_expect_success 'setup avoid unnecessary update, modify/delete' '
709         git rm -rf . &&
710         git clean -fdqx &&
711         rm -rf .git &&
712         git init &&
713
714         >irrelevant &&
715         >file &&
716         git add -A &&
717         git commit -mA &&
718
719         git checkout -b side
720         git rm -f file &&
721         git commit -m "Delete file" &&
722
723         git checkout master &&
724         echo bla >file &&
725         git add -A &&
726         git commit -m "Modify file"
727 '
728
729 test_expect_success 'avoid unnecessary update, modify/delete' '
730         git checkout -q master^0 &&
731         test-chmtime =1000000000 file &&
732         test-chmtime -v +0 file >expect &&
733         test_must_fail git merge side &&
734         test-chmtime -v +0 file >actual &&
735         test_cmp expect actual # "file" should have stayed intact
736 '
737
738 test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
739         git rm -rf . &&
740         git clean -fdqx &&
741         rm -rf .git &&
742         git init &&
743
744         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
745         git add -A &&
746         git commit -mA &&
747
748         git checkout -b side
749         cp file newfile &&
750         git add -A &&
751         git commit -m "Add file copy" &&
752
753         git checkout master &&
754         git mv file newfile &&
755         git commit -m "Rename file"
756 '
757
758 test_expect_success 'avoid unnecessary update, rename/add-dest' '
759         git checkout -q master^0 &&
760         test-chmtime =1000000000 newfile &&
761         test-chmtime -v +0 newfile >expect &&
762         git merge side &&
763         test-chmtime -v +0 newfile >actual &&
764         test_cmp expect actual # "file" should have stayed intact
765 '
766
767 test_expect_success 'setup merge of rename + small change' '
768         git reset --hard &&
769         git checkout --orphan rename-plus-small-change &&
770         git rm -rf . &&
771         git clean -fdqx &&
772
773         echo ORIGINAL >file &&
774         git add file &&
775
776         test_tick &&
777         git commit -m Initial &&
778         git checkout -b rename_branch &&
779         git mv file renamed_file &&
780         git commit -m Rename &&
781         git checkout rename-plus-small-change &&
782         echo NEW-VERSION >file &&
783         git commit -a -m Reformat
784 '
785
786 test_expect_success 'merge rename + small change' '
787         git merge rename_branch &&
788
789         test 1 -eq $(git ls-files -s | wc -l) &&
790         test 0 -eq $(git ls-files -o | wc -l) &&
791         test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
792 '
793
794 test_expect_success 'setup for use of extended merge markers' '
795         git rm -rf . &&
796         git clean -fdqx &&
797         rm -rf .git &&
798         git init &&
799
800         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
801         git add original_file &&
802         git commit -mA &&
803
804         git checkout -b rename &&
805         echo 9 >>original_file &&
806         git add original_file &&
807         git mv original_file renamed_file &&
808         git commit -mB &&
809
810         git checkout master &&
811         echo 8.5 >>original_file &&
812         git add original_file &&
813         git commit -mC
814 '
815
816 cat >expected <<\EOF &&
817 1
818 2
819 3
820 4
821 5
822 6
823 7
824 8
825 <<<<<<< HEAD:renamed_file
826 9
827 =======
828 8.5
829 >>>>>>> master^0:original_file
830 EOF
831
832 test_expect_success 'merge master into rename has correct extended markers' '
833         git checkout rename^0 &&
834         test_must_fail git merge -s recursive master^0 &&
835         test_cmp expected renamed_file
836 '
837
838 cat >expected <<\EOF &&
839 1
840 2
841 3
842 4
843 5
844 6
845 7
846 8
847 <<<<<<< HEAD:original_file
848 8.5
849 =======
850 9
851 >>>>>>> rename^0:renamed_file
852 EOF
853
854 test_expect_success 'merge rename into master has correct extended markers' '
855         git reset --hard &&
856         git checkout master^0 &&
857         test_must_fail git merge -s recursive rename^0 &&
858         test_cmp expected renamed_file
859 '
860
861 test_expect_success 'setup spurious "refusing to lose untracked" message' '
862         git rm -rf . &&
863         git clean -fdqx &&
864         rm -rf .git &&
865         git init &&
866
867         > irrelevant_file &&
868         printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
869         git add irrelevant_file original_file &&
870         git commit -mA &&
871
872         git checkout -b rename &&
873         git mv original_file renamed_file &&
874         git commit -mB &&
875
876         git checkout master &&
877         git rm original_file &&
878         git commit -mC
879 '
880
881 test_expect_success 'no spurious "refusing to lose untracked" message' '
882         git checkout master^0 &&
883         test_must_fail git merge rename^0 2>errors.txt &&
884         ! grep "refusing to lose untracked file" errors.txt
885 '
886
887 test_expect_success 'do not follow renames for empty files' '
888         git checkout -f -b empty-base &&
889         >empty1 &&
890         git add empty1 &&
891         git commit -m base &&
892         echo content >empty1 &&
893         git add empty1 &&
894         git commit -m fill &&
895         git checkout -b empty-topic HEAD^ &&
896         git mv empty1 empty2 &&
897         git commit -m rename &&
898         test_must_fail git merge empty-base &&
899         >expect &&
900         test_cmp expect empty2
901 '
902
903 test_done