Skip to content

Commit 3c217c0

Browse files
newrengitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4f66dad commit 3c217c0

File tree

3 files changed

+97
-8
lines changed

3 files changed

+97
-8
lines changed

merge-recursive.c

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,7 @@ static int merge_content(struct merge_options *o,
13531353
struct rename_conflict_info *rename_conflict_info)
13541354
{
13551355
const char *reason = "content";
1356+
char *side1 = NULL, *side2 = NULL;
13561357
struct merge_file_info mfi;
13571358
struct diff_filespec one, a, b;
13581359
unsigned df_conflict_remains = 0;
@@ -1369,10 +1370,31 @@ static int merge_content(struct merge_options *o,
13691370
hashcpy(b.sha1, b_sha);
13701371
b.mode = b_mode;
13711372

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;
13751393
}
1394+
mfi = merge_file(o, &one, &a, &b,
1395+
side1 ? side1 : o->branch1, side2 ? side2 : o->branch2);
1396+
free(side1);
1397+
free(side2);
13761398

13771399
if (mfi.clean && !df_conflict_remains &&
13781400
sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)

t/t6022-merge-rename.sh

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ cat >expected <<\EOF &&
351351
8
352352
9
353353
10
354-
<<<<<<< HEAD
354+
<<<<<<< HEAD:dir
355355
12
356356
=======
357357
11
358-
>>>>>>> dir-not-in-way
358+
>>>>>>> dir-not-in-way:sub/file
359359
EOF
360360

361361
test_expect_success 'Rename+D/F conflict; renamed file cannot merge, dir not in way' '
@@ -405,11 +405,11 @@ cat >expected <<\EOF &&
405405
8
406406
9
407407
10
408-
<<<<<<< HEAD
408+
<<<<<<< HEAD:sub/file
409409
11
410410
=======
411411
12
412-
>>>>>>> renamed-file-has-conflicts
412+
>>>>>>> renamed-file-has-conflicts:dir
413413
EOF
414414

415415
test_expect_success 'Same as previous, but merged other way' '
@@ -700,4 +700,71 @@ test_expect_success 'merge rename + small change' '
700700
test $(git rev-parse HEAD:renamed_file) = $(git rev-parse HEAD~1:file)
701701
'
702702

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+
703770
test_done

t/t6042-merge-rename-corner-cases.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ test_expect_success 'rename/directory conflict + clean content merge' '
258258
test -f newfile~HEAD
259259
'
260260

261-
test_expect_failure 'rename/directory conflict + content merge conflict' '
261+
test_expect_success 'rename/directory conflict + content merge conflict' '
262262
git reset --hard &&
263263
git reset --hard &&
264264
git clean -fdqx &&

0 commit comments

Comments
 (0)