Skip to content

Commit

Permalink
merge-recursive: do not look at the index during recursive merge
Browse files Browse the repository at this point in the history
When merging another branch into ours, if their tree is the same as
the common ancestor's, we can declare that our tree represents the
result of three-way merge.  In such a case, the recursive merge
backend incorrectly used to create a commit out of our index, even
when the index has changes.

A recent fix attempted to prevent this by adding a comparison
between "our" tree and the index, but forgot that this check must be
restricted only to the outermost merge.  Inner merges performed by
the recursive backend across merge bases are by definition made from
scratch without having any local changes added to the index.  The
call to index_has_changes() during an inner merge is working on the
index that has no relation to the merge being performed, preventing
legitimate merges from getting carried out.

Fix it by limiting the check to the outermost merge.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
gitster committed Jan 9, 2018
1 parent 65170c0 commit f309e8e
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
2 changes: 1 addition & 1 deletion merge-recursive.c
Original file line number Diff line number Diff line change
Expand Up @@ -1954,7 +1954,7 @@ int merge_trees(struct merge_options *o,
if (oid_eq(&common->object.oid, &merge->object.oid)) {
struct strbuf sb = STRBUF_INIT;

if (index_has_changes(&sb)) {
if (!o->call_depth && index_has_changes(&sb)) {
err(o, _("Dirty index: cannot merge (dirty: %s)"),
sb.buf);
return 0;
Expand Down
50 changes: 50 additions & 0 deletions t/t3030-merge-recursive.sh
Original file line number Diff line number Diff line change
Expand Up @@ -678,4 +678,54 @@ test_expect_success 'merge-recursive remembers the names of all base trees' '
test_cmp expect actual
'

test_expect_success 'merge-recursive internal merge resolves to the sameness' '
git reset --hard HEAD &&
# We are going to create a history leading to two criss-cross
# branches A and B. The common ancestor at the bottom, O0,
# has two child commits O1 and O2, both of which will be merge
# base between A and B, like so:
#
# O1---A
# / \ /
# O0 .
# \ / \
# O2---B
#
# The recently added "check to see if the index is different from
# the tree into which something else is getting merged" check must
# NOT kick in when an inner merge between O1 and O2 is made. Both
# O1 and O2 happen to have the same tree as O0 in this test to
# trigger the bug---whether the inner merge is made by merging O2
# into O1 or O1 into O2, their common ancestor O0 and the branch
# being merged have the same tree. We should not trigger the "is
# the index dirty?" check in this case.
echo "zero" >file &&
git add file &&
test_tick &&
git commit -m "O0" &&
O0=$(git rev-parse HEAD) &&
test_tick &&
git commit --allow-empty -m "O1" &&
O1=$(git rev-parse HEAD) &&
git reset --hard $O0 &&
test_tick &&
git commit --allow-empty -m "O2" &&
O2=$(git rev-parse HEAD) &&
test_tick &&
git merge -s ours $O1 &&
B=$(git rev-parse HEAD) &&
git reset --hard $O1 &&
test_tick &&
git merge -s ours $O2 &&
A=$(git rev-parse HEAD) &&
git merge $B
'

test_done

0 comments on commit f309e8e

Please sign in to comment.