Code

merge-recursive: Provide more info in conflict markers with file renames
authorElijah Newren <newren@gmail.com>
Fri, 12 Aug 2011 05:20:09 +0000 (23:20 -0600)
committerJunio C Hamano <gitster@pobox.com>
Sun, 14 Aug 2011 21:19:37 +0000 (14:19 -0700)
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>
merge-recursive.c
t/t6022-merge-rename.sh
t/t6042-merge-rename-corner-cases.sh

index e68396bcb026bf0b7fd3db43c3d9b902756b6cc7..a3bbca8d580bde3fc7c7d5ae06a8c07e630d8fbb 100644 (file)
@@ -1353,6 +1353,7 @@ static int merge_content(struct merge_options *o,
                         struct rename_conflict_info *rename_conflict_info)
 {
        const char *reason = "content";
+       char *side1 = NULL, *side2 = NULL;
        struct merge_file_info mfi;
        struct diff_filespec one, a, b;
        unsigned df_conflict_remains = 0;
@@ -1369,10 +1370,31 @@ static int merge_content(struct merge_options *o,
        hashcpy(b.sha1, b_sha);
        b.mode = b_mode;
 
-       mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2);
-       if (rename_conflict_info && dir_in_way(path, !o->call_depth)) {
-               df_conflict_remains = 1;
+       if (rename_conflict_info) {
+               const char *path1, *path2;
+               struct diff_filepair *pair1 = rename_conflict_info->pair1;
+
+               path1 = (o->branch1 == rename_conflict_info->branch1) ?
+                       pair1->two->path : pair1->one->path;
+               /* If rename_conflict_info->pair2 != NULL, we are in
+                * RENAME_ONE_FILE_TO_ONE case.  Otherwise, we have a
+                * normal rename.
+                */
+               path2 = (rename_conflict_info->pair2 ||
+                        o->branch2 == rename_conflict_info->branch1) ?
+                       pair1->two->path : pair1->one->path;
+               side1 = xmalloc(strlen(o->branch1) + strlen(path1) + 2);
+               side2 = xmalloc(strlen(o->branch2) + strlen(path2) + 2);
+               sprintf(side1, "%s:%s", o->branch1, path1);
+               sprintf(side2, "%s:%s", o->branch2, path2);
+
+               if (dir_in_way(path, !o->call_depth))
+                       df_conflict_remains = 1;
        }
+       mfi = merge_file(o, &one, &a, &b,
+                        side1 ? side1 : o->branch1, side2 ? side2 : o->branch2);
+       free(side1);
+       free(side2);
 
        if (mfi.clean && !df_conflict_remains &&
            sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)
index fcc1d4cfff7fe71d0c581ce2177a719671dfb66d..4695cbccb13c05d4a437b3d91d5f98dadf0c8cc2 100755 (executable)
@@ -351,11 +351,11 @@ cat >expected <<\EOF &&
 8
 9
 10
-<<<<<<< HEAD
+<<<<<<< HEAD:dir
 12
 =======
 11
->>>>>>> dir-not-in-way
+>>>>>>> dir-not-in-way:sub/file
 EOF
 
 test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
@@ -405,11 +405,11 @@ cat >expected <<\EOF &&
 8
 9
 10
-<<<<<<< HEAD
+<<<<<<< HEAD:sub/file
 11
 =======
 12
->>>>>>> renamed-file-has-conflicts
+>>>>>>> renamed-file-has-conflicts:dir
 EOF
 
 test_expect_success 'Same as previous, but merged other way' '
@@ -700,4 +700,71 @@ test_expect_success 'merge rename + small change' '
        test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
 '
 
+test_expect_success 'setup for use of extended merge markers' '
+       git rm -rf . &&
+       git clean -fdqx &&
+       rm -rf .git &&
+       git init &&
+
+       printf "1\n2\n3\n4\n5\n6\n7\n8\n" >original_file &&
+       git add original_file &&
+       git commit -mA &&
+
+       git checkout -b rename &&
+       echo 9 >>original_file &&
+       git add original_file &&
+       git mv original_file renamed_file &&
+       git commit -mB &&
+
+       git checkout master &&
+       echo 8.5 >>original_file &&
+       git add original_file &&
+       git commit -mC
+'
+
+cat >expected <<\EOF &&
+1
+2
+3
+4
+5
+6
+7
+8
+<<<<<<< HEAD:renamed_file
+9
+=======
+8.5
+>>>>>>> master^0:original_file
+EOF
+
+test_expect_success 'merge master into rename has correct extended markers' '
+       git checkout rename^0 &&
+       test_must_fail git merge -s recursive master^0 &&
+       test_cmp expected renamed_file
+'
+
+cat >expected <<\EOF &&
+1
+2
+3
+4
+5
+6
+7
+8
+<<<<<<< HEAD:original_file
+8.5
+=======
+9
+>>>>>>> rename^0:renamed_file
+EOF
+
+test_expect_success 'merge rename into master has correct extended markers' '
+       git reset --hard &&
+       git checkout master^0 &&
+       test_must_fail git merge -s recursive rename^0 &&
+       test_cmp expected renamed_file
+'
+
 test_done
index 968055d47cfe2cd55110c606d694c76b648934fe..bfc3179332f566e443a0acebb044cd61dd3d52d2 100755 (executable)
@@ -258,7 +258,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '
        test -f newfile~HEAD
 '
 
-test_expect_failure 'rename/directory conflict + content merge conflict' '
+test_expect_success 'rename/directory conflict + content merge conflict' '
        git reset --hard &&
        git reset --hard &&
        git clean -fdqx &&