merge-recursive: Fix working copy handling for rename/rename/add/add

If either side of a rename/rename(1to2) conflict is itself also involved in a rename/add-dest conflict, then we need to make sure both the rename and the added file appear in the working copy. 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 3672c971483020ba5255576aec0be670c76d019b
2 files changed +58 -26
merge-recursive.c
+48 -25
@@ -1084,6 +1084,52 @@ static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
1084 return target;
1085 }
1086
1087 +static void handle_file(struct merge_options *o,
1088 + struct diff_filespec *rename,
1089 + int stage,
1090 + struct rename_conflict_info *ci)
1091 +{
1092 + char *dst_name = rename->path;
1093 + struct stage_data *dst_entry;
1094 + const char *cur_branch, *other_branch;
1095 + struct diff_filespec other;
1096 + struct diff_filespec *add;
1097 +
1098 + if (stage == 2) {
1099 + dst_entry = ci->dst_entry1;
1100 + cur_branch = ci->branch1;
1101 + other_branch = ci->branch2;
1102 + } else {
1103 + dst_entry = ci->dst_entry2;
1104 + cur_branch = ci->branch2;
1105 + other_branch = ci->branch1;
1106 + }
1107 +
1108 + add = filespec_from_entry(&other, dst_entry, stage ^ 1);
1109 + if (stage == 2)
1110 + update_stages(rename->path, NULL, rename, add);
1111 + else
1112 + update_stages(rename->path, NULL, add, rename);
1113 +
1114 + if (add) {
1115 + char *add_name = unique_path(o, rename->path, other_branch);
1116 + update_file(o, 0, add->sha1, add->mode, add_name);
1117 +
1118 + remove_file(o, 0, rename->path, 0);
1119 + dst_name = unique_path(o, rename->path, cur_branch);
1120 + } else {
1121 + if (dir_in_way(rename->path, !o->call_depth)) {
1122 + dst_name = unique_path(o, rename->path, cur_branch);
1123 + output(o, 1, "%s is a directory in %s adding as %s instead",
1124 + rename->path, other_branch, dst_name);
1125 + }
1126 + }
1127 + update_file(o, 0, rename->sha1, rename->mode, dst_name);
1128 +
1129 + if (dst_name != rename->path)
1130 + free(dst_name);
1131 +}
1132 +
1133 static void conflict_rename_rename_1to2(struct merge_options *o,
1134 struct rename_conflict_info *ci)
1135 {
@@ -1091,10 +1137,6 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
1137 struct diff_filespec *one = ci->pair1->one;
1138 struct diff_filespec *a = ci->pair1->two;
1139 struct diff_filespec *b = ci->pair2->two;
1094 - const char *dst_name_a = a->path;
1095 - const char *dst_name_b = b->path;
1096 - char *del[2];
1097 - int delp = 0;
1140
1141 output(o, 1, "CONFLICT (rename/rename): "
1142 "Rename \"%s\"->\"%s\" in branch \"%s\" "
@@ -1102,16 +1144,6 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
1144 one->path, a->path, ci->branch1,
1145 one->path, b->path, ci->branch2,
1146 o->call_depth ? " (left unresolved)" : "");
1105 - if (dir_in_way(a->path, !o->call_depth)) {
1106 - dst_name_a = del[delp++] = unique_path(o, a->path, ci->branch1);
1107 - output(o, 1, "%s is a directory in %s adding as %s instead",
1108 - a->path, ci->branch2, dst_name_a);
1109 - }
1110 - if (dir_in_way(b->path, !o->call_depth)) {
1111 - dst_name_b = del[delp++] = unique_path(o, b->path, ci->branch2);
1112 - output(o, 1, "%s is a directory in %s adding as %s instead",
1113 - b->path, ci->branch1, dst_name_b);
1114 - }
1147 if (o->call_depth) {
1148 struct merge_file_info mfi;
1149 mfi = merge_file(o, one->path,
@@ -1129,18 +1161,9 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
1161 remove_file_from_cache(a->path);
1162 remove_file_from_cache(b->path);
1163 } else {
1132 - struct diff_filespec other;
1133 - update_stages(a->path, NULL,
1134 - a, filespec_from_entry(&other, ci->dst_entry1, 3));
1135 -
1136 - update_stages(b->path, NULL,
1137 - filespec_from_entry(&other, ci->dst_entry2, 2), b);
1138 -
1139 - update_file(o, 0, a->sha1, a->mode, dst_name_a);
1140 - update_file(o, 0, b->sha1, b->mode, dst_name_b);
1164 + handle_file(o, a, 2, ci);
1165 + handle_file(o, b, 3, ci);
1166 }
1142 - while (delp--)
1143 - free(del[delp]);
1167 }
1168
1169 static void conflict_rename_rename_2to1(struct merge_options *o,
t/t6042-merge-rename-corner-cases.sh
+10 -1
@@ -558,12 +558,21 @@ test_expect_success 'rename/rename/add-dest merge still knows about conflicting
558 test 5 -eq $(git ls-files -s | wc -l) &&
559 test 2 -eq $(git ls-files -u b | wc -l) &&
560 test 2 -eq $(git ls-files -u c | wc -l) &&
561 + test 4 -eq $(git ls-files -o | wc -l) &&
562
563 test $(git rev-parse :1:a) = $(git rev-parse A:a) &&
564 test $(git rev-parse :2:b) = $(git rev-parse C:b) &&
565 test $(git rev-parse :3:b) = $(git rev-parse B:b) &&
566 test $(git rev-parse :2:c) = $(git rev-parse C:c) &&
566 - test $(git rev-parse :3:c) = $(git rev-parse B:c)
567 + test $(git rev-parse :3:c) = $(git rev-parse B:c) &&
568 +
569 + test $(git hash-object c~HEAD) = $(git rev-parse C:c) &&
570 + test $(git hash-object c~B\^0) = $(git rev-parse B:c) &&
571 + test $(git hash-object b~HEAD) = $(git rev-parse C:b) &&
572 + test $(git hash-object b~B\^0) = $(git rev-parse B:b) &&
573 +
574 + test ! -f b &&
575 + test ! -f c
576 '
577
578 test_done