]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'en/merge-ort-api-null-impl'
authorJunio C Hamano <gitster@pobox.com>
Wed, 18 Nov 2020 21:32:53 +0000 (13:32 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 18 Nov 2020 21:32:53 +0000 (13:32 -0800)
Preparation for a new merge strategy.

* en/merge-ort-api-null-impl:
  merge,rebase,revert: select ort or recursive by config or environment
  fast-rebase: demonstrate merge-ort's API via new test-tool command
  merge-ort-wrappers: new convience wrappers to mimic the old merge API
  merge-ort: barebones API of new merge strategy with empty implementation

1  2 
Makefile
builtin/merge.c
builtin/rebase.c
builtin/revert.c
sequencer.c
sequencer.h
t/helper/test-tool.c
t/helper/test-tool.h

diff --combined Makefile
index fea5ade9b9506d05a66f2453a0055a191dae68a7,8d531bb7944f3984444bb51161a371701b27bf3c..dd1cf41e007a0036e18eef4b0acae505ec52f168
+++ b/Makefile
@@@ -694,7 -694,6 +694,7 @@@ TEST_BUILTINS_OBJS += test-advise.
  TEST_BUILTINS_OBJS += test-bloom.o
  TEST_BUILTINS_OBJS += test-chmtime.o
  TEST_BUILTINS_OBJS += test-config.o
 +TEST_BUILTINS_OBJS += test-crontab.o
  TEST_BUILTINS_OBJS += test-ctype.o
  TEST_BUILTINS_OBJS += test-date.o
  TEST_BUILTINS_OBJS += test-delta.o
@@@ -705,6 -704,7 +705,7 @@@ TEST_BUILTINS_OBJS += test-dump-fsmonit
  TEST_BUILTINS_OBJS += test-dump-split-index.o
  TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
  TEST_BUILTINS_OBJS += test-example-decorate.o
+ TEST_BUILTINS_OBJS += test-fast-rebase.o
  TEST_BUILTINS_OBJS += test-genrandom.o
  TEST_BUILTINS_OBJS += test-genzeros.o
  TEST_BUILTINS_OBJS += test-hash-speed.o
@@@ -922,6 -922,8 +923,8 @@@ LIB_OBJS += mailmap.
  LIB_OBJS += match-trees.o
  LIB_OBJS += mem-pool.o
  LIB_OBJS += merge-blobs.o
+ LIB_OBJS += merge-ort.o
+ LIB_OBJS += merge-ort-wrappers.o
  LIB_OBJS += merge-recursive.o
  LIB_OBJS += merge.o
  LIB_OBJS += mergesort.o
@@@ -1090,7 -1092,6 +1093,7 @@@ BUILTIN_OBJS += builtin/fetch-pack.
  BUILTIN_OBJS += builtin/fetch.o
  BUILTIN_OBJS += builtin/fmt-merge-msg.o
  BUILTIN_OBJS += builtin/for-each-ref.o
 +BUILTIN_OBJS += builtin/for-each-repo.o
  BUILTIN_OBJS += builtin/fsck.o
  BUILTIN_OBJS += builtin/gc.o
  BUILTIN_OBJS += builtin/get-tar-commit-id.o
@@@ -2769,9 -2770,6 +2772,9 @@@ ifdef GIT_INTEROP_MAKE_OPT
  endif
  ifdef GIT_TEST_INDEX_VERSION
        @echo GIT_TEST_INDEX_VERSION=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_INDEX_VERSION)))'\' >>$@+
 +endif
 +ifdef GIT_TEST_PERL_FATAL_WARNINGS
 +      @echo GIT_TEST_PERL_FATAL_WARNINGS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_PERL_FATAL_WARNINGS)))'\' >>$@+
  endif
        @if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
  
@@@ -3055,6 -3053,9 +3058,6 @@@ quick-install-html
  
  ### Maintainer's dist rules
  
 -# Allow tweaking to hide local environment effects, like perm bits.
 -# With GNU tar, "--mode=u+rwX,og+rX,og-w" would be a good idea, for example.
 -TAR_DIST_EXTRA_OPTS =
  GIT_TARNAME = git-$(GIT_VERSION)
  GIT_ARCHIVE_EXTRA_FILES = \
        --prefix=$(GIT_TARNAME)/ \
