Merge branch 'cm/rebase-i-fixup-amend-reword'

"git commit --fixup=<commit>", which was to tweak the changes made
to the contents while keeping the original log message intact,
learned "--fixup=(amend|reword):<commit>", that can be used to
tweak both the message and the contents, and only the message,
respectively.

* cm/rebase-i-fixup-amend-reword:
  doc/git-commit: add documentation for fixup=[amend|reword] options
  t3437: use --fixup with options to create amend! commit
  t7500: add tests for --fixup=[amend|reword] options
  commit: add a reword suboption to --fixup
  commit: add amend suboption to --fixup to create amend! commit
  sequencer: export and rename subject_length()
This commit is contained in:
Junio C Hamano 2021-03-26 14:59:03 -07:00
commit 89519f662c
8 changed files with 342 additions and 68 deletions

View File

@ -9,7 +9,7 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend] 'git commit' [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
[--dry-run] [(-c | -C | --fixup | --squash) <commit>] [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>)]
[-F <file> | -m <msg>] [--reset-author] [--allow-empty] [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
[--allow-empty-message] [--no-verify] [-e] [--author=<author>] [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
[--date=<date>] [--cleanup=<mode>] [--[no-]status] [--date=<date>] [--cleanup=<mode>] [--[no-]status]
@ -86,11 +86,44 @@ OPTIONS
Like '-C', but with `-c` the editor is invoked, so that Like '-C', but with `-c` the editor is invoked, so that
the user can further edit the commit message. the user can further edit the commit message.
--fixup=<commit>:: --fixup=[(amend|reword):]<commit>::
Construct a commit message for use with `rebase --autosquash`. Create a new commit which "fixes up" `<commit>` when applied with
The commit message will be the subject line from the specified `git rebase --autosquash`. Plain `--fixup=<commit>` creates a
commit with a prefix of "fixup! ". See linkgit:git-rebase[1] "fixup!" commit which changes the content of `<commit>` but leaves
for details. its log message untouched. `--fixup=amend:<commit>` is similar but
creates an "amend!" commit which also replaces the log message of
`<commit>` with the log message of the "amend!" commit.
`--fixup=reword:<commit>` creates an "amend!" commit which
replaces the log message of `<commit>` with its own log message
but makes no changes to the content of `<commit>`.
+
The commit created by plain `--fixup=<commit>` has a subject
composed of "fixup!" followed by the subject line from <commit>,
and is recognized specially by `git rebase --autosquash`. The `-m`
option may be used to supplement the log message of the created
commit, but the additional commentary will be thrown away once the
"fixup!" commit is squashed into `<commit>` by
`git rebase --autosquash`.
+
The commit created by `--fixup=amend:<commit>` is similar but its
subject is instead prefixed with "amend!". The log message of
<commit> is copied into the log message of the "amend!" commit and
opened in an editor so it can be refined. When `git rebase
--autosquash` squashes the "amend!" commit into `<commit>`, the
log message of `<commit>` is replaced by the refined log message
from the "amend!" commit. It is an error for the "amend!" commit's
log message to be empty unless `--allow-empty-message` is
specified.
+
`--fixup=reword:<commit>` is shorthand for `--fixup=amend:<commit>
--only`. It creates an "amend!" commit with only a log message
(ignoring any changes staged in the index). When squashed by `git
rebase --autosquash`, it replaces the log message of `<commit>`
without making any other changes.
+
Neither "fixup!" nor "amend!" commits change authorship of
`<commit>` when applied by `git rebase --autosquash`.
See linkgit:git-rebase[1] for details.
--squash=<commit>:: --squash=<commit>::
Construct a commit message for use with `rebase --autosquash`. Construct a commit message for use with `rebase --autosquash`.

View File

@ -593,16 +593,17 @@ See also INCOMPATIBLE OPTIONS below.
--autosquash:: --autosquash::
--no-autosquash:: --no-autosquash::
When the commit log message begins with "squash! ..." (or When the commit log message begins with "squash! ..." or "fixup! ..."
"fixup! ..."), and there is already a commit in the todo list that or "amend! ...", and there is already a commit in the todo list that
matches the same `...`, automatically modify the todo list of rebase matches the same `...`, automatically modify the todo list of
-i so that the commit marked for squashing comes right after the `rebase -i`, so that the commit marked for squashing comes right after
commit to be modified, and change the action of the moved commit the commit to be modified, and change the action of the moved commit
from `pick` to `squash` (or `fixup`). A commit matches the `...` if from `pick` to `squash` or `fixup` or `fixup -C` respectively. A commit
the commit subject matches, or if the `...` refers to the commit's matches the `...` if the commit subject matches, or if the `...` refers
hash. As a fall-back, partial matches of the commit subject work, to the commit's hash. As a fall-back, partial matches of the commit
too. The recommended way to create fixup/squash commits is by using subject work, too. The recommended way to create fixup/amend/squash
the `--fixup`/`--squash` options of linkgit:git-commit[1]. commits is by using the `--fixup`, `--fixup=amend:` or `--fixup=reword:`
and `--squash` options respectively of linkgit:git-commit[1].
+ +
If the `--autosquash` option is enabled by default using the If the `--autosquash` option is enabled by default using the
configuration variable `rebase.autoSquash`, this option can be configuration variable `rebase.autoSquash`, this option can be

View File

@ -105,7 +105,8 @@ static const char *template_file;
*/ */
static const char *author_message, *author_message_buffer; static const char *author_message, *author_message_buffer;
static char *edit_message, *use_message; 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 all, also, interactive, patch_interactive, only, amend, signoff;
static int edit_flag = -1; /* unspecified */ static int edit_flag = -1; /* unspecified */
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
@ -357,7 +358,8 @@ static const char *prepare_index(const char **argv, const char *prefix,
die(_("--pathspec-file-nul requires --pathspec-from-file")); die(_("--pathspec-file-nul requires --pathspec-from-file"));
} }
if (!pathspec.nr && (also || (only && !amend && !allow_empty))) if (!pathspec.nr && (also || (only && !allow_empty &&
(!amend || (fixup_message && strcmp(fixup_prefix, "amend"))))))
die(_("No paths with --include/--only does not make sense.")); die(_("No paths with --include/--only does not make sense."));
if (read_cache_preload(&pathspec) < 0) if (read_cache_preload(&pathspec) < 0)
@ -681,6 +683,22 @@ static void adjust_comment_line_char(const struct strbuf *sb)
comment_line_char = *p; comment_line_char = *p;
} }
static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
struct pretty_print_context *ctx)
{
const char *buffer, *subject, *fmt;
buffer = get_commit_buffer(commit, NULL);
find_commit_subject(buffer, &subject);
/*
* If we amend the 'amend!' commit then we don't want to
* duplicate the subject line.
*/
fmt = starts_with(subject, "amend!") ? "%b" : "%B";
format_commit_message(commit, fmt, sb, ctx);
unuse_commit_buffer(commit, buffer);
}
static int prepare_to_commit(const char *index_file, const char *prefix, static int prepare_to_commit(const char *index_file, const char *prefix,
struct commit *current_head, struct commit *current_head,
struct wt_status *s, struct wt_status *s,
@ -745,15 +763,33 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
} else if (fixup_message) { } else if (fixup_message) {
struct pretty_print_context ctx = {0}; struct pretty_print_context ctx = {0};
struct commit *commit; struct commit *commit;
commit = lookup_commit_reference_by_name(fixup_message); char *fmt;
commit = lookup_commit_reference_by_name(fixup_commit);
if (!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(); ctx.output_encoding = get_commit_output_encoding();
format_commit_message(commit, "fixup! %s\n\n", fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
&sb, &ctx); format_commit_message(commit, fmt, &sb, &ctx);
if (have_option_m) free(fmt);
strbuf_addbuf(&sb, &message);
hook_arg1 = "message"; hook_arg1 = "message";
/*
* Only `-m` commit message option is checked here, as
* it supports `--fixup` to append the commit message.
*
* The other commit message options `-c`/`-C`/`-F` are
* incompatible with all the forms of `--fixup` and
* have already errored out while parsing the `git commit`
* options.
*/
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);
prepare_amend_commit(commit, &sb, &ctx);
}
} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) { } else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
size_t merge_msg_start; size_t merge_msg_start;
@ -1152,6 +1188,19 @@ static void finalize_deferred_config(struct wt_status *s)
s->ahead_behind_flags = AHEAD_BEHIND_FULL; s->ahead_behind_flags = AHEAD_BEHIND_FULL;
} }
static void check_fixup_reword_options(int argc, const char *argv[]) {
if (whence != FROM_COMMIT) {
if (whence == FROM_MERGE)
die(_("You are in the middle of a merge -- cannot reword."));
else if (is_from_cherry_pick(whence))
die(_("You are in the middle of a cherry-pick -- cannot reword."));
}
if (argc)
die(_("cannot combine reword option of --fixup with path '%s'"), *argv);
if (patch_interactive || interactive || all || also || only)
die(_("reword option of --fixup is mutually exclusive with --patch/--interactive/--all/--include/--only"));
}
static int parse_and_validate_options(int argc, const char *argv[], static int parse_and_validate_options(int argc, const char *argv[],
const struct option *options, const struct option *options,
const char * const usage[], const char * const usage[],
@ -1170,7 +1219,7 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (force_author && renew_authorship) if (force_author && renew_authorship)
die(_("Using both --reset-author and --author does not make sense")); 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; use_editor = 0;
if (0 <= edit_flag) if (0 <= edit_flag)
use_editor = edit_flag; use_editor = edit_flag;
@ -1227,6 +1276,42 @@ static int parse_and_validate_options(int argc, const char *argv[],
if (also + only + all + interactive > 1) if (also + only + all + interactive > 1)
die(_("Only one of --include/--only/--all/--interactive/--patch can be used.")); die(_("Only one of --include/--only/--all/--interactive/--patch can be used."));
if (fixup_message) {
/*
* We limit --fixup's suboptions to only alpha characters.
* If the first character after a run of alpha is colon,
* then the part before the colon may be a known suboption
* name like `amend` or `reword`, or a misspelt suboption
* name. In either case, we treat it as
* --fixup=<suboption>:<arg>.
*
* Otherwise, we are dealing with --fixup=<commit>.
*/
char *p = fixup_message;
while (isalpha(*p))
p++;
if (p > fixup_message && *p == ':') {
*p = '\0';
fixup_commit = p + 1;
if (!strcmp("amend", fixup_message) ||
!strcmp("reword", fixup_message)) {
fixup_prefix = "amend";
allow_empty = 1;
if (*fixup_message == 'r') {
check_fixup_reword_options(argc, argv);
only = 1;
}
} 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); cleanup_mode = get_cleanup_mode(cleanup_arg, use_editor);
handle_untracked_files_arg(s); handle_untracked_files_arg(s);
@ -1504,7 +1589,11 @@ 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_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', "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('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: Leave "[(amend|reword):]" as-is,
* and only translate <commit>.
*/
OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash 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(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")), OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
@ -1663,6 +1752,19 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
exit(1); exit(1);
} }
if (fixup_message && starts_with(sb.buf, "amend! ") &&
!allow_empty_message) {
struct strbuf body = STRBUF_INIT;
size_t len = commit_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) { if (amend) {
const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL }; const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
extra = read_commit_extra_headers(current_head, exclude_gpgsig); extra = read_commit_extra_headers(current_head, exclude_gpgsig);

View File

@ -535,6 +535,20 @@ int find_commit_subject(const char *commit_buffer, const char **subject)
return eol - p; return eol - p;
} }
size_t commit_subject_length(const char *body)
{
const char *p = body;
while (*p) {
const char *next = skip_blank_lines(p);
if (next != p)
break;
p = strchrnul(p, '\n');
if (*p)
p++;
}
return p - body;
}
struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p) struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
{ {
struct commit_list *new_list = xmalloc(sizeof(struct commit_list)); struct commit_list *new_list = xmalloc(sizeof(struct commit_list));

View File

@ -167,6 +167,9 @@ const void *detach_commit_buffer(struct commit *, unsigned long *sizep);
/* Find beginning and length of commit subject. */ /* Find beginning and length of commit subject. */
int find_commit_subject(const char *commit_buffer, const char **subject); int find_commit_subject(const char *commit_buffer, const char **subject);
/* Return length of the commit subject from commit log message. */
size_t commit_subject_length(const char *body);
struct commit_list *commit_list_insert(struct commit *item, struct commit_list *commit_list_insert(struct commit *item,
struct commit_list **list); struct commit_list **list);
int commit_list_contains(struct commit *item, int commit_list_contains(struct commit *item,

View File

@ -1732,20 +1732,6 @@ enum todo_item_flags {
TODO_EDIT_FIXUP_MSG = (1 << 2), TODO_EDIT_FIXUP_MSG = (1 << 2),
}; };
static size_t subject_length(const char *body)
{
const char *p = body;
while (*p) {
const char *next = skip_blank_lines(p);
if (next != p)
break;
p = strchrnul(p, '\n');
if (*p)
p++;
}
return p - body;
}
static const char first_commit_msg_str[] = N_("This is the 1st commit message:"); static const char first_commit_msg_str[] = N_("This is the 1st commit message:");
static const char nth_commit_msg_fmt[] = N_("This is the commit message #%d:"); static const char nth_commit_msg_fmt[] = N_("This is the commit message #%d:");
static const char skip_first_commit_msg_str[] = N_("The 1st commit message will be skipped:"); static const char skip_first_commit_msg_str[] = N_("The 1st commit message will be skipped:");
@ -1869,7 +1855,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,
if (starts_with(body, "amend!") || if (starts_with(body, "amend!") ||
((command == TODO_SQUASH || seen_squash(opts)) && ((command == TODO_SQUASH || seen_squash(opts)) &&
(starts_with(body, "squash!") || starts_with(body, "fixup!")))) (starts_with(body, "squash!") || starts_with(body, "fixup!"))))
commented_len = subject_length(body); commented_len = commit_subject_length(body);
strbuf_addf(buf, "\n%c ", comment_line_char); strbuf_addf(buf, "\n%c ", comment_line_char);
strbuf_addf(buf, _(nth_commit_msg_fmt), strbuf_addf(buf, _(nth_commit_msg_fmt),

View File

@ -72,40 +72,16 @@ test_expect_success 'setup' '
git commit --fixup=HEAD -a && git commit --fixup=HEAD -a &&
git tag B1 && git tag B1 &&
test_tick && test_tick &&
git commit --allow-empty -F - <<-EOF && FAKE_COMMIT_AMEND="edited 1" git commit --fixup=reword:B &&
amend! B
$EMPTY
B
$EMPTY
edited 1
EOF
test_tick && test_tick &&
git commit --allow-empty -F - <<-EOF && FAKE_COMMIT_AMEND="edited 2" git commit --fixup=reword:HEAD &&
amend! amend! B
$EMPTY
B
$EMPTY
edited 1
$EMPTY
edited 2
EOF
echo B2 >B && echo B2 >B &&
test_tick && test_tick &&
FAKE_COMMIT_AMEND="edited squash" git commit --squash=HEAD -a && FAKE_COMMIT_AMEND="edited squash" git commit --squash=HEAD -a &&
git tag B2 && git tag B2 &&
echo B3 >B && echo B3 >B &&
test_tick && test_tick &&
git commit -a -F - <<-EOF && FAKE_COMMIT_AMEND="edited 3" git commit -a --fixup=amend:HEAD^ &&
amend! amend! amend! B
$EMPTY
B
$EMPTY
edited 1
$EMPTY
edited 2
$EMPTY
edited 3
EOF
git tag B3 && git tag B3 &&
GIT_AUTHOR_NAME="Rebase Author" && GIT_AUTHOR_NAME="Rebase Author" &&

View File

@ -9,6 +9,8 @@ Tests for template, signoff, squash and -F functions.'
. ./test-lib.sh . ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
commit_msg_is () { commit_msg_is () {
expect=commit_msg_is.expect expect=commit_msg_is.expect
actual=commit_msg_is.actual actual=commit_msg_is.actual
@ -279,6 +281,163 @@ test_expect_success 'commit --fixup -m"something" -m"extra"' '
extra" extra"
' '
get_commit_msg () {
rev="$1" &&
git log -1 --pretty=format:"%B" "$rev"
}
test_expect_success 'commit --fixup=amend: creates amend! commit' '
commit_for_rebase_autosquash_setup &&
cat >expected <<-EOF &&
amend! $(git log -1 --format=%s HEAD~)
$(get_commit_msg HEAD~)
edited
EOF
(
set_fake_editor &&
FAKE_COMMIT_AMEND="edited" \
git commit --fixup=amend:HEAD~
) &&
get_commit_msg HEAD >actual &&
test_cmp expected actual
'
test_expect_success '--fixup=amend: --only ignores staged changes' '
commit_for_rebase_autosquash_setup &&
cat >expected <<-EOF &&
amend! $(git log -1 --format=%s HEAD~)
$(get_commit_msg HEAD~)
edited
EOF
(
set_fake_editor &&
FAKE_COMMIT_AMEND="edited" \
git commit --fixup=amend:HEAD~ --only
) &&
get_commit_msg HEAD >actual &&
test_cmp expected actual &&
test_cmp_rev HEAD@{1}^{tree} HEAD^{tree} &&
test_cmp_rev HEAD@{1} HEAD^ &&
test_expect_code 1 git diff --cached --exit-code &&
git cat-file blob :foo >actual &&
test_cmp foo actual
'
test_expect_success '--fixup=reword: ignores staged changes' '
commit_for_rebase_autosquash_setup &&
cat >expected <<-EOF &&
amend! $(git log -1 --format=%s HEAD~)
$(get_commit_msg HEAD~)
edited
EOF
(
set_fake_editor &&
FAKE_COMMIT_AMEND="edited" \
git commit --fixup=reword:HEAD~
) &&
get_commit_msg HEAD >actual &&
test_cmp expected actual &&
test_cmp_rev HEAD@{1}^{tree} HEAD^{tree} &&
test_cmp_rev HEAD@{1} HEAD^ &&
test_expect_code 1 git diff --cached --exit-code &&
git cat-file blob :foo >actual &&
test_cmp foo actual
'
test_expect_success '--fixup=reword: error out with -m option' '
commit_for_rebase_autosquash_setup &&
echo "fatal: cannot combine -m with --fixup:reword" >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -m "reword commit message" 2>actual &&
test_cmp expect actual
'
test_expect_success '--fixup=amend: error out with -m option' '
commit_for_rebase_autosquash_setup &&
echo "fatal: cannot combine -m with --fixup:amend" >expect &&
test_must_fail git commit --fixup=amend:HEAD~ -m "amend commit message" 2>actual &&
test_cmp expect actual
'
test_expect_success 'consecutive amend! commits remove amend! line from commit msg body' '
commit_for_rebase_autosquash_setup &&
cat >expected <<-EOF &&
amend! amend! $(git log -1 --format=%s HEAD~)
$(get_commit_msg HEAD~)
edited 1
edited 2
EOF
echo "reword new commit message" >actual &&
(
set_fake_editor &&
FAKE_COMMIT_AMEND="edited 1" \
git commit --fixup=reword:HEAD~ &&
FAKE_COMMIT_AMEND="edited 2" \
git commit --fixup=reword:HEAD
) &&
get_commit_msg HEAD >actual &&
test_cmp expected actual
'
test_expect_success 'deny to create amend! commit if its commit msg body is empty' '
commit_for_rebase_autosquash_setup &&
echo "Aborting commit due to empty commit message body." >expected &&
(
set_fake_editor &&
test_must_fail env FAKE_COMMIT_MESSAGE="amend! target message subject line" \
git commit --fixup=amend:HEAD~ 2>actual
) &&
test_cmp expected actual
'
test_expect_success 'amend! commit allows empty commit msg body with --allow-empty-message' '
commit_for_rebase_autosquash_setup &&
cat >expected <<-EOF &&
amend! $(git log -1 --format=%s HEAD~)
EOF
(
set_fake_editor &&
FAKE_COMMIT_MESSAGE="amend! target message subject line" \
git commit --fixup=amend:HEAD~ --allow-empty-message &&
get_commit_msg HEAD >actual
) &&
test_cmp expected actual
'
test_fixup_reword_opt () {
test_expect_success C_LOCALE_OUTPUT "--fixup=reword: incompatible with $1" "
echo 'fatal: reword option of --fixup is mutually exclusive with'\
'--patch/--interactive/--all/--include/--only' >expect &&
test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual &&
test_cmp expect actual
"
}
for opt in --all --include --only --interactive --patch
do
test_fixup_reword_opt $opt
done
test_expect_success '--fixup=reword: give error with pathsec' '
commit_for_rebase_autosquash_setup &&
echo "fatal: cannot combine reword option of --fixup with path '\''foo'\''" >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -- foo 2>actual &&
test_cmp expect actual
'
test_expect_success '--fixup=reword: -F give error message' '
echo "fatal: Only one of -c/-C/-F/--fixup can be used." >expect &&
test_must_fail git commit --fixup=reword:HEAD~ -F msg 2>actual &&
test_cmp expect actual
'
test_expect_success 'commit --squash works with -F' ' test_expect_success 'commit --squash works with -F' '
commit_for_rebase_autosquash_setup && commit_for_rebase_autosquash_setup &&