merge-recursive: don't segfault while handling rename clashes
When a branch moves A to B while the other branch created B (or moved C to B), the code tried to rename one of them to B~something to preserve both versions, and failed to register temporary resolution for the original path B at stage#0 during virtual ancestor computation. This left the index in unmerged state and caused a segfault. A better solution is to merge these two versions of B's in place and use the (potentially conflicting) result as the intermediate merge result in the virtual ancestor. Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano committed
Jul 30, 2009 at 17:38 UTC
c94736a27f89bfc268aed0de7264deecdc136a58
2 files changed
+80
-3
merge-recursive.c
+25
-3
@@ -947,9 +947,31 @@ static int process_renames(struct merge_options *o,
947
"%s added in %s",
948
ren1_src, ren1_dst, branch1,
949
ren1_dst, branch2);
950
- new_path = unique_path(o, ren1_dst, branch2);
951
- output(o, 1, "Adding as %s instead", new_path);
952
- update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
950
+ if (o->call_depth) {
951
+ struct merge_file_info mfi;
952
+ struct diff_filespec one, a, b;
953
+
954
+ one.path = a.path = b.path =
955
+ (char *)ren1_dst;
956
+ hashcpy(one.sha1, null_sha1);
957
+ one.mode = 0;
958
+ hashcpy(a.sha1, ren1->pair->two->sha1);
959
+ a.mode = ren1->pair->two->mode;
960
+ hashcpy(b.sha1, dst_other.sha1);
961
+ b.mode = dst_other.mode;
962
+ mfi = merge_file(o, &one, &a, &b,
963
+ branch1,
964
+ branch2);
965
+ output(o, 1, "Adding merged %s", ren1_dst);
966
+ update_file(o, 0,
967
+ mfi.sha,
968
+ mfi.mode,
969
+ ren1_dst);
970
+ } else {
971
+ new_path = unique_path(o, ren1_dst, branch2);
972
+ output(o, 1, "Adding as %s instead", new_path);
973
+ update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
974
+ }
975
} else if ((item = string_list_lookup(ren1_dst, renames2Dst))) {
976
ren2 = item->util;
977
clean_merge = 0;
t/t6036-recursive-corner-cases.sh
new
+55
@@ -0,0 +1,55 @@
1
+#!/bin/sh
2
+
3
+test_description='recursive merge corner cases'
4
+
5
+. ./test-lib.sh
6
+
7
+#
8
+# L1 L2
9
+# o---o
10
+# / \ / \
11
+# o X ?
12
+# \ / \ /
13
+# o---o
14
+# R1 R2
15
+#
16
+
17
+test_expect_success setup '
18
+ ten="0 1 2 3 4 5 6 7 8 9"
19
+ for i in $ten
20
+ do
21
+ echo line $i in a sample file
22
+ done >one &&
23
+ for i in $ten
24
+ do
25
+ echo line $i in another sample file
26
+ done >two &&
27
+ git add one two &&
28
+ test_tick && git commit -m initial &&
29
+
30
+ git branch L1 &&
31
+ git checkout -b R1 &&
32
+ git mv one three &&
33
+ test_tick && git commit -m R1 &&
34
+
35
+ git checkout L1 &&
36
+ git mv two three &&
37
+ test_tick && git commit -m L1 &&
38
+
39
+ git checkout L1^0 &&
40
+ test_tick && git merge -s ours R1 &&
41
+ git tag L2 &&
42
+
43
+ git checkout R1^0 &&
44
+ test_tick && git merge -s ours L1 &&
45
+ git tag R2
46
+'
47
+
48
+test_expect_success merge '
49
+ git reset --hard &&
50
+ git checkout L2^0 &&
51
+
52
+ test_must_fail git merge -s recursive R2^0
53
+'
54
+
55
+test_done