sequencer: fast-forward `merge` commands, if possible

Just like with regular `pick` commands, if we are trying to rebase a merge commit, we now test whether the parents of said commit match HEAD and the commits to be merged, and fast-forward if possible. This is not only faster, but also avoids unnecessary proliferation of new objects. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Apr 25, 2018 at 14:28 UTC d1e8b0114bef98e8efe3f8d35430300ff9e00443
1 file changed +32 -1
sequencer.c
+32 -1
@@ -2687,7 +2687,7 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
2687 struct commit *head_commit, *merge_commit, *i;
2688 struct commit_list *bases, *j, *reversed = NULL;
2689 struct merge_options o;
2690 - int merge_arg_len, oneline_offset, ret;
2690 + int merge_arg_len, oneline_offset, can_fast_forward, ret;
2691 static struct lock_file lock;
2692 const char *p;
2693
@@ -2772,6 +2772,37 @@ static int do_merge(struct commit *commit, const char *arg, int arg_len,
2772 }
2773 }
2774
2775 + /*
2776 + * If HEAD is not identical to the first parent of the original merge
2777 + * commit, we cannot fast-forward.
2778 + */
2779 + can_fast_forward = opts->allow_ff && commit && commit->parents &&
2780 + !oidcmp(&commit->parents->item->object.oid,
2781 + &head_commit->object.oid);
2782 +
2783 + /*
2784 + * If the merge head is different from the original one, we cannot
2785 + * fast-forward.
2786 + */
2787 + if (can_fast_forward) {
2788 + struct commit_list *second_parent = commit->parents->next;
2789 +
2790 + if (second_parent && !second_parent->next &&
2791 + oidcmp(&merge_commit->object.oid,
2792 + &second_parent->item->object.oid))
2793 + can_fast_forward = 0;
2794 + }
2795 +
2796 + if (can_fast_forward && commit->parents->next &&
2797 + !commit->parents->next->next &&
2798 + !oidcmp(&commit->parents->next->item->object.oid,
2799 + &merge_commit->object.oid)) {
2800 + rollback_lock_file(&lock);
2801 + ret = fast_forward_to(&commit->object.oid,
2802 + &head_commit->object.oid, 0, opts);
2803 + goto leave_merge;
2804 + }
2805 +
2806 write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
2807 git_path_merge_head(), 0);
2808 write_message("no-ff", 5, git_path_merge_mode(), 0);