Skip to content

Commit 74aabf4

Browse files
committed
Merge branch 'mm/merge-rename-delete-message'
When "git merge" detects a path that is renamed in one history while the other history deleted (or modified) it, it now reports both paths to help the user understand what is going on in the two histories being merged. * mm/merge-rename-delete-message: merge-recursive: make "CONFLICT (rename/delete)" message show both paths
2 parents 3ad8b5b + b26d87f commit 74aabf4

File tree

2 files changed

+86
-54
lines changed

2 files changed

+86
-54
lines changed

merge-recursive.c

Lines changed: 63 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,16 +1061,20 @@ static int merge_file_one(struct merge_options *o,
10611061
}
10621062

10631063
static int handle_change_delete(struct merge_options *o,
1064-
const char *path,
1064+
const char *path, const char *old_path,
10651065
const struct object_id *o_oid, int o_mode,
1066-
const struct object_id *a_oid, int a_mode,
1067-
const struct object_id *b_oid, int b_mode,
1066+
const struct object_id *changed_oid,
1067+
int changed_mode,
1068+
const char *change_branch,
1069+
const char *delete_branch,
10681070
const char *change, const char *change_past)
10691071
{
1070-
char *renamed = NULL;
1072+
char *alt_path = NULL;
1073+
const char *update_path = path;
10711074
int ret = 0;
1075+
10721076
if (dir_in_way(path, !o->call_depth, 0)) {
1073-
renamed = unique_path(o, path, a_oid ? o->branch1 : o->branch2);
1077+
update_path = alt_path = unique_path(o, path, change_branch);
10741078
}
10751079

10761080
if (o->call_depth) {
@@ -1081,72 +1085,61 @@ static int handle_change_delete(struct merge_options *o,
10811085
*/
10821086
ret = remove_file_from_cache(path);
10831087
if (!ret)
1084-
ret = update_file(o, 0, o_oid, o_mode,
1085-
renamed ? renamed : path);
1086-
} else if (!a_oid) {
1087-
if (!renamed) {
1088-
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1089-
"and %s in %s. Version %s of %s left in tree."),
1090-
change, path, o->branch1, change_past,
1091-
o->branch2, o->branch2, path);
1092-
ret = update_file(o, 0, b_oid, b_mode, path);
1093-
} else {
1094-
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1095-
"and %s in %s. Version %s of %s left in tree at %s."),
1096-
change, path, o->branch1, change_past,
1097-
o->branch2, o->branch2, path, renamed);
1098-
ret = update_file(o, 0, b_oid, b_mode, renamed);
1099-
}
1088+
ret = update_file(o, 0, o_oid, o_mode, update_path);
11001089
} else {
1101-
if (!renamed) {
1102-
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1103-
"and %s in %s. Version %s of %s left in tree."),
1104-
change, path, o->branch2, change_past,
1105-
o->branch1, o->branch1, path);
1090+
if (!alt_path) {
1091+
if (!old_path) {
1092+
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1093+
"and %s in %s. Version %s of %s left in tree."),
1094+
change, path, delete_branch, change_past,
1095+
change_branch, change_branch, path);
1096+
} else {
1097+
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1098+
"and %s to %s in %s. Version %s of %s left in tree."),
1099+
change, old_path, delete_branch, change_past, path,
1100+
change_branch, change_branch, path);
1101+
}
11061102
} else {
1107-
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1108-
"and %s in %s. Version %s of %s left in tree at %s."),
1109-
change, path, o->branch2, change_past,
1110-
o->branch1, o->branch1, path, renamed);
1111-
ret = update_file(o, 0, a_oid, a_mode, renamed);
1103+
if (!old_path) {
1104+
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1105+
"and %s in %s. Version %s of %s left in tree at %s."),
1106+
change, path, delete_branch, change_past,
1107+
change_branch, change_branch, path, alt_path);
1108+
} else {
1109+
output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
1110+
"and %s to %s in %s. Version %s of %s left in tree at %s."),
1111+
change, old_path, delete_branch, change_past, path,
1112+
change_branch, change_branch, path, alt_path);
1113+
}
11121114
}
11131115
/*
1114-
* No need to call update_file() on path when !renamed, since
1115-
* that would needlessly touch path. We could call
1116-
* update_file_flags() with update_cache=0 and update_wd=0,
1117-
* but that's a no-op.
1116+
* No need to call update_file() on path when change_branch ==
1117+
* o->branch1 && !alt_path, since that would needlessly touch
1118+
* path. We could call update_file_flags() with update_cache=0
1119+
* and update_wd=0, but that's a no-op.
11181120
*/
1121+
if (change_branch != o->branch1 || alt_path)
1122+
ret = update_file(o, 0, changed_oid, changed_mode, update_path);
11191123
}
1120-
free(renamed);
1124+
free(alt_path);
11211125

