builtin/merge.c: fix a bug with trivial merges

If read_tree_trivial() succeeds and produces a tree that is already
in the object store, then the index is not written to disk, leaving
it out-of-sync with both HEAD and the working tree.

In order to write the index back out to disk after a merge,
write_index_locked() needs to be called.  For most merge strategies, this
is done from try_merge_strategy().  For fast forward updates, this is
done from checkout_fast_forward().  When trivial merges work, the call to
write_index_locked() is buried a little deeper:

  merge_trivial()
  -> write_tree_trivial()
     -> write_cache_as_tree()
        -> write_index_as_tree()
           -> write_locked_index()

However, it is only called when !cache_tree_fully_valid(), which is how
this bug is triggered.  But that also shows why this bug doesn't affect
any other merge strategies or cases.

Add a direct call to write_index_locked() from merge_trivial() to fix
this issue.  Since the indirect call to write_locked_index() was
conditional on cache_tree_fully_valid(), it won't be written twice.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Elijah Newren 2016-04-09 23:13:40 -07:00 committed by Junio C Hamano
parent ef7d3621d7
commit 40d71940b6
2 changed files with 9 additions and 1 deletions

View File

@ -822,6 +822,14 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
{
unsigned char result_tree[20], result_commit[20];
struct commit_list *parents, **pptr = &parents;
static struct lock_file lock;
hold_locked_index(&lock, 1);
refresh_cache(REFRESH_QUIET);
if (active_cache_changed &&
write_locked_index(&the_index, &lock, COMMIT_LOCK))
return error(_("Unable to write index."));
rollback_lock_file(&lock);
write_tree_trivial(result_tree);
printf(_("Wonderful.\n"));

View File

@ -43,7 +43,7 @@ merge_c1_to_c2_cmds='
test_expect_success 'merge c1 to c2' "$merge_c1_to_c2_cmds"
test_expect_failure 'merge c1 to c2, again' "$merge_c1_to_c2_cmds"
test_expect_success 'merge c1 to c2, again' "$merge_c1_to_c2_cmds"
test_expect_success 'merge c2 to c3 (fails)' '
git reset --hard c2 &&