When there is no "common" tree (for whatever reason), we must not throw a segmentation fault. Noticed by Dave O. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- Sorry, did not have much time, so I only fixed the segfault. Could you verify that the result is correct? merge-recursive.c | 23 +++++-- t/t3031-merge-criscross.sh | 135 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 7 deletions(-) create mode 100755 t/t3031-merge-criscross.sh diff --git a/merge-recursive.c b/merge-recursive.c index a3721ef..920ccc1 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -176,17 +176,26 @@ static int git_merge_trees(int index_only, opts.index_only = 1; else opts.update = 1; - opts.merge = 1; - opts.head_idx = 2; opts.fn = threeway_merge; opts.src_index = &the_index; opts.dst_index = &the_index; - init_tree_desc_from_tree(t+0, common); - init_tree_desc_from_tree(t+1, head); - init_tree_desc_from_tree(t+2, merge); + if (common) { + opts.merge = 1; + opts.head_idx = 2; + init_tree_desc_from_tree(t+0, common); + init_tree_desc_from_tree(t+1, head); + init_tree_desc_from_tree(t+2, merge); + rc = unpack_trees(3, t, &opts); + } + else { + opts.merge = 0; + opts.head_idx = 1; + init_tree_desc_from_tree(t+0, head); + init_tree_desc_from_tree(t+1, merge); + rc = unpack_trees(2, t, &opts); + } - rc = unpack_trees(3, t, &opts); cache_tree_free(&active_cache_tree); return rc; } @@ -1152,7 +1161,7 @@ int merge_trees(struct merge_options *o, common = shift_tree_object(head, common); } - if (sha_eq(common->object.sha1, merge->object.sha1)) { + if (common && sha_eq(common->object.sha1, merge->object.sha1)) { output(o, 0, "Already uptodate!"); *result = head; return 1; diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh new file mode 100755 index 0000000..525afea --- /dev/null +++ b/t/t3031-merge-criscross.sh @@ -0,0 +1,135 @@ +#!/bin/sh + +test_description='merge-recursive backend test' + +. ./test-lib.sh + +# A <- create some files +# / \ +# B C <- cause rename/delete conflicts between B and C +# / \ +# -> 1 1 <- merge-bases for F and G: B1, C1 +# |\ /| +# 2 D E 2 +# | | | | +# | 1 1 | <- overload rename_limit in E1 +# | \ / | +# | X | +# | / \ | +# | / \ | +# |/ \| +# F G <- merge E into B, D into C +# \ / +# \ / +# \ / +# H <- recursive merge crashes +# + +# initialize +test_expect_success 'setup' ' + mkdir data && + + test_debug create a bunch of files && + n=1 && + while test $n -le 1000 + do + echo $n > data/$n && + n=$(($n+1)) || + break + done && + + test_debug check them in && + git add data && + git commit -m A && + git branch A && + + test_debug remove some files in one branch && + git checkout -b B A && + git rm data/99* && + git add data && + git commit -m B && + + test_debug few more commits on B && + echo testB > data/testB && + git add data && + git commit -m B1 && + + test_debug with a branch off of it && + git branch D && + + echo testB2 > data/testB2 && + git add data && + git commit -m B2 && + + test_debug put some commits on D && + git checkout D && + echo testD > data/testD && + git add data && + git commit -m D && + + echo testD1 > data/testD1 && + git add data && + git commit -m D1 && + + test_debug back up to the top, create another branch and cause a rename && + test_debug conflict with the files we deleted earlier && + git checkout -b C A && + git rm --cached data/99* && + rename "s!/9!/moved-9!" data/99* && + git add data && + git commit -m C && + + test_debug few more commits on C && + echo testC > data/testC && + git add data && + git commit -m C1 && + + test_debug with a branch off of it && + git branch E && + + echo testC2 > data/testC2 && + git add data && + git commit -m C2 && + + test_debug put a commits on E && + git checkout E && + echo testE > data/testE && + git add data && + git commit -m E && + + test_debug and now, overload add/delete && + git rm data/[123456]* && + n=10000 && + while test $n -le 11000 + do + echo $n > data/$n && + n=$(($n+1)) || + break + done && + git add data && + git commit -m E1 && + + + test_debug now, merge E into B && + git checkout B && + test_must_fail git merge E && + test_debug force-resolve? && + git add data && + git commit -m F && + git branch F && + + + test_debug and merge D into C && + git checkout C && + test_must_fail git merge D && + test_debug force-resolve? && + git add data && + git commit -m G && + git branch G +' + +test_expect_failure 'now, force a recursive merge between F and G' ' + git merge F +' + +test_done -- 1.6.2.1.493.g67cf3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html