merge-recursive: Provide more info in conflict markers with file renames

Whenever there are merge conflicts in file contents, we would mark the different sides of the conflict with the two branches being merged. However, when there is a rename involved as well, the branchname is not sufficient to specify where the conflicting content came from. In such cases, mark the two sides of the conflict with branchname:filename rather than just branchname. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Aug 11, 2011 at 23:20 UTC 3c217c077a86d9ae06ed26bb0baa4475d0e28a0e
3 files changed +97 -8
merge-recursive.c
+25 -3
@@ -1353,6 +1353,7 @@ static int merge_content(struct merge_options *o,
1353 struct rename_conflict_info *rename_conflict_info)
1354 {
1355 const char *reason = "content";
1356 + char *side1 = NULL, *side2 = NULL;
1357 struct merge_file_info mfi;
1358 struct diff_filespec one, a, b;
1359 unsigned df_conflict_remains = 0;
@@ -1369,10 +1370,31 @@ static int merge_content(struct merge_options *o,
1370 hashcpy(b.sha1, b_sha);
1371 b.mode = b_mode;
1372
1372 - mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2);
1373 - if (rename_conflict_info && dir_in_way(path, !o->call_depth)) {
1374 - df_conflict_remains = 1;
1373 + if (rename_conflict_info) {
1374 + const char *path1, *path2;
1375 + struct diff_filepair *pair1 = rename_conflict_info->pair1;
1376 +
1377 + path1 = (o->branch1 == rename_conflict_info->branch1) ?
1378 + pair1->two->path : pair1->one->path;
1379 + /* If rename_conflict_info->pair2 != NULL, we are in
1380 + * RENAME_ONE_FILE_TO_ONE case. Otherwise, we have a
1381 + * normal rename.
1382 + */
1383 + path2 = (rename_conflict_info->pair2 ||
1384 + o->branch2 == rename_conflict_info->branch1) ?
1385 + pair1->two->path : pair1->one->path;
1386 + side1 = xmalloc(strlen(o->branch1) + strlen(path1) + 2);
1387 + side2 = xmalloc(strlen(o->branch2) + strlen(path2) + 2);
1388 + sprintf(side1, "%s:%s", o->branch1, path1);
1389 + sprintf(side2, "%s:%s", o->branch2, path2);
1390 +
1391 + if (dir_in_way(path, !o->call_depth))
1392 + df_conflict_remains = 1;
1393 }
1394 + mfi = merge_file(o, &one, &a, &b,
1395 + side1 ? side1 : o->branch1, side2 ? side2 : o->branch2);
1396 + free(side1);
1397 + free(side2);
1398
1399 if (mfi.clean && !df_conflict_remains &&
1400 sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)
t/t6022-merge-rename.sh
+71 -4
@@ -351,11 +351,11 @@ cat >expected <<\EOF &&
351 8
352 9
353 10
354 -<<<<<<< HEAD
354 +<<<<<<< HEAD:dir
355 12
356 =======
357 11
358 ->>>>>>> dir-not-in-way
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' '
@@ -405,11 +405,11 @@ cat >expected <<\EOF &&
405 8
406 9
407 10
408 -<<<<<<< HEAD
408 +<<<<<<< HEAD:sub/file
409 11
410 =======
411 12
412 ->>>>>>> renamed-file-has-conflicts
412 +>>>>>>> renamed-file-has-conflicts:dir
413 EOF
414
415 test_expect_success 'Same as previous, but merged other way' '
@@ -700,4 +700,71 @@ test_expect_success 'merge rename + small change' '
700 test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
701 '
702
703 +test_expect_success 'setup for use of extended merge markers' '
704 + git rm -rf . &&
705 + git clean -fdqx &&
706 + rm -rf .git &&
707 + git init &&
708 +
709 + printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
710 + git add original_file &&
711 + git commit -mA &&
712 +
713 + git checkout -b rename &&
714 + echo 9 >>original_file &&
715 + git add original_file &&
716 + git mv original_file renamed_file &&
717 + git commit -mB &&
718 +
719 + git checkout master &&
720 + echo 8.5 >>original_file &&
721 + git add original_file &&
722 + git commit -mC
723 +'
724 +
725 +cat >expected <<\EOF &&
726 +1
727 +2
728 +3
729 +4
730 +5
731 +6
732 +7
733 +8
734 +<<<<<<< HEAD:renamed_file
735 +9
736 +=======
737 +8.5
738 +>>>>>>> master^0:original_file
739 +EOF
740 +
741 +test_expect_success 'merge master into rename has correct extended markers' '
742 + git checkout rename^0 &&
743 + test_must_fail git merge -s recursive master^0 &&
744 + test_cmp expected renamed_file
745 +'
746 +
747 +cat >expected <<\EOF &&
748 +1
749 +2
750 +3
751 +4
752 +5
753 +6
754 +7
755 +8
756 +<<<<<<< HEAD:original_file
757 +8.5
758 +=======
759 +9
760 +>>>>>>> rename^0:renamed_file
761 +EOF
762 +
763 +test_expect_success 'merge rename into master has correct extended markers' '
764 + git reset --hard &&
765 + git checkout master^0 &&
766 + test_must_fail git merge -s recursive rename^0 &&
767 + test_cmp expected renamed_file
768 +'
769 +
770 test_done
t/t6042-merge-rename-corner-cases.sh
+1 -1
@@ -258,7 +258,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '
258 test -f newfile~HEAD
259 '
260
261 -test_expect_failure 'rename/directory conflict + content merge conflict' '
261 +test_expect_success 'rename/directory conflict + content merge conflict' '
262 git reset --hard &&
263 git reset --hard &&
264 git clean -fdqx &&