@@@ -3104,15 -3105,11 +3107,15 @@@ artifacts-tar:: $(ALL_COMMANDS_TO_INSTA
  htmldocs = git-htmldocs-$(GIT_VERSION)
  manpages = git-manpages-$(GIT_VERSION)
  .PHONY: dist-doc distclean
 -dist-doc:
 +dist-doc: git$X
        $(RM) -r .doc-tmp-dir
        mkdir .doc-tmp-dir
        $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
 -      cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar $(TAR_DIST_EXTRA_OPTS) .
 +      ./git -C .doc-tmp-dir init
 +      ./git -C .doc-tmp-dir add .
 +      ./git -C .doc-tmp-dir commit -m htmldocs
 +      ./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
 +              > $(htmldocs).tar
        gzip -n -9 -f $(htmldocs).tar
        :
        $(RM) -r .doc-tmp-dir
                man5dir=../.doc-tmp-dir/man5 \
                man7dir=../.doc-tmp-dir/man7 \
                install
 -      cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar $(TAR_DIST_EXTRA_OPTS) .
 +      ./git -C .doc-tmp-dir init
 +      ./git -C .doc-tmp-dir add .
 +      ./git -C .doc-tmp-dir commit -m manpages
 +      ./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
 +              > $(manpages).tar
        gzip -n -9 -f $(manpages).tar
        $(RM) -r .doc-tmp-dir
  
diff --combined builtin/merge.c
index 4c133402a62332768b7a7136ded5ea7f4def93fe,87dfc9bc0652700ce2bbd0af28c0508e533afcac..1cff730715394fa5874c12323bba653ffe5b8abe
@@@ -28,6 -28,7 +28,7 @@@
  #include "rerere.h"
  #include "help.h"
  #include "merge-recursive.h"
+ #include "merge-ort-wrappers.h"
  #include "resolve-undo.h"
  #include "remote.h"
  #include "fmt-merge-msg.h"
@@@ -88,6 -89,7 +89,7 @@@ static int no_verify
  static struct strategy all_strategy[] = {
        { "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
        { "octopus",    DEFAULT_OCTOPUS },
+       { "ort",        NO_TRIVIAL },
        { "resolve",    0 },
        { "ours",       NO_FAST_FORWARD | NO_TRIVIAL },
        { "subtree",    NO_FAST_FORWARD | NO_TRIVIAL },
@@@ -159,10 -161,17 +161,17 @@@ static struct strategy *get_strategy(co
        struct strategy *ret;
        static struct cmdnames main_cmds, other_cmds;
        static int loaded;
+       char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
  
        if (!name)
                return NULL;
  
+       if (default_strategy &&
+           !strcmp(default_strategy, "ort") &&
+           !strcmp(name, "recursive")) {
+               name = "ort";
+       }
        for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
                if (!strcmp(name, all_strategy[i].name))
                        return &all_strategy[i];
@@@ -289,7 -298,7 +298,7 @@@ static struct option builtin_merge_opti
          N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
        OPT_AUTOSTASH(&autostash),
        OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
 -      OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")),
 +      OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),
        OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
        OPT_END()
  };
@@@ -701,7 -710,8 +710,8 @@@ static int try_merge_strategy(const cha
        if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0)
                return error(_("Unable to write index."));
  
-       if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) {
+       if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
+           !strcmp(strategy, "ort")) {
                struct lock_file lock = LOCK_INIT;
                int clean, x;
                struct commit *result;
                        commit_list_insert(j->item, &reversed);
  
                hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
-               clean = merge_recursive(&o, head,
-                               remoteheads->item, reversed, &result);
+               if (!strcmp(strategy, "ort"))
+                       clean = merge_ort_recursive(&o, head, remoteheads->item,
+                                                   reversed, &result);
+               else
+                       clean = merge_recursive(&o, head, remoteheads->item,
+                                               reversed, &result);
                if (clean < 0)
                        exit(128);
                if (write_locked_index(&the_index, &lock,
@@@ -1264,6 -1278,12 +1278,12 @@@ int cmd_merge(int argc, const char **ar
        if (branch)
                skip_prefix(branch, "refs/heads/", &branch);
  
+       if (!pull_twohead) {
+               char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
+               if (default_strategy && !strcmp(default_strategy, "ort"))
+                       pull_twohead = "ort";
+       }
        init_diff_ui_defaults();
        git_config(git_merge_config, NULL);
  
diff --combined builtin/rebase.c
index 4bd9f257b988df584fa88ae941ca7cd7e356049b,4ba5295ddf1dd5b5f2b852c944d4e7bb90c0e095..19c7b377aa3fc603c63ad0abedd0ed643bce146f
@@@ -119,6 -119,7 +119,7 @@@ static struct replay_opts get_replay_op
        struct replay_opts replay = REPLAY_OPTS_INIT;
  
        replay.action = REPLAY_INTERACTIVE_REBASE;
+       replay.strategy = NULL;
        sequencer_init_config(&replay);
  
        replay.signoff = opts->signoff;
                                        opts->committer_date_is_author_date;
        replay.ignore_date = opts->ignore_date;
        replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
-       replay.strategy = opts->strategy;
+       if (opts->strategy)
+               replay.strategy = opts->strategy;
+       else if (!replay.strategy && replay.default_strategy) {
+               replay.strategy = replay.default_strategy;
+               replay.default_strategy = NULL;
+       }
  
        if (opts->strategy_opts)
                parse_strategy_opts(&replay, opts->strategy_opts);
@@@ -270,14 -276,15 +276,14 @@@ static int edit_todo_file(unsigned flag
  }
  
  static int get_revision_ranges(struct commit *upstream, struct commit *onto,
 -                             struct object_id *orig_head, const char **head_hash,
 -                             char **revisions, char **shortrevisions)
 +                             struct object_id *orig_head, char **revisions,
 +                             char **shortrevisions)
  {
        struct commit *base_rev = upstream ? upstream : onto;
        const char *shorthead;
  
 -      *head_hash = find_unique_abbrev(orig_head, GIT_MAX_HEXSZ);
        *revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
 -                                                 *head_hash);
 +                           oid_to_hex(orig_head));
  
        shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
  
  }
  
  static int init_basic_state(struct replay_opts *opts, const char *head_name,
 -                          struct commit *onto, const char *orig_head)
 +                          struct commit *onto,
 +                          const struct object_id *orig_head)
  {
        FILE *interactive;
  
@@@ -327,6 -333,7 +333,6 @@@ static void split_exec_commands(const c
  static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
  {
        int ret;
 -      const char *head_hash = NULL;
        char *revisions = NULL, *shortrevisions = NULL;
        struct strvec make_script_args = STRVEC_INIT;
        struct todo_list todo_list = TODO_LIST_INIT;
        struct string_list commands = STRING_LIST_INIT_DUP;
  
        if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
 -                              &head_hash, &revisions, &shortrevisions))
 +                              &revisions, &shortrevisions))
                return -1;
  
        if (init_basic_state(&replay,
                             opts->head_name ? opts->head_name : "detached HEAD",
 -                           opts->onto, head_hash)) {
 +                           opts->onto, &opts->orig_head)) {
                free(revisions);
                free(shortrevisions);
  
  
                split_exec_commands(opts->cmd, &commands);
                ret = complete_action(the_repository, &replay, flags,
 -                      shortrevisions, opts->onto_name, opts->onto, head_hash,
 -                      &commands, opts->autosquash, &todo_list);
 +                      shortrevisions, opts->onto_name, opts->onto,
 +                      &opts->orig_head, &commands, opts->autosquash,
 +                      &todo_list);
        }
  
        string_list_clear(&commands, 0);
