sequencer (rebase -i): implement the 'reword' command
[gitweb.git] / sequencer.c
index 6a840216b16fe55bdd116619aa0778eeb30f9295..50e998acc4c5749fbd37b1dfbcf73dc495a7f233 100644 (file)
@@ -102,6 +102,8 @@ static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
 static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, "rebase-merge/gpg_sign_opt")
 static GIT_PATH_FUNC(rebase_path_orig_head, "rebase-merge/orig-head")
 static GIT_PATH_FUNC(rebase_path_verbose, "rebase-merge/verbose")
+static GIT_PATH_FUNC(rebase_path_head_name, "rebase-merge/head-name")
+static GIT_PATH_FUNC(rebase_path_onto, "rebase-merge/onto")
 
 static inline int is_rebase_i(const struct replay_opts *opts)
 {
@@ -716,6 +718,7 @@ enum todo_command {
        TODO_PICK = 0,
        TODO_REVERT,
        TODO_EDIT,
+       TODO_REWORD,
        TODO_FIXUP,
        TODO_SQUASH,
        /* commands that do something else than handling a single commit */
@@ -731,6 +734,7 @@ static struct {
        { 'p', "pick" },
        { 0,   "revert" },
        { 'e', "edit" },
+       { 'r', "reword" },
        { 'f', "fixup" },
        { 's', "squash" },
        { 'x', "exec" },
@@ -960,7 +964,9 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
                }
        }
 
-       if (is_fixup(command)) {
+       if (command == TODO_REWORD)
+               edit = 1;
+       else if (is_fixup(command)) {
                if (update_squash_messages(command, commit, opts))
                        return -1;
                amend = 1;
@@ -1767,7 +1773,10 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                                        intend_to_amend();
                                return error_failed_squash(item->commit, opts,
                                        item->arg_len, item->arg);
-                       }
+                       } else if (res && is_rebase_i(opts))
+                               return res | error_with_patch(item->commit,
+                                       item->arg, item->arg_len, opts, res,
+                                       item->command == TODO_REWORD);
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(item->arg + item->arg_len);
                        int saved = *end_of_arg;
@@ -1784,12 +1793,53 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
        }
 
        if (is_rebase_i(opts)) {
-               struct strbuf buf = STRBUF_INIT;
+               struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
 
                /* Stopped in the middle, as planned? */
                if (todo_list->current < todo_list->nr)
                        return 0;
 
+               if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
+                               starts_with(head_ref.buf, "refs/")) {
+                       unsigned char head[20], orig[20];
+                       int res;
+
+                       if (get_sha1("HEAD", head)) {
+                               res = error(_("cannot read HEAD"));
+cleanup_head_ref:
+                               strbuf_release(&head_ref);
+                               strbuf_release(&buf);
+                               return res;
+                       }
+                       if (!read_oneliner(&buf, rebase_path_orig_head(), 0) ||
+                                       get_sha1_hex(buf.buf, orig)) {
+                               res = error(_("could not read orig-head"));
+                               goto cleanup_head_ref;
+                       }
+                       strbuf_addf(&buf, "rebase -i (finish): %s onto ",
+                               head_ref.buf);
+                       if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
+                               res = error(_("could not read 'onto'"));
+                               goto cleanup_head_ref;
+                       }
+                       if (update_ref(buf.buf, head_ref.buf, head, orig,
+                                       REF_NODEREF, UPDATE_REFS_MSG_ON_ERR)) {
+                               res = error(_("could not update %s"),
+                                       head_ref.buf);
+                               goto cleanup_head_ref;
+                       }
+                       strbuf_reset(&buf);
+                       strbuf_addf(&buf,
+                               "rebase -i (finish): returning to %s",
+                               head_ref.buf);
+                       if (create_symref("HEAD", head_ref.buf, buf.buf)) {
+                               res = error(_("could not update HEAD to %s"),
+                                       head_ref.buf);
+                               goto cleanup_head_ref;
+                       }
+                       strbuf_reset(&buf);
+               }
+
                if (opts->verbose) {
                        struct rev_info log_tree_opt;
                        struct object_id orig, head;
@@ -1810,6 +1860,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                        }
                }
                strbuf_release(&buf);
+               strbuf_release(&head_ref);
        }
 
        /*