merge-recursive: Defer rename/rename(2to1) handling until process_entry

This puts the code for the different types of double rename conflicts closer together (fewer lines of other code separating the two paths) and increases similarity between how they are handled. 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 461f5041178c02f3360920f42b542df7add0033f
1 file changed +62 -42
merge-recursive.c
+62 -42
@@ -67,7 +67,8 @@ enum rename_type {
67 RENAME_NORMAL = 0,
68 RENAME_DELETE,
69 RENAME_ONE_FILE_TO_ONE,
70 - RENAME_ONE_FILE_TO_TWO
70 + RENAME_ONE_FILE_TO_TWO,
71 + RENAME_TWO_FILES_TO_ONE
72 };
73
74 struct rename_conflict_info {
@@ -1019,32 +1020,40 @@ static void conflict_rename_rename_1to2(struct merge_options *o,
1020 }
1021
1022 static void conflict_rename_rename_2to1(struct merge_options *o,
1022 - struct rename *ren1,
1023 - const char *branch1,
1024 - struct rename *ren2,
1025 - const char *branch2)
1023 + struct rename_conflict_info *ci)
1024 {
1027 - char *path = ren1->pair->two->path; /* same as ren2->pair->two->path */
1028 - /* Two files were renamed to the same thing. */
1025 + /* Two files, a & b, were renamed to the same thing, c. */
1026 + struct diff_filespec *a = ci->pair1->one;
1027 + struct diff_filespec *b = ci->pair2->one;
1028 + struct diff_filespec *c1 = ci->pair1->two;
1029 + struct diff_filespec *c2 = ci->pair2->two;
1030 + char *path = c1->path; /* == c2->path */
1031 +
1032 + output(o, 1, "CONFLICT (rename/rename): "
1033 + "Rename %s->%s in %s. "
1034 + "Rename %s->%s in %s",
1035 + a->path, c1->path, ci->branch1,
1036 + b->path, c2->path, ci->branch2);
1037 +
1038 + remove_file(o, 1, a->path, would_lose_untracked(a->path));
1039 + remove_file(o, 1, b->path, would_lose_untracked(b->path));
1040 +
1041 if (o->call_depth) {
1042 struct merge_file_info mfi;
1043 mfi = merge_file(o, path, null_sha1, 0,
1032 - ren1->pair->two->sha1, ren1->pair->two->mode,
1033 - ren2->pair->two->sha1, ren2->pair->two->mode,
1034 - branch1, branch2);
1044 + c1->sha1, c1->mode,
1045 + c2->sha1, c2->mode,
1046 + ci->branch1, ci->branch2);
1047 output(o, 1, "Adding merged %s", path);
1048 update_file(o, 0, mfi.sha, mfi.mode, path);
1049 } else {
1038 - char *new_path1 = unique_path(o, path, branch1);
1039 - char *new_path2 = unique_path(o, path, branch2);
1050 + char *new_path1 = unique_path(o, path, ci->branch1);
1051 + char *new_path2 = unique_path(o, path, ci->branch2);
1052 output(o, 1, "Renaming %s to %s and %s to %s instead",
1041 - ren1->pair->one->path, new_path1,
1042 - ren2->pair->one->path, new_path2);
1053 + a->path, new_path1, b->path, new_path2);
1054 remove_file(o, 0, path, 0);
1044 - update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode,
1045 - new_path1);
1046 - update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode,
1047 - new_path2);
1055 + update_file(o, 0, c1->sha1, c1->mode, new_path1);
1056 + update_file(o, 0, c2->sha1, c2->mode, new_path2);
1057 free(new_path2);
1058 free(new_path1);
1059 }
@@ -1075,6 +1084,7 @@ static int process_renames(struct merge_options *o,
1084 struct rename *ren1 = NULL, *ren2 = NULL;
1085 const char *branch1, *branch2;
1086 const char *ren1_src, *ren1_dst;
1087 + struct string_list_item *lookup;
1088
1089 if (i >= a_renames->nr) {
1090 ren2 = b_renames->items[j++].util;
@@ -1106,30 +1116,30 @@ static int process_renames(struct merge_options *o,
1116 ren1 = tmp;
1117 }
1118
1119 + if (ren1->processed)
1120 + continue;
1121 + ren1->processed = 1;
1122 ren1->dst_entry->processed = 1;
1123 /* BUG: We should only mark src_entry as processed if we
1124 * are not dealing with a rename + add-source case.
1125 */
1126 ren1->src_entry->processed = 1;
1127
1115 - if (ren1->processed)
1116 - continue;
1117 - ren1->processed = 1;
1118 -
1128 ren1_src = ren1->pair->one->path;
1129 ren1_dst = ren1->pair->two->path;
1130
1131 if (ren2) {
1132 + /* One file renamed on both sides */
1133 const char *ren2_src = ren2->pair->one->path;
1134 const char *ren2_dst = ren2->pair->two->path;
1135 enum rename_type rename_type;
1126 - /* Renamed in 1 and renamed in 2 */
1136 if (strcmp(ren1_src, ren2_src) != 0)
1128 - die("ren1.src != ren2.src");
1137 + die("ren1_src != ren2_src");
1138 ren2->dst_entry->processed = 1;
1139 ren2->processed = 1;
1140 if (strcmp(ren1_dst, ren2_dst) != 0) {
1141 rename_type = RENAME_ONE_FILE_TO_TWO;
1142 + clean_merge = 0;
1143 } else {
1144 rename_type = RENAME_ONE_FILE_TO_ONE;
1145 /* BUG: We should only remove ren1_src in
@@ -1149,9 +1159,32 @@ static int process_renames(struct merge_options *o,
1159 branch2,
1160 ren1->dst_entry,
1161 ren2->dst_entry);
1162 + } else if ((lookup = string_list_lookup(renames2Dst, ren1_dst))) {
1163 + /* Two different files renamed to the same thing */
1164 + char *ren2_dst;
1165 + ren2 = lookup->util;
1166 + ren2_dst = ren2->pair->two->path;
1167 + if (strcmp(ren1_dst, ren2_dst) != 0)
1168 + die("ren1_dst != ren2_dst");
1169 +
1170 + clean_merge = 0;
1171 + ren2->processed = 1;
1172 + /*
1173 + * BUG: We should only mark src_entry as processed
1174 + * if we are not dealing with a rename + add-source
1175 + * case.
1176 + */
1177 + ren2->src_entry->processed = 1;
1178 +
1179 + setup_rename_conflict_info(RENAME_TWO_FILES_TO_ONE,
1180 + ren1->pair,
1181 + ren2->pair,
1182 + branch1,
1183 + branch2,
1184 + ren1->dst_entry,
1185 + ren2->dst_entry);
1186 } else {
1187 /* Renamed in 1, maybe changed in 2 */
1154 - struct string_list_item *item;
1188 /* we only use sha1 and mode of these */
1189 struct diff_filespec src_other, dst_other;
1190 int try_merge;
@@ -1186,23 +1219,6 @@ static int process_renames(struct merge_options *o,
1219 branch2,
1220 ren1->dst_entry,
1221 NULL);
1189 - } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
1190 - char *ren2_src, *ren2_dst;
1191 - ren2 = item->util;
1192 - ren2_src = ren2->pair->one->path;
1193 - ren2_dst = ren2->pair->two->path;
1194 -
1195 - clean_merge = 0;
1196 - ren2->processed = 1;
1197 - remove_file(o, 1, ren2_src,
1198 - renamed_stage == 3 || would_lose_untracked(ren1_src));
1199 -
1200 - output(o, 1, "CONFLICT (rename/rename): "
1201 - "Rename %s->%s in %s. "
1202 - "Rename %s->%s in %s",
1203 - ren1_src, ren1_dst, branch1,
1204 - ren2_src, ren2_dst, branch2);
1205 - conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
1222 } else if ((dst_other.mode == ren1->pair->two->mode) &&
1223 sha_eq(dst_other.sha1, ren1->pair->two->sha1)) {
1224 /* Added file on the other side
@@ -1502,6 +1518,10 @@ static int process_entry(struct merge_options *o,
1518 clean_merge = 0;
1519 conflict_rename_rename_1to2(o, conflict_info);
1520 break;
1521 + case RENAME_TWO_FILES_TO_ONE:
1522 + clean_merge = 0;
1523 + conflict_rename_rename_2to1(o, conflict_info);
1524 + break;
1525 default:
1526 entry->processed = 0;
1527 break;