@@@ -1324,7 -1330,7 +1330,7 @@@ int cmd_rebase(int argc, const char **a
                        N_("do not show diffstat of what changed upstream"),
                        PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
                OPT_BOOL(0, "signoff", &options.signoff,
 -                       N_("add a Signed-off-by: line to each commit")),
 +                       N_("add a Signed-off-by trailer to each commit")),
                OPT_BOOL(0, "committer-date-is-author-date",
                         &options.committer_date_is_author_date,
                         N_("make committer date match author date")),
                            options.default_backend);
        }
  
+       if (options.type == REBASE_MERGE &&
+           !options.strategy &&
+           getenv("GIT_TEST_MERGE_ALGORITHM"))
+               options.strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
        switch (options.type) {
        case REBASE_MERGE:
        case REBASE_PRESERVE_MERGES:
diff --combined builtin/revert.c
index da8997dc861ce37362372659e3eb59dcc694b9d4,5b01a9bacacb19e85ce3ad424b1a92094cfb03f9..314a86c5621bd26b7ddcd35cab1a21702453a2ca
@@@ -107,7 -107,7 +107,7 @@@ static int run_sequencer(int argc, cons
                OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
                OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
                OPT_NOOP_NOARG('r', NULL),
 -              OPT_BOOL('s', "signoff", &opts->signoff, N_("add Signed-off-by:")),
 +              OPT_BOOL('s', "signoff", &opts->signoff, N_("add a Signed-off-by trailer")),
                OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
                             N_("select mainline parent"), option_parse_m),
                OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
                                NULL);
        }
  
