diff options
-rw-r--r-- | Documentation/git-rebase.txt | 2 | ||||
-rw-r--r-- | rebase-interactive.c | 9 | ||||
-rw-r--r-- | sequencer.c | 23 | ||||
-rw-r--r-- | t/lib-rebase.sh | 7 | ||||
-rwxr-xr-x | t/t3437-rebase-fixup-options.sh | 122 |
5 files changed, 87 insertions, 76 deletions
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index a6903419c4..8bfa5a9272 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -894,7 +894,7 @@ is used. In that case the suggested commit message is only the message of the "fixup -c" commit, and an editor is opened allowing you to edit the message. The contents (patch) of the "fixup -c" commit are still incorporated into the folded commit. If there is more than one "fixup -c" -commit, the message from the last last one is used. You can also use +commit, the message from the final one is used. You can also use "fixup -C" to get the same behavior as "fixup -c" except without opening an editor. diff --git a/rebase-interactive.c b/rebase-interactive.c index c3bd02adee..b6cbd16a17 100644 --- a/rebase-interactive.c +++ b/rebase-interactive.c @@ -44,9 +44,10 @@ void append_todo_help(int command_count, "r, reword <commit> = use commit, but edit the commit message\n" "e, edit <commit> = use commit, but stop for amending\n" "s, squash <commit> = use commit, but meld into previous commit\n" -"f, fixup [-C | -c] <commit> = like \"squash\", but discard this\n" -" commit's log message. Use -C to replace with this\n" -" commit message or -c to edit the commit message\n" +"f, fixup [-C | -c] <commit> = like \"squash\" but keep only the previous\n" +" commit's log message, unless -C is used, in which case\n" +" keep only this commit's message; -c is same as -C but\n" +" opens the editor\n" "x, exec <command> = run command (the rest of the line) using shell\n" "b, break = stop here (continue rebase later with 'git rebase --continue')\n" "d, drop <commit> = remove commit\n" @@ -55,7 +56,7 @@ void append_todo_help(int command_count, "m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]\n" ". create a merge commit using the original merge commit's\n" ". message (or the oneline, if no original merge commit was\n" -". specified). Use -c <commit> to reword the commit message.\n" +". specified); use -c <commit> to reword the commit message\n" "\n" "These lines can be re-ordered; they are executed from top to bottom.\n"); unsigned edit_todo = !(shortrevisions && shortonto); diff --git a/sequencer.c b/sequencer.c index e32020252d..aedca2d52b 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1752,8 +1752,7 @@ static const char skip_first_commit_msg_str[] = N_("The 1st commit message will static const char skip_nth_commit_msg_fmt[] = N_("The commit message #%d will be skipped:"); static const char combined_commit_msg_fmt[] = N_("This is a combination of %d commits."); -static int check_fixup_flag(enum todo_command command, - enum todo_item_flags flag) +static int is_fixup_flag(enum todo_command command, unsigned flag) { return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) || (flag & TODO_EDIT_FIXUP_MSG)); @@ -1858,7 +1857,7 @@ static void update_squash_message_for_fixup(struct strbuf *msg) static int append_squash_message(struct strbuf *buf, const char *body, enum todo_command command, struct replay_opts *opts, - enum todo_item_flags flag) + unsigned flag) { const char *fixup_msg; size_t commented_len = 0, fixup_off; @@ -1882,7 +1881,7 @@ static int append_squash_message(struct strbuf *buf, const char *body, strbuf_addstr(buf, body + commented_len); /* fixup -C after squash behaves like squash */ - if (check_fixup_flag(command, flag) && !seen_squash(opts)) { + if (is_fixup_flag(command, flag) && !seen_squash(opts)) { /* * We're replacing the commit message so we need to * append the Signed-off-by: trailer if the user @@ -1914,7 +1913,7 @@ static int update_squash_messages(struct repository *r, enum todo_command command, struct commit *commit, struct replay_opts *opts, - enum todo_item_flags flag) + unsigned flag) { struct strbuf buf = STRBUF_INIT; int res = 0; @@ -1937,7 +1936,7 @@ static int update_squash_messages(struct repository *r, opts->current_fixup_count + 2); strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len); strbuf_release(&header); - if (check_fixup_flag(command, flag) && !seen_squash(opts)) + if (is_fixup_flag(command, flag) && !seen_squash(opts)) update_squash_message_for_fixup(&buf); } else { struct object_id head; @@ -1960,11 +1959,11 @@ static int update_squash_messages(struct repository *r, strbuf_addf(&buf, "%c ", comment_line_char); strbuf_addf(&buf, _(combined_commit_msg_fmt), 2); strbuf_addf(&buf, "\n%c ", comment_line_char); - strbuf_addstr(&buf, check_fixup_flag(command, flag) ? + strbuf_addstr(&buf, is_fixup_flag(command, flag) ? _(skip_first_commit_msg_str) : _(first_commit_msg_str)); strbuf_addstr(&buf, "\n\n"); - if (check_fixup_flag(command, flag)) + if (is_fixup_flag(command, flag)) strbuf_add_commented_lines(&buf, body, strlen(body)); else strbuf_addstr(&buf, body); @@ -1977,7 +1976,7 @@ static int update_squash_messages(struct repository *r, oid_to_hex(&commit->object.oid)); find_commit_subject(message, &body); - if (command == TODO_SQUASH || check_fixup_flag(command, flag)) { + if (command == TODO_SQUASH || is_fixup_flag(command, flag)) { res = append_squash_message(&buf, body, command, opts, flag); } else if (command == TODO_FIXUP) { strbuf_addf(&buf, "\n%c ", comment_line_char); @@ -5670,7 +5669,7 @@ static int subject2item_cmp(const void *fndata, define_commit_slab(commit_todo_item, struct todo_item *); -static inline int skip_fixup_amend_squash(const char *subject, const char **p) { +static int skip_fixupish(const char *subject, const char **p) { return skip_prefix(subject, "fixup! ", p) || skip_prefix(subject, "amend! ", p) || skip_prefix(subject, "squash! ", p); @@ -5734,13 +5733,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list) format_subject(&buf, subject, " "); subject = subjects[i] = strbuf_detach(&buf, &subject_len); unuse_commit_buffer(item->commit, commit_buffer); - if (skip_fixup_amend_squash(subject, &p)) { + if (skip_fixupish(subject, &p)) { struct commit *commit2; for (;;) { while (isspace(*p)) p++; - if (!skip_fixup_amend_squash(p, &p)) + if (!skip_fixupish(p, &p)) break; } diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh index 27928ecb94..dc75b83451 100644 --- a/t/lib-rebase.sh +++ b/t/lib-rebase.sh @@ -15,10 +15,11 @@ # specified line. # # "<cmd> <lineno>" -- add a line with the specified command -# ("pick", "squash", "fixup", "edit", "reword" or "drop") and the -# SHA1 taken from the specified line. +# ("pick", "squash", "fixup"|"fixup_-C"|"fixup_-c", "edit", "reword" or "drop") +# and the SHA1 taken from the specified line. # -# "exec_cmd_with_args" -- add an "exec cmd with args" line. +# "_" -- add a space, like "fixup_-C" implies "fixup -C" and +# "exec_cmd_with_args" add an "exec cmd with args" line. # # "#" -- Add a comment line. # diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh index 945df2555b..a5a20354e3 100755 --- a/t/t3437-rebase-fixup-options.sh +++ b/t/t3437-rebase-fixup-options.sh @@ -9,7 +9,9 @@ This test checks the "fixup [-C|-c]" command of rebase interactive. In addition to amending the contents of the commit, "fixup -C" replaces the original commit message with the message of the fixup commit. "fixup -c" also replaces the original message, but opens the -editor to allow the user to edit the message before committing. +editor to allow the user to edit the message before committing. Similar +to the "fixup" command that works with "fixup!", "fixup -C" works with +"amend!" upon --autosquash. ' . ./test-lib.sh @@ -18,35 +20,35 @@ editor to allow the user to edit the message before committing. EMPTY="" +# test_commit_message <rev> -m <msg> +# test_commit_message <rev> <path> +# Verify that the commit message of <rev> matches +# <msg> or the content of <path>. test_commit_message () { - rev="$1" && # commit or tag we want to test - file="$2" && # test against the content of a file - git show --no-patch --pretty=format:%B "$rev" >actual-message && - if test "$2" = -m - then - str="$3" && # test against a string - printf "%s\n" "$str" >tmp-expected-message && - file="tmp-expected-message" - fi - test_cmp "$file" actual-message + git show --no-patch --pretty=format:%B "$1" >actual && + case "$2" in + -m) + echo "$3" >expect && + test_cmp expect actual ;; + *) + test_cmp "$2" actual ;; + esac } get_author () { rev="$1" && - git log -1 --pretty=format:"%an %ae" "$rev" + git log -1 --pretty=format:"%an %ae %at" "$rev" } test_expect_success 'setup' ' cat >message <<-EOF && - amend! B - ${EMPTY} - new subject - ${EMPTY} - new - body - EOF - - sed "1,2d" message >expected-message && + amend! B + $EMPTY + new subject + $EMPTY + new + body + EOF test_commit A A && test_commit B B && @@ -68,40 +70,43 @@ test_expect_success 'setup' ' echo B1 >B && test_tick && git commit --fixup=HEAD -a && + git tag B1 && test_tick && git commit --allow-empty -F - <<-EOF && - amend! B - ${EMPTY} - B - ${EMPTY} - edited 1 - EOF + amend! B + $EMPTY + B + $EMPTY + edited 1 + EOF test_tick && git commit --allow-empty -F - <<-EOF && - amend! amend! B - ${EMPTY} - B - ${EMPTY} - edited 1 - ${EMPTY} - edited 2 - EOF + amend! amend! B + $EMPTY + B + $EMPTY + edited 1 + $EMPTY + edited 2 + EOF echo B2 >B && test_tick && FAKE_COMMIT_AMEND="edited squash" git commit --squash=HEAD -a && + git tag B2 && echo B3 >B && test_tick && git commit -a -F - <<-EOF && - amend! amend! amend! B - ${EMPTY} - B - ${EMPTY} - edited 1 - ${EMPTY} - edited 2 - ${EMPTY} - edited 3 - EOF + amend! amend! amend! B + $EMPTY + B + $EMPTY + edited 1 + $EMPTY + edited 2 + $EMPTY + edited 3 + EOF + git tag B3 && GIT_AUTHOR_NAME="Rebase Author" && GIT_AUTHOR_EMAIL="rebase.author@example.com" && @@ -134,6 +139,7 @@ test_expect_success 'simple fixup -c works' ' test_expect_success 'fixup -C removes amend! from message' ' test_when_finished "test_might_fail git rebase --abort" && git checkout --detach A1 && + git log -1 --pretty=format:%b >expected-message && FAKE_LINES="1 fixup_-C 2" git rebase -i A && test_cmp_rev HEAD^ A && test_cmp_rev HEAD^{tree} A1^{tree} && @@ -145,13 +151,14 @@ test_expect_success 'fixup -C removes amend! from message' ' test_expect_success 'fixup -C with conflicts gives correct message' ' test_when_finished "test_might_fail git rebase --abort" && git checkout --detach A1 && + git log -1 --pretty=format:%b >expected-message && + test_write_lines "" "edited" >>expected-message && test_must_fail env FAKE_LINES="1 fixup_-C 2" git rebase -i conflicts && git checkout --theirs -- A && git add A && FAKE_COMMIT_AMEND=edited git rebase --continue && test_cmp_rev HEAD^ conflicts && test_cmp_rev HEAD^{tree} A1^{tree} && - test_write_lines "" edited >>expected-message && test_commit_message HEAD expected-message && get_author HEAD >actual-author && test_cmp expected-author actual-author @@ -167,12 +174,12 @@ test_expect_success 'skipping fixup -C after fixup gives correct message' ' ' test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' ' - git checkout --detach branch && + git checkout --detach B3 && FAKE_LINES="1 fixup 2 fixup_-C 3 fixup_-C 4 squash 5 fixup_-C 6" \ FAKE_COMMIT_AMEND=squashed \ FAKE_MESSAGE_COPY=actual-squash-message \ git -c commit.status=false rebase -ik --signoff A && - git diff-tree --exit-code --patch HEAD branch -- && + git diff-tree --exit-code --patch HEAD B3 -- && test_cmp_rev HEAD^ A && test_i18ncmp "$TEST_DIRECTORY/t3437/expected-squash-message" \ actual-squash-message @@ -180,7 +187,7 @@ test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' ' test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' ' test_when_finished "test_might_fail git rebase --abort" && - git checkout branch && git checkout --detach branch~2 && + git checkout --detach B2~ && git log -1 --pretty=format:%b >expected-message && FAKE_LINES="1 fixup 2 fixup_-C 3 fixup_-C 4" git rebase -i A && test_cmp_rev HEAD^ A && @@ -190,13 +197,16 @@ test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fix test_expect_success 'multiple fixup -c opens editor once' ' test_when_finished "test_might_fail git rebase --abort" && git checkout --detach A3 && - base=$(git rev-parse HEAD~4) && - FAKE_COMMIT_MESSAGE="Modified-A3" \ + git log -1 --pretty=format:%B >expected-message && + test_write_lines "" "Modified-A3" >>expected-message && + FAKE_COMMIT_AMEND="Modified-A3" \ FAKE_LINES="1 fixup_-C 2 fixup_-c 3 fixup_-c 4" \ EXPECT_HEADER_COUNT=4 \ - git rebase -i $base && - test_cmp_rev $base HEAD^ && - test 1 = $(git show | grep Modified-A3 | wc -l) + git rebase -i A && + test_cmp_rev HEAD^ A && + get_author HEAD >actual-author && + test_cmp expected-author actual-author && + test_commit_message HEAD expected-message ' test_expect_success 'sequence squash, fixup & fixup -c gives combined message' ' @@ -211,12 +221,12 @@ test_expect_success 'sequence squash, fixup & fixup -c gives combined message' ' ' test_expect_success 'fixup -C works upon --autosquash with amend!' ' - git checkout --detach branch && + git checkout --detach B3 && FAKE_COMMIT_AMEND=squashed \ FAKE_MESSAGE_COPY=actual-squash-message \ git -c commit.status=false rebase -ik --autosquash \ --signoff A && - git diff-tree --exit-code --patch HEAD branch -- && + git diff-tree --exit-code --patch HEAD B3 -- && test_cmp_rev HEAD^ A && test_i18ncmp "$TEST_DIRECTORY/t3437/expected-squash-message" \ actual-squash-message |