in sequencer.c [4943:5174]
static int pick_commits(struct repository *r,
struct todo_list *todo_list,
struct replay_opts *opts)
{
struct replay_ctx *ctx = opts->ctx;
int res = 0, reschedule = 0;
ctx->reflog_message = sequencer_reflog_action(opts);
if (opts->allow_ff)
ASSERT(!(opts->signoff || opts->no_commit ||
opts->record_origin || should_edit(opts) ||
opts->committer_date_is_author_date ||
opts->ignore_date));
if (read_and_refresh_cache(r, opts))
return -1;
unlink(rebase_path_message());
unlink(rebase_path_stopped_sha());
unlink(rebase_path_amend());
unlink(rebase_path_patch());
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, reschedule))
return -1;
if (is_rebase_i(opts)) {
if (item->command != TODO_COMMENT) {
FILE *f = fopen(rebase_path_msgnum(), "w");
todo_list->done_nr++;
if (f) {
fprintf(f, "%d\n", todo_list->done_nr);
fclose(f);
}
if (!opts->quiet)
fprintf(stderr, _("Rebasing (%d/%d)%s"),
todo_list->done_nr,
todo_list->total_nr,
opts->verbose ? "\n" : "\r");
}
unlink(rebase_path_author_script());
unlink(git_path_merge_head(r));
refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
NULL, REF_NO_DEREF);
refs_delete_ref(get_main_ref_store(r), "", "REBASE_HEAD",
NULL, REF_NO_DEREF);
if (item->command == TODO_BREAK) {
if (!opts->verbose)
term_clear_line();
return stopped_at_head(r);
}
}
strbuf_reset(&ctx->message);
ctx->have_message = 0;
if (item->command <= TODO_SQUASH) {
res = pick_one_commit(r, todo_list, opts, &check_todo,
&reschedule);
if (!res && item->command == TODO_EDIT)
return 0;
} else if (item->command == TODO_EXEC) {
char *end_of_arg = (char *)(arg + item->arg_len);
int saved = *end_of_arg;
if (!opts->verbose)
term_clear_line();
*end_of_arg = '\0';
res = do_exec(r, arg, opts->quiet);
*end_of_arg = saved;
if (res) {
if (opts->reschedule_failed_exec)
reschedule = 1;
}
check_todo = 1;
} else if (item->command == TODO_LABEL) {
if ((res = do_label(r, arg, item->arg_len)))
reschedule = 1;
} else if (item->command == TODO_RESET) {
if ((res = do_reset(r, arg, item->arg_len, opts)))
reschedule = 1;
} else if (item->command == TODO_MERGE) {
if ((res = do_merge(r, item->commit, arg, item->arg_len,
item->flags, &check_todo, opts)) < 0)
reschedule = 1;
else if (item->commit)
record_in_rewritten(&item->commit->object.oid,
peek_command(todo_list, 1));
if (res > 0)
/* failed with merge conflicts */
return error_with_patch(r, item->commit,
arg, item->arg_len,
opts, res, 0);
} else if (item->command == TODO_UPDATE_REF) {
struct strbuf ref = STRBUF_INIT;
strbuf_add(&ref, arg, item->arg_len);
if ((res = do_update_ref(r, ref.buf)))
reschedule = 1;
strbuf_release(&ref);
} else if (!is_noop(item->command))
return error(_("unknown command %d"), item->command);
if (reschedule) {
advise(_(rescheduled_advice),
get_item_line_length(todo_list,
todo_list->current),
get_item_line(todo_list, todo_list->current));
if (save_todo(todo_list, opts, reschedule))
return -1;
if (item->commit)
write_rebase_head(&item->commit->object.oid);
} else if (is_rebase_i(opts) && check_todo && !res &&
reread_todo_if_changed(r, todo_list, opts)) {
return -1;
}
if (res)
return res;
todo_list->current++;
}
if (is_rebase_i(opts)) {
struct strbuf head_ref = STRBUF_INIT, buf = STRBUF_INIT;
struct stat st;
if (read_oneliner(&head_ref, rebase_path_head_name(), 0) &&
starts_with(head_ref.buf, "refs/")) {
const char *msg;
struct object_id head, orig;
int res;
if (repo_get_oid(r, "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_oid_hex(buf.buf, &orig)) {
res = error(_("could not read orig-head"));
goto cleanup_head_ref;
}
strbuf_reset(&buf);
if (!read_oneliner(&buf, rebase_path_onto(), 0)) {
res = error(_("could not read 'onto'"));
goto cleanup_head_ref;
}
msg = reflog_message(opts, "finish", "%s onto %s",
head_ref.buf, buf.buf);
if (refs_update_ref(get_main_ref_store(the_repository), msg, head_ref.buf, &head, &orig,
REF_NO_DEREF, UPDATE_REFS_MSG_ON_ERR)) {
res = error(_("could not update %s"),
head_ref.buf);
goto cleanup_head_ref;
}
msg = reflog_message(opts, "finish", "returning to %s",
head_ref.buf);
if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", head_ref.buf, msg)) {
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;
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.diff = 1;
log_tree_opt.diffopt.output_format =
DIFF_FORMAT_DIFFSTAT;
log_tree_opt.disable_stdin = 1;
if (read_oneliner(&buf, rebase_path_orig_head(), 0) &&
!repo_get_oid(r, buf.buf, &orig) &&
!repo_get_oid(r, "HEAD", &head)) {
diff_tree_oid(&orig, &head, "",
&log_tree_opt.diffopt);
log_tree_diff_flush(&log_tree_opt);
}
release_revisions(&log_tree_opt);
}
flush_rewritten_pending();
if (!stat(rebase_path_rewritten_list(), &st) &&
st.st_size > 0) {
struct child_process child = CHILD_PROCESS_INIT;
struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
child.in = open(rebase_path_rewritten_list(), O_RDONLY);
child.git_cmd = 1;
strvec_push(&child.args, "notes");
strvec_push(&child.args, "copy");
strvec_push(&child.args, "--for-rewrite=rebase");
/* we don't care if this copying failed */
run_command(&child);
hook_opt.path_to_stdin = rebase_path_rewritten_list();
strvec_push(&hook_opt.args, "rebase");
run_hooks_opt(r, "post-rewrite", &hook_opt);
}
apply_autostash(rebase_path_autostash());
if (!opts->quiet) {
if (!opts->verbose)
term_clear_line();
fprintf(stderr,
_("Successfully rebased and updated %s.\n"),
head_ref.buf);
}
strbuf_release(&buf);
strbuf_release(&head_ref);
if (do_update_refs(r, opts->quiet))
return -1;
}
/*
* Sequence of picks finished successfully; cleanup by
* removing the .git/sequencer directory
*/
return sequencer_remove_state(opts);
}