diff --git a/builtin/commit.c b/builtin/commit.c
index 505fe60956..56ae15a762 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -105,7 +105,8 @@ static const char *template_file;
*/
static const char *author_message, *author_message_buffer;
static char *edit_message, *use_message;
-static char *fixup_message, *squash_message;
+static char *fixup_message, *fixup_commit, *squash_message;
+static const char *fixup_prefix;
static int all, also, interactive, patch_interactive, only, amend, signoff;
static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
@@ -681,6 +682,21 @@ static void adjust_comment_line_char(const struct strbuf *sb)
comment_line_char = *p;
}
+static int prepare_amend_commit(struct commit *commit, struct strbuf *sb,
+ struct pretty_print_context *ctx) {
+ /*
+ * If we amend the 'amend!' commit then we don't want to
+ * duplicate the subject line.
+ */
+ const char *format = NULL;
+ if (starts_with(sb->buf, "amend! amend!"))
+ format = "%b";
+ else
+ format = "%B";
+ format_commit_message(commit, format, sb, ctx);
+ return 0;
+}
+
static int prepare_to_commit(const char *index_file, const char *prefix,
struct commit *current_head,
struct wt_status *s,@@ -745,15 +761,24 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
} else if (fixup_message) {
struct pretty_print_context ctx = {0};
struct commit *commit;
- commit = lookup_commit_reference_by_name(fixup_message);
+ char *fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
+ commit = lookup_commit_reference_by_name(fixup_commit);
if (!commit)
- die(_("could not lookup commit %s"), fixup_message);
+ die(_("could not lookup commit %s"), fixup_commit);
ctx.output_encoding = get_commit_output_encoding();
- format_commit_message(commit, "fixup! %s\n\n",
- &sb, &ctx);
- if (have_option_m)
- strbuf_addbuf(&sb, &message);
+ format_commit_message(commit, fmt, &sb, &ctx);
+ free(fmt);
hook_arg1 = "message";
+
+ if ((have_option_m) && !strcmp(fixup_prefix,"fixup"))
+ strbuf_addbuf(&sb, &message);
+
+ if (!strcmp(fixup_prefix,"amend")) {
+ if (have_option_m)
+ die(_("cannot combine -m with --fixup:%s"), fixup_message);
+ else
+ prepare_amend_commit(commit, &sb, &ctx);
+ }
} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
size_t merge_msg_start;
@@ -1152,6 +1177,12 @@ static void finalize_deferred_config(struct wt_status *s)
s->ahead_behind_flags = AHEAD_BEHIND_FULL;
}
+/* returns the length of intial segment of alpha characters only */
+static size_t get_alpha_len(char *fixup_message) {
+ const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
+ return strspn(fixup_message, alphas);
+}
+
static int parse_and_validate_options(int argc, const char *argv[],
const struct option *options,
const char * const usage[],@@ -1170,7 +1201,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (force_author && renew_authorship)
die(_("Using both --reset-author and --author does not make sense"));
- if (logfile || have_option_m || use_message || fixup_message)
+ if (logfile || have_option_m || use_message)
use_editor = 0;
if (0 <= edit_flag)
use_editor = edit_flag;@@ -1227,6 +1258,28 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
+
+ if (fixup_message) {
+ /*
+ * As `amend` suboption contains only alpha
+ * character. So check if first non alpha
+ * character in fixup_message is ':'.
+ */
+ size_t len = get_alpha_len(fixup_message);
+ if (len && fixup_message[len] == ':') {
+ fixup_message[len] = '\0';
+ fixup_commit = fixup_message + ++len;
+ if (starts_with("amend", fixup_message))
+ fixup_prefix = "amend";
+ else
+ die(_("unknown option: --fixup=%s:%s"), fixup_message, fixup_commit);
+ } else {
+ fixup_commit = fixup_message;
+ fixup_prefix = "fixup";
+ use_editor = 0;
+ }
+ }
+
cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
handle_untracked_files_arg(s);@@ -1504,7 +1557,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
- OPT_STRING(0, "fixup", &fixup_message, N_("commit"), N_("use autosquash formatted message to fixup specified commit")),
+ /*
+ * TRANSLATORS: please do not translate [amend:]
+ * Here "amend" is an option to the --fixup command
+ * line flag, that creates amend! commit.
+ */
+ OPT_STRING(0, "fixup", &fixup_message, N_("[amend:]commit"), N_("use autosquash formatted message to fixup or amend specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),@@ -1663,6 +1721,19 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
exit(1);
}
+ if (fixup_message && starts_with(sb.buf, "amend! ") &&
+ !allow_empty_message) {
+ struct strbuf body = STRBUF_INIT;
+ size_t len = subject_length(sb.buf);
+ strbuf_addstr(&body, sb.buf + len);
+ if (message_is_empty(&body, cleanup_mode)) {
+ rollback_index_files();
+ fprintf(stderr, _("Aborting commit due to empty commit message body.\n"));
+ exit(1);
+ }
+ strbuf_release(&body);
+ }
+
if (amend) {
const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
extra = read_commit_extra_headers(current_head, exclude_gpgsig);--
2.29.0.rc1