rebase -i: rewrite setup_reflog_action() in C
[gitweb.git] / sequencer.c
index 03c47405fbf2c1896d4a1d38ef9f204518d7e92d..e48b37bc0e704a012945b2249776ac1ae617766c 100644 (file)
@@ -52,7 +52,7 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge")
  * the lines are processed, they are removed from the front of this
  * file and written to the tail of 'done'.
  */
-static GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
+GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo")
 /*
  * The rebase command lines that have already been processed. A line
  * is moved here when it is first handled, before any associated user
@@ -373,8 +373,8 @@ static void print_advice(int show_hint, struct replay_opts *opts)
        }
 }
 
-static int write_message(const void *buf, size_t len, const char *filename,
-                        int append_eol)
+int write_message(const void *buf, size_t len, const char *filename,
+                 int append_eol)
 {
        struct lock_file msg_file = LOCK_INIT;
 
@@ -769,6 +769,23 @@ N_("you have staged changes in your working tree\n"
 #define VERIFY_MSG  (1<<4)
 #define CREATE_ROOT_COMMIT (1<<5)
 
+static int run_command_silent_on_success(struct child_process *cmd)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int rc;
+
+       cmd->stdout_to_stderr = 1;
+       rc = pipe_command(cmd,
+                         NULL, 0,
+                         NULL, 0,
+                         &buf, 0);
+
+       if (rc)
+               fputs(buf.buf, stderr);
+       strbuf_release(&buf);
+       return rc;
+}
+
 /*
  * If we are cherry-pick, and if the merge did not result in
  * hand-editing, we will hit this commit and inherit the original
@@ -823,18 +840,11 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
 
        cmd.git_cmd = 1;
 
-       if (is_rebase_i(opts)) {
-               if (!(flags & EDIT_MSG)) {
-                       cmd.stdout_to_stderr = 1;
-                       cmd.err = -1;
-               }
-
-               if (read_env_script(&cmd.env_array)) {
-                       const char *gpg_opt = gpg_sign_opt_quoted(opts);
+       if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) {
+               const char *gpg_opt = gpg_sign_opt_quoted(opts);
 
-                       return error(_(staged_changes_advice),
-                                    gpg_opt, gpg_opt);
-               }
+               return error(_(staged_changes_advice),
+                            gpg_opt, gpg_opt);
        }
 
        argv_array_push(&cmd.args, "commit");
@@ -864,21 +874,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        if (opts->allow_empty_message)
                argv_array_push(&cmd.args, "--allow-empty-message");
 
-       if (cmd.err == -1) {
-               /* hide stderr on success */
-               struct strbuf buf = STRBUF_INIT;
-               int rc = pipe_command(&cmd,
-                                     NULL, 0,
-                                     /* stdout is already redirected */
-                                     NULL, 0,
-                                     &buf, 0);
-               if (rc)
-                       fputs(buf.buf, stderr);
-               strbuf_release(&buf);
-               return rc;
-       }
-
-       return run_command(&cmd);
+       if (is_rebase_i(opts) && !(flags & EDIT_MSG))
+               return run_command_silent_on_success(&cmd);
+       else
+               return run_command(&cmd);
 }
 
 static int rest_is_empty(const struct strbuf *sb, int start)
@@ -3140,6 +3139,36 @@ static const char *reflog_message(struct replay_opts *opts,
        return buf.buf;
 }
 
+static int run_git_checkout(struct replay_opts *opts, const char *commit,
+                           const char *action)
+{
+       struct child_process cmd = CHILD_PROCESS_INIT;
+
+       cmd.git_cmd = 1;
+
+       argv_array_push(&cmd.args, "checkout");
+       argv_array_push(&cmd.args, commit);
+       argv_array_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action);
+
+       if (opts->verbose)
+               return run_command(&cmd);
+       else
+               return run_command_silent_on_success(&cmd);
+}
+
+int prepare_branch_to_be_rebased(struct replay_opts *opts, const char *commit)
+{
+       const char *action;
+
+       if (commit && *commit) {
+               action = reflog_message(opts, "start", "checkout %s", commit);
+               if (run_git_checkout(opts, commit, action))
+                       return error(_("could not checkout %s"), commit);
+       }
+
+       return 0;
+}
+
 static const char rescheduled_advice[] =
 N_("Could not execute the todo command\n"
 "\n"
@@ -4245,24 +4274,20 @@ int transform_todos(unsigned flags)
        return i;
 }
 
-enum check_level {
-       CHECK_IGNORE = 0, CHECK_WARN, CHECK_ERROR
-};
-
-static enum check_level get_missing_commit_check_level(void)
+enum missing_commit_check_level get_missing_commit_check_level(void)
 {
        const char *value;
 
        if (git_config_get_value("rebase.missingcommitscheck", &value) ||
                        !strcasecmp("ignore", value))
-               return CHECK_IGNORE;
+               return MISSING_COMMIT_CHECK_IGNORE;
        if (!strcasecmp("warn", value))
-               return CHECK_WARN;
+               return MISSING_COMMIT_CHECK_WARN;
        if (!strcasecmp("error", value))
-               return CHECK_ERROR;
+               return MISSING_COMMIT_CHECK_ERROR;
        warning(_("unrecognized setting %s for option "
                  "rebase.missingCommitsCheck. Ignoring."), value);
-       return CHECK_IGNORE;
+       return MISSING_COMMIT_CHECK_IGNORE;
 }
 
 define_commit_slab(commit_seen, unsigned char);
@@ -4274,7 +4299,7 @@ define_commit_slab(commit_seen, unsigned char);
  */
 int check_todo_list(void)
 {
-       enum check_level check_level = get_missing_commit_check_level();
+       enum missing_commit_check_level check_level = get_missing_commit_check_level();
        struct strbuf todo_file = STRBUF_INIT;
        struct todo_list todo_list = TODO_LIST_INIT;
        struct strbuf missing = STRBUF_INIT;
@@ -4291,7 +4316,7 @@ int check_todo_list(void)
        advise_to_edit_todo = res =
                parse_insn_buffer(todo_list.buf.buf, &todo_list);
 
-       if (res || check_level == CHECK_IGNORE)
+       if (res || check_level == MISSING_COMMIT_CHECK_IGNORE)
                goto leave_check;
 
        /* Mark the commits in git-rebase-todo as seen */
@@ -4326,7 +4351,7 @@ int check_todo_list(void)
        if (!missing.len)
                goto leave_check;
 
-       if (check_level == CHECK_ERROR)
+       if (check_level == MISSING_COMMIT_CHECK_ERROR)
                advise_to_edit_todo = res = 1;
 
        fprintf(stderr,