]> git.ipfire.org Git - thirdparty/git.git/commitdiff
rebase: allow more types of rebases to fast-forward
authorElijah Newren <newren@gmail.com>
Sat, 15 Feb 2020 21:36:31 +0000 (21:36 +0000)
committerJunio C Hamano <gitster@pobox.com>
Sun, 16 Feb 2020 23:40:42 +0000 (15:40 -0800)
In the past, we dis-allowed rebases using the interactive backend from
performing a fast-forward to short-circuit the rebase operation.  This
made sense for explicitly interactive rebases and some implicitly
interactive rebases, but certainly became overly stringent when the
merge backend was re-implemented via the interactive backend.

Just as the am-based rebase has always had to disable the fast-forward
based on a variety of conditions or flags (e.g. --signoff, --whitespace,
etc.), we need to do the same but now with a few more options.  However,
continuing to use REBASE_FORCE for tracking this is problematic because
the interactive backend used it for a different purpose.  (When
REBASE_FORCE wasn't set, the interactive backend would not fast-forward
the whole series but would fast-forward individual "pick" commits at the
beginning of the todo list, and then a squash or something would cause
it to start generating new commits.)  So, introduce a new
allow_preemptive_ff flag contained within cmd_rebase() and use it to
track whether we are going to allow a pre-emptive fast-forward that
short-circuits the whole rebase.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/rebase.c
t/t3432-rebase-fast-forward.sh

index 8264a9243f10a84be8063fe6122f7e02da77d27b..6e9a2fedc7faae9f285fd8e534b07962ff192142 100644 (file)
@@ -1467,6 +1467,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        struct object_id squash_onto;
        char *squash_onto_name = NULL;
        int reschedule_failed_exec = -1;
+       int allow_preemptive_ff = 1;
        struct option builtin_rebase_options[] = {
                OPT_STRING(0, "onto", &options.onto_name,
                           N_("revision"),
@@ -1774,13 +1775,20 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                    state_dir_base, cmd_live_rebase, buf.buf);
        }
 
+       if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
+           (action != ACTION_NONE) ||
+           (exec.nr > 0) ||
+           options.autosquash) {
+               allow_preemptive_ff = 0;
+       }
+
        for (i = 0; i < options.git_am_opts.argc; i++) {
                const char *option = options.git_am_opts.argv[i], *p;
                if (!strcmp(option, "--committer-date-is-author-date") ||
                    !strcmp(option, "--ignore-date") ||
                    !strcmp(option, "--whitespace=fix") ||
                    !strcmp(option, "--whitespace=strip"))
-                       options.flags |= REBASE_FORCE;
+                       allow_preemptive_ff = 0;
                else if (skip_prefix(option, "-C", &p)) {
                        while (*p)
                                if (!isdigit(*(p++)))
@@ -2116,12 +2124,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        /*
         * Check if we are already based on onto with linear history,
         * in which case we could fast-forward without replacing the commits
-        * with new commits recreated by replaying their changes. This
-        * optimization must not be done if this is an interactive rebase.
+        * with new commits recreated by replaying their changes.
+        *
+        * Note that can_fast_forward() initializes merge_base, so we have to
+        * call it before checking allow_preemptive_ff.
         */
        if (can_fast_forward(options.onto, options.upstream, options.restrict_revision,
                    &options.orig_head, &merge_base) &&
-           !is_interactive(&options)) {
+           allow_preemptive_ff) {
                int flag;
 
                if (!(options.flags & REBASE_FORCE)) {
index 7432c0e24150c30cbebbe8b8650e07eb22b34c0d..40388ccf9f3ba589583514a8a81d52935a5e5264 100755 (executable)
@@ -30,6 +30,8 @@ test_rebase_same_head () {
        shift &&
        test_rebase_same_head_ $status_n $what_n $cmp_n "" "$*" &&
        test_rebase_same_head_ $status_f $what_f $cmp_f " --no-ff" "$*"
+       test_rebase_same_head_ $status_n $what_n $cmp_n " --merge" "$*" &&
+       test_rebase_same_head_ $status_f $what_f $cmp_f " --merge --no-ff" "$*"
 }
 
 test_rebase_same_head_ () {