Imported Upstream version 2.27.0
[platform/upstream/git.git] / builtin / rebase.c
index bff53d5..37ba76a 100644 (file)
@@ -27,6 +27,9 @@
 #include "branch.h"
 #include "sequencer.h"
 #include "rebase-interactive.h"
+#include "reset.h"
+
+#define DEFAULT_REFLOG_ACTION "rebase"
 
 static char const * const builtin_rebase_usage[] = {
        N_("git rebase [-i] [options] [--exec <cmd>] "
@@ -85,6 +88,7 @@ struct rebase_options {
        const char *action;
        int signoff;
        int allow_rerere_autoupdate;
+       int keep_empty;
        int autosquash;
        char *gpg_sign_opt;
        int autostash;
@@ -95,11 +99,13 @@ struct rebase_options {
        struct strbuf git_format_patch_opt;
        int reschedule_failed_exec;
        int use_legacy_rebase;
+       int reapply_cherry_picks;
 };
 
 #define REBASE_OPTIONS_INIT {                          \
                .type = REBASE_UNSPECIFIED,             \
                .empty = EMPTY_UNSPECIFIED,             \
+               .keep_empty = 1,                        \
                .default_backend = "merge",             \
                .flags = REBASE_NO_QUIET,               \
                .git_am_opts = ARGV_ARRAY_INIT,         \
@@ -379,11 +385,13 @@ static int run_sequencer_rebase(struct rebase_options *opts,
 
        git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
 
+       flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
        flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
        flags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
        flags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
        flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
        flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;
+       flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
 
        switch (command) {
        case ACTION_NONE: {
@@ -442,6 +450,7 @@ static int run_sequencer_rebase(struct rebase_options *opts,
        return ret;
 }
 
+static void imply_merge(struct rebase_options *opts, const char *option);
 static int parse_opt_keep_empty(const struct option *opt, const char *arg,
                                int unset)
 {
@@ -449,10 +458,8 @@ static int parse_opt_keep_empty(const struct option *opt, const char *arg,
 
        BUG_ON_OPT_ARG(arg);
 
-       /*
-        * If we ever want to remap --keep-empty to --empty=keep, insert:
-        *      opts->empty = unset ? EMPTY_UNSPECIFIED : EMPTY_KEEP;
-        */
+       imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
+       opts->keep_empty = !unset;
        opts->type = REBASE_MERGE;
        return 0;
 }
@@ -470,10 +477,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
        struct option options[] = {
                OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"),
                           REBASE_FORCE),
-               { OPTION_CALLBACK, 'k', "keep-empty", &options, NULL,
-                       N_("(DEPRECATED) keep empty commits"),
+               OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
+                       N_("keep commits which start empty"),
                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
-                       parse_opt_keep_empty },
+                       parse_opt_keep_empty),
                OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message,
                           N_("allow commits with empty messages"),
                           PARSE_OPT_HIDDEN),
@@ -559,7 +566,7 @@ static void imply_merge(struct rebase_options *opts, const char *option)
 {
        switch (opts->type) {
        case REBASE_APPLY:
-               die(_("%s requires an interactive rebase"), option);
+               die(_("%s requires the merge backend"), option);
                break;
        case REBASE_MERGE:
        case REBASE_PRESERVE_MERGES:
@@ -586,15 +593,6 @@ static const char *state_dir_path(const char *filename, struct rebase_options *o
        return path.buf;
 }
 
-/* Read one file, then strip line endings */
-static int read_one(const char *path, struct strbuf *buf)
-{
-       if (strbuf_read_file(buf, path, 0) < 0)
-               return error_errno(_("could not read '%s'"), path);
-       strbuf_trim_trailing_newline(buf);
-       return 0;
-}
-
 /* Initialize the rebase options from the state directory. */
 static int read_basic_state(struct rebase_options *opts)
 {
@@ -602,8 +600,10 @@ static int read_basic_state(struct rebase_options *opts)
        struct strbuf buf = STRBUF_INIT;
        struct object_id oid;
 
-       if (read_one(state_dir_path("head-name", opts), &head_name) ||
-           read_one(state_dir_path("onto", opts), &buf))
+       if (!read_oneliner(&head_name, state_dir_path("head-name", opts),
+                          READ_ONELINER_WARN_MISSING) ||
+           !read_oneliner(&buf, state_dir_path("onto", opts),
+                          READ_ONELINER_WARN_MISSING))
                return -1;
        opts->head_name = starts_with(head_name.buf, "refs/") ?
                xstrdup(head_name.buf) : NULL;
@@ -619,9 +619,11 @@ static int read_basic_state(struct rebase_options *opts)
         */
        strbuf_reset(&buf);
        if (file_exists(state_dir_path("orig-head", opts))) {
-               if (read_one(state_dir_path("orig-head", opts), &buf))
+               if (!read_oneliner(&buf, state_dir_path("orig-head", opts),
+                                  READ_ONELINER_WARN_MISSING))
                        return -1;
-       } else if (read_one(state_dir_path("head", opts), &buf))
+       } else if (!read_oneliner(&buf, state_dir_path("head", opts),
+                                 READ_ONELINER_WARN_MISSING))
                return -1;
        if (get_oid(buf.buf, &opts->orig_head))
                return error(_("invalid orig-head: '%s'"), buf.buf);
@@ -641,8 +643,8 @@ static int read_basic_state(struct rebase_options *opts)
 
        if (file_exists(state_dir_path("allow_rerere_autoupdate", opts))) {
                strbuf_reset(&buf);
-               if (read_one(state_dir_path("allow_rerere_autoupdate", opts),
-                           &buf))
+               if (!read_oneliner(&buf, state_dir_path("allow_rerere_autoupdate", opts),
+                                  READ_ONELINER_WARN_MISSING))
                        return -1;
                if (!strcmp(buf.buf, "--rerere-autoupdate"))
                        opts->allow_rerere_autoupdate = RERERE_AUTOUPDATE;
@@ -655,8 +657,8 @@ static int read_basic_state(struct rebase_options *opts)
 
        if (file_exists(state_dir_path("gpg_sign_opt", opts))) {
                strbuf_reset(&buf);
-               if (read_one(state_dir_path("gpg_sign_opt", opts),
-                           &buf))
+               if (!read_oneliner(&buf, state_dir_path("gpg_sign_opt", opts),
+                                  READ_ONELINER_WARN_MISSING))
                        return -1;
                free(opts->gpg_sign_opt);
                opts->gpg_sign_opt = xstrdup(buf.buf);
@@ -664,7 +666,8 @@ static int read_basic_state(struct rebase_options *opts)
 
        if (file_exists(state_dir_path("strategy", opts))) {
                strbuf_reset(&buf);
-               if (read_one(state_dir_path("strategy", opts), &buf))
+               if (!read_oneliner(&buf, state_dir_path("strategy", opts),
+                                  READ_ONELINER_WARN_MISSING))
                        return -1;
                free(opts->strategy);
                opts->strategy = xstrdup(buf.buf);
@@ -672,7 +675,8 @@ static int read_basic_state(struct rebase_options *opts)
 
        if (file_exists(state_dir_path("strategy_opts", opts))) {
                strbuf_reset(&buf);
-               if (read_one(state_dir_path("strategy_opts", opts), &buf))
+               if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts),
+                                  READ_ONELINER_WARN_MISSING))
                        return -1;
                free(opts->strategy_opts);
                opts->strategy_opts = xstrdup(buf.buf);
@@ -715,65 +719,19 @@ static int rebase_write_basic_state(struct rebase_options *opts)
        return 0;
 }
 
-static int apply_autostash(struct rebase_options *opts)
-{
-       const char *path = state_dir_path("autostash", opts);
-       struct strbuf autostash = STRBUF_INIT;
-       struct child_process stash_apply = CHILD_PROCESS_INIT;
-
-       if (!file_exists(path))
-               return 0;
-
-       if (read_one(path, &autostash))
-               return error(_("Could not read '%s'"), path);
-       /* Ensure that the hash is not mistaken for a number */
-       strbuf_addstr(&autostash, "^0");
-       argv_array_pushl(&stash_apply.args,
-                        "stash", "apply", autostash.buf, NULL);
-       stash_apply.git_cmd = 1;
-       stash_apply.no_stderr = stash_apply.no_stdout =
-               stash_apply.no_stdin = 1;
-       if (!run_command(&stash_apply))
-               printf(_("Applied autostash.\n"));
-       else {
-               struct argv_array args = ARGV_ARRAY_INIT;
-               int res = 0;
-
-               argv_array_pushl(&args,
-                                "stash", "store", "-m", "autostash", "-q",
-                                autostash.buf, NULL);
-               if (run_command_v_opt(args.argv, RUN_GIT_CMD))
-                       res = error(_("Cannot store %s"), autostash.buf);
-               argv_array_clear(&args);
-               strbuf_release(&autostash);
-               if (res)
-                       return res;
-
-               fprintf(stderr,
-                       _("Applying autostash resulted in conflicts.\n"
-                         "Your changes are safe in the stash.\n"
-                         "You can run \"git stash pop\" or \"git stash drop\" "
-                         "at any time.\n"));
-       }
-
-       strbuf_release(&autostash);
-       return 0;
-}
-
 static int finish_rebase(struct rebase_options *opts)
 {
        struct strbuf dir = STRBUF_INIT;
-       const char *argv_gc_auto[] = { "gc", "--auto", NULL };
        int ret = 0;
 
        delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
-       apply_autostash(opts);
+       apply_autostash(state_dir_path("autostash", opts));
        close_object_store(the_repository->objects);
        /*
         * We ignore errors in 'gc --auto', since the
         * user should see them.
         */
-       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+       run_auto_gc(!(opts->flags & (REBASE_NO_QUIET|REBASE_VERBOSE)));
        if (opts->type == REBASE_MERGE) {
                struct replay_opts replay = REPLAY_OPTS_INIT;
 
@@ -812,143 +770,6 @@ static void add_var(struct strbuf *buf, const char *name, const char *value)
        }
 }
 
-#define GIT_REFLOG_ACTION_ENVIRONMENT "GIT_REFLOG_ACTION"
-
-#define RESET_HEAD_DETACH (1<<0)
-#define RESET_HEAD_HARD (1<<1)
-#define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2)
-#define RESET_HEAD_REFS_ONLY (1<<3)
-#define RESET_ORIG_HEAD (1<<4)
-
-static int reset_head(struct object_id *oid, const char *action,
-                     const char *switch_to_branch, unsigned flags,
-                     const char *reflog_orig_head, const char *reflog_head)
-{
-       unsigned detach_head = flags & RESET_HEAD_DETACH;
-       unsigned reset_hard = flags & RESET_HEAD_HARD;
-       unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
-       unsigned refs_only = flags & RESET_HEAD_REFS_ONLY;
-       unsigned update_orig_head = flags & RESET_ORIG_HEAD;
-       struct object_id head_oid;
-       struct tree_desc desc[2] = { { NULL }, { NULL } };
-       struct lock_file lock = LOCK_INIT;
-       struct unpack_trees_options unpack_tree_opts;
-       struct tree *tree;
-       const char *reflog_action;
-       struct strbuf msg = STRBUF_INIT;
-       size_t prefix_len;
-       struct object_id *orig = NULL, oid_orig,
-               *old_orig = NULL, oid_old_orig;
-       int ret = 0, nr = 0;
-
-       if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
-               BUG("Not a fully qualified branch: '%s'", switch_to_branch);
-
-       if (!refs_only && hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0) {
-               ret = -1;
-               goto leave_reset_head;
-       }
-
-       if ((!oid || !reset_hard) && get_oid("HEAD", &head_oid)) {
-               ret = error(_("could not determine HEAD revision"));
-               goto leave_reset_head;
-       }
-
-       if (!oid)
-               oid = &head_oid;
-
-       if (refs_only)
-               goto reset_head_refs;
-
-       memset(&unpack_tree_opts, 0, sizeof(unpack_tree_opts));
-       setup_unpack_trees_porcelain(&unpack_tree_opts, action);
-       unpack_tree_opts.head_idx = 1;
-       unpack_tree_opts.src_index = the_repository->index;
-       unpack_tree_opts.dst_index = the_repository->index;
-       unpack_tree_opts.fn = reset_hard ? oneway_merge : twoway_merge;
-       unpack_tree_opts.update = 1;
-       unpack_tree_opts.merge = 1;
-       if (!detach_head)
-               unpack_tree_opts.reset = 1;
-
-       if (repo_read_index_unmerged(the_repository) < 0) {
-               ret = error(_("could not read index"));
-               goto leave_reset_head;
-       }
-
-       if (!reset_hard && !fill_tree_descriptor(the_repository, &desc[nr++], &head_oid)) {
-               ret = error(_("failed to find tree of %s"),
-                           oid_to_hex(&head_oid));
-               goto leave_reset_head;
-       }
-
-       if (!fill_tree_descriptor(the_repository, &desc[nr++], oid)) {
-               ret = error(_("failed to find tree of %s"), oid_to_hex(oid));
-               goto leave_reset_head;
-       }
-
-       if (unpack_trees(nr, desc, &unpack_tree_opts)) {
-               ret = -1;
-               goto leave_reset_head;
-       }
-
-       tree = parse_tree_indirect(oid);
-       prime_cache_tree(the_repository, the_repository->index, tree);
-
-       if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK) < 0) {
-               ret = error(_("could not write index"));
-               goto leave_reset_head;
-       }
-
-reset_head_refs:
-       reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
-       strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase");
-       prefix_len = msg.len;
-
-       if (update_orig_head) {
-               if (!get_oid("ORIG_HEAD", &oid_old_orig))
-                       old_orig = &oid_old_orig;
-               if (!get_oid("HEAD", &oid_orig)) {
-                       orig = &oid_orig;
-                       if (!reflog_orig_head) {
-                               strbuf_addstr(&msg, "updating ORIG_HEAD");
-                               reflog_orig_head = msg.buf;
-                       }
-                       update_ref(reflog_orig_head, "ORIG_HEAD", orig,
-                                  old_orig, 0, UPDATE_REFS_MSG_ON_ERR);
-               } else if (old_orig)
-                       delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
-       }
-
-       if (!reflog_head) {
-               strbuf_setlen(&msg, prefix_len);
-               strbuf_addstr(&msg, "updating HEAD");
-               reflog_head = msg.buf;
-       }
-       if (!switch_to_branch)
-               ret = update_ref(reflog_head, "HEAD", oid, orig,
-                                detach_head ? REF_NO_DEREF : 0,
-                                UPDATE_REFS_MSG_ON_ERR);
-       else {
-               ret = update_ref(reflog_head, switch_to_branch, oid,
-                                NULL, 0, UPDATE_REFS_MSG_ON_ERR);
-               if (!ret)
-                       ret = create_symref("HEAD", switch_to_branch,
-                                           reflog_head);
-       }
-       if (run_hook)
-               run_hook_le(NULL, "post-checkout",
-                           oid_to_hex(orig ? orig : &null_oid),
-                           oid_to_hex(oid), "1", NULL);
-
-leave_reset_head:
-       strbuf_release(&msg);
-       rollback_lock_file(&lock);
-       while (nr)
-               free((void *)desc[--nr].buffer);
-       return ret;
-}
-
 static int move_to_original_branch(struct rebase_options *opts)
 {
        struct strbuf orig_head_reflog = STRBUF_INIT, head_reflog = STRBUF_INIT;
@@ -964,8 +785,10 @@ static int move_to_original_branch(struct rebase_options *opts)
                    opts->head_name, oid_to_hex(&opts->onto->object.oid));
        strbuf_addf(&head_reflog, "rebase finished: returning to %s",
                    opts->head_name);
-       ret = reset_head(NULL, "", opts->head_name, RESET_HEAD_REFS_ONLY,
-                        orig_head_reflog.buf, head_reflog.buf);
+       ret = reset_head(the_repository, NULL, "", opts->head_name,
+                        RESET_HEAD_REFS_ONLY,
+                        orig_head_reflog.buf, head_reflog.buf,
+                        DEFAULT_REFLOG_ACTION);
 
        strbuf_release(&orig_head_reflog);
        strbuf_release(&head_reflog);
@@ -1053,8 +876,9 @@ static int run_am(struct rebase_options *opts)
                free(rebased_patches);
                argv_array_clear(&am.args);
 
-               reset_head(&opts->orig_head, "checkout", opts->head_name, 0,
-                          "HEAD", NULL);
+               reset_head(the_repository, &opts->orig_head, "checkout",
+                          opts->head_name, 0,
+                          "HEAD", NULL, DEFAULT_REFLOG_ACTION);
                error(_("\ngit encountered an error while preparing the "
                        "patches to replay\n"
                        "these revisions:\n"
@@ -1162,6 +986,7 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
                opts->allow_rerere_autoupdate ?
                        opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?
                        "--rerere-autoupdate" : "--no-rerere-autoupdate" : "");
+       add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
        add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
        add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
        add_var(&script_snippet, "cmd", opts->cmd);
@@ -1212,7 +1037,7 @@ finished_rebase:
        } else if (status == 2) {
                struct strbuf dir = STRBUF_INIT;
 
-               apply_autostash(opts);
+               apply_autostash(state_dir_path("autostash", opts));
                strbuf_addstr(&dir, opts->state_dir);
                remove_dir_recursively(&dir, 0);
                strbuf_release(&dir);
@@ -1453,7 +1278,6 @@ static int check_exec_cmd(const char *cmd)
        return 0;
 }
 
-
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
        struct rebase_options options = REBASE_OPTIONS_INIT;
@@ -1526,18 +1350,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_CMDMODE(0, "show-current-patch", &action,
                            N_("show the patch file being applied or merged"),
                            ACTION_SHOW_CURRENT_PATCH),
-               { OPTION_CALLBACK, 0, "apply", &options, NULL,
+               OPT_CALLBACK_F(0, "apply", &options, NULL,
                        N_("use apply strategies to rebase"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
-                       parse_opt_am },
-               { OPTION_CALLBACK, 'm', "merge", &options, NULL,
+                       parse_opt_am),
+               OPT_CALLBACK_F('m', "merge", &options, NULL,
                        N_("use merging strategies to rebase"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
-                       parse_opt_merge },
-               { OPTION_CALLBACK, 'i', "interactive", &options, NULL,
+                       parse_opt_merge),
+               OPT_CALLBACK_F('i', "interactive", &options, NULL,
                        N_("let the user edit the list of commits to rebase"),
                        PARSE_OPT_NOARG | PARSE_OPT_NONEG,
-                       parse_opt_interactive },
+                       parse_opt_interactive),
                OPT_SET_INT_F('p', "preserve-merges", &options.type,
                              N_("(DEPRECATED) try to recreate merges instead of "
                                 "ignoring them"),
@@ -1546,18 +1370,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_CALLBACK_F(0, "empty", &options, "{drop,keep,ask}",
                               N_("how to handle commits that become empty"),
                               PARSE_OPT_NONEG, parse_opt_empty),
-               { OPTION_CALLBACK, 'k', "keep-empty", &options, NULL,
-                       N_("(DEPRECATED) keep empty commits"),
+               OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
+                       N_("keep commits which start empty"),
                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
-                       parse_opt_keep_empty },
+                       parse_opt_keep_empty),
                OPT_BOOL(0, "autosquash", &options.autosquash,
                         N_("move commits that begin with "
                            "squash!/fixup! under -i")),
                { OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
                        N_("GPG-sign commits"),
                        PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
-               OPT_BOOL(0, "autostash", &options.autostash,
-                        N_("automatically stash/stash pop before and after")),
+               OPT_AUTOSTASH(&options.autostash),
                OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
                                N_("add exec lines after each commit of the "
                                   "editable list")),
@@ -1582,6 +1405,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "reschedule-failed-exec",
                         &reschedule_failed_exec,
                         N_("automatically re-schedule any `exec` that fails")),
+               OPT_BOOL(0, "reapply-cherry-picks", &options.reapply_cherry_picks,
+                        N_("apply all changes, even those already present upstream")),
                OPT_END(),
        };
        int i;
@@ -1592,6 +1417,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        options.allow_empty_message = 1;
        git_config(rebase_config, &options);
+       /* options.gpg_sign_opt will be either "-S" or NULL */
+       gpg_sign = options.gpg_sign_opt ? "" : NULL;
+       FREE_AND_NULL(options.gpg_sign_opt);
 
        if (options.use_legacy_rebase ||
            !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1))
@@ -1652,6 +1480,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                        die(_("cannot combine '--keep-base' with '--root'"));
        }
 
+       if (options.root && fork_point > 0)
+               die(_("cannot combine '--root' with '--fork-point'"));
+
        if (action != ACTION_NONE && !in_progress)
                die(_("No rebase in progress?"));
        setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0);
@@ -1709,8 +1540,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                rerere_clear(the_repository, &merge_rr);
                string_list_clear(&merge_rr, 1);
 
-               if (reset_head(NULL, "reset", NULL, RESET_HEAD_HARD,
-                              NULL, NULL) < 0)
+               if (reset_head(the_repository, NULL, "reset", NULL, RESET_HEAD_HARD,
+                              NULL, NULL, DEFAULT_REFLOG_ACTION) < 0)
                        die(_("could not discard worktree changes"));
                remove_branch_state(the_repository, 0);
                if (read_basic_state(&options))
@@ -1727,9 +1558,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
                if (read_basic_state(&options))
                        exit(1);
-               if (reset_head(&options.orig_head, "reset",
+               if (reset_head(the_repository, &options.orig_head, "reset",
                               options.head_name, RESET_HEAD_HARD,
-                              NULL, NULL) < 0)
+                              NULL, NULL, DEFAULT_REFLOG_ACTION) < 0)
                        die(_("could not move back to %s"),
                            oid_to_hex(&options.orig_head));
                remove_branch_state(the_repository, 0);
@@ -1737,6 +1568,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                goto cleanup;
        }
        case ACTION_QUIT: {
+               save_autostash(state_dir_path("autostash", &options));
                if (options.type == REBASE_MERGE) {
                        struct replay_opts replay = REPLAY_OPTS_INIT;
 
@@ -1822,10 +1654,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
        if (options.empty != EMPTY_UNSPECIFIED)
                imply_merge(&options, "--empty");
 
-       if (gpg_sign) {
-               free(options.gpg_sign_opt);
+       if (options.reapply_cherry_picks)
+               imply_merge(&options, "--reapply-cherry-picks");
+
+       if (gpg_sign)
                options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
-       }
 
        if (exec.nr) {
                int i;
@@ -2086,49 +1919,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                die(_("could not read index"));
 
        if (options.autostash) {
-               struct lock_file lock_file = LOCK_INIT;
-               int fd;
-
-               fd = hold_locked_index(&lock_file, 0);
-               refresh_cache(REFRESH_QUIET);
-               if (0 <= fd)
-                       repo_update_index_if_able(the_repository, &lock_file);
-               rollback_lock_file(&lock_file);
-
-               if (has_unstaged_changes(the_repository, 1) ||
-                   has_uncommitted_changes(the_repository, 1)) {
-                       const char *autostash =
-                               state_dir_path("autostash", &options);
-                       struct child_process stash = CHILD_PROCESS_INIT;
-                       struct object_id oid;
-
-                       argv_array_pushl(&stash.args,
-                                        "stash", "create", "autostash", NULL);
-                       stash.git_cmd = 1;
-                       stash.no_stdin = 1;
-                       strbuf_reset(&buf);
-                       if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
-                               die(_("Cannot autostash"));
-                       strbuf_trim_trailing_newline(&buf);
-                       if (get_oid(buf.buf, &oid))
-                               die(_("Unexpected stash response: '%s'"),
-                                   buf.buf);
-                       strbuf_reset(&buf);
-                       strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
-
-                       if (safe_create_leading_directories_const(autostash))
-                               die(_("Could not create directory for '%s'"),
-                                   options.state_dir);
-                       write_file(autostash, "%s", oid_to_hex(&oid));
-                       printf(_("Created autostash: %s\n"), buf.buf);
-                       if (reset_head(NULL, "reset --hard",
-                                      NULL, RESET_HEAD_HARD, NULL, NULL) < 0)
-                               die(_("could not reset --hard"));
-
-                       if (discard_index(the_repository->index) < 0 ||
-                               repo_read_index(the_repository) < 0)
-                               die(_("could not read index"));
-               }
+               create_autostash(the_repository, state_dir_path("autostash", &options),
+                                DEFAULT_REFLOG_ACTION);
        }
 
        if (require_clean_work_tree(the_repository, "rebase",
@@ -2162,10 +1954,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                                strbuf_addf(&buf, "%s: checkout %s",
                                            getenv(GIT_REFLOG_ACTION_ENVIRONMENT),
                                            options.switch_to);
-                               if (reset_head(&options.orig_head, "checkout",
+                               if (reset_head(the_repository,
+                                              &options.orig_head, "checkout",
                                               options.head_name,
                                               RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
-                                              NULL, buf.buf) < 0) {
+                                              NULL, buf.buf,
+                                              DEFAULT_REFLOG_ACTION) < 0) {
                                        ret = !!error(_("could not switch to "
                                                        "%s"),
                                                      options.switch_to);
@@ -2237,10 +2031,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
        strbuf_addf(&msg, "%s: checkout %s",
                    getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name);
-       if (reset_head(&options.onto->object.oid, "checkout", NULL,
+       if (reset_head(the_repository, &options.onto->object.oid, "checkout", NULL,
                       RESET_HEAD_DETACH | RESET_ORIG_HEAD |
                       RESET_HEAD_RUN_POST_CHECKOUT_HOOK,
-                      NULL, msg.buf))
+                      NULL, msg.buf, DEFAULT_REFLOG_ACTION))
                die(_("Could not detach HEAD"));
        strbuf_release(&msg);
 
@@ -2255,8 +2049,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
                strbuf_addf(&msg, "rebase finished: %s onto %s",
                        options.head_name ? options.head_name : "detached HEAD",
                        oid_to_hex(&options.onto->object.oid));
-               reset_head(NULL, "Fast-forwarded", options.head_name,
-                          RESET_HEAD_REFS_ONLY, "HEAD", msg.buf);
+               reset_head(the_repository, NULL, "Fast-forwarded", options.head_name,
+                          RESET_HEAD_REFS_ONLY, "HEAD", msg.buf,
+                          DEFAULT_REFLOG_ACTION);
                strbuf_release(&msg);
                ret = !!finish_rebase(&options);
                goto cleanup;