+       if (!opts->strategy && opts->default_strategy) {
+               opts->strategy = opts->default_strategy;
+               opts->default_strategy = NULL;
+       }
        if (opts->allow_ff)
                verify_opt_compatible(me, "--ff",
                                "--signoff", opts->signoff,
        /* These option values will be free()d */
        opts->gpg_sign = xstrdup_or_null(opts->gpg_sign);
        opts->strategy = xstrdup_or_null(opts->strategy);
+       if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
+               opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
  
        if (cmd == 'q') {
                int ret = sequencer_remove_state(opts);
diff --combined sequencer.c
index 3dce6c963cec91e6b69de360d931a7d9e294db07,6b6c15c35724d50b5296ea01806819788427c545..221e98721d23b398c115b3ae743cdc889d81515f
@@@ -14,7 -14,8 +14,8 @@@
  #include "diff.h"
  #include "revision.h"
  #include "rerere.h"
- #include "merge-recursive.h"
+ #include "merge-ort.h"
+ #include "merge-ort-wrappers.h"
  #include "refs.h"
  #include "strvec.h"
  #include "quote.h"
@@@ -204,6 -205,20 +205,20 @@@ static int git_sequencer_config(const c
                return 0;
        }
  
+       if (!opts->default_strategy && !strcmp(k, "pull.twohead")) {
+               int ret = git_config_string((const char**)&opts->default_strategy, k, v);
+               if (ret == 0) {
+                       /*
+                        * pull.twohead is allowed to be multi-valued; we only
+                        * care about the first value.
+                        */
+                       char *tmp = strchr(opts->default_strategy, ' ');
+                       if (tmp)
+                               *tmp = '\0';
+               }
+               return ret;
+       }
        status = git_gpg_config(k, v, NULL);
        if (status)
                return status;
@@@ -314,7 -329,10 +329,8 @@@ int sequencer_remove_state(struct repla
                }
        }
  
 -      free(opts->committer_name);
 -      free(opts->committer_email);
        free(opts->gpg_sign);
+       free(opts->default_strategy);
        free(opts->strategy);
        for (i = 0; i < opts->xopts_nr; i++)
                free(opts->xopts[i]);
@@@ -593,8 -611,9 +609,9 @@@ static int do_recursive_merge(struct re
                              struct replay_opts *opts)
  {
        struct merge_options o;
+       struct merge_result result;
        struct tree *next_tree, *base_tree, *head_tree;
-       int clean;
+       int clean, show_output;
        int i;
        struct lock_file index_lock = LOCK_INIT;
  
        for (i = 0; i < opts->xopts_nr; i++)
                parse_merge_opt(&o, opts->xopts[i]);
  
-       clean = merge_trees(&o,
-                           head_tree,
-                           next_tree, base_tree);
-       if (is_rebase_i(opts) && clean <= 0)
-               fputs(o.obuf.buf, stdout);
-       strbuf_release(&o.obuf);
+       if (opts->strategy && !strcmp(opts->strategy, "ort")) {
+               memset(&result, 0, sizeof(result));
+               merge_incore_nonrecursive(&o, base_tree, head_tree, next_tree,
+                                           &result);
+               show_output = !is_rebase_i(opts) || !result.clean;
+               /*
+                * TODO: merge_switch_to_result will update index/working tree;
+                * we only really want to do that if !result.clean || this is
+                * the final patch to be picked.  But determining this is the
+                * final patch would take some work, and "head_tree" would need
+                * to be replace with the tree the index matched before we
+                * started doing any picks.
+                */
+               merge_switch_to_result(&o, head_tree, &result, 1, show_output);
+               clean = result.clean;
+       } else {
+               clean = merge_trees(&o, head_tree, next_tree, base_tree);
+               if (is_rebase_i(opts) && clean <= 0)
+                       fputs(o.obuf.buf, stdout);
+               strbuf_release(&o.obuf);
+       }
        if (clean < 0) {
                rollback_lock_file(&index_lock);
                return clean;
@@@ -1458,8 -1492,8 +1490,8 @@@ static int try_to_commit(struct reposit
                } else {
                        reset_ident_date();
                }
 -              committer = fmt_ident(opts->committer_name,
 -                                    opts->committer_email,
 +              committer = fmt_ident(getenv("GIT_COMMITTER_NAME"),
 +                                    getenv("GIT_COMMITTER_EMAIL"),
                                      WANT_COMMITTER_IDENT,
                                      opts->ignore_date ? NULL : date.buf,
                                      IDENT_STRICT);
@@@ -1989,7 -2023,10 +2021,10 @@@ static int do_pick_commit(struct reposi
  
        if (is_rebase_i(opts) && write_author_script(msg.message) < 0)
                res = -1;
-       else if (!opts->strategy || !strcmp(opts->strategy, "recursive") || command == TODO_REVERT) {
+       else if (!opts->strategy ||
+                !strcmp(opts->strategy, "recursive") ||
+                !strcmp(opts->strategy, "ort") ||
+                command == TODO_REVERT) {
                res = do_recursive_merge(r, base, next, base_label, next_label,
                                         &head, &msgbuf, opts);
                if (res < 0)
@@@ -2651,7 -2688,7 +2686,7 @@@ static int read_populate_opts(struct re
                }
  
                if (read_oneliner(&buf, rebase_path_squash_onto(), 0)) {
 -                      if (get_oid_hex(buf.buf, &opts->squash_onto) < 0) {
 +                      if (get_oid_committish(buf.buf, &opts->squash_onto) < 0) {
                                ret = error(_("unusable squash-onto"));
                                goto done_rebase_i;
                        }
@@@ -2690,7 -2727,7 +2725,7 @@@ static void write_strategy_opts(struct 
  }
  
  int write_basic_state(struct replay_opts *opts, const char *head_name,
 -                    struct commit *onto, const char *orig_head)
 +                    struct commit *onto, const struct object_id *orig_head)
  {
        if (head_name)
                write_file(rebase_path_head_name(), "%s\n", head_name);
                write_file(rebase_path_onto(), "%s\n",
                           oid_to_hex(&onto->object.oid));
        if (orig_head)
 -              write_file(rebase_path_orig_head(), "%s\n", orig_head);
 +              write_file(rebase_path_orig_head(), "%s\n",
 +                         oid_to_hex(orig_head));
  
        if (opts->quiet)
                write_file(rebase_path_quiet(), "%s", "");
@@@ -3484,7 -3520,9 +3519,9 @@@ static int do_merge(struct repository *
        struct commit_list *bases, *j, *reversed = NULL;
        struct commit_list *to_merge = NULL, **tail = &to_merge;
        const char *strategy = !opts->xopts_nr &&
-               (!opts->strategy || !strcmp(opts->strategy, "recursive")) ?
+               (!opts->strategy ||
+                !strcmp(opts->strategy, "recursive") ||
+                !strcmp(opts->strategy, "ort")) ?
                NULL : opts->strategy;
        struct merge_options o;
        int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
                strvec_push(&cmd.args, "-F");
                strvec_push(&cmd.args, git_path_merge_msg(r));
                if (opts->gpg_sign)
 -                      strvec_push(&cmd.args, opts->gpg_sign);
 +                      strvec_pushf(&cmd.args, "-S%s", opts->gpg_sign);
 +              else
 +                      strvec_push(&cmd.args, "--no-gpg-sign");
  
                /* Add the tips to be merged */
                for (j = to_merge; j; j = j->next)
                                NULL, 0);
                rollback_lock_file(&lock);
  
 -              rollback_lock_file(&lock);
                ret = run_command(&cmd);
  
                /* force re-reading of the cache */
        o.branch2 = ref_name.buf;
        o.buffer_output = 2;
  
-       ret = merge_recursive(&o, head_commit, merge_commit, reversed, &i);
+       if (opts->strategy && !strcmp(opts->strategy, "ort")) {
+               /*
+                * TODO: Should use merge_incore_recursive() and
+                * merge_switch_to_result(), skipping the call to
+                * merge_switch_to_result() when we don't actually need to
+                * update the index and working copy immediately.
+                */
+               ret = merge_ort_recursive(&o,
+                                         head_commit, merge_commit, reversed,
+                                         &i);
+       } else {
+               ret = merge_recursive(&o, head_commit, merge_commit, reversed,
+                                     &i);
+       }
        if (ret <= 0)
                fputs(o.obuf.buf, stdout);
        strbuf_release(&o.obuf);
@@@ -3965,17 -4015,21 +4015,17 @@@ static int run_git_checkout(struct repo
  
  static int checkout_onto(struct repository *r, struct replay_opts *opts,
                         const char *onto_name, const struct object_id *onto,
 -                       const char *orig_head)
 +                       const struct object_id *orig_head)
  {
 -      struct object_id oid;
        const char *action = reflog_message(opts, "start", "checkout %s", onto_name);
  
 -      if (get_oid(orig_head, &oid))
 -              return error(_("%s: not a valid OID"), orig_head);
 -
        if (run_git_checkout(r, opts, oid_to_hex(onto), action)) {
                apply_autostash(rebase_path_autostash());
                sequencer_remove_state(opts);
                return error(_("could not detach HEAD"));
        }
  
 -      return update_ref(NULL, "ORIG_HEAD", &oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
 +      return update_ref(NULL, "ORIG_HEAD", orig_head, NULL, 0, UPDATE_REFS_MSG_ON_ERR);
  }
  
  static int stopped_at_head(struct repository *r)
@@@ -4463,6 -4517,22 +4513,6 @@@ static int commit_staged_changes(struc
        return 0;
  }
  
 -static int init_committer(struct replay_opts *opts)
 -{
 -      struct ident_split id;
 -      const char *committer;
 -
 -      committer = git_committer_info(IDENT_STRICT);
 -      if (split_ident_line(&id, committer, strlen(committer)) < 0)
 -              return error(_("invalid committer '%s'"), committer);
 -      opts->committer_name =
 -              xmemdupz(id.name_begin, id.name_end - id.name_begin);
 -      opts->committer_email =
 -              xmemdupz(id.mail_begin, id.mail_end - id.mail_end);
 -
 -      return 0;
 -}
 -
  int sequencer_continue(struct repository *r, struct replay_opts *opts)
  {
        struct todo_list todo_list = TODO_LIST_INIT;
        if (read_populate_opts(opts))
                return -1;
        if (is_rebase_i(opts)) {
 -              if (opts->committer_date_is_author_date && init_committer(opts))
 -                      return -1;
 -
                if ((res = read_populate_todo(r, &todo_list, opts)))
                        goto release_todo_list;
  
@@@ -5291,7 -5364,7 +5341,7 @@@ static int skip_unnecessary_picks(struc
  
  int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
                    const char *shortrevisions, const char *onto_name,
 -                  struct commit *onto, const char *orig_head,
 +                  struct commit *onto, const struct object_id *orig_head,
                    struct string_list *commands, unsigned autosquash,
                    struct todo_list *todo_list)
  {
  
        res = -1;
  
 -      if (opts->committer_date_is_author_date && init_committer(opts))
 -              goto cleanup;
 -
        if (checkout_onto(r, opts, onto_name, &oid, orig_head))
                goto cleanup;
  
diff --combined sequencer.h
index ce044ae49bec7fea96be02c8174b6b64e2e25c48,020b7fa1186f25c3b7695417dd1371f7657cf4dd..f8b2e4ab8527b5742cbd4b9beff246938f421c3d
@@@ -50,11 -50,14 +50,12 @@@ struct replay_opts 
  
        int mainline;
  
 -      char *committer_name;
 -      char *committer_email;
        char *gpg_sign;
        enum commit_msg_cleanup_mode default_msg_cleanup;
        int explicit_cleanup;
  
        /* Merge strategy */
+       char *default_strategy;  /* from config options */
        char *strategy;
        char **xopts;
        size_t xopts_nr, xopts_alloc;
@@@ -161,9 -164,8 +162,9 @@@ void todo_list_add_exec_commands(struc
                                 struct string_list *commands);
  int complete_action(struct repository *r, struct replay_opts *opts, unsigned flags,
                    const char *shortrevisions, const char *onto_name,
 -                  struct commit *onto, const char *orig_head, struct string_list *commands,
 -                  unsigned autosquash, struct todo_list *todo_list);
 +                  struct commit *onto, const struct object_id *orig_head,
 +                  struct string_list *commands, unsigned autosquash,
 +                  struct todo_list *todo_list);
  int todo_list_rearrange_squash(struct todo_list *todo_list);
  
  /*
@@@ -225,7 -227,7 +226,7 @@@ int read_author_script(const char *path
                       int allow_missing);
  void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
  int write_basic_state(struct replay_opts *opts, const char *head_name,
 -                    struct commit *onto, const char *orig_head);
 +                    struct commit *onto, const struct object_id *orig_head);
  void sequencer_post_commit_cleanup(struct repository *r, int verbose);
  int sequencer_get_last_command(struct repository* r,
                               enum replay_action *action);
diff --combined t/helper/test-tool.c
index cab19a9eb5fb826afcc07309115144c06b483b1f,8bce7db07613a54e8674fc76941f0d1e6e306e20..9d6d14d92937533e84bb30fc689750cceb1180b1
@@@ -18,7 -18,6 +18,7 @@@ static struct test_cmd cmds[] = 
        { "bloom", cmd__bloom },
        { "chmtime", cmd__chmtime },
        { "config", cmd__config },
 +      { "crontab", cmd__crontab },
        { "ctype", cmd__ctype },
        { "date", cmd__date },
        { "delta", cmd__delta },
@@@ -29,6 -28,7 +29,7 @@@
        { "dump-split-index", cmd__dump_split_index },
        { "dump-untracked-cache", cmd__dump_untracked_cache },
        { "example-decorate", cmd__example_decorate },
+       { "fast-rebase", cmd__fast_rebase },
        { "genrandom", cmd__genrandom },
        { "genzeros", cmd__genzeros },
        { "hashmap", cmd__hashmap },
diff --combined t/helper/test-tool.h
index 1467f003afe4314c106812aa1276ae7f4c6e4dec,fd0cafe5ca17660cb303a102949870c008ebf744..a6470ff62c42521d3ba16e505d37b31b53554925
@@@ -8,7 -8,6 +8,7 @@@ int cmd__advise_if_enabled(int argc, co
  int cmd__bloom(int argc, const char **argv);
  int cmd__chmtime(int argc, const char **argv);
  int cmd__config(int argc, const char **argv);
 +int cmd__crontab(int argc, const char **argv);
  int cmd__ctype(int argc, const char **argv);
  int cmd__date(int argc, const char **argv);
  int cmd__delta(int argc, const char **argv);
@@@ -19,6 -18,7 +19,7 @@@ int cmd__dump_fsmonitor(int argc, cons
  int cmd__dump_split_index(int argc, const char **argv);
  int cmd__dump_untracked_cache(int argc, const char **argv);
  int cmd__example_decorate(int argc, const char **argv);
+ int cmd__fast_rebase(int argc, const char **argv);
  int cmd__genrandom(int argc, const char **argv);
  int cmd__genzeros(int argc, const char **argv);
  int cmd__hashmap(int argc, const char **argv);