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.schinde...@gmx.de>
---
 sequencer.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/sequencer.c b/sequencer.c
index 35fcacbdf0f..5944d3a34eb 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2680,7 +2680,7 @@ static int do_merge(struct commit *commit, const char 
*arg, int arg_len,
        struct commit *head_commit, *merge_commit, *i;
        struct commit_list *bases, *j, *reversed = NULL;
        struct merge_options o;
-       int merge_arg_len, oneline_offset, ret;
+       int merge_arg_len, oneline_offset, can_fast_forward, ret;
        static struct lock_file lock;
        const char *p;
 
@@ -2765,6 +2765,37 @@ static int do_merge(struct commit *commit, const char 
*arg, int arg_len,
                }
        }
 
+       /*
+        * If HEAD is not identical to the first parent of the original merge
+        * commit, we cannot fast-forward.
+        */
+       can_fast_forward = opts->allow_ff && commit && commit->parents &&
+               !oidcmp(&commit->parents->item->object.oid,
+                       &head_commit->object.oid);
+
+       /*
+        * If the merge head is different from the original one, we cannot
+        * fast-forward.
+        */
+       if (can_fast_forward) {
+               struct commit_list *second_parent = commit->parents->next;
+
+               if (second_parent && !second_parent->next &&
+                   oidcmp(&merge_commit->object.oid,
+                          &second_parent->item->object.oid))
+                       can_fast_forward = 0;
+       }
+
+       if (can_fast_forward && commit->parents->next &&
+           !commit->parents->next->next &&
+           !oidcmp(&commit->parents->next->item->object.oid,
+                   &merge_commit->object.oid)) {
+               rollback_lock_file(&lock);
+               ret = fast_forward_to(&commit->object.oid,
+                                     &head_commit->object.oid, 0, opts);
+               goto leave_merge;
+       }
+
        write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ,
                      git_path_merge_head(), 0);
        write_message("no-ff", 5, git_path_merge_mode(), 0);
-- 
2.17.0.windows.1.15.gaa56ade3205


Reply via email to