summaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c372
1 files changed, 201 insertions, 171 deletions
diff --git a/sequencer.c b/sequencer.c
index c4f4b7d571..eec8a60d6b 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -21,6 +21,11 @@
const char sign_off_header[] = "Signed-off-by: ";
static const char cherry_picked_prefix[] = "(cherry picked from commit ";
+static GIT_PATH_FUNC(git_path_todo_file, SEQ_TODO_FILE)
+static GIT_PATH_FUNC(git_path_opts_file, SEQ_OPTS_FILE)
+static GIT_PATH_FUNC(git_path_seq_dir, SEQ_DIR)
+static GIT_PATH_FUNC(git_path_head_file, SEQ_HEAD_FILE)
+
static int is_rfc2822_line(const char *buf, int len)
{
int i;
@@ -107,7 +112,7 @@ static void remove_sequencer_state(void)
{
struct strbuf seq_dir = STRBUF_INIT;
- strbuf_addf(&seq_dir, "%s", git_path(SEQ_DIR));
+ strbuf_addstr(&seq_dir, git_path(SEQ_DIR));
remove_dir_recursively(&seq_dir, 0);
strbuf_release(&seq_dir);
}
@@ -119,62 +124,36 @@ static const char *action_name(const struct replay_opts *opts)
struct commit_message {
char *parent_label;
- const char *label;
- const char *subject;
+ char *label;
+ char *subject;
const char *message;
};
static int get_message(struct commit *commit, struct commit_message *out)
{
const char *abbrev, *subject;
- int abbrev_len, subject_len;
- char *q;
-
- if (!git_commit_encoding)
- git_commit_encoding = "UTF-8";
+ int subject_len;
- out->message = logmsg_reencode(commit, NULL, git_commit_encoding);
- abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
- abbrev_len = strlen(abbrev);
+ out->message = logmsg_reencode(commit, NULL, get_commit_output_encoding());
+ abbrev = find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV);
subject_len = find_commit_subject(out->message, &subject);
- out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
- strlen("... ") + subject_len + 1);
- q = out->parent_label;
- q = mempcpy(q, "parent of ", strlen("parent of "));
- out->label = q;
- q = mempcpy(q, abbrev, abbrev_len);
- q = mempcpy(q, "... ", strlen("... "));
- out->subject = q;
- q = mempcpy(q, subject, subject_len);
- *q = '\0';
+ out->subject = xmemdupz(subject, subject_len);
+ out->label = xstrfmt("%s... %s", abbrev, out->subject);
+ out->parent_label = xstrfmt("parent of %s", out->label);
+
return 0;
}
static void free_message(struct commit *commit, struct commit_message *msg)
{
free(msg->parent_label);
+ free(msg->label);
+ free(msg->subject);
unuse_commit_buffer(commit, msg->message);
}
-static void write_cherry_pick_head(struct commit *commit, const char *pseudoref)
-{
- const char *filename;
- int fd;
- struct strbuf buf = STRBUF_INIT;
-
- strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
-
- filename = git_path("%s", pseudoref);
- fd = open(filename, O_WRONLY | O_CREAT, 0666);
- if (fd < 0)
- die_errno(_("Could not open '%s' for writing"), filename);
- if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
- die_errno(_("Could not write to '%s'"), filename);
- strbuf_release(&buf);
-}
-
static void print_advice(int show_hint, struct replay_opts *opts)
{
char *msg = getenv("GIT_CHERRY_PICK_HELP");
@@ -186,7 +165,7 @@ static void print_advice(int show_hint, struct replay_opts *opts)
* (typically rebase --interactive) wants to take care
* of the commit itself so remove CHERRY_PICK_HEAD
*/
- unlink(git_path("CHERRY_PICK_HEAD"));
+ unlink(git_path_cherry_pick_head());
return;
}
@@ -201,17 +180,20 @@ static void print_advice(int show_hint, struct replay_opts *opts)
}
}
-static void write_message(struct strbuf *msgbuf, const char *filename)
+static int write_message(struct strbuf *msgbuf, const char *filename)
{
static struct lock_file msg_file;
- int msg_fd = hold_lock_file_for_update(&msg_file, filename,
- LOCK_DIE_ON_ERROR);
+ int msg_fd = hold_lock_file_for_update(&msg_file, filename, 0);
+ if (msg_fd < 0)
+ return error_errno(_("Could not lock '%s'"), filename);
if (write_in_full(msg_fd, msgbuf->buf, msgbuf->len) < 0)
- die_errno(_("Could not write to %s"), filename);
+ return error_errno(_("Could not write to %s"), filename);
strbuf_release(msgbuf);
if (commit_lock_file(&msg_file) < 0)
- die(_("Error wrapping up %s"), filename);
+ return error(_("Error wrapping up %s."), filename);
+
+ return 0;
}
static struct tree *empty_tree(void)
@@ -244,9 +226,9 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
read_cache();
if (checkout_fast_forward(from, to, 1))
- exit(128); /* the callee should have complained already */
+ return -1; /* the callee should have complained already */
- strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
+ strbuf_addf(&sb, _("%s: fast-forward"), action_name(opts));
transaction = ref_transaction_begin(&err);
if (!transaction ||
@@ -314,11 +296,15 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
clean = merge_trees(&o,
head_tree,
next_tree, base_tree, &result);
+ strbuf_release(&o.obuf);
+ if (clean < 0)
+ return clean;
if (active_cache_changed &&
write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
/* TRANSLATORS: %s will be "revert" or "cherry-pick" */
- die(_("%s: Unable to write new index file"), action_name(opts));
+ return error(_("%s: Unable to write new index file"),
+ action_name(opts));
rollback_lock_file(&index_lock);
if (opts->signoff)
@@ -358,7 +344,7 @@ 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.sha1);
+ return !hashcmp(active_cache_tree->sha1, head_commit->tree->object.oid.hash);
}
/*
@@ -409,18 +395,18 @@ static int is_original_commit_empty(struct commit *commit)
if (parse_commit(commit))
return error(_("Could not parse commit %s\n"),
- sha1_to_hex(commit->object.sha1));
+ oid_to_hex(&commit->object.oid));
if (commit->parents) {
struct commit *parent = commit->parents->item;
if (parse_commit(parent))
return error(_("Could not parse parent commit %s\n"),
- sha1_to_hex(parent->object.sha1));
- ptree_sha1 = parent->tree->object.sha1;
+ oid_to_hex(&parent->object.oid));
+ ptree_sha1 = parent->tree->object.oid.hash;
} else {
ptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */
}
- return !hashcmp(ptree_sha1, commit->tree->object.sha1);
+ return !hashcmp(ptree_sha1, commit->tree->object.oid.hash);
}
/*
@@ -467,7 +453,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
struct commit *base, *next, *parent;
const char *base_label, *next_label;
struct commit_message msg = { NULL, NULL, NULL, NULL };
- char *defmsg = NULL;
struct strbuf msgbuf = STRBUF_INIT;
int res, unborn = 0, allow;
@@ -479,7 +464,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* to work on.
*/
if (write_cache_as_tree(head, 0, NULL))
- die (_("Your index file is unmerged."));
+ return error(_("Your index file is unmerged."));
} else {
unborn = get_sha1("HEAD", head);
if (unborn)
@@ -499,7 +484,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
if (!opts->mainline)
return error(_("Commit %s is a merge but no -m option was given."),
- sha1_to_hex(commit->object.sha1));
+ oid_to_hex(&commit->object.oid));
for (cnt = 1, p = commit->parents;
cnt != opts->mainline && p;
@@ -507,28 +492,28 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
p = p->next;
if (cnt != opts->mainline || !p)
return error(_("Commit %s does not have parent %d"),
- sha1_to_hex(commit->object.sha1), opts->mainline);
+ oid_to_hex(&commit->object.oid), opts->mainline);
parent = p->item;
} else if (0 < opts->mainline)
return error(_("Mainline was specified but commit %s is not a merge."),
- sha1_to_hex(commit->object.sha1));
+ oid_to_hex(&commit->object.oid));
else
parent = commit->parents->item;
if (opts->allow_ff &&
- ((parent && !hashcmp(parent->object.sha1, head)) ||
+ ((parent && !hashcmp(parent->object.oid.hash, head)) ||
(!parent && unborn)))
- return fast_forward_to(commit->object.sha1, head, unborn, opts);
+ return fast_forward_to(commit->object.oid.hash, head, unborn, opts);
if (parent && parse_commit(parent) < 0)
/* TRANSLATORS: The first %s will be "revert" or
"cherry-pick", the second %s a SHA1 */
return error(_("%s: cannot parse parent commit %s"),
- action_name(opts), sha1_to_hex(parent->object.sha1));
+ action_name(opts), oid_to_hex(&parent->object.oid));
if (get_message(commit, &msg) != 0)
return error(_("Cannot get commit message for %s"),
- sha1_to_hex(commit->object.sha1));
+ oid_to_hex(&commit->object.oid));
/*
* "commit" is an existing commit. We would want to apply
@@ -537,8 +522,6 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* reverse of it if we are revert.
*/
- defmsg = git_pathdup("MERGE_MSG");
-
if (opts->action == REPLAY_REVERT) {
base = commit;
base_label = msg.label;
@@ -547,11 +530,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
strbuf_addstr(&msgbuf, "Revert \"");
strbuf_addstr(&msgbuf, msg.subject);
strbuf_addstr(&msgbuf, "\"\n\nThis reverts commit ");
- strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
if (commit->parents && commit->parents->next) {
strbuf_addstr(&msgbuf, ", reversing\nchanges made to ");
- strbuf_addstr(&msgbuf, sha1_to_hex(parent->object.sha1));
+ strbuf_addstr(&msgbuf, oid_to_hex(&parent->object.oid));
}
strbuf_addstr(&msgbuf, ".\n");
} else {
@@ -568,16 +551,14 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* information followed by "\n\n".
*/
p = strstr(msg.message, "\n\n");
- if (p) {
- p += 2;
- strbuf_addstr(&msgbuf, p);
- }
+ if (p)
+ strbuf_addstr(&msgbuf, skip_blank_lines(p + 2));
if (opts->record_origin) {
if (!has_conforming_footer(&msgbuf, NULL, 0))
strbuf_addch(&msgbuf, '\n');
strbuf_addstr(&msgbuf, cherry_picked_prefix);
- strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
+ strbuf_addstr(&msgbuf, oid_to_hex(&commit->object.oid));
strbuf_addstr(&msgbuf, ")\n");
}
}
@@ -585,16 +566,18 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
if (!opts->strategy || !strcmp(opts->strategy, "recursive") || opts->action == REPLAY_REVERT) {
res = do_recursive_merge(base, next, base_label, next_label,
head, &msgbuf, opts);
- write_message(&msgbuf, defmsg);
+ if (res < 0)
+ return res;
+ res |= write_message(&msgbuf, git_path_merge_msg());
} else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
- write_message(&msgbuf, defmsg);
+ res = write_message(&msgbuf, git_path_merge_msg());
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
- res = try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
+ res |= try_merge_command(opts->strategy, opts->xopts_nr, opts->xopts,
common, sha1_to_hex(head), remotes);
free_commit_list(common);
free_commit_list(remotes);
@@ -606,16 +589,20 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* However, if the merge did not even start, then we don't want to
* write it at all.
*/
- if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
- write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
- if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
- write_cherry_pick_head(commit, "REVERT_HEAD");
+ if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1) &&
+ update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.oid.hash, NULL,
+ REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
+ res = -1;
+ if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1) &&
+ update_ref(NULL, "REVERT_HEAD", commit->object.oid.hash, NULL,
+ REF_NODEREF, UPDATE_REFS_MSG_ON_ERR))
+ res = -1;
if (res) {
error(opts->action == REPLAY_REVERT
? _("could not revert %s... %s")
: _("could not apply %s... %s"),
- find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV),
+ find_unique_abbrev(commit->object.oid.hash, DEFAULT_ABBREV),
msg.subject);
print_advice(res == 1, opts);
rerere(opts->allow_rerere_auto);
@@ -628,16 +615,15 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
goto leave;
}
if (!opts->no_commit)
- res = run_git_commit(defmsg, opts, allow);
+ res = run_git_commit(git_path_merge_msg(), opts, allow);
leave:
free_message(commit, &msg);
- free(defmsg);
return res;
}
-static void prepare_revs(struct replay_opts *opts)
+static int prepare_revs(struct replay_opts *opts)
{
/*
* picking (but not reverting) ranges (but not individual revisions)
@@ -647,24 +633,32 @@ static void prepare_revs(struct replay_opts *opts)
opts->revs->reverse ^= 1;
if (prepare_revision_walk(opts->revs))
- die(_("revision walk setup failed"));
+ return error(_("revision walk setup failed"));
if (!opts->revs->commits)
- die(_("empty commit set passed"));
+ return error(_("empty commit set passed"));
+ return 0;
}
-static void read_and_refresh_cache(struct replay_opts *opts)
+static int read_and_refresh_cache(struct replay_opts *opts)
{
static struct lock_file index_lock;
int index_fd = hold_locked_index(&index_lock, 0);
- if (read_index_preload(&the_index, NULL) < 0)
- die(_("git %s: failed to read the index"), action_name(opts));
+ if (read_index_preload(&the_index, NULL) < 0) {
+ rollback_lock_file(&index_lock);
+ return error(_("git %s: failed to read the index"),
+ action_name(opts));
+ }
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL, NULL);
if (the_index.cache_changed && index_fd >= 0) {
- if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
- die(_("git %s: failed to refresh the index"), action_name(opts));
+ if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) {
+ rollback_lock_file(&index_lock);
+ return error(_("git %s: failed to refresh the index"),
+ action_name(opts));
+ }
}
rollback_lock_file(&index_lock);
+ return 0;
}
static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
@@ -678,7 +672,7 @@ static int format_todo(struct strbuf *buf, struct commit_list *todo_list,
for (cur = todo_list; cur; cur = cur->next) {
const char *commit_buffer = get_commit_buffer(cur->item, NULL);
- sha1_abbrev = find_unique_abbrev(cur->item->object.sha1, DEFAULT_ABBREV);
+ sha1_abbrev = find_unique_abbrev(cur->item->object.oid.hash, DEFAULT_ABBREV);
subject_len = find_commit_subject(commit_buffer, &subject);
strbuf_addf(buf, "%s %s %.*s\n", action_str, sha1_abbrev,
subject_len, subject);
@@ -720,9 +714,14 @@ static struct commit *parse_insn_line(char *bol, char *eol, struct replay_opts *
* opts; we don't support arbitrary instructions
*/
if (action != opts->action) {
- const char *action_str;
- action_str = action == REPLAY_REVERT ? "revert" : "cherry-pick";
- error(_("Cannot %s during a %s"), action_str, action_name(opts));
+ if (action == REPLAY_REVERT)
+ error((opts->action == REPLAY_REVERT)
+ ? _("Cannot revert during another revert.")
+ : _("Cannot revert during a cherry-pick."));
+ else
+ error((opts->action == REPLAY_REVERT)
+ ? _("Cannot cherry-pick during a revert.")
+ : _("Cannot cherry-pick during another cherry-pick."));
return NULL;
}
@@ -753,27 +752,29 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
return 0;
}
-static void read_populate_todo(struct commit_list **todo_list,
+static int read_populate_todo(struct commit_list **todo_list,
struct replay_opts *opts)
{
- const char *todo_file = git_path(SEQ_TODO_FILE);
struct strbuf buf = STRBUF_INIT;
int fd, res;
- fd = open(todo_file, O_RDONLY);
+ fd = open(git_path_todo_file(), O_RDONLY);
if (fd < 0)
- die_errno(_("Could not open %s"), todo_file);
+ return error_errno(_("Could not open %s"),
+ git_path_todo_file());
if (strbuf_read(&buf, fd, 0) < 0) {
close(fd);
strbuf_release(&buf);
- die(_("Could not read %s."), todo_file);
+ return error(_("Could not read %s."), git_path_todo_file());
}
close(fd);
res = parse_insn_buffer(buf.buf, todo_list, opts);
strbuf_release(&buf);
if (res)
- die(_("Unusable instruction sheet: %s"), todo_file);
+ return error(_("Unusable instruction sheet: %s"),
+ git_path_todo_file());
+ return 0;
}
static int populate_opts_cb(const char *key, const char *value, void *data)
@@ -811,56 +812,72 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
return 0;
}
-static void read_populate_opts(struct replay_opts **opts_ptr)
+static int read_populate_opts(struct replay_opts **opts)
{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
-
- if (!file_exists(opts_file))
- return;
- if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
- die(_("Malformed options sheet: %s"), opts_file);
+ if (!file_exists(git_path_opts_file()))
+ return 0;
+ /*
+ * The function git_parse_source(), called from git_config_from_file(),
+ * may die() in case of a syntactically incorrect file. We do not care
+ * about this case, though, because we wrote that file ourselves, so we
+ * are pretty certain that it is syntactically correct.
+ */
+ if (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts) < 0)
+ return error(_("Malformed options sheet: %s"),
+ git_path_opts_file());
+ return 0;
}
-static void walk_revs_populate_todo(struct commit_list **todo_list,
+static int walk_revs_populate_todo(struct commit_list **todo_list,
struct replay_opts *opts)
{
struct commit *commit;
struct commit_list **next;
- prepare_revs(opts);
+ if (prepare_revs(opts))
+ return -1;
next = todo_list;
while ((commit = get_revision(opts->revs)))
next = commit_list_append(commit, next);
+ return 0;
}
static int create_seq_dir(void)
{
- const char *seq_dir = git_path(SEQ_DIR);
-
- if (file_exists(seq_dir)) {
+ if (file_exists(git_path_seq_dir())) {
error(_("a cherry-pick or revert is already in progress"));
advise(_("try \"git cherry-pick (--continue | --quit | --abort)\""));
return -1;
}
- else if (mkdir(seq_dir, 0777) < 0)
- die_errno(_("Could not create sequencer directory %s"), seq_dir);
+ else if (mkdir(git_path_seq_dir(), 0777) < 0)
+ return error_errno(_("Could not create sequencer directory %s"),
+ git_path_seq_dir());
return 0;
}
-static void save_head(const char *head)
+static int save_head(const char *head)
{
- const char *head_file = git_path(SEQ_HEAD_FILE);
static struct lock_file head_lock;
struct strbuf buf = STRBUF_INIT;
int fd;
- fd = hold_lock_file_for_update(&head_lock, head_file, LOCK_DIE_ON_ERROR);
+ fd = hold_lock_file_for_update(&head_lock, git_path_head_file(), 0);
+ if (fd < 0) {
+ rollback_lock_file(&head_lock);
+ return error_errno(_("Could not lock HEAD"));
+ }
strbuf_addf(&buf, "%s\n", head);
- if (write_in_full(fd, buf.buf, buf.len) < 0)
- die_errno(_("Could not write to %s"), head_file);
- if (commit_lock_file(&head_lock) < 0)
- die(_("Error wrapping up %s."), head_file);
+ if (write_in_full(fd, buf.buf, buf.len) < 0) {
+ rollback_lock_file(&head_lock);
+ return error_errno(_("Could not write to %s"),
+ git_path_head_file());
+ }
+ if (commit_lock_file(&head_lock) < 0) {
+ rollback_lock_file(&head_lock);
+ return error(_("Error wrapping up %s."), git_path_head_file());
+ }
+ return 0;
}
static int reset_for_rollback(const unsigned char *sha1)
@@ -877,8 +894,8 @@ static int rollback_single_pick(void)
{
unsigned char head_sha1[20];
- if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
- !file_exists(git_path("REVERT_HEAD")))
+ if (!file_exists(git_path_cherry_pick_head()) &&
+ !file_exists(git_path_revert_head()))
return error(_("no cherry-pick or revert in progress"));
if (read_ref_full("HEAD", 0, head_sha1, NULL))
return error(_("cannot resolve HEAD"));
@@ -889,13 +906,11 @@ static int rollback_single_pick(void)
static int sequencer_rollback(struct replay_opts *opts)
{
- const char *filename;
FILE *f;
unsigned char sha1[20];
struct strbuf buf = STRBUF_INIT;
- filename = git_path(SEQ_HEAD_FILE);
- f = fopen(filename, "r");
+ f = fopen(git_path_head_file(), "r");
if (!f && errno == ENOENT) {
/*
* There is no multiple-cherry-pick in progress.
@@ -905,18 +920,21 @@ static int sequencer_rollback(struct replay_opts *opts)
return rollback_single_pick();
}
if (!f)
- return error(_("cannot open %s: %s"), filename,
- strerror(errno));
- if (strbuf_getline(&buf, f, '\n')) {
- error(_("cannot read %s: %s"), filename, ferror(f) ?
- strerror(errno) : _("unexpected end of file"));
+ return error_errno(_("cannot open %s"), git_path_head_file());
+ if (strbuf_getline_lf(&buf, f)) {
+ error(_("cannot read %s: %s"), git_path_head_file(),
+ ferror(f) ? strerror(errno) : _("unexpected end of file"));
fclose(f);
goto fail;
}
fclose(f);
if (get_sha1_hex(buf.buf, sha1) || buf.buf[40] != '\0') {
error(_("stored pre-cherry-pick HEAD file '%s' is corrupt"),
- filename);
+ git_path_head_file());
+ goto fail;
+ }
+ if (is_null_sha1(sha1)) {
+ error(_("cannot abort from a branch yet to be born"));
goto fail;
}
if (reset_for_rollback(sha1))
@@ -929,58 +947,66 @@ fail:
return -1;
}
-static void save_todo(struct commit_list *todo_list, struct replay_opts *opts)
+static int save_todo(struct commit_list *todo_list, struct replay_opts *opts)
{
- const char *todo_file = git_path(SEQ_TODO_FILE);
static struct lock_file todo_lock;
struct strbuf buf = STRBUF_INIT;
int fd;
- fd = hold_lock_file_for_update(&todo_lock, todo_file, LOCK_DIE_ON_ERROR);
- if (format_todo(&buf, todo_list, opts) < 0)
- die(_("Could not format %s."), todo_file);
+ fd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), 0);
+ if (fd < 0)
+ return error_errno(_("Could not lock '%s'"),
+ git_path_todo_file());
+ if (format_todo(&buf, todo_list, opts) < 0) {
+ strbuf_release(&buf);
+ return error(_("Could not format %s."), git_path_todo_file());
+ }
if (write_in_full(fd, buf.buf, buf.len) < 0) {
strbuf_release(&buf);
- die_errno(_("Could not write to %s"), todo_file);
+ return error_errno(_("Could not write to %s"),
+ git_path_todo_file());
}
if (commit_lock_file(&todo_lock) < 0) {
strbuf_release(&buf);
- die(_("Error wrapping up %s."), todo_file);
+ return error(_("Error wrapping up %s."), git_path_todo_file());
}
strbuf_release(&buf);
+ return 0;
}
-static void save_opts(struct replay_opts *opts)
+static int save_opts(struct replay_opts *opts)
{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
+ const char *opts_file = git_path_opts_file();
+ int res = 0;
if (opts->no_commit)
- git_config_set_in_file(opts_file, "options.no-commit", "true");
+ res |= git_config_set_in_file_gently(opts_file, "options.no-commit", "true");
if (opts->edit)
- git_config_set_in_file(opts_file, "options.edit", "true");
+ res |= git_config_set_in_file_gently(opts_file, "options.edit", "true");
if (opts->signoff)
- git_config_set_in_file(opts_file, "options.signoff", "true");
+ res |= git_config_set_in_file_gently(opts_file, "options.signoff", "true");
if (opts->record_origin)
- git_config_set_in_file(opts_file, "options.record-origin", "true");
+ res |= git_config_set_in_file_gently(opts_file, "options.record-origin", "true");
if (opts->allow_ff)
- git_config_set_in_file(opts_file, "options.allow-ff", "true");
+ res |= git_config_set_in_file_gently(opts_file, "options.allow-ff", "true");
if (opts->mainline) {
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "%d", opts->mainline);
- git_config_set_in_file(opts_file, "options.mainline", buf.buf);
+ res |= git_config_set_in_file_gently(opts_file, "options.mainline", buf.buf);
strbuf_release(&buf);
}
if (opts->strategy)
- git_config_set_in_file(opts_file, "options.strategy", opts->strategy);
+ res |= git_config_set_in_file_gently(opts_file, "options.strategy", opts->strategy);
if (opts->gpg_sign)
- git_config_set_in_file(opts_file, "options.gpg-sign", opts->gpg_sign);
+ res |= git_config_set_in_file_gently(opts_file, "options.gpg-sign", opts->gpg_sign);
if (opts->xopts) {
int i;
for (i = 0; i < opts->xopts_nr; i++)
- git_config_set_multivar_in_file(opts_file,
+ res |= git_config_set_multivar_in_file_gently(opts_file,
"options.strategy-option",
opts->xopts[i], "^$", 0);
}
+ return res;
}
static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
@@ -992,10 +1018,12 @@ static int pick_commits(struct commit_list *todo_list, struct replay_opts *opts)
if (opts->allow_ff)
assert(!(opts->signoff || opts->no_commit ||
opts->record_origin || opts->edit));
- read_and_refresh_cache(opts);
+ if (read_and_refresh_cache(opts))
+ return -1;
for (cur = todo_list; cur; cur = cur->next) {
- save_todo(cur, opts);
+ if (save_todo(cur, opts))
+ return -1;
res = do_pick_commit(cur->item, opts);
if (res)
return res;
@@ -1013,8 +1041,8 @@ static int continue_single_pick(void)
{
const char *argv[] = { "commit", NULL };
- if (!file_exists(git_path("CHERRY_PICK_HEAD")) &&
- !file_exists(git_path("REVERT_HEAD")))
+ if (!file_exists(git_path_cherry_pick_head()) &&
+ !file_exists(git_path_revert_head()))
return error(_("no cherry-pick or revert in progress"));
return run_command_v_opt(argv, RUN_GIT_CMD);
}
@@ -1023,14 +1051,15 @@ static int sequencer_continue(struct replay_opts *opts)
{
struct commit_list *todo_list = NULL;
- if (!file_exists(git_path(SEQ_TODO_FILE)))
+ if (!file_exists(git_path_todo_file()))
return continue_single_pick();
- read_populate_opts(&opts);
- read_populate_todo(&todo_list, opts);
+ if (read_populate_opts(&opts) ||
+ read_populate_todo(&todo_list, opts))
+ return -1;
/* Verify that the conflict has been resolved */
- if (file_exists(git_path("CHERRY_PICK_HEAD")) ||
- file_exists(git_path("REVERT_HEAD"))) {
+ if (file_exists(git_path_cherry_pick_head()) ||
+ file_exists(git_path_revert_head())) {
int ret = continue_single_pick();
if (ret)
return ret;
@@ -1056,7 +1085,8 @@ int sequencer_pick_revisions(struct replay_opts *opts)
if (opts->subcommand == REPLAY_NONE)
assert(opts->revs);
- read_and_refresh_cache(opts);
+ if (read_and_refresh_cache(opts))
+ return -1;
/*
* Decide what to do depending on the arguments; a fresh
@@ -1083,10 +1113,11 @@ int sequencer_pick_revisions(struct replay_opts *opts)
if (!get_sha1(name, sha1)) {
if (!lookup_commit_reference_gently(sha1, 1)) {
enum object_type type = sha1_object_info(sha1, NULL);
- die(_("%s: can't cherry-pick a %s"), name, typename(type));
+ return error(_("%s: can't cherry-pick a %s"),
+ name, typename(type));
}
} else
- die(_("%s: bad revision"), name);
+ return error(_("%s: bad revision"), name);
}
/*
@@ -1102,10 +1133,10 @@ int sequencer_pick_revisions(struct replay_opts *opts)
!opts->revs->cmdline.rev->flags) {
struct commit *cmit;
if (prepare_revision_walk(opts->revs))
- die(_("revision walk setup failed"));
+ return error(_("revision walk setup failed"));
cmit = get_revision(opts->revs);
if (!cmit || get_revision(opts->revs))
- die("BUG: expected exactly one commit from walk");
+ return error("BUG: expected exactly one commit from walk");
return single_pick(cmit, opts);
}
@@ -1115,16 +1146,15 @@ int sequencer_pick_revisions(struct replay_opts *opts)
* progress
*/
- walk_revs_populate_todo(&todo_list, opts);
- if (create_seq_dir() < 0)
+ if (walk_revs_populate_todo(&todo_list, opts) ||
+ create_seq_dir() < 0)
+ return -1;
+ if (get_sha1("HEAD", sha1) && (opts->action == REPLAY_REVERT))
+ return error(_("Can't revert as initial commit"));
+ if (save_head(sha1_to_hex(sha1)))
+ return -1;
+ if (save_opts(opts))
return -1;
- if (get_sha1("HEAD", sha1)) {
- if (opts->action == REPLAY_REVERT)
- return error(_("Can't revert as initial commit"));
- return error(_("Can't cherry-pick into empty head"));
- }
- save_head(sha1_to_hex(sha1));
- save_opts(opts);
return pick_commits(todo_list, opts);
}