revision: rename add_pending_sha1 to add_pending_oid
[gitweb.git] / sequencer.c
index d76dc9cb2b07227d311e4a667aaa5f0d305da45d..218895fde1ba0f1059e60227f3695ee60fb589c3 100644 (file)
@@ -344,7 +344,7 @@ static int read_oneliner(struct strbuf *buf,
 
 static struct tree *empty_tree(void)
 {
-       return lookup_tree(EMPTY_TREE_SHA1_BIN);
+       return lookup_tree(&empty_tree_oid);
 }
 
 static int error_dirty_index(struct replay_opts *opts)
@@ -482,13 +482,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
 
 static int is_index_unchanged(void)
 {
-       unsigned char head_sha1[20];
+       struct object_id head_oid;
        struct commit *head_commit;
 
-       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
+       if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
                return error(_("could not resolve HEAD commit\n"));
 
-       head_commit = lookup_commit(head_sha1);
+       head_commit = lookup_commit(&head_oid);
 
        /*
         * If head_commit is NULL, check_commit, called from
@@ -508,7 +508,8 @@ static int is_index_unchanged(void)
                if (cache_tree_update(&the_index, 0))
                        return error(_("unable to update cache tree\n"));
 
-       return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
+       return !oidcmp(&active_cache_tree->oid,
+                      &head_commit->tree->object.oid);
 }
 
 static int write_author_script(const char *message)
@@ -602,6 +603,12 @@ N_("you have staged changes in your working tree\n"
 "\n"
 "  git rebase --continue\n");
 
+#define ALLOW_EMPTY (1<<0)
+#define EDIT_MSG    (1<<1)
+#define AMEND_MSG   (1<<2)
+#define CLEANUP_MSG (1<<3)
+#define VERIFY_MSG  (1<<4)
+
 /*
  * If we are cherry-pick, and if the merge did not result in
  * hand-editing, we will hit this commit and inherit the original
@@ -615,8 +622,7 @@ N_("you have staged changes in your working tree\n"
  * author metadata.
  */
 static int run_git_commit(const char *defmsg, struct replay_opts *opts,
-                         int allow_empty, int edit, int amend,
-                         int cleanup_commit_message)
+                         unsigned int flags)
 {
        struct child_process cmd = CHILD_PROCESS_INIT;
        const char *value;
@@ -624,7 +630,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        cmd.git_cmd = 1;
 
        if (is_rebase_i(opts)) {
-               if (!edit) {
+               if (!(flags & EDIT_MSG)) {
                        cmd.stdout_to_stderr = 1;
                        cmd.err = -1;
                }
@@ -638,9 +644,10 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
        }
 
        argv_array_push(&cmd.args, "commit");
-       argv_array_push(&cmd.args, "-n");
 
-       if (amend)
+       if (!(flags & VERIFY_MSG))
+               argv_array_push(&cmd.args, "-n");
+       if ((flags & AMEND_MSG))
                argv_array_push(&cmd.args, "--amend");
        if (opts->gpg_sign)
                argv_array_pushf(&cmd.args, "-S%s", opts->gpg_sign);
@@ -648,16 +655,16 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
                argv_array_push(&cmd.args, "-s");
        if (defmsg)
                argv_array_pushl(&cmd.args, "-F", defmsg, NULL);
-       if (cleanup_commit_message)
+       if ((flags & CLEANUP_MSG))
                argv_array_push(&cmd.args, "--cleanup=strip");
-       if (edit)
+       if ((flags & EDIT_MSG))
                argv_array_push(&cmd.args, "-e");
-       else if (!cleanup_commit_message &&
+       else if (!(flags & CLEANUP_MSG) &&
                 !opts->signoff && !opts->record_origin &&
                 git_config_get_value("commit.cleanup", &value))
                argv_array_push(&cmd.args, "--cleanup=verbatim");
 
-       if (allow_empty)
+       if ((flags & ALLOW_EMPTY))
                argv_array_push(&cmd.args, "--allow-empty");
 
        if (opts->allow_empty_message)
@@ -828,13 +835,13 @@ static int update_squash_messages(enum todo_command command,
                strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);
                strbuf_release(&header);
        } else {
-               unsigned char head[20];
+               struct object_id head;
                struct commit *head_commit;
                const char *head_message, *body;
 
-               if (get_sha1("HEAD", head))
+               if (get_oid("HEAD", &head))
                        return error(_("need a HEAD to fixup"));
-               if (!(head_commit = lookup_commit_reference(head)))
+               if (!(head_commit = lookup_commit_reference(&head)))
                        return error(_("could not read HEAD"));
                if (!(head_message = get_commit_buffer(head_commit, NULL)))
                        return error(_("could not read HEAD's commit message"));
@@ -926,14 +933,14 @@ static void record_in_rewritten(struct object_id *oid,
 static int do_pick_commit(enum todo_command command, struct commit *commit,
                struct replay_opts *opts, int final_fixup)
 {
-       int edit = opts->edit, cleanup_commit_message = 0;
-       const char *msg_file = edit ? NULL : git_path_merge_msg();
+       unsigned int flags = opts->edit ? EDIT_MSG : 0;
+       const char *msg_file = opts->edit ? NULL : git_path_merge_msg();
        unsigned char head[20];
        struct commit *base, *next, *parent;
        const char *base_label, *next_label;
        struct commit_message msg = { NULL, NULL, NULL, NULL };
        struct strbuf msgbuf = STRBUF_INIT;
-       int res, unborn = 0, amend = 0, allow = 0;
+       int res, unborn = 0, allow;
 
        if (opts->no_commit) {
                /*
@@ -991,7 +998,9 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
                        opts);
                if (res || command != TODO_REWORD)
                        goto leave;
-               edit = amend = 1;
+               flags |= EDIT_MSG | AMEND_MSG;
+               if (command == TODO_REWORD)
+                       flags |= VERIFY_MSG;
                msg_file = NULL;
                goto fast_forward_edit;
        }
@@ -1046,25 +1055,25 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
        }
 
        if (command == TODO_REWORD)
-               edit = 1;
+               flags |= EDIT_MSG | VERIFY_MSG;
        else if (is_fixup(command)) {
                if (update_squash_messages(command, commit, opts))
                        return -1;
-               amend = 1;
+               flags |= AMEND_MSG;
                if (!final_fixup)
                        msg_file = rebase_path_squash_msg();
                else if (file_exists(rebase_path_fixup_msg())) {
-                       cleanup_commit_message = 1;
+                       flags |= CLEANUP_MSG;
                        msg_file = rebase_path_fixup_msg();
                } else {
-                       const char *dest = git_path("SQUASH_MSG");
+                       const char *dest = git_path_squash_msg();
                        unlink(dest);
                        if (copy_file(dest, rebase_path_squash_msg(), 0666))
                                return error(_("could not rename '%s' to '%s'"),
                                             rebase_path_squash_msg(), dest);
-                       unlink(git_path("MERGE_MSG"));
+                       unlink(git_path_merge_msg());
                        msg_file = dest;
-                       edit = 1;
+                       flags |= EDIT_MSG;
                }
        }
 
@@ -1123,11 +1132,11 @@ static int do_pick_commit(enum todo_command command, struct commit *commit,
        if (allow < 0) {
                res = allow;
                goto leave;
-       }
+       } else if (allow)
+               flags |= ALLOW_EMPTY;
        if (!opts->no_commit)
 fast_forward_edit:
-               res = run_git_commit(msg_file, opts, allow, edit, amend,
-                                    cleanup_commit_message);
+               res = run_git_commit(msg_file, opts, flags);
 
        if (!res && final_fixup) {
                unlink(rebase_path_fixup_msg());
@@ -1192,6 +1201,7 @@ struct todo_list {
        struct todo_item *items;
        int nr, alloc, current;
        int done_nr, total_nr;
+       struct stat_data stat;
 };
 
 #define TODO_LIST_INIT { STRBUF_INIT }
@@ -1212,7 +1222,7 @@ static struct todo_item *append_new_todo(struct todo_list *todo_list)
 
 static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
 {
-       unsigned char commit_sha1[20];
+       struct object_id commit_oid;
        char *end_of_object_name;
        int i, saved, status, padding;
 
@@ -1261,7 +1271,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
        end_of_object_name = (char *) bol + strcspn(bol, " \t\n");
        saved = *end_of_object_name;
        *end_of_object_name = '\0';
-       status = get_sha1(bol, commit_sha1);
+       status = get_oid(bol, &commit_oid);
        *end_of_object_name = saved;
 
        item->arg = end_of_object_name + strspn(end_of_object_name, " \t");
@@ -1270,7 +1280,7 @@ static int parse_insn_line(struct todo_item *item, const char *bol, char *eol)
        if (status < 0)
                return -1;
 
-       item->commit = lookup_commit_reference(commit_sha1);
+       item->commit = lookup_commit_reference(&commit_oid);
        return !item->commit;
 }
 
@@ -1322,6 +1332,7 @@ static int count_commands(struct todo_list *todo_list)
 static int read_populate_todo(struct todo_list *todo_list,
                        struct replay_opts *opts)
 {
+       struct stat st;
        const char *todo_file = get_todo_path(opts);
        int fd, res;
 
@@ -1335,6 +1346,11 @@ static int read_populate_todo(struct todo_list *todo_list,
        }
        close(fd);
 
+       res = stat(todo_file, &st);
+       if (res)
+               return error(_("could not stat '%s'"), todo_file);
+       fill_stat_data(&todo_list->stat, &st);
+
        res = parse_insn_buffer(todo_list->buf.buf, todo_list);
        if (res) {
                if (is_rebase_i(opts))
@@ -1812,10 +1828,10 @@ static int error_failed_squash(struct commit *commit,
                return error(_("could not rename '%s' to '%s'"),
                        rebase_path_squash_msg(), rebase_path_message());
        unlink(rebase_path_fixup_msg());
-       unlink(git_path("MERGE_MSG"));
-       if (copy_file(git_path("MERGE_MSG"), rebase_path_message(), 0666))
+       unlink(git_path_merge_msg());
+       if (copy_file(git_path_merge_msg(), rebase_path_message(), 0666))
                return error(_("could not copy '%s' to '%s'"),
-                            rebase_path_message(), git_path("MERGE_MSG"));
+                            rebase_path_message(), git_path_merge_msg());
        return error_with_patch(commit, subject, subject_len, opts, 1, 0);
 }
 
@@ -2020,10 +2036,25 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
                } else if (item->command == TODO_EXEC) {
                        char *end_of_arg = (char *)(item->arg + item->arg_len);
                        int saved = *end_of_arg;
+                       struct stat st;
 
                        *end_of_arg = '\0';
                        res = do_exec(item->arg);
                        *end_of_arg = saved;
+
+                       /* Reread the todo file if it has changed. */
+                       if (res)
+                               ; /* fall through */
+                       else if (stat(get_todo_path(opts), &st))
+                               res = error_errno(_("could not stat '%s'"),
+                                                 get_todo_path(opts));
+                       else if (match_stat_data(&todo_list->stat, &st)) {
+                               todo_list_release(todo_list);
+                               if (read_populate_todo(todo_list, opts))
+                                       res = -1; /* message was printed */
+                               /* `current` will be incremented below */
+                               todo_list->current = -1;
+                       }
                } else if (!is_noop(item->command))
                        return error(_("unknown command %d"), item->command);
 
@@ -2154,12 +2185,12 @@ static int continue_single_pick(void)
 
 static int commit_staged_changes(struct replay_opts *opts)
 {
-       int amend = 0;
+       unsigned int flags = ALLOW_EMPTY | EDIT_MSG;
 
        if (has_unstaged_changes(1))
                return error(_("cannot rebase: You have unstaged changes."));
        if (!has_uncommitted_changes(0)) {
-               const char *cherry_pick_head = git_path("CHERRY_PICK_HEAD");
+               const char *cherry_pick_head = git_path_cherry_pick_head();
 
                if (file_exists(cherry_pick_head) && unlink(cherry_pick_head))
                        return error(_("could not remove CHERRY_PICK_HEAD"));
@@ -2184,10 +2215,10 @@ static int commit_staged_changes(struct replay_opts *opts)
                                       "--continue' again."));
 
                strbuf_release(&rev);
-               amend = 1;
+               flags |= AMEND_MSG;
        }
 
-       if (run_git_commit(rebase_path_message(), opts, 1, 1, amend, 0))
+       if (run_git_commit(rebase_path_message(), opts, flags))
                return error(_("could not commit staged changes."));
        unlink(rebase_path_amend());
        return 0;
@@ -2250,7 +2281,7 @@ static int single_pick(struct commit *cmit, struct replay_opts *opts)
 int sequencer_pick_revisions(struct replay_opts *opts)
 {
        struct todo_list todo_list = TODO_LIST_INIT;
-       unsigned char sha1[20];
+       struct object_id oid;
        int i, res;
 
        assert(opts->revs);
@@ -2258,16 +2289,16 @@ int sequencer_pick_revisions(struct replay_opts *opts)
                return -1;
 
        for (i = 0; i < opts->revs->pending.nr; i++) {
-               unsigned char sha1[20];
+               struct object_id oid;
                const char *name = opts->revs->pending.objects[i].name;
 
                /* This happens when using --stdin. */
                if (!strlen(name))
                        continue;
 
-               if (!get_sha1(name, sha1)) {
-                       if (!lookup_commit_reference_gently(sha1, 1)) {
-                               enum object_type type = sha1_object_info(sha1, NULL);
+               if (!get_oid(name, &oid)) {
+                       if (!lookup_commit_reference_gently(&oid, 1)) {
+                               enum object_type type = sha1_object_info(oid.hash, NULL);
                                return error(_("%s: can't cherry-pick a %s"),
                                        name, typename(type));
                        }
@@ -2304,9 +2335,9 @@ int sequencer_pick_revisions(struct replay_opts *opts)
        if (walk_revs_populate_todo(&todo_list, opts) ||
                        create_seq_dir() < 0)
                return -1;
-       if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
+       if (get_oid("HEAD", &oid) && (opts->action == REPLAY_REVERT))
                return error(_("can't revert as initial commit"));
-       if (save_head(sha1_to_hex(sha1)))
+       if (save_head(oid_to_hex(&oid)))
                return -1;
        if (save_opts(opts))
                return -1;