if (status)
return status;
- if (!strcmp(s, "verbatim"))
+ if (!strcmp(s, "verbatim")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE;
- else if (!strcmp(s, "whitespace"))
+ opts->explicit_cleanup = 1;
+ } else if (!strcmp(s, "whitespace")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
- else if (!strcmp(s, "strip"))
+ opts->explicit_cleanup = 1;
+ } else if (!strcmp(s, "strip")) {
opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL;
- else if (!strcmp(s, "scissors"))
- opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE;
- else
+ opts->explicit_cleanup = 1;
+ } else if (!strcmp(s, "scissors")) {
+ opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS;
+ opts->explicit_cleanup = 1;
+ } else {
warning(_("invalid commit message cleanup mode '%s'"),
s);
+ }
free((char *)s);
return status;
return 0;
}
+enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
+ int use_editor)
+{
+ if (!cleanup_arg || !strcmp(cleanup_arg, "default"))
+ return use_editor ? COMMIT_MSG_CLEANUP_ALL :
+ COMMIT_MSG_CLEANUP_SPACE;
+ else if (!strcmp(cleanup_arg, "verbatim"))
+ return COMMIT_MSG_CLEANUP_NONE;
+ else if (!strcmp(cleanup_arg, "whitespace"))
+ return COMMIT_MSG_CLEANUP_SPACE;
+ else if (!strcmp(cleanup_arg, "strip"))
+ return COMMIT_MSG_CLEANUP_ALL;
+ else if (!strcmp(cleanup_arg, "scissors"))
+ return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS :
+ COMMIT_MSG_CLEANUP_SPACE;
+ else
+ die(_("Invalid cleanup mode %s"), cleanup_arg);
+}
+
+/*
+ * NB using int rather than enum cleanup_mode to stop clang's
+ * -Wtautological-constant-out-of-range-compare complaining that the comparison
+ * is always true.
+ */
+static const char *describe_cleanup_mode(int cleanup_mode)
+{
+ static const char *modes[] = { "whitespace",
+ "verbatim",
+ "scissors",
+ "strip" };
+
+ if (cleanup_mode < ARRAY_SIZE(modes))
+ return modes[cleanup_mode];
+
+ BUG("invalid cleanup_mode provided (%d)", cleanup_mode);
+}
+
void append_conflicts_hint(struct index_state *istate,
- struct strbuf *msgbuf)
+ struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode)
{
int i;
+ if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+ strbuf_addch(msgbuf, '\n');
+ wt_status_append_cut_line(msgbuf);
+ strbuf_addch(msgbuf, comment_line_char);
+ }
+
strbuf_addch(msgbuf, '\n');
strbuf_commented_addf(msgbuf, "Conflicts:\n");
for (i = 0; i < istate->cache_nr;) {
_(action_name(opts)));
if (!clean)
- append_conflicts_hint(r->index, msgbuf);
+ append_conflicts_hint(r->index, msgbuf,
+ opts->default_msg_cleanup);
return !clean;
}
unsigned int flags)
{
struct child_process cmd = CHILD_PROCESS_INIT;
- const char *value;
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
argv_array_push(&cmd.args, "-e");
else if (!(flags & CLEANUP_MSG) &&
!opts->signoff && !opts->record_origin &&
- git_config_get_value("commit.cleanup", &value))
+ !opts->explicit_cleanup)
argv_array_push(&cmd.args, "--cleanup=verbatim");
if ((flags & ALLOW_EMPTY))
return 1;
}
+void cleanup_message(struct strbuf *msgbuf,
+ enum commit_msg_cleanup_mode cleanup_mode, int verbose)
+{
+ if (verbose || /* Truncate the message just before the diff, if any. */
+ cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+ strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));
+ if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)
+ strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);
+}
+
/*
* Find out if the message in the strbuf contains only whitespace and
* Signed-off-by lines.
msg = &commit_msg;
}
- cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL :
- opts->default_msg_cleanup;
+ if (flags & CLEANUP_MSG)
+ cleanup = COMMIT_MSG_CLEANUP_ALL;
+ else if ((opts->signoff || opts->record_origin) &&
+ !opts->explicit_cleanup)
+ cleanup = COMMIT_MSG_CLEANUP_SPACE;
+ else
+ cleanup = opts->default_msg_cleanup;
if (cleanup != COMMIT_MSG_CLEANUP_NONE)
strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);
item->arg_len = (int)(eol - bol);
if (status < 0)
- return -1;
+ return error(_("could not parse '%.*s'"),
+ (int)(end_of_object_name - bol), bol);
item->commit = lookup_commit_reference(r, &commit_oid);
return !item->commit;
}
+int sequencer_get_last_command(struct repository *r, enum replay_action *action)
+{
+ struct todo_item item;
+ char *eol;
+ const char *todo_file;
+ struct strbuf buf = STRBUF_INIT;
+ int ret = -1;
+
+ todo_file = git_path_todo_file();
+ if (strbuf_read_file(&buf, todo_file, 0) < 0) {
+ if (errno == ENOENT)
+ return -1;
+ else
+ return error_errno("unable to open '%s'", todo_file);
+ }
+ eol = strchrnul(buf.buf, '\n');
+ if (buf.buf != eol && eol[-1] == '\r')
+ eol--; /* strip Carriage Return */
+ if (parse_insn_line(r, &item, buf.buf, buf.buf, eol))
+ goto fail;
+ if (item.command == TODO_PICK)
+ *action = REPLAY_PICK;
+ else if (item.command == TODO_REVERT)
+ *action = REPLAY_REVERT;
+ else
+ goto fail;
+
+ ret = 0;
+
+ fail:
+ strbuf_release(&buf);
+
+ return ret;
+}
+
int todo_list_parse_insn_buffer(struct repository *r, char *buf,
struct todo_list *todo_list)
{
return len;
}
+static int have_finished_the_last_pick(void)
+{
+ struct strbuf buf = STRBUF_INIT;
+ const char *eol;
+ const char *todo_path = git_path_todo_file();
+ int ret = 0;
+
+ if (strbuf_read_file(&buf, todo_path, 0) < 0) {
+ if (errno == ENOENT) {
+ return 0;
+ } else {
+ error_errno("unable to open '%s'", todo_path);
+ return 0;
+ }
+ }
+ /* If there is only one line then we are done */
+ eol = strchr(buf.buf, '\n');
+ if (!eol || !eol[1])
+ ret = 1;
+
+ strbuf_release(&buf);
+
+ return ret;
+}
+
+void sequencer_post_commit_cleanup(struct repository *r)
+{
+ struct replay_opts opts = REPLAY_OPTS_INIT;
+ int need_cleanup = 0;
+
+ if (file_exists(git_path_cherry_pick_head(r))) {
+ unlink(git_path_cherry_pick_head(r));
+ opts.action = REPLAY_PICK;
+ need_cleanup = 1;
+ }
+
+ if (file_exists(git_path_revert_head(r))) {
+ unlink(git_path_revert_head(r));
+ opts.action = REPLAY_REVERT;
+ need_cleanup = 1;
+ }
+
+ if (!need_cleanup)
+ return;
+
+ if (!have_finished_the_last_pick())
+ return;
+
+ sequencer_remove_state(&opts);
+}
+
static int read_populate_todo(struct repository *r,
struct todo_list *todo_list,
struct replay_opts *opts)
opts->no_commit = git_config_bool_or_int(key, value, &error_flag);
else if (!strcmp(key, "options.edit"))
opts->edit = git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.allow-empty"))
+ opts->allow_empty =
+ git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.allow-empty-message"))
+ opts->allow_empty_message =
+ git_config_bool_or_int(key, value, &error_flag);
+ else if (!strcmp(key, "options.keep-redundant-commits"))
+ opts->keep_redundant_commits =
+ git_config_bool_or_int(key, value, &error_flag);
else if (!strcmp(key, "options.signoff"))
opts->signoff = git_config_bool_or_int(key, value, &error_flag);
else if (!strcmp(key, "options.record-origin"))
opts->allow_rerere_auto =
git_config_bool_or_int(key, value, &error_flag) ?
RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE;
- else
+ else if (!strcmp(key, "options.default-msg-cleanup")) {
+ opts->explicit_cleanup = 1;
+ opts->default_msg_cleanup = get_cleanup_mode(value, 1);
+ } else
return error(_("invalid key: %s"), key);
if (!error_flag)
int res = 0;
if (opts->no_commit)
- res |= git_config_set_in_file_gently(opts_file, "options.no-commit", "true");
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.no-commit", "true");
if (opts->edit)
- res |= git_config_set_in_file_gently(opts_file, "options.edit", "true");
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.edit", "true");
+ if (opts->allow_empty)
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.allow-empty", "true");
+ if (opts->allow_empty_message)
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.allow-empty-message", "true");
+ if (opts->keep_redundant_commits)
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.keep-redundant-commits", "true");
if (opts->signoff)
- res |= git_config_set_in_file_gently(opts_file, "options.signoff", "true");
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.signoff", "true");
if (opts->record_origin)
- res |= git_config_set_in_file_gently(opts_file, "options.record-origin", "true");
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.record-origin", "true");
if (opts->allow_ff)
- res |= git_config_set_in_file_gently(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);
- res |= git_config_set_in_file_gently(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)
- res |= git_config_set_in_file_gently(opts_file, "options.strategy", opts->strategy);
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.strategy", opts->strategy);
if (opts->gpg_sign)
- res |= git_config_set_in_file_gently(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++)
res |= git_config_set_multivar_in_file_gently(opts_file,
- "options.strategy-option",
- opts->xopts[i], "^$", 0);
+ "options.strategy-option",
+ opts->xopts[i], "^$", 0);
}
if (opts->allow_rerere_auto)
- res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto",
- opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
- "true" : "false");
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.allow-rerere-auto",
+ opts->allow_rerere_auto == RERERE_AUTOUPDATE ?
+ "true" : "false");
+
+ if (opts->explicit_cleanup)
+ res |= git_config_set_in_file_gently(opts_file,
+ "options.default-msg-cleanup",
+ describe_cleanup_mode(opts->default_msg_cleanup));
return res;
}
res = do_exec(r, arg);
*end_of_arg = saved;
- /* Reread the todo file if it has changed. */
if (res) {
if (opts->reschedule_failed_exec)
reschedule = 1;
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 */