1#!/bin/sh
2
3test_description='Merge-recursive merging renames'
4. ./test-lib.sh
5
6modify () {
7	sed -e "$1" <"$2" >"$2.x" &&
8	mv "$2.x" "$2"
9}
10
11test_expect_success setup \
12'
13cat >A <<\EOF &&
14a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
15b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
16c cccccccccccccccccccccccccccccccccccccccccccccccc
17d dddddddddddddddddddddddddddddddddddddddddddddddd
18e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
19f ffffffffffffffffffffffffffffffffffffffffffffffff
20g gggggggggggggggggggggggggggggggggggggggggggggggg
21h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
22i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
23j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
24k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
25l llllllllllllllllllllllllllllllllllllllllllllllll
26m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
27n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
28o oooooooooooooooooooooooooooooooooooooooooooooooo
29EOF
30
31cat >M <<\EOF &&
32A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
33B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
34C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
35D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
36E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
37F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
38G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
39H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
40I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
41J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
42K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
43L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
44M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
45N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
46O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
47EOF
48
49git add A M &&
50git commit -m "initial has A and M" &&
51git branch white &&
52git branch red &&
53git branch blue &&
54git branch yellow &&
55git branch change &&
56git branch change+rename &&
57
58sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
59mv A+ A &&
60git commit -a -m "master updates A" &&
61
62git checkout yellow &&
63rm -f M &&
64git commit -a -m "yellow removes M" &&
65
66git checkout white &&
67sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
68sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
69rm -f A M &&
70git update-index --add --remove A B M N &&
71git commit -m "white renames A->B, M->N" &&
72
73git checkout red &&
74sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
75sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
76rm -f A M &&
77git update-index --add --remove A B M N &&
78git commit -m "red renames A->B, M->N" &&
79
80git checkout blue &&
81sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
82sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
83rm -f A M &&
84git update-index --add --remove A C M N &&
85git commit -m "blue renames A->C, M->N" &&
86
87git checkout change &&
88sed -e "/^g /s/.*/g : changed line/" <A >A+ &&
89mv A+ A &&
90git commit -q -a -m "changed" &&
91
92git checkout change+rename &&
93sed -e "/^g /s/.*/g : changed line/" <A >B &&
94rm A &&
95git update-index --add B &&
96git commit -q -a -m "changed and renamed" &&
97
98git checkout master'
99
100test_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
116test_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
133test_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
149test_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
169test_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
177test_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
187test_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
198test_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
211test_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
225test_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
241test_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 >out &&
246	test_i18ngrep "^Skipped B" out &&
247	git reset --hard HEAD^ &&
248	git checkout change &&
249	GIT_MERGE_VERBOSITY=3 git merge change+rename >out &&
250	test_i18ngrep ! "^Skipped B" out
251'
252
253test_expect_success 'setup for rename + d/f conflicts' '
254	git reset --hard &&
255	git checkout --orphan dir-in-way &&
256	git rm -rf . &&
257	git clean -fdqx &&
258
259	mkdir sub &&
260	mkdir dir &&
261	printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
262	echo foo >dir/file-in-the-way &&
263	git add -A &&
264	git commit -m "Common commit" &&
265
266	echo 11 >>sub/file &&
267	echo more >>dir/file-in-the-way &&
268	git add -u &&
269	git commit -m "Commit to merge, with dir in the way" &&
270
271	git checkout -b dir-not-in-way &&
272	git reset --soft HEAD^ &&
273	git rm -rf dir &&
274	git commit -m "Commit to merge, with dir removed" -- dir sub/file &&
275
276	git checkout -b renamed-file-has-no-conflicts dir-in-way~1 &&
277	git rm -rf dir &&
278	git rm sub/file &&
279	printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n" >dir &&
280	git add dir &&
281	git commit -m "Independent change" &&
282
283	git checkout -b renamed-file-has-conflicts dir-in-way~1 &&
284	git rm -rf dir &&
285	git mv sub/file dir &&
286	echo 12 >>dir &&
287	git add dir &&
288	git commit -m "Conflicting change"
289'
290
291printf "1\n2\n3\n4\n5555\n6\n7\n8\n9\n10\n11\n" >expected
292
293test_expect_success 'Rename+D/F conflict; renamed file merges + dir not in way' '
294	git reset --hard &&
295	git checkout -q renamed-file-has-no-conflicts^0 &&
296	git merge --strategy=recursive dir-not-in-way &&
297	git diff --quiet &&
298	test -f dir &&
299	test_cmp expected dir
300'
301
302test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' '
303	git reset --hard &&
304	rm -rf dir~* &&
305	git checkout -q renamed-file-has-no-conflicts^0 &&
306	test_must_fail git merge --strategy=recursive dir-in-way >output &&
307
308	test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
309	test_i18ngrep "Auto-merging dir" output &&
310	test_i18ngrep "Adding as dir~HEAD instead" output &&
311
312	test 3 -eq "$(git ls-files -u | wc -l)" &&
313	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
314
315	test_must_fail git diff --quiet &&
316	test_must_fail git diff --cached --quiet &&
317
318	test -f dir/file-in-the-way &&
319	test -f dir~HEAD &&
320	test_cmp expected dir~HEAD
321'
322
323test_expect_success 'Same as previous, but merged other way' '
324	git reset --hard &&
325	rm -rf dir~* &&
326	git checkout -q dir-in-way^0 &&
327	test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors &&
328
329	! grep "error: refusing to lose untracked file at" errors &&
330	test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output &&
331	test_i18ngrep "Auto-merging dir" output &&
332	test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output &&
333
334	test 3 -eq "$(git ls-files -u | wc -l)" &&
335	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
336
337	test_must_fail git diff --quiet &&
338	test_must_fail git diff --cached --quiet &&
339
340	test -f dir/file-in-the-way &&
341	test -f dir~renamed-file-has-no-conflicts &&
342	test_cmp expected dir~renamed-file-has-no-conflicts
343'
344
345cat >expected <<\EOF &&
3461
3472
3483
3494
3505
3516
3527
3538
3549
35510
356<<<<<<< HEAD:dir
35712
358=======
35911
360>>>>>>> dir-not-in-way:sub/file
361EOF
362
363test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
364	git reset --hard &&
365	rm -rf dir~* &&
366	git checkout -q renamed-file-has-conflicts^0 &&
367	test_must_fail git merge --strategy=recursive dir-not-in-way &&
368
369	test 3 -eq "$(git ls-files -u | wc -l)" &&
370	test 3 -eq "$(git ls-files -u dir | wc -l)" &&
371
372	test_must_fail git diff --quiet &&
373	test_must_fail git diff --cached --quiet &&
374
375	test -f dir &&
376	test_cmp expected dir
377'
378
379test_expect_success 'Rename+D/F conflict; renamed file cannot merge and dir in the way' '
380	modify s/dir-not-in-way/dir-in-way/ expected &&
381
382	git reset --hard &&
383	rm -rf dir~* &&
384	git checkout -q renamed-file-has-conflicts^0 &&
385	test_must_fail git merge --strategy=recursive dir-in-way &&
386
387	test 5 -eq "$(git ls-files -u | wc -l)" &&
388	test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
389	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
390
391	test_must_fail git diff --quiet &&
392	test_must_fail git diff --cached --quiet &&
393
394	test -f dir/file-in-the-way &&
395	test -f dir~HEAD &&
396	test_cmp expected dir~HEAD
397'
398
399cat >expected <<\EOF &&
4001
4012
4023
4034
4045
4056
4067
4078
4089
40910
410<<<<<<< HEAD:sub/file
41111
412=======
41312
414>>>>>>> renamed-file-has-conflicts:dir
415EOF
416
417test_expect_success 'Same as previous, but merged other way' '
418	git reset --hard &&
419	rm -rf dir~* &&
420	git checkout -q dir-in-way^0 &&
421	test_must_fail git merge --strategy=recursive renamed-file-has-conflicts &&
422
423	test 5 -eq "$(git ls-files -u | wc -l)" &&
424	test 3 -eq "$(git ls-files -u dir | grep -v file-in-the-way | wc -l)" &&
425	test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" &&
426
427	test_must_fail git diff --quiet &&
428	test_must_fail git diff --cached --quiet &&
429
430	test -f dir/file-in-the-way &&
431	test -f dir~renamed-file-has-conflicts &&
432	test_cmp expected dir~renamed-file-has-conflicts
433'
434
435test_expect_success 'setup both rename source and destination involved in D/F conflict' '
436	git reset --hard &&
437	git checkout --orphan rename-dest &&
438	git rm -rf . &&
439	git clean -fdqx &&
440
441	mkdir one &&
442	echo stuff >one/file &&
443	git add -A &&
444	git commit -m "Common commit" &&
445
446	git mv one/file destdir &&
447	git commit -m "Renamed to destdir" &&
448
449	git checkout -b source-conflict HEAD~1 &&
450	git rm -rf one &&
451	mkdir destdir &&
452	touch one destdir/foo &&
453	git add -A &&
454	git commit -m "Conflicts in the way"
455'
456
457test_expect_success 'both rename source and destination involved in D/F conflict' '
458	git reset --hard &&
459	rm -rf dir~* &&
460	git checkout -q rename-dest^0 &&
461	test_must_fail git merge --strategy=recursive source-conflict &&
462
463	test 1 -eq "$(git ls-files -u | wc -l)" &&
464
465	test_must_fail git diff --quiet &&
466
467	test -f destdir/foo &&
468	test -f one &&
469	test -f destdir~HEAD &&
470	test "stuff" = "$(cat destdir~HEAD)"
471'
472
473test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
474	git reset --hard &&
475	git checkout --orphan rename-two &&
476	git rm -rf . &&
477	git clean -fdqx &&
478
479	mkdir one &&
480	mkdir two &&
481	echo stuff >one/file &&
482	echo other >two/file &&
483	git add -A &&
484	git commit -m "Common commit" &&
485
486	git rm -rf one &&
487	git mv two/file one &&
488	git commit -m "Rename two/file -> one" &&
489
490	git checkout -b rename-one HEAD~1 &&
491	git rm -rf two &&
492	git mv one/file two &&
493	rm -r one &&
494	git commit -m "Rename one/file -> two"
495'
496
497test_expect_success 'pair rename to parent of other (D/F conflicts) w/ untracked dir' '
498	git checkout -q rename-one^0 &&
499	mkdir one &&
500	test_must_fail git merge --strategy=recursive rename-two &&
501
502	test 2 -eq "$(git ls-files -u | wc -l)" &&
503	test 1 -eq "$(git ls-files -u one | wc -l)" &&
504	test 1 -eq "$(git ls-files -u two | wc -l)" &&
505
506	test_must_fail git diff --quiet &&
507
508	test 4 -eq $(find . | grep -v .git | wc -l) &&
509
510	test -d one &&
511	test -f one~rename-two &&
512	test -f two &&
513	test "other" = $(cat one~rename-two) &&
514	test "stuff" = $(cat two)
515'
516
517test_expect_success 'pair rename to parent of other (D/F conflicts) w/ clean start' '
518	git reset --hard &&
519	git clean -fdqx &&
520	test_must_fail git merge --strategy=recursive rename-two &&
521
522	test 2 -eq "$(git ls-files -u | wc -l)" &&
523	test 1 -eq "$(git ls-files -u one | wc -l)" &&
524	test 1 -eq "$(git ls-files -u two | wc -l)" &&
525
526	test_must_fail git diff --quiet &&
527
528	test 3 -eq $(find . | grep -v .git | wc -l) &&
529
530	test -f one &&
531	test -f two &&
532	test "other" = $(cat one) &&
533	test "stuff" = $(cat two)
534'
535
536test_expect_success 'setup rename of one file to two, with directories in the way' '
537	git reset --hard &&
538	git checkout --orphan first-rename &&
539	git rm -rf . &&
540	git clean -fdqx &&
541
542	echo stuff >original &&
543	git add -A &&
544	git commit -m "Common commit" &&
545
546	mkdir two &&
547	>two/file &&
548	git add two/file &&
549	git mv original one &&
550	git commit -m "Put two/file in the way, rename to one" &&
551
552	git checkout -b second-rename HEAD~1 &&
553	mkdir one &&
554	>one/file &&
555	git add one/file &&
556	git mv original two &&
557	git commit -m "Put one/file in the way, rename to two"
558'
559
560test_expect_success 'check handling of differently renamed file with D/F conflicts' '
561	git checkout -q first-rename^0 &&
562	test_must_fail git merge --strategy=recursive second-rename &&
563
564	test 5 -eq "$(git ls-files -s | wc -l)" &&
565	test 3 -eq "$(git ls-files -u | wc -l)" &&
566	test 1 -eq "$(git ls-files -u one | wc -l)" &&
567	test 1 -eq "$(git ls-files -u two | wc -l)" &&
568	test 1 -eq "$(git ls-files -u original | wc -l)" &&
569	test 2 -eq "$(git ls-files -o | wc -l)" &&
570
571	test -f one/file &&
572	test -f two/file &&
573	test -f one~HEAD &&
574	test -f two~second-rename &&
575	! test -f original
576'
577
578test_expect_success 'setup rename one file to two; directories moving out of the way' '
579	git reset --hard &&
580	git checkout --orphan first-rename-redo &&
581	git rm -rf . &&
582	git clean -fdqx &&
583
584	echo stuff >original &&
585	mkdir one two &&
586	touch one/file two/file &&
587	git add -A &&
588	git commit -m "Common commit" &&
589
590	git rm -rf one &&
591	git mv original one &&
592	git commit -m "Rename to one" &&
593
594	git checkout -b second-rename-redo HEAD~1 &&
595	git rm -rf two &&
596	git mv original two &&
597	git commit -m "Rename to two"
598'
599
600test_expect_success 'check handling of differently renamed file with D/F conflicts' '
601	git checkout -q first-rename-redo^0 &&
602	test_must_fail git merge --strategy=recursive second-rename-redo &&
603
604	test 3 -eq "$(git ls-files -u | wc -l)" &&
605	test 1 -eq "$(git ls-files -u one | wc -l)" &&
606	test 1 -eq "$(git ls-files -u two | wc -l)" &&
607	test 1 -eq "$(git ls-files -u original | wc -l)" &&
608	test 0 -eq "$(git ls-files -o | wc -l)" &&
609
610	test -f one &&
611	test -f two &&
612	! test -f original
613'
614
615test_expect_success 'setup avoid unnecessary update, normal rename' '
616	git reset --hard &&
617	git checkout --orphan avoid-unnecessary-update-1 &&
618	git rm -rf . &&
619	git clean -fdqx &&
620
621	printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
622	git add -A &&
623	git commit -m "Common commit" &&
624
625	git mv original rename &&
626	echo 11 >>rename &&
627	git add -u &&
628	git commit -m "Renamed and modified" &&
629
630	git checkout -b merge-branch-1 HEAD~1 &&
631	echo "random content" >random-file &&
632	git add -A &&
633	git commit -m "Random, unrelated changes"
634'
635
636test_expect_success 'avoid unnecessary update, normal rename' '
637	git checkout -q avoid-unnecessary-update-1^0 &&
638	test-tool chmtime --get =1000000000 rename >expect &&
639	git merge merge-branch-1 &&
640	test-tool chmtime --get rename >actual &&
641	test_cmp expect actual # "rename" should have stayed intact
642'
643
644test_expect_success 'setup to test avoiding unnecessary update, with D/F conflict' '
645	git reset --hard &&
646	git checkout --orphan avoid-unnecessary-update-2 &&
647	git rm -rf . &&
648	git clean -fdqx &&
649
650	mkdir df &&
651	printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
652	git add -A &&
653	git commit -m "Common commit" &&
654
655	git mv df/file temp &&
656	rm -rf df &&
657	git mv temp df &&
658	echo 11 >>df &&
659	git add -u &&
660	git commit -m "Renamed and modified" &&
661
662	git checkout -b merge-branch-2 HEAD~1 &&
663	>unrelated-change &&
664	git add unrelated-change &&
665	git commit -m "Only unrelated changes"
666'
667
668test_expect_success 'avoid unnecessary update, with D/F conflict' '
669	git checkout -q avoid-unnecessary-update-2^0 &&
670	test-tool chmtime --get =1000000000 df >expect &&
671	git merge merge-branch-2 &&
672	test-tool chmtime --get df >actual &&
673	test_cmp expect actual # "df" should have stayed intact
674'
675
676test_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
699test_expect_success 'avoid unnecessary update, dir->(file,nothing)' '
700	git checkout -q master^0 &&
701	test-tool chmtime --get =1000000000 df >expect &&
702	git merge side &&
703	test-tool chmtime --get df >actual &&
704	test_cmp expect actual # "df" should have stayed intact
705'
706
707test_expect_success 'setup avoid unnecessary update, modify/delete' '
708	git rm -rf . &&
709	git clean -fdqx &&
710	rm -rf .git &&
711	git init &&
712
713	>irrelevant &&
714	>file &&
715	git add -A &&
716	git commit -mA &&
717
718	git checkout -b side &&
719	git rm -f file &&
720	git commit -m "Delete file" &&
721
722	git checkout master &&
723	echo bla >file &&
724	git add -A &&
725	git commit -m "Modify file"
726'
727
728test_expect_success 'avoid unnecessary update, modify/delete' '
729	git checkout -q master^0 &&
730	test-tool chmtime --get =1000000000 file >expect &&
731	test_must_fail git merge side &&
732	test-tool chmtime --get file >actual &&
733	test_cmp expect actual # "file" should have stayed intact
734'
735
736test_expect_success 'setup avoid unnecessary update, rename/add-dest' '
737	git rm -rf . &&
738	git clean -fdqx &&
739	rm -rf .git &&
740	git init &&
741
742	printf "1\n2\n3\n4\n5\n6\n7\n8\n" >file &&
743	git add -A &&
744	git commit -mA &&
745
746	git checkout -b side &&
747	cp file newfile &&
748	git add -A &&
749	git commit -m "Add file copy" &&
750
751	git checkout master &&
752	git mv file newfile &&
753	git commit -m "Rename file"
754'
755
756test_expect_success 'avoid unnecessary update, rename/add-dest' '
757	git checkout -q master^0 &&
758	test-tool chmtime --get =1000000000 newfile >expect &&
759	git merge side &&
760	test-tool chmtime --get newfile >actual &&
761	test_cmp expect actual # "file" should have stayed intact
762'
763
764test_expect_success 'setup merge of rename + small change' '
765	git reset --hard &&
766	git checkout --orphan rename-plus-small-change &&
767	git rm -rf . &&
768	git clean -fdqx &&
769
770	echo ORIGINAL >file &&
771	git add file &&
772
773	test_tick &&
774	git commit -m Initial &&
775	git checkout -b rename_branch &&
776	git mv file renamed_file &&
777	git commit -m Rename &&
778	git checkout rename-plus-small-change &&
779	echo NEW-VERSION >file &&
780	git commit -a -m Reformat
781'
782
783test_expect_success 'merge rename + small change' '
784	git merge rename_branch &&
785
786	test 1 -eq $(git ls-files -s | wc -l) &&
787	test 0 -eq $(git ls-files -o | wc -l) &&
788	test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
789'
790
791test_expect_success 'setup for use of extended merge markers' '
792	git rm -rf . &&
793	git clean -fdqx &&
794	rm -rf .git &&
795	git init &&
796
797	printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
798	git add original_file &&
799	git commit -mA &&
800
801	git checkout -b rename &&
802	echo 9 >>original_file &&
803	git add original_file &&
804	git mv original_file renamed_file &&
805	git commit -mB &&
806
807	git checkout master &&
808	echo 8.5 >>original_file &&
809	git add original_file &&
810	git commit -mC
811'
812
813cat >expected <<\EOF &&
8141
8152
8163
8174
8185
8196
8207
8218
822<<<<<<< HEAD:renamed_file
8239
824=======
8258.5
826>>>>>>> master^0:original_file
827EOF
828
829test_expect_success 'merge master into rename has correct extended markers' '
830	git checkout rename^0 &&
831	test_must_fail git merge -s recursive master^0 &&
832	test_cmp expected renamed_file
833'
834
835cat >expected <<\EOF &&
8361
8372
8383
8394
8405
8416
8427
8438
844<<<<<<< HEAD:original_file
8458.5
846=======
8479
848>>>>>>> rename^0:renamed_file
849EOF
850
851test_expect_success 'merge rename into master has correct extended markers' '
852	git reset --hard &&
853	git checkout master^0 &&
854	test_must_fail git merge -s recursive rename^0 &&
855	test_cmp expected renamed_file
856'
857
858test_expect_success 'setup spurious "refusing to lose untracked" message' '
859	git rm -rf . &&
860	git clean -fdqx &&
861	rm -rf .git &&
862	git init &&
863
864	> irrelevant_file &&
865	printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
866	git add irrelevant_file original_file &&
867	git commit -mA &&
868
869	git checkout -b rename &&
870	git mv original_file renamed_file &&
871	git commit -mB &&
872
873	git checkout master &&
874	git rm original_file &&
875	git commit -mC
876'
877
878test_expect_success 'no spurious "refusing to lose untracked" message' '
879	git checkout master^0 &&
880	test_must_fail git merge rename^0 2>errors.txt &&
881	! grep "refusing to lose untracked file" errors.txt
882'
883
884test_expect_success 'do not follow renames for empty files' '
885	git checkout -f -b empty-base &&
886	>empty1 &&
887	git add empty1 &&
888	git commit -m base &&
889	echo content >empty1 &&
890	git add empty1 &&
891	git commit -m fill &&
892	git checkout -b empty-topic HEAD^ &&
893	git mv empty1 empty2 &&
894	git commit -m rename &&
895	test_must_fail git merge empty-base &&
896	test_must_be_empty empty2
897'
898
899test_done
900