11221126
return ret;
11231127
}
11241128

11251129
static int conflict_rename_delete(struct merge_options *o,
11261130
struct diff_filepair *pair,
11271131
const char *rename_branch,
1128-
const char *other_branch)
1132+
const char *delete_branch)
11291133
{
11301134
const struct diff_filespec *orig = pair->one;
11311135
const struct diff_filespec *dest = pair->two;
1132-
const struct object_id *a_oid = NULL;
1133-
const struct object_id *b_oid = NULL;
1134-
int a_mode = 0;
1135-
int b_mode = 0;
1136-
1137-
if (rename_branch == o->branch1) {
1138-
a_oid = &dest->oid;
1139-
a_mode = dest->mode;
1140-
} else {
1141-
b_oid = &dest->oid;
1142-
b_mode = dest->mode;
1143-
}
11441136

11451137
if (handle_change_delete(o,
11461138
o->call_depth ? orig->path : dest->path,
1139+
o->call_depth ? NULL : orig->path,
11471140
&orig->oid, orig->mode,
1148-
a_oid, a_mode,
1149-
b_oid, b_mode,
1141+
&dest->oid, dest->mode,
1142+
rename_branch, delete_branch,
11501143
_("rename"), _("renamed")))
11511144
return -1;
11521145

@@ -1662,11 +1655,27 @@ static int handle_modify_delete(struct merge_options *o,
16621655
struct object_id *a_oid, int a_mode,
16631656
struct object_id *b_oid, int b_mode)
16641657
{
1658+
const char *modify_branch, *delete_branch;
1659+
struct object_id *changed_oid;
1660+
int changed_mode;
1661+
1662+
if (a_oid) {
1663+
modify_branch = o->branch1;
1664+
delete_branch = o->branch2;
1665+
changed_oid = a_oid;
1666+
changed_mode = a_mode;
1667+
} else {
1668+
modify_branch = o->branch2;
1669+
delete_branch = o->branch1;
1670+
changed_oid = b_oid;
1671+
changed_mode = b_mode;
1672+
}
1673+
16651674
return handle_change_delete(o,
1666-
path,
1675+
path, NULL,
16671676
o_oid, o_mode,
1668-
a_oid, a_mode,
1669-
b_oid, b_mode,
1677+
changed_oid, changed_mode,
1678+
modify_branch, delete_branch,
16701679
_("modify"), _("modified"));
16711680
}
16721681

t/t6045-merge-rename-delete.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/sh
2+
3+
test_description='Merge-recursive rename/delete conflict message'
4+
. ./test-lib.sh
5+
6+
test_expect_success 'rename/delete' '
7+
echo foo >A &&
8+
git add A &&
9+
git commit -m "initial" &&
10+
11+
git checkout -b rename &&
12+
git mv A B &&
13+
git commit -m "rename" &&
14+
15+
git checkout master &&
16+
git rm A &&
17+
git commit -m "delete" &&
18+
19+
test_must_fail git merge --strategy=recursive rename >output &&
20+
test_i18ngrep "CONFLICT (rename/delete): A deleted in HEAD and renamed to B in rename. Version rename of B left in tree." output
21+
'
22+
23+
test_done

0 commit comments

Comments
 (0)