aboutsummaryrefslogtreecommitdiff
path: root/sequencer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sequencer.c')
-rw-r--r--sequencer.c207
1 files changed, 100 insertions, 107 deletions
diff --git a/sequencer.c b/sequencer.c
index bbaddcb05..a0600aebc 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include "lockfile.h"
#include "sequencer.h"
#include "dir.h"
#include "object.h"
@@ -20,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;
@@ -157,23 +163,6 @@ static void free_message(struct commit *commit, struct commit_message *msg)
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");
@@ -185,7 +174,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;
}
@@ -237,19 +226,50 @@ static int error_dirty_index(struct replay_opts *opts)
static int fast_forward_to(const unsigned char *to, const unsigned char *from,
int unborn, struct replay_opts *opts)
{
- struct ref_lock *ref_lock;
+ struct ref_transaction *transaction;
struct strbuf sb = STRBUF_INIT;
- int ret;
+ struct strbuf err = STRBUF_INIT;
read_cache();
if (checkout_fast_forward(from, to, 1))
- exit(1); /* the callee should have complained already */
- ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
- 0, NULL);
+ exit(128); /* the callee should have complained already */
+
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
- ret = write_ref_sha1(ref_lock, to, sb.buf);
+
+ transaction = ref_transaction_begin(&err);
+ if (!transaction ||
+ ref_transaction_update(transaction, "HEAD",
+ to, unborn ? null_sha1 : from,
+ 0, sb.buf, &err) ||
+ ref_transaction_commit(transaction, &err)) {
+ ref_transaction_free(transaction);
+ error("%s", err.buf);
+ strbuf_release(&sb);
+ strbuf_release(&err);
+ return -1;
+ }
+
strbuf_release(&sb);
- return ret;
+ strbuf_release(&err);
+ ref_transaction_free(transaction);
+ return 0;
+}
+
+void append_conflicts_hint(struct strbuf *msgbuf)
+{
+ int i;
+
+ strbuf_addch(msgbuf, '\n');
+ strbuf_commented_addf(msgbuf, "Conflicts:\n");
+ for (i = 0; i < active_nr;) {
+ const struct cache_entry *ce = active_cache[i++];
+ if (ce_stage(ce)) {
+ strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+ while (i < active_nr && !strcmp(ce->name,
+ active_cache[i]->name))
+ i++;
+ }
+ }
}
static int do_recursive_merge(struct commit *base, struct commit *next,
@@ -259,11 +279,11 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
{
struct merge_options o;
struct tree *result, *next_tree, *base_tree, *head_tree;
- int clean, index_fd;
+ int clean;
const char **xopt;
static struct lock_file index_lock;
- index_fd = hold_locked_index(&index_lock, 1);
+ hold_locked_index(&index_lock, 1);
read_cache();
@@ -284,8 +304,7 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
next_tree, base_tree, &result);
if (active_cache_changed &&
- (write_cache(index_fd, active_cache, active_nr) ||
- commit_locked_index(&index_lock)))
+ 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));
rollback_lock_file(&index_lock);
@@ -293,21 +312,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
if (opts->signoff)
append_signoff(msgbuf, 0, 0);
- if (!clean) {
- int i;
- strbuf_addstr(msgbuf, "\nConflicts:\n");
- for (i = 0; i < active_nr;) {
- const struct cache_entry *ce = active_cache[i++];
- if (ce_stage(ce)) {
- strbuf_addch(msgbuf, '\t');
- strbuf_addstr(msgbuf, ce->name);
- strbuf_addch(msgbuf, '\n');
- while (i < active_nr && !strcmp(ce->name,
- active_cache[i]->name))
- i++;
- }
- }
- }
+ if (!clean)
+ append_conflicts_hint(msgbuf);
return !clean;
}
@@ -317,7 +323,7 @@ static int is_index_unchanged(void)
unsigned char head_sha1[20];
struct commit *head_commit;
- if (!resolve_ref_unsafe("HEAD", head_sha1, 1, NULL))
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_sha1, NULL))
return error(_("Could not resolve HEAD commit\n"));
head_commit = lookup_commit(head_sha1);
@@ -337,9 +343,7 @@ static int is_index_unchanged(void)
active_cache_tree = cache_tree();
if (!cache_tree_fully_valid(active_cache_tree))
- if (cache_tree_update(active_cache_tree,
- (const struct cache_entry * const *)active_cache,
- active_nr, 0))
+ 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);
@@ -357,23 +361,23 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
{
struct argv_array array;
int rc;
- char *gpg_sign;
+ const char *value;
argv_array_init(&array);
argv_array_push(&array, "commit");
argv_array_push(&array, "-n");
- if (opts->gpg_sign) {
- gpg_sign = xmalloc(3 + strlen(opts->gpg_sign));
- sprintf(gpg_sign, "-S%s", opts->gpg_sign);
- argv_array_push(&array, gpg_sign);
- free(gpg_sign);
- }
+ if (opts->gpg_sign)
+ argv_array_pushf(&array, "-S%s", opts->gpg_sign);
if (opts->signoff)
argv_array_push(&array, "-s");
if (!opts->edit) {
argv_array_push(&array, "-F");
argv_array_push(&array, defmsg);
+ if (!opts->signoff &&
+ !opts->record_origin &&
+ git_config_get_value("commit.cleanup", &value))
+ argv_array_push(&array, "--cleanup=verbatim");
}
if (allow_empty)
@@ -451,7 +455,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;
@@ -521,8 +524,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;
@@ -569,12 +570,12 @@ 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);
+ write_message(&msgbuf, git_path_merge_msg());
} else {
struct commit_list *common = NULL;
struct commit_list *remotes = NULL;
- write_message(&msgbuf, defmsg);
+ write_message(&msgbuf, git_path_merge_msg());
commit_list_insert(base, &common);
commit_list_insert(next, &remotes);
@@ -591,9 +592,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
* write it at all.
*/
if (opts->action == REPLAY_PICK && !opts->no_commit && (res == 0 || res == 1))
- write_cherry_pick_head(commit, "CHERRY_PICK_HEAD");
+ update_ref(NULL, "CHERRY_PICK_HEAD", commit->object.sha1, NULL,
+ REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
if (opts->action == REPLAY_REVERT && ((opts->no_commit && res == 0) || res == 1))
- write_cherry_pick_head(commit, "REVERT_HEAD");
+ update_ref(NULL, "REVERT_HEAD", commit->object.sha1, NULL,
+ REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
if (res) {
error(opts->action == REPLAY_REVERT
@@ -612,11 +615,10 @@ 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;
}
@@ -644,9 +646,8 @@ static void read_and_refresh_cache(struct replay_opts *opts)
if (read_index_preload(&the_index, NULL) < 0)
die(_("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) {
- if (write_index(&the_index, index_fd) ||
- commit_locked_index(&index_lock))
+ 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));
}
rollback_lock_file(&index_lock);
@@ -741,24 +742,23 @@ static int parse_insn_buffer(char *buf, struct commit_list **todo_list,
static void 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);
+ die_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);
+ die(_("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);
+ die(_("Unusable instruction sheet: %s"), git_path_todo_file());
}
static int populate_opts_cb(const char *key, const char *value, void *data)
@@ -798,12 +798,10 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
static void read_populate_opts(struct replay_opts **opts_ptr)
{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
-
- if (!file_exists(opts_file))
+ if (!file_exists(git_path_opts_file()))
return;
- if (git_config_from_file(populate_opts_cb, opts_file, *opts_ptr) < 0)
- die(_("Malformed options sheet: %s"), opts_file);
+ if (git_config_from_file(populate_opts_cb, git_path_opts_file(), *opts_ptr) < 0)
+ die(_("Malformed options sheet: %s"), git_path_opts_file());
}
static void walk_revs_populate_todo(struct commit_list **todo_list,
@@ -821,31 +819,29 @@ static void walk_revs_populate_todo(struct commit_list **todo_list,
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)
+ die_errno(_("Could not create sequencer directory %s"),
+ git_path_seq_dir());
return 0;
}
static void 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(), LOCK_DIE_ON_ERROR);
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);
+ die_errno(_("Could not write to %s"), git_path_head_file());
if (commit_lock_file(&head_lock) < 0)
- die(_("Error wrapping up %s."), head_file);
+ die(_("Error wrapping up %s."), git_path_head_file());
}
static int reset_for_rollback(const unsigned char *sha1)
@@ -862,10 +858,10 @@ 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", head_sha1, 0, NULL))
+ if (read_ref_full("HEAD", 0, head_sha1, NULL))
return error(_("cannot resolve HEAD"));
if (is_null_sha1(head_sha1))
return error(_("cannot abort from a branch yet to be born"));
@@ -874,13 +870,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.
@@ -890,18 +884,18 @@ static int sequencer_rollback(struct replay_opts *opts)
return rollback_single_pick();
}
if (!f)
- return error(_("cannot open %s: %s"), filename,
+ return error(_("cannot open %s: %s"), git_path_head_file(),
strerror(errno));
if (strbuf_getline(&buf, f, '\n')) {
- error(_("cannot read %s: %s"), filename, ferror(f) ?
- strerror(errno) : _("unexpected end of file"));
+ 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 (reset_for_rollback(sha1))
@@ -916,28 +910,27 @@ fail:
static void 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);
+ fd = hold_lock_file_for_update(&todo_lock, git_path_todo_file(), LOCK_DIE_ON_ERROR);
if (format_todo(&buf, todo_list, opts) < 0)
- die(_("Could not format %s."), todo_file);
+ die(_("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);
+ die_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);
+ die(_("Error wrapping up %s."), git_path_todo_file());
}
strbuf_release(&buf);
}
static void save_opts(struct replay_opts *opts)
{
- const char *opts_file = git_path(SEQ_OPTS_FILE);
+ const char *opts_file = git_path_opts_file();
if (opts->no_commit)
git_config_set_in_file(opts_file, "options.no-commit", "true");
@@ -998,8 +991,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);
}
@@ -1008,14 +1001,14 @@ 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);
/* 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;