diff options
author | Vincent Ambo <tazjin@google.com> | 2020-05-25T23·06+0100 |
---|---|---|
committer | Vincent Ambo <tazjin@google.com> | 2020-05-25T23·06+0100 |
commit | 93ba78d6f4632ef1c5228965e3edc8c0faf88c1e (patch) | |
tree | 85730c182a9f5f492ade8e8ccdb1c2356f9900bd /third_party/git/sequencer.c | |
parent | 6f8fbf4aa4b1654ab27d4829e114538761817de0 (diff) |
revert(3p/git): Revert merge of git upstream at v2.26.2 r/852
This causes cgit to serve error pages, which is undesirable. This reverts commit 5229c9b232de5bfa959ad6ebbb4c8192ac513352, reversing changes made to f2b211131f2347342dde63975b09cf603149f1a3.
Diffstat (limited to 'third_party/git/sequencer.c')
-rw-r--r-- | third_party/git/sequencer.c | 566 |
1 files changed, 272 insertions, 294 deletions
diff --git a/third_party/git/sequencer.c b/third_party/git/sequencer.c index e528225e787f..34ebf8ed94ad 100644 --- a/third_party/git/sequencer.c +++ b/third_party/git/sequencer.c @@ -57,8 +57,6 @@ static GIT_PATH_FUNC(rebase_path, "rebase-merge") GIT_PATH_FUNC(rebase_path_todo, "rebase-merge/git-rebase-todo") GIT_PATH_FUNC(rebase_path_todo_backup, "rebase-merge/git-rebase-todo.backup") -GIT_PATH_FUNC(rebase_path_dropped, "rebase-merge/dropped") - /* * The rebase command lines that have already been processed. A line * is moved here when it is first handled, before any associated user @@ -133,7 +131,7 @@ static GIT_PATH_FUNC(rebase_path_rewritten_pending, "rebase-merge/rewritten-pending") /* - * The path of the file containing the OID of the "squash onto" commit, i.e. + * The path of the file containig the OID of the "squash onto" commit, i.e. * the dummy commit used for `reset [new root]`. */ static GIT_PATH_FUNC(rebase_path_squash_onto, "rebase-merge/squash-onto") @@ -160,8 +158,6 @@ static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy") static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts") static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate") static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec") -static GIT_PATH_FUNC(rebase_path_drop_redundant_commits, "rebase-merge/drop_redundant_commits") -static GIT_PATH_FUNC(rebase_path_keep_redundant_commits, "rebase-merge/keep_redundant_commits") static int git_sequencer_config(const char *k, const char *v, void *cb) { @@ -292,7 +288,7 @@ int sequencer_remove_state(struct replay_opts *opts) char *eol = strchr(p, '\n'); if (eol) *eol = '\0'; - if (delete_ref("(rebase) cleanup", p, NULL, 0) < 0) { + if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) { warning(_("could not delete '%s'"), p); ret = -1; } @@ -326,7 +322,7 @@ static const char *action_name(const struct replay_opts *opts) case REPLAY_PICK: return N_("cherry-pick"); case REPLAY_INTERACTIVE_REBASE: - return N_("rebase"); + return N_("rebase -i"); } die(_("unknown action: %d"), opts->action); } @@ -590,9 +586,9 @@ static int do_recursive_merge(struct repository *r, struct replay_opts *opts) { struct merge_options o; - struct tree *next_tree, *base_tree, *head_tree; + struct tree *result, *next_tree, *base_tree, *head_tree; int clean; - int i; + char **xopt; struct lock_file index_lock = LOCK_INIT; if (repo_hold_locked_index(r, &index_lock, LOCK_REPORT_ON_ERROR) < 0) @@ -612,15 +608,16 @@ static int do_recursive_merge(struct repository *r, next_tree = next ? get_commit_tree(next) : empty_tree(r); base_tree = base ? get_commit_tree(base) : empty_tree(r); - for (i = 0; i < opts->xopts_nr; i++) - parse_merge_opt(&o, opts->xopts[i]); + for (xopt = opts->xopts; xopt != opts->xopts + opts->xopts_nr; xopt++) + parse_merge_opt(&o, *xopt); clean = merge_trees(&o, head_tree, - next_tree, base_tree); + next_tree, base_tree, &result); if (is_rebase_i(opts) && clean <= 0) fputs(o.obuf.buf, stdout); strbuf_release(&o.obuf); + diff_warn_rename_limit("merge.renamelimit", o.needed_rename_limit, 0); if (clean < 0) { rollback_lock_file(&index_lock); return clean; @@ -630,7 +627,7 @@ static int do_recursive_merge(struct repository *r, COMMIT_LOCK | SKIP_IF_UNCHANGED)) /* * TRANSLATORS: %s will be "revert", "cherry-pick" or - * "rebase". + * "rebase -i". */ return error(_("%s: Unable to write new index file"), _(action_name(opts))); @@ -872,6 +869,34 @@ static char *get_author(const char *message) return NULL; } +/* Read author-script and return an ident line (author <email> timestamp) */ +static const char *read_author_ident(struct strbuf *buf) +{ + struct strbuf out = STRBUF_INIT; + char *name, *email, *date; + + if (read_author_script(rebase_path_author_script(), + &name, &email, &date, 0)) + return NULL; + + /* validate date since fmt_ident() will die() on bad value */ + if (parse_date(date, &out)){ + warning(_("invalid date format '%s' in '%s'"), + date, rebase_path_author_script()); + strbuf_release(&out); + return NULL; + } + + strbuf_reset(&out); + strbuf_addstr(&out, fmt_ident(name, email, WANT_AUTHOR_IDENT, date, 0)); + strbuf_swap(buf, &out); + strbuf_release(&out); + free(name); + free(email); + free(date); + return buf->buf; +} + static const char staged_changes_advice[] = N_("you have staged changes in your working tree\n" "If these changes are meant to be squashed into the previous commit, run:\n" @@ -929,6 +954,47 @@ static int run_git_commit(struct repository *r, { struct child_process cmd = CHILD_PROCESS_INIT; + if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) { + struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT; + const char *author = NULL; + struct object_id root_commit, *cache_tree_oid; + int res = 0; + + if (is_rebase_i(opts)) { + author = read_author_ident(&script); + if (!author) { + strbuf_release(&script); + return -1; + } + } + + if (!defmsg) + BUG("root commit without message"); + + if (!(cache_tree_oid = get_cache_tree_oid(r->index))) + res = -1; + + if (!res) + res = strbuf_read_file(&msg, defmsg, 0); + + if (res <= 0) + res = error_errno(_("could not read '%s'"), defmsg); + else + res = commit_tree(msg.buf, msg.len, cache_tree_oid, + NULL, &root_commit, author, + opts->gpg_sign); + + strbuf_release(&msg); + strbuf_release(&script); + if (!res) { + update_ref(NULL, "CHERRY_PICK_HEAD", &root_commit, NULL, + REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR); + res = update_ref(NULL, "HEAD", &root_commit, NULL, 0, + UPDATE_REFS_MSG_ON_ERR); + } + return res < 0 ? error(_("writing root commit")) : 0; + } + cmd.git_cmd = 1; if (is_rebase_i(opts) && read_env_script(&cmd.env_array)) { @@ -1130,22 +1196,25 @@ static int run_prepare_commit_msg_hook(struct repository *r, struct strbuf *msg, const char *commit) { - int ret = 0; - const char *name, *arg1 = NULL, *arg2 = NULL; + struct argv_array hook_env = ARGV_ARRAY_INIT; + int ret; + const char *name; name = git_path_commit_editmsg(); if (write_message(msg->buf, msg->len, name, 0)) return -1; - if (commit) { - arg1 = "commit"; - arg2 = commit; - } else { - arg1 = "message"; - } - if (run_commit_hook(0, r->index_file, "prepare-commit-msg", name, - arg1, arg2, NULL)) + argv_array_pushf(&hook_env, "GIT_INDEX_FILE=%s", r->index_file); + argv_array_push(&hook_env, "GIT_EDITOR=:"); + if (commit) + ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name, + "commit", commit, NULL); + else + ret = run_hook_le(hook_env.argv, "prepare-commit-msg", name, + "message", NULL); + if (ret) ret = error(_("'prepare-commit-msg' hook failed")); + argv_array_clear(&hook_env); return ret; } @@ -1309,7 +1378,7 @@ static int try_to_commit(struct repository *r, struct object_id *oid) { struct object_id tree; - struct commit *current_head = NULL; + struct commit *current_head; struct commit_list *parents = NULL; struct commit_extra_header *extra = NULL; struct strbuf err = STRBUF_INIT; @@ -1344,8 +1413,7 @@ static int try_to_commit(struct repository *r, } parents = copy_commit_list(current_head->parents); extra = read_commit_extra_headers(current_head, exclude_gpgsig); - } else if (current_head && - (!(flags & CREATE_ROOT_COMMIT) || (flags & AMEND_MSG))) { + } else if (current_head) { commit_list_insert(current_head, &parents); } @@ -1354,27 +1422,11 @@ static int try_to_commit(struct repository *r, goto out; } - if (!(flags & ALLOW_EMPTY)) { - struct commit *first_parent = current_head; - - if (flags & AMEND_MSG) { - if (current_head->parents) { - first_parent = current_head->parents->item; - if (repo_parse_commit(r, first_parent)) { - res = error(_("could not parse HEAD commit")); - goto out; - } - } else { - first_parent = NULL; - } - } - if (oideq(first_parent - ? get_commit_tree_oid(first_parent) - : the_hash_algo->empty_tree, - &tree)) { - res = 1; /* run 'git commit' to display error message */ - goto out; - } + if (!(flags & ALLOW_EMPTY) && oideq(current_head ? + get_commit_tree_oid(current_head) : + the_hash_algo->empty_tree, &tree)) { + res = 1; /* run 'git commit' to display error message */ + goto out; } if (find_hook("prepare-commit-msg")) { @@ -1420,7 +1472,6 @@ static int try_to_commit(struct repository *r, goto out; } - run_commit_hook(0, r->index_file, "post-commit", NULL); if (flags & AMEND_MSG) commit_post_rewrite(r, current_head, oid); @@ -1439,7 +1490,8 @@ static int do_commit(struct repository *r, { int res = 1; - if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG)) { + if (!(flags & EDIT_MSG) && !(flags & VERIFY_MSG) && + !(flags & CREATE_ROOT_COMMIT)) { struct object_id oid; struct strbuf sb = STRBUF_INIT; @@ -1487,30 +1539,23 @@ static int is_original_commit_empty(struct commit *commit) } /* - * Should empty commits be allowed? Return status: - * <0: Error in is_index_unchanged(r) or is_original_commit_empty(commit) - * 0: Halt on empty commit - * 1: Allow empty commit - * 2: Drop empty commit + * Do we run "git commit" with "--allow-empty"? */ static int allow_empty(struct repository *r, struct replay_opts *opts, struct commit *commit) { - int index_unchanged, originally_empty; + int index_unchanged, empty_commit; /* - * Four cases: + * Three cases: * * (1) we do not allow empty at all and error out. * - * (2) we allow ones that were initially empty, and - * just drop the ones that become empty + * (2) we allow ones that were initially empty, but + * forbid the ones that become empty; * - * (3) we allow ones that were initially empty, but - * halt for the ones that become empty; - * - * (4) we allow both. + * (3) we allow both. */ if (!opts->allow_empty) return 0; /* let "git commit" barf as necessary */ @@ -1524,15 +1569,13 @@ static int allow_empty(struct repository *r, if (opts->keep_redundant_commits) return 1; - originally_empty = is_original_commit_empty(commit); - if (originally_empty < 0) - return originally_empty; - if (originally_empty) - return 1; - else if (opts->drop_redundant_commits) - return 2; - else + empty_commit = is_original_commit_empty(commit); + if (empty_commit < 0) + return empty_commit; + if (!empty_commit) return 0; + else + return 1; } static struct { @@ -1603,7 +1646,6 @@ static int update_squash_messages(struct repository *r, struct strbuf buf = STRBUF_INIT; int res; const char *message, *body; - const char *encoding = get_commit_output_encoding(); if (opts->current_fixup_count > 0) { struct strbuf header = STRBUF_INIT; @@ -1630,7 +1672,7 @@ static int update_squash_messages(struct repository *r, return error(_("need a HEAD to fixup")); if (!(head_commit = lookup_commit_reference(r, &head))) return error(_("could not read HEAD")); - if (!(head_message = logmsg_reencode(head_commit, NULL, encoding))) + if (!(head_message = get_commit_buffer(head_commit, NULL))) return error(_("could not read HEAD's commit message")); find_commit_subject(head_message, &body); @@ -1651,7 +1693,7 @@ static int update_squash_messages(struct repository *r, unuse_commit_buffer(head_commit, head_message); } - if (!(message = logmsg_reencode(commit, NULL, encoding))) + if (!(message = get_commit_buffer(commit, NULL))) return error(_("could not read commit message of %s"), oid_to_hex(&commit->object.oid)); find_commit_subject(message, &body); @@ -1733,7 +1775,7 @@ static int do_pick_commit(struct repository *r, enum todo_command command, struct commit *commit, struct replay_opts *opts, - int final_fixup, int *check_todo) + int final_fixup) { unsigned int flags = opts->edit ? EDIT_MSG : 0; const char *msg_file = opts->edit ? NULL : git_path_merge_msg(r); @@ -1743,7 +1785,7 @@ static int do_pick_commit(struct repository *r, char *author = NULL; struct commit_message msg = { NULL, NULL, NULL, NULL }; struct strbuf msgbuf = STRBUF_INIT; - int res, unborn = 0, reword = 0, allow, drop_commit; + int res, unborn = 0, allow; if (opts->no_commit) { /* @@ -1813,7 +1855,7 @@ static int do_pick_commit(struct repository *r, opts); if (res || command != TODO_REWORD) goto leave; - reword = 1; + flags |= EDIT_MSG | AMEND_MSG | VERIFY_MSG; msg_file = NULL; goto fast_forward_edit; } @@ -1871,7 +1913,7 @@ static int do_pick_commit(struct repository *r, } if (command == TODO_REWORD) - reword = 1; + flags |= EDIT_MSG | VERIFY_MSG; else if (is_fixup(command)) { if (update_squash_messages(r, command, commit, opts)) return -1; @@ -1948,37 +1990,20 @@ static int do_pick_commit(struct repository *r, goto leave; } - drop_commit = 0; allow = allow_empty(r, opts, commit); if (allow < 0) { res = allow; goto leave; - } else if (allow == 1) { + } else if (allow) flags |= ALLOW_EMPTY; - } else if (allow == 2) { - drop_commit = 1; - unlink(git_path_cherry_pick_head(r)); - unlink(git_path_merge_msg(r)); - fprintf(stderr, - _("dropping %s %s -- patch contents already upstream\n"), - oid_to_hex(&commit->object.oid), msg.subject); - } /* else allow == 0 and there's nothing special to do */ - if (!opts->no_commit && !drop_commit) { + if (!opts->no_commit) { +fast_forward_edit: if (author || command == TODO_REVERT || (flags & AMEND_MSG)) res = do_commit(r, msg_file, author, opts, flags); else res = error(_("unable to parse commit author")); - *check_todo = !!(flags & EDIT_MSG); - if (!res && reword) { -fast_forward_edit: - res = run_git_commit(r, NULL, opts, EDIT_MSG | - VERIFY_MSG | AMEND_MSG | - (flags & ALLOW_EMPTY)); - *check_todo = 1; - } } - if (!res && final_fixup) { unlink(rebase_path_fixup_msg()); unlink(rebase_path_squash_msg()); @@ -2045,7 +2070,6 @@ void todo_list_release(struct todo_list *todo_list) static struct todo_item *append_new_todo(struct todo_list *todo_list) { ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc); - todo_list->total_nr++; return todo_list->items + todo_list->nr++; } @@ -2140,8 +2164,6 @@ static int parse_insn_line(struct repository *r, struct todo_item *item, saved = *end_of_object_name; *end_of_object_name = '\0'; status = get_oid(bol, &commit_oid); - if (status < 0) - error(_("could not parse '%s'"), bol); /* return later */ *end_of_object_name = saved; bol = end_of_object_name + strspn(end_of_object_name, " \t"); @@ -2149,10 +2171,11 @@ static int parse_insn_line(struct repository *r, struct todo_item *item, item->arg_len = (int)(eol - bol); if (status < 0) - return status; + return error(_("could not parse '%.*s'"), + (int)(end_of_object_name - bol), bol); item->commit = lookup_commit_reference(r, &commit_oid); - return item->commit ? 0 : -1; + return !item->commit; } int sequencer_get_last_command(struct repository *r, enum replay_action *action) @@ -2318,16 +2341,6 @@ void sequencer_post_commit_cleanup(struct repository *r, int verbose) sequencer_remove_state(&opts); } -static void todo_list_write_total_nr(struct todo_list *todo_list) -{ - FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w"); - - if (f) { - fprintf(f, "%d\n", todo_list->total_nr); - fclose(f); - } -} - static int read_populate_todo(struct repository *r, struct todo_list *todo_list, struct replay_opts *opts) @@ -2373,6 +2386,7 @@ static int read_populate_todo(struct repository *r, if (is_rebase_i(opts)) { struct todo_list done = TODO_LIST_INIT; + FILE *f = fopen_or_warn(rebase_path_msgtotal(), "w"); if (strbuf_read_file(&done.buf, rebase_path_done(), 0) > 0 && !todo_list_parse_insn_buffer(r, done.buf.buf, &done)) @@ -2384,7 +2398,10 @@ static int read_populate_todo(struct repository *r, + count_commands(todo_list); todo_list_release(&done); - todo_list_write_total_nr(todo_list); + if (f) { + fprintf(f, "%d\n", todo_list->total_nr); + fclose(f); + } } return 0; @@ -2518,12 +2535,6 @@ static int read_populate_opts(struct replay_opts *opts) if (file_exists(rebase_path_reschedule_failed_exec())) opts->reschedule_failed_exec = 1; - if (file_exists(rebase_path_drop_redundant_commits())) - opts->drop_redundant_commits = 1; - - if (file_exists(rebase_path_keep_redundant_commits())) - opts->keep_redundant_commits = 1; - read_strategy_opts(opts, &buf); strbuf_release(&buf); @@ -2575,6 +2586,8 @@ static void write_strategy_opts(struct replay_opts *opts) int write_basic_state(struct replay_opts *opts, const char *head_name, struct commit *onto, const char *orig_head) { + const char *quiet = getenv("GIT_QUIET"); + if (head_name) write_file(rebase_path_head_name(), "%s\n", head_name); if (onto) @@ -2583,8 +2596,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name, if (orig_head) write_file(rebase_path_orig_head(), "%s\n", orig_head); - if (opts->quiet) - write_file(rebase_path_quiet(), "%s", ""); + if (quiet) + write_file(rebase_path_quiet(), "%s\n", quiet); if (opts->verbose) write_file(rebase_path_verbose(), "%s", ""); if (opts->strategy) @@ -2601,10 +2614,6 @@ int write_basic_state(struct replay_opts *opts, const char *head_name, write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign); if (opts->signoff) write_file(rebase_path_signoff(), "--signoff\n"); - if (opts->drop_redundant_commits) - write_file(rebase_path_drop_redundant_commits(), "%s", ""); - if (opts->keep_redundant_commits) - write_file(rebase_path_keep_redundant_commits(), "%s", ""); if (opts->reschedule_failed_exec) write_file(rebase_path_reschedule_failed_exec(), "%s", ""); @@ -2617,17 +2626,14 @@ static int walk_revs_populate_todo(struct todo_list *todo_list, enum todo_command command = opts->action == REPLAY_PICK ? TODO_PICK : TODO_REVERT; const char *command_string = todo_command_info[command].str; - const char *encoding; struct commit *commit; if (prepare_revs(opts)) return -1; - encoding = get_log_output_encoding(); - while ((commit = get_revision(opts->revs))) { struct todo_item *item = append_new_todo(todo_list); - const char *commit_buffer = logmsg_reencode(commit, NULL, encoding); + const char *commit_buffer = get_commit_buffer(commit, NULL); const char *subject; int subject_len; @@ -3024,8 +3030,7 @@ static int make_patch(struct repository *r, strbuf_addf(&buf, "%s/message", get_dir(opts)); if (!file_exists(buf.buf)) { - const char *encoding = get_commit_output_encoding(); - const char *commit_buffer = logmsg_reencode(commit, NULL, encoding); + const char *commit_buffer = get_commit_buffer(commit, NULL); find_commit_subject(commit_buffer, &subject); res |= write_message(subject, strlen(subject), buf.buf, 1); unuse_commit_buffer(commit, commit_buffer); @@ -3204,7 +3209,7 @@ static int do_label(struct repository *r, const char *name, int len) return error(_("illegal label name: '%.*s'"), len, name); strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name); - strbuf_addf(&msg, "rebase (label) '%.*s'", len, name); + strbuf_addf(&msg, "rebase -i (label) '%.*s'", len, name); transaction = ref_store_transaction_begin(refs, &err); if (!transaction) { @@ -3359,9 +3364,6 @@ static int do_merge(struct repository *r, struct commit *head_commit, *merge_commit, *i; 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")) ? - NULL : opts->strategy; struct merge_options o; int merge_arg_len, oneline_offset, can_fast_forward, ret, k; static struct lock_file lock; @@ -3427,8 +3429,7 @@ static int do_merge(struct repository *r, } if (commit) { - const char *encoding = get_commit_output_encoding(); - const char *message = logmsg_reencode(commit, NULL, encoding); + const char *message = get_commit_buffer(commit, NULL); const char *body; int len; @@ -3515,7 +3516,7 @@ static int do_merge(struct repository *r, goto leave_merge; } - if (strategy || to_merge->next) { + if (to_merge->next) { /* Octopus merge */ struct child_process cmd = CHILD_PROCESS_INIT; @@ -3529,14 +3530,7 @@ static int do_merge(struct repository *r, cmd.git_cmd = 1; argv_array_push(&cmd.args, "merge"); argv_array_push(&cmd.args, "-s"); - if (!strategy) - argv_array_push(&cmd.args, "octopus"); - else { - argv_array_push(&cmd.args, strategy); - for (k = 0; k < opts->xopts_nr; k++) - argv_array_pushf(&cmd.args, - "-X%s", opts->xopts[k]); - } + argv_array_push(&cmd.args, "octopus"); argv_array_push(&cmd.args, "--no-edit"); argv_array_push(&cmd.args, "--no-ff"); argv_array_push(&cmd.args, "--no-log"); @@ -3574,7 +3568,7 @@ static int do_merge(struct repository *r, goto leave_merge; } - write_message(oid_to_hex(&merge_commit->object.oid), the_hash_algo->hexsz, + write_message(oid_to_hex(&merge_commit->object.oid), GIT_SHA1_HEXSZ, git_path_merge_head(r), 0); write_message("no-ff", 5, git_path_merge_mode(r), 0); @@ -3746,6 +3740,20 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts, return ret; } +int prepare_branch_to_be_rebased(struct repository *r, 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(r, opts, commit, action)) + return error(_("could not checkout %s"), commit); + } + + return 0; +} + static int checkout_onto(struct repository *r, struct replay_opts *opts, const char *onto_name, const struct object_id *onto, const char *orig_head) @@ -3810,7 +3818,6 @@ static int pick_commits(struct repository *r, while (todo_list->current < todo_list->nr) { struct todo_item *item = todo_list->items + todo_list->current; const char *arg = todo_item_get_arg(todo_list, item); - int check_todo = 0; if (save_todo(todo_list, opts)) return -1; @@ -3849,8 +3856,7 @@ static int pick_commits(struct repository *r, command_to_string(item->command), NULL), 1); res = do_pick_commit(r, item->command, item->commit, - opts, is_final_fixup(todo_list), - &check_todo); + opts, is_final_fixup(todo_list)); if (is_rebase_i(opts) && res < 0) { /* Reschedule */ advise(_(rescheduled_advice), @@ -3907,6 +3913,7 @@ static int pick_commits(struct repository *r, } else if (item->command == TODO_EXEC) { char *end_of_arg = (char *)(arg + item->arg_len); int saved = *end_of_arg; + struct stat st; if (!opts->verbose) term_clear_line(); @@ -3917,8 +3924,17 @@ static int pick_commits(struct repository *r, if (res) { if (opts->reschedule_failed_exec) reschedule = 1; + } 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)) { + /* Reread the todo file if it has changed. */ + todo_list_release(todo_list); + if (read_populate_todo(r, todo_list, opts)) + res = -1; /* message was printed */ + /* `current` will be incremented below */ + todo_list->current = -1; } - check_todo = 1; } else if (item->command == TODO_LABEL) { if ((res = do_label(r, arg, item->arg_len))) reschedule = 1; @@ -3954,20 +3970,6 @@ static int pick_commits(struct repository *r, item->commit, arg, item->arg_len, opts, res, 0); - } else if (is_rebase_i(opts) && check_todo && !res) { - struct stat st; - - 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)) { - /* Reread the todo file if it has changed. */ - todo_list_release(todo_list); - if (read_populate_todo(r, todo_list, opts)) - res = -1; /* message was printed */ - /* `current` will be incremented below */ - todo_list->current = -1; - } } todo_list->current++; @@ -4195,10 +4197,9 @@ static int commit_staged_changes(struct repository *r, */ struct commit *commit; const char *path = rebase_path_squash_msg(); - const char *encoding = get_commit_output_encoding(); if (parse_head(r, &commit) || - !(p = logmsg_reencode(commit, NULL, encoding)) || + !(p = get_commit_buffer(commit, NULL)) || write_message(p, strlen(p), path, 0)) { unuse_commit_buffer(commit, p); return error(_("could not write file: " @@ -4255,18 +4256,8 @@ int sequencer_continue(struct repository *r, struct replay_opts *opts) if (is_rebase_i(opts)) { if ((res = read_populate_todo(r, &todo_list, opts))) goto release_todo_list; - - if (file_exists(rebase_path_dropped())) { - if ((res = todo_list_check_against_backup(r, &todo_list))) - goto release_todo_list; - - unlink(rebase_path_dropped()); - } - - if (commit_staged_changes(r, opts, &todo_list)) { - res = -1; - goto release_todo_list; - } + if (commit_staged_changes(r, opts, &todo_list)) + return -1; } else if (!file_exists(get_todo_path(opts))) return continue_single_pick(r); else if ((res = read_populate_todo(r, &todo_list, opts))) @@ -4305,12 +4296,9 @@ static int single_pick(struct repository *r, struct commit *cmit, struct replay_opts *opts) { - int check_todo; - setenv(GIT_REFLOG_ACTION, action_name(opts), 0); return do_pick_commit(r, opts->action == REPLAY_PICK ? - TODO_PICK : TODO_REVERT, cmit, opts, 0, - &check_todo); + TODO_PICK : TODO_REVERT, cmit, opts, 0); } int sequencer_pick_revisions(struct repository *r, @@ -4452,14 +4440,9 @@ struct labels_entry { char label[FLEX_ARRAY]; }; -static int labels_cmp(const void *fndata, const struct hashmap_entry *eptr, - const struct hashmap_entry *entry_or_key, const void *key) +static int labels_cmp(const void *fndata, const struct labels_entry *a, + const struct labels_entry *b, const void *key) { - const struct labels_entry *a, *b; - - a = container_of(eptr, const struct labels_entry, entry); - b = container_of(entry_or_key, const struct labels_entry, entry); - return key ? strcmp(a->label, key) : strcmp(a->label, b->label); } @@ -4480,6 +4463,7 @@ static const char *label_oid(struct object_id *oid, const char *label, struct labels_entry *labels_entry; struct string_entry *string_entry; struct object_id dummy; + size_t len; int i; string_entry = oidmap_get(&state->commit2label, oid); @@ -4499,11 +4483,11 @@ static const char *label_oid(struct object_id *oid, const char *label, * abbreviation for any uninteresting commit's names that does not * clash with any other label. */ - strbuf_reset(&state->buf); if (!label) { char *p; - strbuf_grow(&state->buf, GIT_MAX_HEXSZ); + strbuf_reset(&state->buf); + strbuf_grow(&state->buf, GIT_SHA1_HEXSZ); label = p = state->buf.buf; find_unique_abbrev_r(p, oid, default_abbrev); @@ -4516,7 +4500,7 @@ static const char *label_oid(struct object_id *oid, const char *label, size_t i = strlen(p) + 1; oid_to_hex_r(p, oid); - for (; i < the_hash_algo->hexsz; i++) { + for (; i < GIT_SHA1_HEXSZ; i++) { char save = p[i]; p[i] = '\0'; if (!hashmap_get_from_hash(&state->labels, @@ -4525,60 +4509,37 @@ static const char *label_oid(struct object_id *oid, const char *label, p[i] = save; } } - } else { - struct strbuf *buf = &state->buf; - + } else if (((len = strlen(label)) == the_hash_algo->hexsz && + !get_oid_hex(label, &dummy)) || + (len == 1 && *label == '#') || + hashmap_get_from_hash(&state->labels, + strihash(label), label)) { /* - * Sanitize labels by replacing non-alpha-numeric characters - * (including white-space ones) by dashes, as they might be - * illegal in file names (and hence in ref names). - * - * Note that we retain non-ASCII UTF-8 characters (identified - * via the most significant bit). They should be all acceptable - * in file names. We do not validate the UTF-8 here, that's not - * the job of this function. + * If the label already exists, or if the label is a valid full + * OID, or the label is a '#' (which we use as a separator + * between merge heads and oneline), we append a dash and a + * number to make it unique. */ - for (; *label; label++) - if ((*label & 0x80) || isalnum(*label)) - strbuf_addch(buf, *label); - /* avoid leading dash and double-dashes */ - else if (buf->len && buf->buf[buf->len - 1] != '-') - strbuf_addch(buf, '-'); - if (!buf->len) { - strbuf_addstr(buf, "rev-"); - strbuf_add_unique_abbrev(buf, oid, default_abbrev); - } - label = buf->buf; + struct strbuf *buf = &state->buf; - if ((buf->len == the_hash_algo->hexsz && - !get_oid_hex(label, &dummy)) || - (buf->len == 1 && *label == '#') || - hashmap_get_from_hash(&state->labels, - strihash(label), label)) { - /* - * If the label already exists, or if the label is a - * valid full OID, or the label is a '#' (which we use - * as a separator between merge heads and oneline), we - * append a dash and a number to make it unique. - */ - size_t len = buf->len; + strbuf_reset(buf); + strbuf_add(buf, label, len); - for (i = 2; ; i++) { - strbuf_setlen(buf, len); - strbuf_addf(buf, "-%d", i); - if (!hashmap_get_from_hash(&state->labels, - strihash(buf->buf), - buf->buf)) - break; - } - - label = buf->buf; + for (i = 2; ; i++) { + strbuf_setlen(buf, len); + strbuf_addf(buf, "-%d", i); + if (!hashmap_get_from_hash(&state->labels, + strihash(buf->buf), + buf->buf)) + break; } + + label = buf->buf; } FLEX_ALLOC_STR(labels_entry, label, label); - hashmap_entry_init(&labels_entry->entry, strihash(label)); - hashmap_add(&state->labels, &labels_entry->entry); + hashmap_entry_init(labels_entry, strihash(label)); + hashmap_add(&state->labels, labels_entry); FLEX_ALLOC_STR(string_entry, string, label); oidcpy(&string_entry->entry.oid, oid); @@ -4591,8 +4552,8 @@ static int make_script_with_merges(struct pretty_print_context *pp, struct rev_info *revs, struct strbuf *out, unsigned flags) { + int keep_empty = flags & TODO_LIST_KEEP_EMPTY; int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS; - int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO; struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT; struct strbuf label = STRBUF_INIT; struct commit_list *commits = NULL, **tail = &commits, *iter; @@ -4612,19 +4573,14 @@ static int make_script_with_merges(struct pretty_print_context *pp, oidmap_init(&commit2todo, 0); oidmap_init(&state.commit2label, 0); - hashmap_init(&state.labels, labels_cmp, NULL, 0); + hashmap_init(&state.labels, (hashmap_cmp_fn) labels_cmp, NULL, 0); strbuf_init(&state.buf, 32); if (revs->cmdline.nr && (revs->cmdline.rev[0].flags & BOTTOM)) { - struct labels_entry *onto_label_entry; struct object_id *oid = &revs->cmdline.rev[0].item->oid; FLEX_ALLOC_STR(entry, string, "onto"); oidcpy(&entry->entry.oid, oid); oidmap_put(&state.commit2label, entry); - - FLEX_ALLOC_STR(onto_label_entry, label, "onto"); - hashmap_entry_init(&onto_label_entry->entry, strihash("onto")); - hashmap_add(&state.labels, &onto_label_entry->entry); } /* @@ -4653,6 +4609,8 @@ static int make_script_with_merges(struct pretty_print_context *pp, if (!to_merge) { /* non-merge commit: easy case */ strbuf_reset(&buf); + if (!keep_empty && is_empty) + strbuf_addf(&buf, "%c ", comment_line_char); strbuf_addf(&buf, "%s %s %s", cmd_pick, oid_to_hex(&commit->object.oid), oneline.buf); @@ -4677,6 +4635,10 @@ static int make_script_with_merges(struct pretty_print_context *pp, else strbuf_addbuf(&label, &oneline); + for (p1 = label.buf; *p1; p1++) + if (isspace(*p1)) + *(char *)p1 = '-'; + strbuf_reset(&buf); strbuf_addf(&buf, "%s -C %s", cmd_merge, oid_to_hex(&commit->object.oid)); @@ -4719,7 +4681,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, label_oid(oid, "branch-point", &state); } - /* Add HEAD as implicit "tip of branch" */ + /* Add HEAD as implict "tip of branch" */ if (!iter->next) tips_tail = &commit_list_insert(iter->item, tips_tail)->next; @@ -4758,8 +4720,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, if (!commit) strbuf_addf(out, "%s %s\n", cmd_reset, - rebase_cousins || root_with_onto ? - "onto" : "[new root]"); + rebase_cousins ? "onto" : "[new root]"); else { const char *to = NULL; @@ -4806,7 +4767,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, oidmap_free(&commit2todo, 1); oidmap_free(&state.commit2label, 1); - hashmap_free_entries(&state.labels, struct labels_entry, entry); + hashmap_free(&state.labels, 1); strbuf_release(&state.buf); return 0; @@ -4819,6 +4780,7 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, struct pretty_print_context pp = {0}; struct rev_info revs; struct commit *commit; + int keep_empty = flags & TODO_LIST_KEEP_EMPTY; const char *insn = flags & TODO_LIST_ABBREVIATE_CMDS ? "p" : "pick"; int rebase_merges = flags & TODO_LIST_REBASE_MERGES; @@ -4854,10 +4816,12 @@ int sequencer_make_script(struct repository *r, struct strbuf *out, int argc, return make_script_with_merges(&pp, &revs, out, flags); while ((commit = get_revision(&revs))) { - int is_empty = is_original_commit_empty(commit); + int is_empty = is_original_commit_empty(commit); if (!is_empty && (commit->object.flags & PATCHSAME)) continue; + if (!keep_empty && is_empty) + strbuf_addf(out, "%c ", comment_line_char); strbuf_addf(out, "%s %s ", insn, oid_to_hex(&commit->object.oid)); pretty_print_commit(&pp, commit, out); @@ -4898,7 +4862,7 @@ void todo_list_add_exec_commands(struct todo_list *todo_list, * are considered part of the pick, so we insert the commands *after* * those chains if there are any. * - * As we insert the exec commands immediately after rearranging + * As we insert the exec commands immediatly after rearranging * any fixups and before the user edits the list, a fixup chain * can never contain comments (any comments are empty picks that * have been commented out because the user did not specify @@ -4994,7 +4958,7 @@ int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list, todo_list_to_strbuf(r, todo_list, &buf, num, flags); if (flags & TODO_LIST_APPEND_TODO_HELP) - append_todo_help(count_commands(todo_list), + append_todo_help(flags & TODO_LIST_KEEP_EMPTY, count_commands(todo_list), shortrevisions, shortonto, &buf); res = write_message(buf.buf, buf.len, file, 0); @@ -5003,6 +4967,41 @@ int todo_list_write_to_file(struct repository *r, struct todo_list *todo_list, return res; } +static const char edit_todo_list_advice[] = +N_("You can fix this with 'git rebase --edit-todo' " +"and then run 'git rebase --continue'.\n" +"Or you can abort the rebase with 'git rebase" +" --abort'.\n"); + +int check_todo_list_from_file(struct repository *r) +{ + struct todo_list old_todo = TODO_LIST_INIT, new_todo = TODO_LIST_INIT; + int res = 0; + + if (strbuf_read_file_or_whine(&new_todo.buf, rebase_path_todo()) < 0) { + res = -1; + goto out; + } + + if (strbuf_read_file_or_whine(&old_todo.buf, rebase_path_todo_backup()) < 0) { + res = -1; + goto out; + } + + res = todo_list_parse_insn_buffer(r, old_todo.buf.buf, &old_todo); + if (!res) + res = todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo); + if (!res) + res = todo_list_check(&old_todo, &new_todo); + if (res) + fprintf(stderr, _(edit_todo_list_advice)); +out: + todo_list_release(&old_todo); + todo_list_release(&new_todo); + + return res; +} + /* skip picking commits whose parents are unchanged */ static int skip_unnecessary_picks(struct repository *r, struct todo_list *todo_list, @@ -5042,7 +5041,6 @@ static int skip_unnecessary_picks(struct repository *r, MOVE_ARRAY(todo_list->items, todo_list->items + i, todo_list->nr - i); todo_list->nr -= i; todo_list->current = 0; - todo_list->done_nr += i; if (is_fixup(peek_command(todo_list, 0))) record_in_rewritten(base_oid, peek_command(todo_list, 0)); @@ -5059,7 +5057,7 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla { const char *shortonto, *todo_file = rebase_path_todo(); struct todo_list new_todo = TODO_LIST_INIT; - struct strbuf *buf = &todo_list->buf, buf2 = STRBUF_INIT; + struct strbuf *buf = &todo_list->buf; struct object_id oid = onto->object.oid; int res; @@ -5100,22 +5098,17 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla todo_list_release(&new_todo); return error(_("nothing to do")); - } else if (res == -4) { + } + + if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) || + todo_list_check(todo_list, &new_todo)) { + fprintf(stderr, _(edit_todo_list_advice)); checkout_onto(r, opts, onto_name, &onto->object.oid, orig_head); todo_list_release(&new_todo); return -1; } - /* Expand the commit IDs */ - todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0); - strbuf_swap(&new_todo.buf, &buf2); - strbuf_release(&buf2); - new_todo.total_nr -= new_todo.nr; - if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0) - BUG("invalid todo list after expanding IDs:\n%s", - new_todo.buf.buf); - if (opts->allow_ff && skip_unnecessary_picks(r, &new_todo, &oid)) { todo_list_release(&new_todo); return error(_("could not skip unnecessary pick commands")); @@ -5127,21 +5120,15 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla return error_errno(_("could not write '%s'"), todo_file); } - res = -1; + todo_list_release(&new_todo); if (checkout_onto(r, opts, onto_name, &oid, orig_head)) - goto cleanup; + return -1; if (require_clean_work_tree(r, "rebase", "", 1, 1)) - goto cleanup; - - todo_list_write_total_nr(&new_todo); - res = pick_commits(r, &new_todo, opts); - -cleanup: - todo_list_release(&new_todo); + return -1; - return res; + return sequencer_continue(r, opts); } struct subject2item_entry { @@ -5151,15 +5138,9 @@ struct subject2item_entry { }; static int subject2item_cmp(const void *fndata, - const struct hashmap_entry *eptr, - const struct hashmap_entry *entry_or_key, - const void *key) + const struct subject2item_entry *a, + const struct subject2item_entry *b, const void *key) { - const struct subject2item_entry *a, *b; - - a = container_of(eptr, const struct subject2item_entry, entry); - b = container_of(entry_or_key, const struct subject2item_entry, entry); - return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject); } @@ -5192,7 +5173,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) * In that case, last[i] will indicate the index of the latest item to * be moved to appear after the i'th. */ - hashmap_init(&subject2item, subject2item_cmp, NULL, todo_list->nr); + hashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp, + NULL, todo_list->nr); ALLOC_ARRAY(next, todo_list->nr); ALLOC_ARRAY(tail, todo_list->nr); ALLOC_ARRAY(subjects, todo_list->nr); @@ -5218,7 +5200,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) *commit_todo_item_at(&commit_todo, item->commit) = item; parse_commit(item->commit); - commit_buffer = logmsg_reencode(item->commit, NULL, "UTF-8"); + commit_buffer = get_commit_buffer(item->commit, NULL); find_commit_subject(commit_buffer, &subject); format_subject(&buf, subject, " "); subject = subjects[i] = strbuf_detach(&buf, &subject_len); @@ -5235,11 +5217,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) break; } - entry = hashmap_get_entry_from_hash(&subject2item, - strhash(p), p, - struct subject2item_entry, - entry); - if (entry) + if ((entry = hashmap_get_from_hash(&subject2item, + strhash(p), p))) /* found by title */ i2 = entry->i; else if (!strchr(p, ' ') && @@ -5273,9 +5252,8 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) strhash(subject), subject)) { FLEX_ALLOC_MEM(entry, subject, subject, subject_len); entry->i = i; - hashmap_entry_init(&entry->entry, - strhash(entry->subject)); - hashmap_put(&subject2item, &entry->entry); + hashmap_entry_init(entry, strhash(entry->subject)); + hashmap_put(&subject2item, entry); } } @@ -5309,7 +5287,7 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) for (i = 0; i < todo_list->nr; i++) free(subjects[i]); free(subjects); - hashmap_free_entries(&subject2item, struct subject2item_entry, entry); + hashmap_free(&subject2item, 1); clear_commit_todo_item(&commit_todo); |