@matheusbsbs / matheus-bagliano / commits / 446247db78
Fork 0

merge: fix numerus bugs around "trivial merge" area

The "trivial merge" codepath wants to optimize itself by making an internal call to the read-tree machinery, but it does not read the index before doing so, and the codepath is never exercised. Incidentally, this failure to read the index upfront means that the safety to refuse doing anything when the index is unmerged does not kick in, either. These two problem are fixed by using read_cache_unmerged() that does read the index before checking if it is unmerged at the beginning of cmd_merge(). The primary logic of the merge, however, assumes that the process never reads the index in-core, and the call to write_cache_as_tree() it makes from write_tree_trivial() will always read from the on-disk index that is prepared the strategy back-ends. This assumption is now broken by the above fix. To fix this issue, we now call discard_cache() before calling write_tree_trivial() when it wants to write the on-disk index as a tree. When multiple strategies are tried, their results are evaluated by reading the resulting index and inspecting it. The codepath needs to make a call to read_cache() for each successful strategy, and for that to work, they need to discard_cache() the one read by the previous round. Also the "trivial merge" forgot that the current commit is one of the parents of the resulting commit. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Aug 23, 2008 at 12:56 UTC 446247db78a733f44d2470afb1f1983d28058159
4 files changed +32 -8
builtin-merge.c
+9 -7
@@ -564,8 +564,6 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote)
564 struct dir_struct dir;
565 struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
566
567 - if (read_cache_unmerged())
568 - die("you need to resolve your current index first");
567 refresh_cache(REFRESH_QUIET);
568
569 fd = hold_locked_index(lock_file, 1);
@@ -651,13 +649,15 @@ static void add_strategies(const char *string, unsigned attr)
649 static int merge_trivial(void)
650 {
651 unsigned char result_tree[20], result_commit[20];
654 - struct commit_list parent;
652 + struct commit_list *parent = xmalloc(sizeof(struct commit_list *));
653
654 write_tree_trivial(result_tree);
655 printf("Wonderful.\n");
658 - parent.item = remoteheads->item;
659 - parent.next = NULL;
660 - commit_tree(merge_msg.buf, result_tree, &parent, result_commit);
656 + parent->item = lookup_commit(head);
657 + parent->next = xmalloc(sizeof(struct commit_list *));
658 + parent->next->item = remoteheads->item;
659 + parent->next->next = NULL;
660 + commit_tree(merge_msg.buf, result_tree, parent, result_commit);
661 finish(result_commit, "In-index merge");
662 drop_save();
663 return 0;
@@ -743,6 +743,7 @@ static int evaluate_result(void)
743 int cnt = 0;
744 struct rev_info rev;
745
746 + discard_cache();
747 if (read_cache() < 0)
748 die("failed to read the cache");
749
@@ -776,7 +777,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
777 struct commit_list **remotes = &remoteheads;
778
779 setup_work_tree();
779 - if (unmerged_cache())
780 + if (read_cache_unmerged())
781 die("You are in the middle of a conflicted merge.");
782
783 /*
@@ -1073,6 +1074,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
1074 }
1075
1076 /* Automerge succeeded. */
1077 + discard_cache();
1078 write_tree_trivial(result_tree);
1079 automerge_was_ok = 1;
1080 break;
t/t3030-merge-recursive.sh
+11
@@ -269,6 +269,17 @@ test_expect_success 'merge-recursive result' '
269
270 '
271
272 +test_expect_success 'fail if the index has unresolved entries' '
273 +
274 + rm -fr [abcd] &&
275 + git checkout -f "$c1" &&
276 +
277 + test_must_fail git merge "$c5" &&
278 + test_must_fail git merge "$c5" 2> out &&
279 + grep "You are in the middle of a conflicted merge" out
280 +
281 +'
282 +
283 test_expect_success 'merge-recursive remove conflict' '
284
285 rm -fr [abcd] &&
t/t7600-merge.sh
+9
@@ -498,4 +498,13 @@ test_expect_success 'merge fast-forward in a dirty tree' '
498
499 test_debug 'gitk --all'
500
501 +test_expect_success 'in-index merge' '
502 + git reset --hard c0 &&
503 + git merge --no-ff -s resolve c1 > out &&
504 + grep "Wonderful." out &&
505 + verify_parents $c0 $c1
506 +'
507 +
508 +test_debug 'gitk --all'
509 +
510 test_done
t/t7605-merge-resolve.sh
+3 -1
@@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' '
36 git diff --exit-code &&
37 test -f c0.c &&
38 test -f c1.c &&
39 - test -f c2.c
39 + test -f c2.c &&
40 + test 3 = $(git ls-tree -r HEAD | wc -l) &&
41 + test 3 = $(git ls-files | wc -l)
42 '
43
44 test_expect_success 'merge c2 to c3 (fails)' '