1#!/bin/sh
2
3test_description="recursive merge corner cases w/ renames but not criss-crosses"
4# t6036 has corner cases that involve both criss-cross merges and renames
5
6. ./test-lib.sh
7
8test_expect_success 'setup rename/delete + untracked file' '
9 test_create_repo rename-delete-untracked &&
10 (
11 cd rename-delete-untracked &&
12
13 echo "A pretty inscription" >ring &&
14 git add ring &&
15 test_tick &&
16 git commit -m beginning &&
17
18 git branch people &&
19 git checkout -b rename-the-ring &&
20 git mv ring one-ring-to-rule-them-all &&
21 test_tick &&
22 git commit -m fullname &&
23
24 git checkout people &&
25 git rm ring &&
26 echo gollum >owner &&
27 git add owner &&
28 test_tick &&
29 git commit -m track-people-instead-of-objects &&
30 echo "Myyy PRECIOUSSS" >ring
31 )
32'
33
34test_expect_success "Does git preserve Gollum's precious artifact?" '
35 (
36 cd rename-delete-untracked &&
37
38 test_must_fail git merge -s recursive rename-the-ring &&
39
40 # Make sure git did not delete an untracked file
41 test -f ring
42 )
43'
44
45# Testcase setup for rename/modify/add-source:
46# Commit A: new file: a
47# Commit B: modify a slightly
48# Commit C: rename a->b, add completely different a
49#
50# We should be able to merge B & C cleanly
51
52test_expect_success 'setup rename/modify/add-source conflict' '
53 test_create_repo rename-modify-add-source &&
54 (
55 cd rename-modify-add-source &&
56
57 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
58 git add a &&
59 git commit -m A &&
60 git tag A &&
61
62 git checkout -b B A &&
63 echo 8 >>a &&
64 git add a &&
65 git commit -m B &&
66
67 git checkout -b C A &&
68 git mv a b &&
69 echo something completely different >a &&
70 git add a &&
71 git commit -m C
72 )
73'
74
75test_expect_failure 'rename/modify/add-source conflict resolvable' '
76 (
77 cd rename-modify-add-source &&
78
79 git checkout B^0 &&
80
81 git merge -s recursive C^0 &&
82
83 test $(git rev-parse B:a) = $(git rev-parse b) &&
84 test $(git rev-parse C:a) = $(git rev-parse a)
85 )
86'
87
88test_expect_success 'setup resolvable conflict missed if rename missed' '
89 test_create_repo break-detection-1 &&
90 (
91 cd break-detection-1 &&
92
93 printf "1\n2\n3\n4\n5\n" >a &&
94 echo foo >b &&
95 git add a b &&
96 git commit -m A &&
97 git tag A &&
98
99 git checkout -b B A &&
100 git mv a c &&
101 echo "Completely different content" >a &&
102 git add a &&
103 git commit -m B &&
104
105 git checkout -b C A &&
106 echo 6 >>a &&
107 git add a &&
108 git commit -m C
109 )
110'
111
112test_expect_failure 'conflict caused if rename not detected' '
113 (
114 cd break-detection-1 &&
115
116 git checkout -q C^0 &&
117 git merge -s recursive B^0 &&
118
119 git ls-files -s >out &&
120 test_line_count = 3 out &&
121 git ls-files -u >out &&
122 test_line_count = 0 out &&
123 git ls-files -o >out &&
124 test_line_count = 1 out &&
125
126 test_line_count = 6 c &&
127 test $(git rev-parse HEAD:a) = $(git rev-parse B:a) &&
128 test $(git rev-parse HEAD:b) = $(git rev-parse A:b)
129 )
130'
131
132test_expect_success 'setup conflict resolved wrong if rename missed' '
133 test_create_repo break-detection-2 &&
134 (
135 cd break-detection-2 &&
136
137 printf "1\n2\n3\n4\n5\n" >a &&
138 echo foo >b &&
139 git add a b &&
140 git commit -m A &&
141 git tag A &&
142
143 git checkout -b D A &&
144 echo 7 >>a &&
145 git add a &&
146 git mv a c &&
147 echo "Completely different content" >a &&
148 git add a &&
149 git commit -m D &&
150
151 git checkout -b E A &&
152 git rm a &&
153 echo "Completely different content" >>a &&
154 git add a &&
155 git commit -m E
156 )
157'
158
159test_expect_failure 'missed conflict if rename not detected' '
160 (
161 cd break-detection-2 &&
162
163 git checkout -q E^0 &&
164 test_must_fail git merge -s recursive D^0
165 )
166'
167
168# Tests for undetected rename/add-source causing a file to erroneously be
169# deleted (and for mishandled rename/rename(1to1) causing the same issue).
170#
171# This test uses a rename/rename(1to1)+add-source conflict (1to1 means the
172# same file is renamed on both sides to the same thing; it should trigger
173# the 1to2 logic, which it would do if the add-source didn't cause issues
174# for git's rename detection):
175# Commit A: new file: a
176# Commit B: rename a->b
177# Commit C: rename a->b, add unrelated a
178
179test_expect_success 'setup undetected rename/add-source causes data loss' '
180 test_create_repo break-detection-3 &&
181 (
182 cd break-detection-3 &&
183
184 printf "1\n2\n3\n4\n5\n" >a &&
185 git add a &&
186 git commit -m A &&
187 git tag A &&
188
189 git checkout -b B A &&
190 git mv a b &&
191 git commit -m B &&
192
193 git checkout -b C A &&
194 git mv a b &&
195 echo foobar >a &&
196 git add a &&
197 git commit -m C
198 )
199'
200
201test_expect_failure 'detect rename/add-source and preserve all data' '
202 (
203 cd break-detection-3 &&
204
205 git checkout B^0 &&
206
207 git merge -s recursive C^0 &&
208
209 git ls-files -s >out &&
210 test_line_count = 2 out &&
211 git ls-files -u >out &&
212 test_line_count = 2 out &&
213 git ls-files -o >out &&
214 test_line_count = 1 out &&
215
216 test -f a &&
217 test -f b &&
218
219 test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
220 test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
221 )
222'
223
224test_expect_failure 'detect rename/add-source and preserve all data, merge other way' '
225 (
226 cd break-detection-3 &&
227
228 git checkout C^0 &&
229
230 git merge -s recursive B^0 &&
231
232 git ls-files -s >out &&
233 test_line_count = 2 out &&
234 git ls-files -u >out &&
235 test_line_count = 2 out &&
236 git ls-files -o >out &&
237 test_line_count = 1 out &&
238
239 test -f a &&
240 test -f b &&
241
242 test $(git rev-parse HEAD:b) = $(git rev-parse A:a) &&
243 test $(git rev-parse HEAD:a) = $(git rev-parse C:a)
244 )
245'
246
247test_expect_success 'setup content merge + rename/directory conflict' '
248 test_create_repo rename-directory-1 &&
249 (
250 cd rename-directory-1 &&
251
252 printf "1\n2\n3\n4\n5\n6\n" >file &&
253 git add file &&
254 test_tick &&
255 git commit -m base &&
256 git tag base &&
257
258 git checkout -b right &&
259 echo 7 >>file &&
260 mkdir newfile &&
261 echo junk >newfile/realfile &&
262 git add file newfile/realfile &&
263 test_tick &&
264 git commit -m right &&
265
266 git checkout -b left-conflict base &&
267 echo 8 >>file &&
268 git add file &&
269 git mv file newfile &&
270 test_tick &&
271 git commit -m left &&
272
273 git checkout -b left-clean base &&
274 echo 0 >newfile &&
275 cat file >>newfile &&
276 git add newfile &&
277 git rm file &&
278 test_tick &&
279 git commit -m left
280 )
281'
282
283test_expect_success 'rename/directory conflict + clean content merge' '
284 (
285 cd rename-directory-1 &&
286
287 git checkout left-clean^0 &&
288
289 test_must_fail git merge -s recursive right^0 &&
290
291 git ls-files -s >out &&
292 test_line_count = 2 out &&
293 git ls-files -u >out &&
294 test_line_count = 1 out &&
295 git ls-files -o >out &&
296 test_line_count = 2 out &&
297
298 echo 0 >expect &&
299 git cat-file -p base:file >>expect &&
300 echo 7 >>expect &&
301 test_cmp expect newfile~HEAD &&
302
303 test $(git rev-parse :2:newfile) = $(git hash-object expect) &&
304
305 test -f newfile/realfile &&
306 test -f newfile~HEAD
307 )
308'
309
310test_expect_success 'rename/directory conflict + content merge conflict' '
311 (
312 cd rename-directory-1 &&
313
314 git reset --hard &&
315 git reset --hard &&
316 git clean -fdqx &&
317
318 git checkout left-conflict^0 &&
319
320 test_must_fail git merge -s recursive right^0 &&
321
322 git ls-files -s >out &&
323 test_line_count = 4 out &&
324 git ls-files -u >out &&
325 test_line_count = 3 out &&
326 git ls-files -o >out &&
327 test_line_count = 2 out &&
328
329 git cat-file -p left-conflict:newfile >left &&
330 git cat-file -p base:file >base &&
331 git cat-file -p right:file >right &&
332 test_must_fail git merge-file \
333 -L "HEAD:newfile" \
334 -L "" \
335 -L "right^0:file" \
336 left base right &&
337 test_cmp left newfile~HEAD &&
338
339 test $(git rev-parse :1:newfile) = $(git rev-parse base:file) &&
340 test $(git rev-parse :2:newfile) = $(git rev-parse left-conflict:newfile) &&
341 test $(git rev-parse :3:newfile) = $(git rev-parse right:file) &&
342
343 test -f newfile/realfile &&
344 test -f newfile~HEAD
345 )
346'
347
348test_expect_success 'setup content merge + rename/directory conflict w/ disappearing dir' '
349 test_create_repo rename-directory-2 &&
350 (
351 cd rename-directory-2 &&
352
353 mkdir sub &&
354 printf "1\n2\n3\n4\n5\n6\n" >sub/file &&
355 git add sub/file &&
356 test_tick &&
357 git commit -m base &&
358 git tag base &&
359
360 git checkout -b right &&
361 echo 7 >>sub/file &&
362 git add sub/file &&
363 test_tick &&
364 git commit -m right &&
365
366 git checkout -b left base &&
367 echo 0 >newfile &&
368 cat sub/file >>newfile &&
369 git rm sub/file &&
370 mv newfile sub &&
371 git add sub &&
372 test_tick &&
373 git commit -m left
374 )
375'
376
377test_expect_success 'disappearing dir in rename/directory conflict handled' '
378 (
379 cd rename-directory-2 &&
380
381 git checkout left^0 &&
382
383 git merge -s recursive right^0 &&
384
385 git ls-files -s >out &&
386 test_line_count = 1 out &&
387 git ls-files -u >out &&
388 test_line_count = 0 out &&
389 git ls-files -o >out &&
390 test_line_count = 1 out &&
391
392 echo 0 >expect &&
393 git cat-file -p base:sub/file >>expect &&
394 echo 7 >>expect &&
395 test_cmp expect sub &&
396
397 test -f sub
398 )
399'
400
401# Test for all kinds of things that can go wrong with rename/rename (2to1):
402# Commit A: new files: a & b
403# Commit B: rename a->c, modify b
404# Commit C: rename b->c, modify a
405#
406# Merging of B & C should NOT be clean. Questions:
407# * Both a & b should be removed by the merge; are they?
408# * The two c's should contain modifications to a & b; do they?
409# * The index should contain two files, both for c; does it?
410# * The working copy should have two files, both of form c~<unique>; does it?
411# * Nothing else should be present. Is anything?
412
413test_expect_success 'setup rename/rename (2to1) + modify/modify' '
414 test_create_repo rename-rename-2to1 &&
415 (
416 cd rename-rename-2to1 &&
417
418 printf "1\n2\n3\n4\n5\n" >a &&
419 printf "5\n4\n3\n2\n1\n" >b &&
420 git add a b &&
421 git commit -m A &&
422 git tag A &&
423
424 git checkout -b B A &&
425 git mv a c &&
426 echo 0 >>b &&
427 git add b &&
428 git commit -m B &&
429
430 git checkout -b C A &&
431 git mv b c &&
432 echo 6 >>a &&
433 git add a &&
434 git commit -m C
435 )
436'
437
438test_expect_success 'handle rename/rename (2to1) conflict correctly' '
439 (
440 cd rename-rename-2to1 &&
441
442 git checkout B^0 &&
443
444 test_must_fail git merge -s recursive C^0 >out &&
445 test_i18ngrep "CONFLICT (rename/rename)" out &&
446
447 git ls-files -s >out &&
448 test_line_count = 2 out &&
449 git ls-files -u >out &&
450 test_line_count = 2 out &&
451 git ls-files -u c >out &&
452 test_line_count = 2 out &&
453 git ls-files -o >out &&
454 test_line_count = 3 out &&
455
456 test ! -f a &&
457 test ! -f b &&
458 test -f c~HEAD &&
459 test -f c~C^0 &&
460
461 test $(git hash-object c~HEAD) = $(git rev-parse C:a) &&
462 test $(git hash-object c~C^0) = $(git rev-parse B:b)
463 )
464'
465
466# Testcase setup for simple rename/rename (1to2) conflict:
467# Commit A: new file: a
468# Commit B: rename a->b
469# Commit C: rename a->c
470test_expect_success 'setup simple rename/rename (1to2) conflict' '
471 test_create_repo rename-rename-1to2 &&
472 (
473 cd rename-rename-1to2 &&
474
475 echo stuff >a &&
476 git add a &&
477 test_tick &&
478 git commit -m A &&
479 git tag A &&
480
481 git checkout -b B A &&
482 git mv a b &&
483 test_tick &&
484 git commit -m B &&
485
486 git checkout -b C A &&
487 git mv a c &&
488 test_tick &&
489 git commit -m C
490 )
491'
492
493test_expect_success 'merge has correct working tree contents' '
494 (
495 cd rename-rename-1to2 &&
496
497 git checkout C^0 &&
498
499 test_must_fail git merge -s recursive B^0 &&
500
501 git ls-files -s >out &&
502 test_line_count = 3 out &&
503 git ls-files -u >out &&
504 test_line_count = 3 out &&
505 git ls-files -o >out &&
506 test_line_count = 1 out &&
507
508 test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
509 test $(git rev-parse :3:b) = $(git rev-parse A:a) &&
510 test $(git rev-parse :2:c) = $(git rev-parse A:a) &&
511
512 test ! -f a &&
513 test $(git hash-object b) = $(git rev-parse A:a) &&
514 test $(git hash-object c) = $(git rev-parse A:a)
515 )
516'
517
518# Testcase setup for rename/rename(1to2)/add-source conflict:
519# Commit A: new file: a
520# Commit B: rename a->b
521# Commit C: rename a->c, add completely different a
522#
523# Merging of B & C should NOT be clean; there's a rename/rename conflict
524
525test_expect_success 'setup rename/rename(1to2)/add-source conflict' '
526 test_create_repo rename-rename-1to2-add-source-1 &&
527 (
528 cd rename-rename-1to2-add-source-1 &&
529
530 printf "1\n2\n3\n4\n5\n6\n7\n" >a &&
531 git add a &&
532 git commit -m A &&
533 git tag A &&
534
535 git checkout -b B A &&
536 git mv a b &&
537 git commit -m B &&
538
539 git checkout -b C A &&
540 git mv a c &&
541 echo something completely different >a &&
542 git add a &&
543 git commit -m C
544 )
545'
546
547test_expect_failure 'detect conflict with rename/rename(1to2)/add-source merge' '
548 (
549 cd rename-rename-1to2-add-source-1 &&
550
551 git checkout B^0 &&
552
553 test_must_fail git merge -s recursive C^0 &&
554
555 git ls-files -s >out &&
556 test_line_count = 4 out &&
557 git ls-files -o >out &&
558 test_line_count = 1 out &&
559
560 test $(git rev-parse 3:a) = $(git rev-parse C:a) &&
561 test $(git rev-parse 1:a) = $(git rev-parse A:a) &&
562 test $(git rev-parse 2:b) = $(git rev-parse B:b) &&
563 test $(git rev-parse 3:c) = $(git rev-parse C:c) &&
564
565 test -f a &&
566 test -f b &&
567 test -f c
568 )
569'
570
571test_expect_success 'setup rename/rename(1to2)/add-source resolvable conflict' '
572 test_create_repo rename-rename-1to2-add-source-2 &&
573 (
574 cd rename-rename-1to2-add-source-2 &&
575
576 >a &&
577 git add a &&
578 test_tick &&
579 git commit -m base &&
580 git tag A &&
581
582 git checkout -b B A &&
583 git mv a b &&
584 test_tick &&
585 git commit -m one &&
586
587 git checkout -b C A &&
588 git mv a b &&
589 echo important-info >a &&
590 git add a &&
591 test_tick &&
592 git commit -m two
593 )
594'
595
596test_expect_failure 'rename/rename/add-source still tracks new a file' '
597 (
598 cd rename-rename-1to2-add-source-2 &&
599
600 git checkout C^0 &&
601 git merge -s recursive B^0 &&
602
603 git ls-files -s >out &&
604 test_line_count = 2 out &&
605 git ls-files -o >out &&
606 test_line_count = 1 out &&
607
608 test $(git rev-parse HEAD:a) = $(git rev-parse C:a) &&
609 test $(git rev-parse HEAD:b) = $(git rev-parse A:a)
610 )
611'
612
613test_expect_success 'setup rename/rename(1to2)/add-dest conflict' '
614 test_create_repo rename-rename-1to2-add-dest &&
615 (
616 cd rename-rename-1to2-add-dest &&
617
618 echo stuff >a &&
619 git add a &&
620 test_tick &&
621 git commit -m base &&
622 git tag A &&
623
624 git checkout -b B A &&
625 git mv a b &&
626 echo precious-data >c &&
627 git add c &&
628 test_tick &&
629 git commit -m one &&
630
631 git checkout -b C A &&
632 git mv a c &&
633 echo important-info >b &&
634 git add b &&
635 test_tick &&
636 git commit -m two
637 )
638'
639
640test_expect_success 'rename/rename/add-dest merge still knows about conflicting file versions' '
641 (
642 cd rename-rename-1to2-add-dest &&
643
644 git checkout C^0 &&
645 test_must_fail git merge -s recursive B^0 &&
646
647 git ls-files -s >out &&
648 test_line_count = 5 out &&
649 git ls-files -u b >out &&
650 test_line_count = 2 out &&
651 git ls-files -u c >out &&
652 test_line_count = 2 out &&
653 git ls-files -o >out &&
654 test_line_count = 5 out &&
655
656 test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
657 test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
658 test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
659 test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
660 test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
661
662 test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
663 test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
664 test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
665 test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
666
667 test ! -f b &&
668 test ! -f c
669 )
670'
671
672test_done