merge-recursive: Make dead code for rename/rename(2to1) conflicts undead
The code for rename_rename_2to1 conflicts (two files both being renamed to the same filename) was dead since the rename/add path was always being independently triggered for each of the renames instead. Further, reviving the dead code showed that it was inherently buggy and would always segfault -- among a few other bugs. Move the else-if branch for the rename/rename block before the rename/add block to make sure it is checked first, and fix up the rename/rename(2to1) code segments to make it handle most cases. Work is still needed to handle higher dimensional corner cases such as rename/rename/modify/modify issues. 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
0a6b87126e6a4e2649f6da23db67eeaad11d102e
2 files changed
+57
-30
merge-recursive.c
+48
-22
@@ -996,17 +996,36 @@ static void conflict_rename_rename_2to1(struct merge_options *o,
996
struct rename *ren2,
997
const char *branch2)
998
{
999
+ char *path = ren1->pair->two->path; /* same as ren2->pair->two->path */
1000
/* Two files were renamed to the same thing. */
1000
- char *new_path1 = unique_path(o, ren1->pair->two->path, branch1);
1001
- char *new_path2 = unique_path(o, ren2->pair->two->path, branch2);
1002
- output(o, 1, "Renaming %s to %s and %s to %s instead",
1003
- ren1->pair->one->path, new_path1,
1004
- ren2->pair->one->path, new_path2);
1005
- remove_file(o, 0, ren1->pair->two->path, 0);
1006
- update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path1);
1007
- update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, new_path2);
1008
- free(new_path2);
1009
- free(new_path1);
1001
+ if (o->call_depth) {
1002
+ struct merge_file_info mfi;
1003
+ struct diff_filespec one, a, b;
1004
+
1005
+ one.path = a.path = b.path = path;
1006
+ hashcpy(one.sha1, null_sha1);
1007
+ one.mode = 0;
1008
+ hashcpy(a.sha1, ren1->pair->two->sha1);
1009
+ a.mode = ren1->pair->two->mode;
1010
+ hashcpy(b.sha1, ren2->pair->two->sha1);
1011
+ b.mode = ren2->pair->two->mode;
1012
+ mfi = merge_file(o, &one, &a, &b, branch1, branch2);
1013
+ output(o, 1, "Adding merged %s", path);
1014
+ update_file(o, 0, mfi.sha, mfi.mode, path);
1015
+ } else {
1016
+ char *new_path1 = unique_path(o, path, branch1);
1017
+ char *new_path2 = unique_path(o, path, branch2);
1018
+ output(o, 1, "Renaming %s to %s and %s to %s instead",
1019
+ ren1->pair->one->path, new_path1,
1020
+ ren2->pair->one->path, new_path2);
1021
+ remove_file(o, 0, path, 0);
1022
+ update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode,
1023
+ new_path1);
1024
+ update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode,
1025
+ new_path2);
1026
+ free(new_path2);
1027
+ free(new_path1);
1028
+ }
1029
}
1030
1031
static int process_renames(struct merge_options *o,
@@ -1021,12 +1040,12 @@ static int process_renames(struct merge_options *o,
1040
for (i = 0; i < a_renames->nr; i++) {
1041
sre = a_renames->items[i].util;
1042
string_list_insert(&a_by_dst, sre->pair->two->path)->util
1024
- = sre->dst_entry;
1043
+ = (void *)sre;
1044
}
1045
for (i = 0; i < b_renames->nr; i++) {
1046
sre = b_renames->items[i].util;
1047
string_list_insert(&b_by_dst, sre->pair->two->path)->util
1029
- = sre->dst_entry;
1048
+ = (void *)sre;
1049
}
1050
1051
for (i = 0, j = 0; i < a_renames->nr || j < b_renames->nr;) {
@@ -1138,6 +1157,23 @@ static int process_renames(struct merge_options *o,
1157
clean_merge = 0;
1158
conflict_rename_delete(o, ren1->pair, branch1, branch2);
1159
}
1160
+ } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
1161
+ char *ren2_src, *ren2_dst;
1162
+ ren2 = item->util;
1163
+ ren2_src = ren2->pair->one->path;
1164
+ ren2_dst = ren2->pair->two->path;
1165
+
1166
+ clean_merge = 0;
1167
+ ren2->processed = 1;
1168
+ remove_file(o, 1, ren2_src,
1169
+ renamed_stage == 3 || would_lose_untracked(ren1_src));
1170
+
1171
+ output(o, 1, "CONFLICT (rename/rename): "
1172
+ "Rename %s->%s in %s. "
1173
+ "Rename %s->%s in %s",
1174
+ ren1_src, ren1_dst, branch1,
1175
+ ren2_src, ren2_dst, branch2);
1176
+ conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
1177
} else if ((dst_other.mode == ren1->pair->two->mode) &&
1178
sha_eq(dst_other.sha1, ren1->pair->two->sha1)) {
1179
/* Added file on the other side
@@ -1178,16 +1214,6 @@ static int process_renames(struct merge_options *o,
1214
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
1215
free(new_path);
1216
}
1181
- } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
1182
- ren2 = item->util;
1183
- clean_merge = 0;
1184
- ren2->processed = 1;
1185
- output(o, 1, "CONFLICT (rename/rename): "
1186
- "Rename %s->%s in %s. "
1187
- "Rename %s->%s in %s",
1188
- ren1_src, ren1_dst, branch1,
1189
- ren2->pair->one->path, ren2->pair->two->path, branch2);
1190
- conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
1217
} else
1218
try_merge = 1;
1219
t/t6036-recursive-corner-cases.sh
+9
-8
@@ -66,13 +66,13 @@ test_expect_success 'merge simple rename+criss-cross with no modifications' '
66
test $(git rev-parse :2:three) = $(git rev-parse L2:three) &&
67
test $(git rev-parse :3:three) = $(git rev-parse R2:three) &&
68
69
- cp two merged &&
69
+ cp one merged &&
70
>empty &&
71
test_must_fail git merge-file \
72
- -L "Temporary merge branch 2" \
73
- -L "" \
72
-L "Temporary merge branch 1" \
75
- merged empty one &&
73
+ -L "" \
74
+ -L "Temporary merge branch 2" \
75
+ merged empty two &&
76
test $(git rev-parse :1:three) = $(git hash-object merged)
77
'
78
@@ -145,11 +145,12 @@ test_expect_success 'merge criss-cross + rename merges with basic modification'
145
cp one merge-me &&
146
>empty &&
147
test_must_fail git merge-file \
148
- -L "Temporary merge branch 2" \
149
- -L "" \
148
-L "Temporary merge branch 1" \
151
- merged empty merge-me &&
152
- test $(git rev-parse :1:three) = $(git hash-object merged)
149
+ -L "" \
150
+ -L "Temporary merge branch 2" \
151
+ merge-me empty merged &&
152
+
153
+ test $(git rev-parse :1:three) = $(git hash-object merge-me)
154
'
155
156
#