* the commit object name of the corresponding patch.
*/
static GIT_PATH_FUNC(rebase_path_stopped_sha, "rebase-merge/stopped-sha")
+/*
+ * When we stop for the user to resolve conflicts this file contains
+ * the patch of the commit that is being picked.
+ */
+static GIT_PATH_FUNC(rebase_path_patch, "rebase-merge/patch")
/*
* For the post-rewrite hook, we make a list of rewritten commits and
* their new sha1s. The rewritten-pending list keeps the sha1s of
return -1;
}
-static int save_todo(struct todo_list *todo_list, struct replay_opts *opts)
+static int save_todo(struct todo_list *todo_list, struct replay_opts *opts,
+ int reschedule)
{
struct lock_file todo_lock = LOCK_INIT;
const char *todo_path = get_todo_path(opts);
* rebase -i writes "git-rebase-todo" without the currently executing
* command, appending it to "done" instead.
*/
- if (is_rebase_i(opts))
+ if (is_rebase_i(opts) && !reschedule)
next++;
fd = hold_lock_file_for_update(&todo_lock, todo_path, 0);
if (commit_lock_file(&todo_lock) < 0)
return error(_("failed to finalize '%s'"), todo_path);
- if (is_rebase_i(opts) && next > 0) {
+ if (is_rebase_i(opts) && !reschedule && next > 0) {
const char *done = rebase_path_done();
int fd = open(done, O_CREAT | O_WRONLY | O_APPEND, 0666);
int ret = 0;
struct commit *commit,
struct replay_opts *opts)
{
- struct strbuf buf = STRBUF_INIT;
struct rev_info log_tree_opt;
const char *subject;
char hex[GIT_MAX_HEXSZ + 1];
int res = 0;
+ if (!is_rebase_i(opts))
+ BUG("make_patch should only be called when rebasing");
+
oid_to_hex_r(hex, &commit->object.oid);
if (write_message(hex, strlen(hex), rebase_path_stopped_sha(), 1) < 0)
return -1;
res |= write_rebase_head(&commit->object.oid);
- strbuf_addf(&buf, "%s/patch", get_dir(opts));
memset(&log_tree_opt, 0, sizeof(log_tree_opt));
repo_init_revisions(r, &log_tree_opt, NULL);
log_tree_opt.abbrev = 0;
log_tree_opt.diffopt.output_format = DIFF_FORMAT_PATCH;
log_tree_opt.disable_stdin = 1;
log_tree_opt.no_commit_id = 1;
- log_tree_opt.diffopt.file = fopen(buf.buf, "w");
+ log_tree_opt.diffopt.file = fopen(rebase_path_patch(), "w");
log_tree_opt.diffopt.use_color = GIT_COLOR_NEVER;
if (!log_tree_opt.diffopt.file)
- res |= error_errno(_("could not open '%s'"), buf.buf);
+ res |= error_errno(_("could not open '%s'"),
+ rebase_path_patch());
else {
res |= log_tree_commit(&log_tree_opt, commit);
fclose(log_tree_opt.diffopt.file);
}
- strbuf_reset(&buf);
- strbuf_addf(&buf, "%s/message", get_dir(opts));
- if (!file_exists(buf.buf)) {
+ if (!file_exists(rebase_path_message())) {
const char *encoding = get_commit_output_encoding();
const char *commit_buffer = repo_logmsg_reencode(r,
commit, NULL,
encoding);
find_commit_subject(commit_buffer, &subject);
- res |= write_message(subject, strlen(subject), buf.buf, 1);
+ res |= write_message(subject, strlen(subject), rebase_path_message(), 1);
repo_unuse_commit_buffer(r, commit,
commit_buffer);
}
- strbuf_release(&buf);
release_revisions(&log_tree_opt);
return res;
if (ret < 0) {
error(_("could not even attempt to merge '%.*s'"),
merge_arg_len, arg);
+ unlink(git_path_merge_msg(r));
goto leave_merge;
}
/*
" git rebase --edit-todo\n"
" git rebase --continue\n");
+static int pick_one_commit(struct repository *r,
+ struct todo_list *todo_list,
+ struct replay_opts *opts,
+ int *check_todo, int* reschedule)
+{
+ int res;
+ struct todo_item *item = todo_list->items + todo_list->current;
+ const char *arg = todo_item_get_arg(todo_list, item);
+ if (is_rebase_i(opts))
+ opts->reflog_message = reflog_message(
+ opts, command_to_string(item->command), NULL);
+
+ res = do_pick_commit(r, item, opts, is_final_fixup(todo_list),
+ check_todo);
+ if (is_rebase_i(opts) && res < 0) {
+ /* Reschedule */
+ *reschedule = 1;
+ return -1;
+ }
+ if (item->command == TODO_EDIT) {
+ struct commit *commit = item->commit;
+ if (!res) {
+ if (!opts->verbose)
+ term_clear_line();
+ fprintf(stderr, _("Stopped at %s... %.*s\n"),
+ short_commit_name(commit), item->arg_len, arg);
+ }
+ return error_with_patch(r, commit,
+ arg, item->arg_len, opts, res, !res);
+ }
+ if (is_rebase_i(opts) && !res)
+ record_in_rewritten(&item->commit->object.oid,
+ peek_command(todo_list, 1));
+ if (res && is_fixup(item->command)) {
+ if (res == 1)
+ intend_to_amend();
+ return error_failed_squash(r, item->commit, opts,
+ item->arg_len, arg);
+ } else if (res && is_rebase_i(opts) && item->commit) {
+ int to_amend = 0;
+ struct object_id oid;
+
+ /*
+ * If we are rewording and have either
+ * fast-forwarded already, or are about to
+ * create a new root commit, we want to amend,
+ * otherwise we do not.
+ */
+ if (item->command == TODO_REWORD &&
+ !repo_get_oid(r, "HEAD", &oid) &&
+ (oideq(&item->commit->object.oid, &oid) ||
+ (opts->have_squash_onto &&
+ oideq(&opts->squash_onto, &oid))))
+ to_amend = 1;
+
+ return res | error_with_patch(r, item->commit,
+ arg, item->arg_len, opts,
+ res, to_amend);
+ }
+ return res;
+}
+
static int pick_commits(struct repository *r,
struct todo_list *todo_list,
struct replay_opts *opts)
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))
+ if (save_todo(todo_list, opts, reschedule))
return -1;
if (is_rebase_i(opts)) {
if (item->command != TODO_COMMENT) {
todo_list->total_nr,
opts->verbose ? "\n" : "\r");
}
- unlink(rebase_path_message());
unlink(rebase_path_author_script());
- unlink(rebase_path_stopped_sha());
- unlink(rebase_path_amend());
unlink(git_path_merge_head(r));
unlink(git_path_auto_merge(r));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
}
}
if (item->command <= TODO_SQUASH) {
- if (is_rebase_i(opts))
- opts->reflog_message = reflog_message(opts,
- command_to_string(item->command), NULL);
-
- res = do_pick_commit(r, item, opts,
- is_final_fixup(todo_list),
- &check_todo);
- if (is_rebase_i(opts) && res < 0) {
- /* Reschedule */
- advise(_(rescheduled_advice),
- get_item_line_length(todo_list,
- todo_list->current),
- get_item_line(todo_list,
- todo_list->current));
- todo_list->current--;
- if (save_todo(todo_list, opts))
- return -1;
- }
- if (item->command == TODO_EDIT) {
- struct commit *commit = item->commit;
- if (!res) {
- if (!opts->verbose)
- term_clear_line();
- fprintf(stderr,
- _("Stopped at %s... %.*s\n"),
- short_commit_name(commit),
- item->arg_len, arg);
- }
- return error_with_patch(r, commit,
- arg, item->arg_len, opts, res, !res);
- }
- if (is_rebase_i(opts) && !res)
- record_in_rewritten(&item->commit->object.oid,
- peek_command(todo_list, 1));
- if (res && is_fixup(item->command)) {
- if (res == 1)
- intend_to_amend();
- return error_failed_squash(r, item->commit, opts,
- item->arg_len, arg);
- } else if (res && is_rebase_i(opts) && item->commit) {
- int to_amend = 0;
- struct object_id oid;
-
- /*
- * If we are rewording and have either
- * fast-forwarded already, or are about to
- * create a new root commit, we want to amend,
- * otherwise we do not.
- */
- if (item->command == TODO_REWORD &&
- !repo_get_oid(r, "HEAD", &oid) &&
- (oideq(&item->commit->object.oid, &oid) ||
- (opts->have_squash_onto &&
- oideq(&opts->squash_onto, &oid))))
- to_amend = 1;
-
- return res | error_with_patch(r, item->commit,
- arg, item->arg_len, opts,
- res, to_amend);
- }
+ 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;
get_item_line_length(todo_list,
todo_list->current),
get_item_line(todo_list, todo_list->current));
- todo_list->current--;
- if (save_todo(todo_list, opts))
+ if (save_todo(todo_list, opts, reschedule))
return -1;
if (item->commit)
- return error_with_patch(r,
- item->commit,
- arg, item->arg_len,
- opts, res, 0);
+ 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;
}
- todo_list->current++;
if (res)
return res;
+
+ todo_list->current++;
}
if (is_rebase_i(opts)) {
is_clean = !has_uncommitted_changes(r, 0);
+ if (!is_clean && !file_exists(rebase_path_message())) {
+ const char *gpg_opt = gpg_sign_opt_quoted(opts);
+
+ return error(_(staged_changes_advice), gpg_opt, gpg_opt);
+ }
if (file_exists(rebase_path_amend())) {
struct strbuf rev = STRBUF_INIT;
struct object_id head, to_amend;