{"thread":{"id":"54958","subject":"[RFC PATCH 0/9][Outreachy] rebase -i: add options to fixup command","startedAt":"2021-01-08T09:25:39Z","lastAt":"2021-02-06T05:39:17Z","messageCount":110,"participants":["Charvi Mendiratta","Taylor Blau","Junio C Hamano","Christian Couder","Phillip Wood","Marc Branchaud","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"413798","messageId":"20210108092345.2178-1-charvi077@gmail.com","threadId":"54958","inReplyTo":null,"subject":"[RFC PATCH 0/9][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:37Z","receivedAt":"2021-01-08T09:25:39Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Everyone,\n\nThis patch series adds fixup [-C|-c] options to interactive rebase. In\naddition to amending the contents of the commit as the `fixup` command\ndoes now, `fixup -C` replaces the commit message of the original commit\nwhich we are fixing up with the message of the fixup commit.\nAnd to edit the fixup commit message before committing, `fixup -c`\ncommand is used instead of `fixup -C`. This convention is similar to\nthe existing `merge` command in the interactive rebase, that also supports\n`-c` and `-C` options with similar meanings.\n\nThis patch series also changes `rebase -i --autosquash` to rearrange\ncommits whose message starts with \"amend!\" and replaces the pick\ncommand with `fixup -C`. The creation of \"amend!\" commits will be\nrebase -i: add options to fixup command added in another patch series.\n\nThis is done in reference to the issue opened by Dscho as here[1] and\nfurther discussed briefly[2]. Also, there is discussion[3] regarding the\nimplementation of reword! commit. The past patches of Phillip Wood’s\nwork[4], implements 'reword!' as 'amend!' in git rebase and these patches\nuses those as the initial base.\nAnd to avoid the extra command in the interactive rebase, this patch\nseries instead add options to the current fixup command in interactive\nrebase (fixup [-C | -c]) as discussed earlier[5].\n\nLooking forward for the reviews.\n\nThanks and Regards,\nCharvi\n\nP.S - I thanks Christian and Phillip for mentoring in this project and\nhappy to work in community.\n\n[1] https://github.com/gitgitgadget/git/issues/259\n[2] https://public-inbox.org/git/alpine.DEB.2.21.1.1710151754070.40514@virtualbox/\n[3] https://lore.kernel.org/git/95cc6fb2-d1bc-11de-febe-c2b5c78a6850@gmail.com/\n[4] https://github.com/phillipwood/git/commits/wip/rebase-amend\n[5] https://lore.kernel.org/git/29fc2f59-1cca-a3db-5586-bbd7b2e4806d@gmail.com/\n\nCharvi Mendiratta (6):\n  sequencer: pass todo_item to do_pick_commit()\n  sequencer: use const variable for commit message comments\n  rebase -i: add fixup [-C | -c] command\n  t3437: test script for fixup [-C|-c] options in interactive rebase\n  rebase -i: teach --autosquash to work with amend!\n  doc/git-rebase: add documentation for fixup [-C|-c] options\n\nPhillip Wood (3):\n  rebase -i: only write fixup-message when it's needed\n  sequencer: factor out code to append squash message\n  rebase -i: comment out squash!/fixup! subjects from squash message\n\n Documentation/git-rebase.txt    |  12 +-\n rebase-interactive.c            |   4 +-\n sequencer.c                     | 307 +++++++++++++++++++++++++++-----\n t/lib-rebase.sh                 |   4 +\n t/t3415-rebase-autosquash.sh    |  27 ++-\n t/t3437-rebase-fixup-options.sh | 202 +++++++++++++++++++++\n t/t3437/expected-squash-message |  51 ++++++\n t/t3900-i18n-commit.sh          |   4 -\n 8 files changed, 549 insertions(+), 62 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-squash-message\n\n--\n2.29.0.rc1\n\n"},{"id":"413799","messageId":"20210108092345.2178-2-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:39Z","receivedAt":"2021-01-08T09:26:26Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThe file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\ncommands, there's no point in writing it for squash commands as it is\nimmediately deleted.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 12 +++++++-----\n 1 file changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8909a46770..f888a7ed3b 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1757,11 +1757,13 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (write_message(body, strlen(body),\n-\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n-\t\t\tunuse_commit_buffer(head_commit, head_message);\n-\t\t\treturn error(_(\"cannot write '%s'\"),\n-\t\t\t\t     rebase_path_fixup_msg());\n+\t\tif (command == TODO_FIXUP) {\n+\t\t\tif (write_message(body, strlen(body),\n+\t\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n+\t\t\t\tunuse_commit_buffer(head_commit, head_message);\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\t     rebase_path_fixup_msg());\n+\t\t\t}\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-- \n2.29.0.rc1\n\n"},{"id":"413800","messageId":"20210108092345.2178-3-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 2/9] sequencer: factor out code to append squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:40Z","receivedAt":"2021-01-08T09:26:26Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis code is going to grow over the next two commits so move it to\nits own function.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex f888a7ed3b..5062976d10 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,17 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static void append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t\t  struct replay_opts *opts)\n+{\n+\tunlink(rebase_path_fixup_msg());\n+\tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n+\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\t\t    ++opts->current_fixup_count + 1);\n+\tstrbuf_addstr(buf, \"\\n\\n\");\n+\tstrbuf_addstr(buf, body);\n+}\n+\n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n@@ -1782,12 +1793,7 @@ static int update_squash_messages(struct repository *r,\n \tfind_commit_subject(message, &body);\n \n \tif (command == TODO_SQUASH) {\n-\t\tunlink(rebase_path_fixup_msg());\n-\t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is the commit message #%d:\"),\n-\t\t\t    ++opts->current_fixup_count + 1);\n-\t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n-- \n2.29.0.rc1\n\n"},{"id":"413801","messageId":"20210108092345.2178-4-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:41Z","receivedAt":"2021-01-08T09:26:32Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen squashing commit messages the squash!/fixup! subjects are not of\ninterest so comment them out to stop them becoming part of the final\nmessage.\n\nThis change breaks a bunch of --autosquash tests which rely on the\n\"squash! <subject>\" line appearing in the final commit message. This is\naddressed by adding a second line to the commit message of the \"squash!\n...\" commits and testing for that.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                  | 25 ++++++++++++++++++++++++-\n t/t3415-rebase-autosquash.sh | 27 +++++++++++++--------------\n t/t3900-i18n-commit.sh       |  4 ----\n 3 files changed, 37 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 5062976d10..b050a9a212 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static size_t subject_length(const char *body)\n+{\n+\tsize_t i, len = 0;\n+\tchar c;\n+\tint blank_line = 1;\n+\tfor (i = 0, c = body[i]; c; c = body[++i]) {\n+\t\tif (c == '\\n') {\n+\t\t\tif (blank_line)\n+\t\t\t\treturn len;\n+\t\t\tlen = i + 1;\n+\t\t\tblank_line = 1;\n+\t\t} else if (!isspace(c)) {\n+\t\t\tblank_line = 0;\n+\t\t}\n+\t}\n+\treturn blank_line ? len : i;\n+}\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n+\tsize_t commented_len = 0;\n+\n \tunlink(rebase_path_fixup_msg());\n+\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+\t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_addstr(buf, body);\n+\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_addstr(buf, body + commented_len);\n }\n \n static int update_squash_messages(struct repository *r,\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 7bab6000dc..45fe6a227e 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -81,8 +81,7 @@ test_auto_squash () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n-\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n \tgit rebase $2 -i HEAD^^^ &&\n@@ -139,7 +138,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag final-multisquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -192,7 +191,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-shasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -203,7 +202,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\tgrep \"extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -213,7 +212,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short=11 HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-longshasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\tgrep \"extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -233,7 +232,7 @@ test_auto_commit_flags () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit --$1 first-commit &&\n+\tgit commit --$1 first-commit -m \"extra para for first\" &&\n \tgit tag final-commit-$1 &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -261,11 +260,11 @@ test_auto_fixup_fixup () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! first\" &&\n+\tgit commit -m \"$1! first\" -m \"extra para for first\" &&\n \techo 2 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! $2! first\" &&\n+\tgit commit -m \"$1! $2! first\" -m \"second extra para for first\" &&\n \tgit tag \"final-$1-$2\" &&\n \ttest_tick &&\n \t(\n@@ -326,12 +325,12 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para for first\" &&\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n \tsubject=$(git log -n 1 --format=%s HEAD~2) &&\n-\tgit commit -m \"squash! $subject\" &&\n+\tgit commit -m \"squash! $subject\" -m \"second extra para for first\" &&\n \tgit tag final-squash-instFmt &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -342,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n-\ttest_line_count = 2 actual\n+\tgrep first commit >actual &&\n+\ttest_line_count = 3 actual\n '\n \n test_expect_success 'autosquash with empty custom instructionFormat' '\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex d277a9f4b7..bfab245eb3 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -226,10 +226,6 @@ test_commit_autosquash_multi_encoding () {\n \t\tgit rev-list HEAD >actual &&\n \t\ttest_line_count = 3 actual &&\n \t\ticonv -f $old -t UTF-8 \"$TEST_DIRECTORY\"/t3900/$msg >expect &&\n-\t\tif test $flag = squash; then\n-\t\t\tsubject=\"$(head -1 expect)\" &&\n-\t\t\tprintf \"\\nsquash! %s\\n\" \"$subject\" >>expect\n-\t\tfi &&\n \t\tgit cat-file commit HEAD^ >raw &&\n \t\t(sed \"1,/^$/d\" raw | iconv -f $new -t utf-8) >actual &&\n \t\ttest_cmp expect actual\n-- \n2.29.0.rc1\n\n"},{"id":"413802","messageId":"20210108092345.2178-5-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 4/9] sequencer: pass todo_item to do_pick_commit()","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:42Z","receivedAt":"2021-01-08T09:26:39Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"As an additional member of the structure todo_item will be required in\nfuture commits pass the complete structure.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex b050a9a212..cdafc2e0e8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1884,8 +1884,7 @@ static void record_in_rewritten(struct object_id *oid,\n }\n \n static int do_pick_commit(struct repository *r,\n-\t\t\t  enum todo_command command,\n-\t\t\t  struct commit *commit,\n+\t\t\t  struct todo_item *item,\n \t\t\t  struct replay_opts *opts,\n \t\t\t  int final_fixup, int *check_todo)\n {\n@@ -1898,6 +1897,8 @@ static int do_pick_commit(struct repository *r,\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res, unborn = 0, reword = 0, allow, drop_commit;\n+\tenum todo_command command = item->command;\n+\tstruct commit *commit = item->commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -4147,8 +4148,8 @@ static int pick_commits(struct repository *r,\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, reflog_message(opts,\n \t\t\t\t\tcommand_to_string(item->command), NULL),\n \t\t\t\t\t1);\n-\t\t\tres = do_pick_commit(r, item->command, item->commit,\n-\t\t\t\t\t     opts, is_final_fixup(todo_list),\n+\t\t\tres = do_pick_commit(r, item, opts,\n+\t\t\t\t\t     is_final_fixup(todo_list),\n \t\t\t\t\t     &check_todo);\n \t\t\tif (is_rebase_i(opts))\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);\n@@ -4610,11 +4611,14 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n+\tstruct todo_item item;\n+\n+\titem.command = opts->action == REPLAY_PICK ?\n+\t\t\tTODO_PICK : TODO_REVERT;\n+\titem.commit = cmit;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(r, opts->action == REPLAY_PICK ?\n-\t\t\t      TODO_PICK : TODO_REVERT, cmit, opts, 0,\n-\t\t\t      &check_todo);\n+\treturn do_pick_commit(r, &item, opts, 0, &check_todo);\n }\n \n int sequencer_pick_revisions(struct repository *r,\n-- \n2.29.0.rc1\n\n"},{"id":"413803","messageId":"20210108092345.2178-6-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 5/9] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:43Z","receivedAt":"2021-01-08T09:27:09Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This makes it easier to use and reuse the comments.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 19 ++++++++++++++-----\n 1 file changed, 14 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex cdafc2e0e8..b9295b5a02 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1736,6 +1736,15 @@ static size_t subject_length(const char *body)\n \treturn blank_line ? len : i;\n }\n \n+static const char first_commit_msg_str[] =\n+N_(\"This is the 1st commit message:\");\n+static const char nth_commit_msg_fmt[] =\n+N_(\"This is the commit message #%d:\");\n+static const char skip_nth_commit_msg_fmt[] =\n+N_(\"The commit message #%d will be skipped:\");\n+static const char combined_commit_msg_str[] =\n+N_(\"This is a combination of %d commits.\");\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n@@ -1745,7 +1754,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n \t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n-\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n@@ -1774,7 +1783,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\tbuf.buf : strchrnul(buf.buf, '\\n');\n \n \t\tstrbuf_addf(&header, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&header, _(\"This is a combination of %d commits.\"),\n+\t\tstrbuf_addf(&header, _(combined_commit_msg_str),\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n@@ -1801,9 +1810,9 @@ static int update_squash_messages(struct repository *r,\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is a combination of %d commits.\"), 2);\n+\t\tstrbuf_addf(&buf, _(combined_commit_msg_str), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(\"This is the 1st commit message:\"));\n+\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_addstr(&buf, body);\n \n@@ -1819,7 +1828,7 @@ static int update_squash_messages(struct repository *r,\n \t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n+\t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n-- \n2.29.0.rc1\n\n"},{"id":"413804","messageId":"20210108092345.2178-7-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:44Z","receivedAt":"2021-01-08T09:27:09Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Add options to `fixup` command to fixup both the commit contents and\nmessage. `fixup -C` command is used to replace the original commit\nmessage and `fixup -c`, additionally allows to edit the commit message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n rebase-interactive.c |   4 +-\n sequencer.c          | 212 +++++++++++++++++++++++++++++++++++++++----\n 2 files changed, 196 insertions(+), 20 deletions(-)\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 762853bc7e..c3bd02adee 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n \"e, edit <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n-\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n+\"                   commit's log message. Use -C to replace with this\\n\"\n+\"                   commit message or -c to edit the commit message\\n\"\n \"x, exec <command> = run command (the rest of the line) using shell\\n\"\n \"b, break = stop here (continue rebase later with 'git rebase --continue')\\n\"\n \"d, drop <commit> = remove commit\\n\"\ndiff --git a/sequencer.c b/sequencer.c\nindex b9295b5a02..db016717d1 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+enum todo_item_flags {\n+\tTODO_EDIT_MERGE_MSG    = (1 << 0),\n+\tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n+\tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+};\n+\n static size_t subject_length(const char *body)\n {\n \tsize_t i, len = 0;\n@@ -1740,34 +1746,177 @@ static const char first_commit_msg_str[] =\n N_(\"This is the 1st commit message:\");\n static const char nth_commit_msg_fmt[] =\n N_(\"This is the commit message #%d:\");\n+static const char skip_first_commit_msg_str[] =\n+N_(\"The 1st commit message will be skipped:\");\n static const char skip_nth_commit_msg_fmt[] =\n N_(\"The commit message #%d will be skipped:\");\n static const char combined_commit_msg_str[] =\n N_(\"This is a combination of %d commits.\");\n \n-static void append_squash_message(struct strbuf *buf, const char *body,\n-\t\t\t\t  struct replay_opts *opts)\n+static int check_fixup_flag(enum todo_command command,\n+\t\t\t    enum todo_item_flags flag)\n+{\n+\treturn command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n+\t\t\t\t\t (flag & TODO_EDIT_FIXUP_MSG));\n+}\n+\n+/*\n+ * Wrapper around strbuf_add_commented_lines() which avoids double\n+ * commenting commit subjects.\n+ */\n+static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n+{\n+\tconst char *s = str;\n+\twhile (len > 0 && s[0] == comment_line_char) {\n+\t\tsize_t count;\n+\t\tconst char *n = memchr(s, '\\n', len);\n+\t\tif (!n)\n+\t\t\tcount = len;\n+\t\telse\n+\t\t\tcount = n - s + 1;\n+\t\tstrbuf_add(buf, s, count);\n+\t\ts += count;\n+\t\tlen -= count;\n+\t}\n+\tstrbuf_add_commented_lines(buf, s, len);\n+}\n+\n+/* Does the current fixup chain contain a squash command? */\n+static int seen_squash(struct replay_opts *opts)\n {\n-\tsize_t commented_len = 0;\n+\treturn starts_with(opts->current_fixups.buf, \"squash\") ||\n+\t\tstrstr(opts->current_fixups.buf, \"\\nsquash\");\n+}\n \n-\tunlink(rebase_path_fixup_msg());\n-\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n+{\n+\tstrbuf_setlen(buf1, 2);\n+\tstrbuf_addf(buf1, nth_commit_msg_fmt, n);\n+\tstrbuf_addch(buf1, '\\n');\n+\tstrbuf_setlen(buf2, 2);\n+\tstrbuf_addf(buf2, skip_nth_commit_msg_fmt, n);\n+\tstrbuf_addch(buf2, '\\n');\n+}\n+\n+/*\n+ * Comment out any un-commented commit messages, updating the message comments\n+ * to say they will be skipped but do not comment out the empty lines that\n+ * surround commit messages and their comments.\n+ */\n+static void update_squash_message_for_fixup(struct strbuf *msg)\n+{\n+\tvoid (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;\n+\tstruct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tconst char *s, *start;\n+\tchar *orig_msg;\n+\tsize_t orig_msg_len;\n+\tint i = 1;\n+\n+\tstrbuf_addf(&buf1, \"# %s\\n\", first_commit_msg_str);\n+\tstrbuf_addf(&buf2, \"# %s\\n\", skip_first_commit_msg_str);\n+\ts = start = orig_msg = strbuf_detach(msg, &orig_msg_len);\n+\twhile (s) {\n+\t\tconst char *next;\n+\t\tsize_t off;\n+\t\tif (skip_prefix(s, buf1.buf, &next)) {\n+\t\t\t/*\n+\t\t\t * Copy the last message, preserving the blank line\n+\t\t\t * preceding the current line\n+\t\t\t */\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tif (off)\n+\t\t\t\tstrbuf_addch(msg, '\\n');\n+\t\t\t/*\n+\t\t\t * The next message needs to be commented out but the\n+\t\t\t * message header is already commented out so just copy\n+\t\t\t * it and the blank line that follows it.\n+\t\t\t */\n+\t\t\tstrbuf_addbuf(msg, &buf2);\n+\t\t\tif (*next == '\\n')\n+\t\t\t\tstrbuf_addch(msg, *next++);\n+\t\t\tstart = s = next;\n+\t\t\tcopy_lines = add_commented_lines;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else if (skip_prefix(s, buf2.buf, &next)) {\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tstart = s - off;\n+\t\t\ts = next;\n+\t\t\tcopy_lines = strbuf_add;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else {\n+\t\t\ts = strchr(s, '\\n');\n+\t\t\tif (s)\n+\t\t\t\ts++;\n+\t\t}\n+\t}\n+\tcopy_lines(msg, start, orig_msg_len - (start - orig_msg));\n+\tfree(orig_msg);\n+\tstrbuf_release(&buf1);\n+\tstrbuf_release(&buf2);\n+}\n+\n+static int append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t enum todo_command command, struct replay_opts *opts,\n+\t\t\t enum todo_item_flags flag)\n+{\n+\tconst char *fixup_msg;\n+\tsize_t commented_len = 0, fixup_off;\n+\t/*\n+\t * amend is non-interactive and not normally used with fixup!\n+\t * or squash! commits, so only comment out those subjects when\n+\t * squashing commit messages.\n+\t */\n+\tif (starts_with(body, \"amend!\") ||\n+\t    ((command == TODO_SQUASH || seen_squash(opts)) &&\n+\t     (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n \t\tcommented_len = subject_length(body);\n+\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n+\t/* buf->buf may be reallocated so store an offset into the buffer */\n+\tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n+\n+\t/* fixup -C after squash behaves like squash */\n+\tif (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n+\t\t/*\n+\t\t * We're replacing the commit message so we need to\n+\t\t * append the Signed-off-by: trailer if the user\n+\t\t * requested '--signoff'.\n+\t\t */\n+\t\tif (opts->signoff)\n+\t\t\tappend_signoff(buf, 0, 0);\n+\n+\t\tif ((command == TODO_FIXUP) &&\n+\t\t    (flag & TODO_REPLACE_FIXUP_MSG)) {\n+\t\t\tfixup_msg = skip_blank_lines(buf->buf + fixup_off);\n+\t\t\tif (write_message(fixup_msg, strlen(fixup_msg),\n+\t\t\t\t\trebase_path_fixup_msg(), 0))\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\trebase_path_fixup_msg());\n+\t\t} else {\n+\t\t\tunlink(rebase_path_fixup_msg());\n+\t\t}\n+\t} else  {\n+\t\tunlink(rebase_path_fixup_msg());\n+\t}\n+\n+\treturn 0;\n }\n \n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n-\t\t\t\t  struct replay_opts *opts)\n+\t\t\t\t  struct replay_opts *opts,\n+\t\t\t\t  enum todo_item_flags flag)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tint res;\n+\tint res = 0;\n \tconst char *message, *body;\n \tconst char *encoding = get_commit_output_encoding();\n \n@@ -1787,6 +1936,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n+\t\tif (check_fixup_flag(command, flag) && !seen_squash(opts))\n+\t\t\tupdate_squash_message_for_fixup(&buf);\n \t} else {\n \t\tstruct object_id head;\n \t\tstruct commit *head_commit;\n@@ -1800,7 +1951,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (command == TODO_FIXUP) {\n+\t\tif (command == TODO_FIXUP && !flag) {\n \t\t\tif (write_message(body, strlen(body),\n \t\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n \t\t\t\tunuse_commit_buffer(head_commit, head_message);\n@@ -1808,13 +1959,17 @@ static int update_squash_messages(struct repository *r,\n \t\t\t\t\t     rebase_path_fixup_msg());\n \t\t\t}\n \t\t}\n-\n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(combined_commit_msg_str), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n+\t\tstrbuf_addstr(&buf, check_fixup_flag(command, flag) ?\n+\t\t\t      _(skip_first_commit_msg_str) :\n+\t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tif (check_fixup_flag(command, flag))\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, body);\n \n \t\tunuse_commit_buffer(head_commit, head_message);\n \t}\n@@ -1824,8 +1979,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tfind_commit_subject(message, &body);\n \n-\tif (command == TODO_SQUASH) {\n-\t\tappend_squash_message(&buf, body, opts);\n+\tif (command == TODO_SQUASH || check_fixup_flag(command, flag)) {\n+\t\tres = append_squash_message(&buf, body, command, opts, flag);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n@@ -1836,7 +1991,9 @@ static int update_squash_messages(struct repository *r,\n \t\treturn error(_(\"unknown command: %d\"), command);\n \tunuse_commit_buffer(commit, message);\n \n-\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);\n+\tif (!res)\n+\t\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(),\n+\t\t\t\t    0);\n \tstrbuf_release(&buf);\n \n \tif (!res) {\n@@ -2037,7 +2194,8 @@ static int do_pick_commit(struct repository *r,\n \tif (command == TODO_REWORD)\n \t\treword = 1;\n \telse if (is_fixup(command)) {\n-\t\tif (update_squash_messages(r, command, commit, opts))\n+\t\tif (update_squash_messages(r, command, commit,\n+\t\t\t\t\t   opts, item->flags))\n \t\t\treturn -1;\n \t\tflags |= AMEND_MSG;\n \t\tif (!final_fixup)\n@@ -2202,10 +2360,6 @@ static int read_and_refresh_cache(struct repository *r,\n \treturn 0;\n }\n \n-enum todo_item_flags {\n-\tTODO_EDIT_MERGE_MSG = 1\n-};\n-\n void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n@@ -2292,6 +2446,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n \t\treturn 0;\n \t}\n \n+\tif (item->command == TODO_FIXUP) {\n+\t\tif (skip_prefix(bol, \"-C\", &bol) &&\n+\t\t   (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_REPLACE_FIXUP_MSG;\n+\t\t} else if (skip_prefix(bol, \"-c\", &bol) &&\n+\t\t\t\t  (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_EDIT_FIXUP_MSG;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_MERGE) {\n \t\tif (skip_prefix(bol, \"-C\", &bol))\n \t\t\tbol += strspn(bol, \" \\t\");\n@@ -5298,6 +5464,14 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis\n \t\t\t\t\t  short_commit_name(item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n \n+\t\t\tif (item->command == TODO_FIXUP) {\n+\t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n+\t\t\t\telse if (item->flags & TODO_REPLACE_FIXUP_MSG) {\n+\t\t\t\t\tstrbuf_addstr(buf, \" -C\");\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_MERGE) {\n \t\t\t\tif (item->flags & TODO_EDIT_MERGE_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n-- \n2.29.0.rc1\n\n"},{"id":"413805","messageId":"20210108092345.2178-9-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:46Z","receivedAt":"2021-01-08T09:27:09Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"If the commit subject starts with \"amend!\" then rearrange it like a\n\"fixup!\" commit and replace `pick` command with `fixup -C` command,\nwhich is used to fixup up the content if any and replaces the original\ncommit message with amend! commit's message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                     | 23 ++++++++++++++++-------\n t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n 2 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex db016717d1..4b2e71cbda 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5672,6 +5672,12 @@ static int subject2item_cmp(const void *fndata,\n \n define_commit_slab(commit_todo_item, struct todo_item *);\n \n+static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n+\treturn skip_prefix(subject, \"fixup! \", p) ||\n+\t       skip_prefix(subject, \"amend! \", p) ||\n+\t       skip_prefix(subject, \"squash! \", p);\n+}\n+\n /*\n  * Rearrange the todo list that has both \"pick commit-id msg\" and \"pick\n  * commit-id fixup!/squash! msg\" in it so that the latter is put immediately\n@@ -5730,15 +5736,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\tformat_subject(&buf, subject, \" \");\n \t\tsubject = subjects[i] = strbuf_detach(&buf, &subject_len);\n \t\tunuse_commit_buffer(item->commit, commit_buffer);\n-\t\tif ((skip_prefix(subject, \"fixup! \", &p) ||\n-\t\t     skip_prefix(subject, \"squash! \", &p))) {\n+\t\tif (skip_fixup_amend_squash(subject, &p)) {\n \t\t\tstruct commit *commit2;\n \n \t\t\tfor (;;) {\n \t\t\t\twhile (isspace(*p))\n \t\t\t\t\tp++;\n-\t\t\t\tif (!skip_prefix(p, \"fixup! \", &p) &&\n-\t\t\t\t    !skip_prefix(p, \"squash! \", &p))\n+\t\t\t\tif (!skip_fixup_amend_squash(p, &p))\n \t\t\t\t\tbreak;\n \t\t\t}\n \n@@ -5768,9 +5772,14 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t}\n \t\tif (i2 >= 0) {\n \t\t\trearranged = 1;\n-\t\t\ttodo_list->items[i].command =\n-\t\t\t\tstarts_with(subject, \"fixup!\") ?\n-\t\t\t\tTODO_FIXUP : TODO_SQUASH;\n+\t\t\tif (starts_with(subject, \"fixup!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t} else if (starts_with(subject, \"amend!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t\ttodo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;\n+\t\t\t} else {\n+\t\t\t\ttodo_list->items[i].command = TODO_SQUASH;\n+\t\t\t}\n \t\t\tif (tail[i2] < 0) {\n \t\t\t\tnext[i] = next[i2];\n \t\t\t\tnext[i2] = i;\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nindex 9e62d74249..532dc1c11b 100755\n--- a/t/t3437-rebase-fixup-options.sh\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -187,4 +187,16 @@ test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fix\n \ttest_commit_message HEAD expected-message\n '\n \n+test_expect_success 'fixup -C works upon --autosquash with amend!' '\n+\tgit checkout --detach branch &&\n+\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --autosquash \\\n+\t\t\t\t\t\t--signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n test_done\n-- \n2.29.0.rc1\n\n"},{"id":"413807","messageId":"20210108092345.2178-8-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:45Z","receivedAt":"2021-01-08T09:27:09Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n t/lib-rebase.sh                 |   4 +\n t/t3437-rebase-fixup-options.sh | 190 ++++++++++++++++++++++++++++++++\n t/t3437/expected-squash-message |  51 +++++++++\n 3 files changed, 245 insertions(+)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-squash-message\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex b72c051f47..e10e38060b 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -4,6 +4,7 @@\n #\n # - override the commit message with $FAKE_COMMIT_MESSAGE\n # - amend the commit message with $FAKE_COMMIT_AMEND\n+# - copy the original commit message to a file with $FAKE_MESSAGE_COPY\n # - check that non-commit messages have a certain line count with $EXPECT_COUNT\n # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT\n # - rewrite a rebase -i script as directed by $FAKE_LINES.\n@@ -33,6 +34,7 @@ set_fake_editor () {\n \t\t\texit\n \t\ttest -z \"$FAKE_COMMIT_MESSAGE\" || echo \"$FAKE_COMMIT_MESSAGE\" > \"$1\"\n \t\ttest -z \"$FAKE_COMMIT_AMEND\" || echo \"$FAKE_COMMIT_AMEND\" >> \"$1\"\n+\t\ttest -z \"$FAKE_MESSAGE_COPY\" || cat \"$1\" >\"$FAKE_MESSAGE_COPY\"\n \t\texit\n \t\t;;\n \tesac\n@@ -51,6 +53,8 @@ set_fake_editor () {\n \t\t\taction=\"$line\";;\n \t\texec_*|x_*|break|b)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n+\t\tmerge_*|fixup_*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\t\"#\")\n \t\t\techo '# comment' >> \"$1\";;\n \t\t\">\")\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nnew file mode 100755\nindex 0000000000..9e62d74249\n--- /dev/null\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -0,0 +1,190 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2018 Phillip Wood\n+#\n+\n+test_description='git rebase interactive fixup options\n+\n+This test checks the \"fixup [-C|-c]\" command of rebase interactive.\n+In addition to amending the contents of the commit, \"fixup -C\"\n+replaces the original commit message with the message of the fixup\n+commit. \"fixup -c\" also replaces the original message, but opens the\n+editor to allow the user to edit the message before committing.\n+'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+EMPTY=\"\"\n+\n+test_commit_message () {\n+\trev=\"$1\" && # commit or tag we want to test\n+\tfile=\"$2\" && # test against the content of a file\n+\tgit show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n+\tif test \"$2\" = -m\n+\tthen\n+\t\tstr=\"$3\" && # test against a string\n+\t\tprintf \"%s\\n\" \"$str\" >tmp-expected-message &&\n+\t\tfile=\"tmp-expected-message\"\n+\tfi\n+\ttest_cmp \"$file\" actual-message\n+}\n+\n+get_author () {\n+\trev=\"$1\" &&\n+\tgit log -1 --pretty=format:\"%an %ae\" \"$rev\"\n+}\n+\n+test_expect_success 'setup' '\n+\tcat >message <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tnew subject\n+\t\t${EMPTY}\n+\t\tnew\n+\t\tbody\n+\t\tEOF\n+\n+\tsed \"1,2d\" message >expected-message &&\n+\n+\ttest_commit A A &&\n+\ttest_commit B B &&\n+\tget_author HEAD >expected-author &&\n+\tORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n+\tORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n+\tGIT_AUTHOR_NAME=\"Amend Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n+\ttest_commit \"$(cat message)\" A A1 A1 &&\n+\ttest_commit A2 A &&\n+\ttest_commit A3 A &&\n+\tGIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n+\tGIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n+\tgit checkout -b conflicts-branch A &&\n+\ttest_commit conflicts A &&\n+\n+\tset_fake_editor &&\n+\tgit checkout -b branch B &&\n+\techo B1 >B &&\n+\ttest_tick &&\n+\tgit commit --fixup=HEAD -a &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\tEOF\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\tEOF\n+\techo B2 >B &&\n+\ttest_tick &&\n+\tFAKE_COMMIT_AMEND=\"edited squash\" git commit --squash=HEAD -a &&\n+\techo B3 >B &&\n+\ttest_tick &&\n+\tgit commit -a -F - <<-EOF &&\n+\t\tamend! amend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\t${EMPTY}\n+\t\tedited 3\n+\t\tEOF\n+\n+\tGIT_AUTHOR_NAME=\"Rebase Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"rebase.author@example.com\" &&\n+\tGIT_COMMITTER_NAME=\"Rebase Committer\" &&\n+\tGIT_COMMITTER_EMAIL=\"rebase.committer@example.com\"\n+'\n+\n+test_expect_success 'simple fixup -C works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD -m \"A2\"\n+'\n+\n+test_expect_success 'simple fixup -c works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tgit log -1 --pretty=format:%B >expected-fixup-message &&\n+\ttest_write_lines \"\" \"Modified A2\" >>expected-fixup-message &&\n+\tFAKE_LINES=\"1 fixup_-c 2\" \\\n+\t\tFAKE_COMMIT_AMEND=\"Modified A2\" \\\n+\t\tgit rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD expected-fixup-message\n+'\n+\n+test_expect_success 'fixup -C removes amend! from message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'fixup -C with conflicts gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n+\tgit checkout --theirs -- A &&\n+\tgit add A &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_cmp_rev HEAD^ conflicts &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_write_lines \"\" edited >>expected-message &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'skipping fixup -C after fixup gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup 2 fixup_-C 4\" git rebase -i A &&\n+\tgit reset --hard &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_commit_message HEAD -m \"B\"\n+'\n+\n+test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' '\n+\tgit checkout --detach branch &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4 squash 5 fixup_-C 6\" \\\n+\t\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n+test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout branch && git checkout --detach branch~2 &&\n+\tgit log -1 --pretty=format:%b >expected-message &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_done\ndiff --git a/t/t3437/expected-squash-message b/t/t3437/expected-squash-message\nnew file mode 100644\nindex 0000000000..ab2434f90e\n--- /dev/null\n+++ b/t/t3437/expected-squash-message\n@@ -0,0 +1,51 @@\n+# This is a combination of 6 commits.\n+# The 1st commit message will be skipped:\n+\n+# B\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# The commit message #2 will be skipped:\n+\n+# fixup! B\n+\n+# The commit message #3 will be skipped:\n+\n+# amend! B\n+#\n+# B\n+#\n+# edited 1\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #4:\n+\n+# amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #5:\n+\n+# squash! amend! amend! B\n+\n+edited squash\n+\n+# This is the commit message #6:\n+\n+# amend! amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+edited 3\n+squashed\n-- \n2.29.0.rc1\n\n"},{"id":"413806","messageId":"20210108092345.2178-10-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[RFC PATCH 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-08T09:23:47Z","receivedAt":"2021-01-08T09:27:10Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n Documentation/git-rebase.txt | 12 +++++++++---\n 1 file changed, 9 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a0487b5cc5..776507e0cc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -887,9 +887,15 @@ If you want to fold two or more commits into one, replace the command\n \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n If the commits had different authors, the folded commit will be\n attributed to the author of the first commit.  The suggested commit\n-message for the folded commit is the concatenation of the commit\n-messages of the first commit and of those with the \"squash\" command,\n-but omits the commit messages of commits with the \"fixup\" command.\n+message for the folded commit is created as follows:\n+\n+ - It is made using the commit message of a commit with the \"fixup -C\"\n+   or \"fixup -c\" command. In the later case an editor is opened to edit\n+   the commit message.\n+ - Otherwise it's the concatenation of the commit messages of the first\n+   commit and of those with the \"squash\" command.\n+ - It omits the commit messages of commits with the \"fixup\"\n+   (without -C or -c) command.\n \n 'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n when a command fails due to merge errors. When you are done editing\n-- \n2.29.0.rc1\n\n"},{"id":"414278","messageId":"X/8/WassxF7ujqjX@nand.local","threadId":"54958","inReplyTo":"20210108092345.2178-2-charvi077@gmail.com","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-01-13T18:43:37Z","receivedAt":"2021-01-13T18:44:39Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Jan 08, 2021 at 02:53:39PM +0530, Charvi Mendiratta wrote:\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> The file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\n> commands, there's no point in writing it for squash commands as it is\n> immediately deleted.\n>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n>  sequencer.c | 12 +++++++-----\n>  1 file changed, 7 insertions(+), 5 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 8909a46770..f888a7ed3b 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -1757,11 +1757,13 @@ static int update_squash_messages(struct repository *r,\n>  \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n>\n>  \t\tfind_commit_subject(head_message, &body);\n> -\t\tif (write_message(body, strlen(body),\n> -\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n> -\t\t\tunuse_commit_buffer(head_commit, head_message);\n> -\t\t\treturn error(_(\"cannot write '%s'\"),\n> -\t\t\t\t     rebase_path_fixup_msg());\n> +\t\tif (command == TODO_FIXUP) {\n> +\t\t\tif (write_message(body, strlen(body),\n> +\t\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n> +\t\t\t\tunuse_commit_buffer(head_commit, head_message);\n> +\t\t\t\treturn error(_(\"cannot write '%s'\"),\n> +\t\t\t\t\t     rebase_path_fixup_msg());\n> +\t\t\t}\n\nI'm nit-picking here, but would this be clearer instead as:\n\n    if (command == TODO_FIXUP && write_message(...) < 0) {\n      unuse_commit_buffer(...);\n      // ...\n    }\n\nThere are two changes there. One is two squash the two if-statements\ntogether, and the latter is to add a check that 'write_message()'\nreturns an error. This explicit '< 0' checking was discussed recently in\nanother thread[1], and I think makes the conditional here read more\nclearly.\n\nThanks,\nTaylor\n\n[1]: https://lore.kernel.org/git/xmqqlfcz8ggj.fsf@gitster.c.googlers.com/\n"},{"id":"414280","messageId":"X/9DdGnYo7RQz5CE@nand.local","threadId":"54958","inReplyTo":"20210108092345.2178-4-charvi077@gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-01-13T19:01:08Z","receivedAt":"2021-01-13T19:01:59Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> When squashing commit messages the squash!/fixup! subjects are not of\n> interest so comment them out to stop them becoming part of the final\n> message.\n>\n> This change breaks a bunch of --autosquash tests which rely on the\n> \"squash! <subject>\" line appearing in the final commit message. This is\n> addressed by adding a second line to the commit message of the \"squash!\n> ...\" commits and testing for that.\n>\n> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n>  sequencer.c                  | 25 ++++++++++++++++++++++++-\n>  t/t3415-rebase-autosquash.sh | 27 +++++++++++++--------------\n>  t/t3900-i18n-commit.sh       |  4 ----\n>  3 files changed, 37 insertions(+), 19 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index 5062976d10..b050a9a212 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n>  \t}\n>  }\n>\n> +static size_t subject_length(const char *body)\n> +{\n> +\tsize_t i, len = 0;\n> +\tchar c;\n> +\tint blank_line = 1;\n> +\tfor (i = 0, c = body[i]; c; c = body[++i]) {\n> +\t\tif (c == '\\n') {\n> +\t\t\tif (blank_line)\n> +\t\t\t\treturn len;\n> +\t\t\tlen = i + 1;\n> +\t\t\tblank_line = 1;\n> +\t\t} else if (!isspace(c)) {\n> +\t\t\tblank_line = 0;\n> +\t\t}\n> +\t}\n> +\treturn blank_line ? len : i;\n> +}\n> +\n\nOK, so this gets the length of the subject in \"body\", which is defined\nas the run of characters before a newline and then a space character. So\n\"foo bar\\n\\nbaz\" would return 7, but \"foo bar\\nbaz\" would return 11.\n\nMakes sense. (Apologies for stating the obvious here, I just had to read\nthis function to myself a couple of times to make sure that I understood\nwhat it was doing.)\n\n>  static void append_squash_message(struct strbuf *buf, const char *body,\n>  \t\t\t\t  struct replay_opts *opts)\n>  {\n> +\tsize_t commented_len = 0;\n> +\n>  \tunlink(rebase_path_fixup_msg());\n> +\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> +\t\tcommented_len = subject_length(body);\n>  \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n>  \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n>  \t\t    ++opts->current_fixup_count + 1);\n>  \tstrbuf_addstr(buf, \"\\n\\n\");\n> -\tstrbuf_addstr(buf, body);\n> +\tstrbuf_add_commented_lines(buf, body, commented_len);\n> +\tstrbuf_addstr(buf, body + commented_len);\n\nVery nice; the subject gets commented when it starts with \"squash!\" or\n\"fixup!\", but the body remains uncommented. Makes sense to me.\n\n> @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n>  \tgit cat-file blob HEAD^:file1 >actual &&\n>  \ttest_cmp expect actual &&\n>  \tgit cat-file commit HEAD^ >commit &&\n> -\tgrep squash commit >actual &&\n> +\tgrep \"extra para\" commit >actual &&\n>  \ttest_line_count = 1 actual\n>  '\n\nWorth checking that \"squash\" doesn't appear in an uncommented part of\nactual? Or better yet, checking that \"# squash ...\" _does_ appear.\n\nI.e., that we would leave this as:\n\n    -\tgrep squash commit >actual &&\n    +\tgrep \"^# squash\" commit >actual &&\n    +\tgrep \"extra para\" commit >actual &&\n\n> @@ -342,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n>  \tgit cat-file blob HEAD^:file1 >actual &&\n>  \ttest_cmp expect actual &&\n>  \tgit cat-file commit HEAD^ >commit &&\n> -\tgrep squash commit >actual &&\n> -\ttest_line_count = 2 actual\n> +\tgrep first commit >actual &&\n> +\ttest_line_count = 3 actual\n>  '\n\nDitto.\n\nThanks,\nTaylor\n"},{"id":"414281","messageId":"X/9GrVjBmnJUZcGn@nand.local","threadId":"54958","inReplyTo":"20210108092345.2178-6-charvi077@gmail.com","subject":"Re: [RFC PATCH 5/9] sequencer: use const variable for commit message comments","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-01-13T19:14:53Z","receivedAt":"2021-01-13T19:15:45Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Fri, Jan 08, 2021 at 02:53:43PM +0530, Charvi Mendiratta wrote:\n> This makes it easier to use and reuse the comments.\n>\n> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> Mentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n>  sequencer.c | 19 ++++++++++++++-----\n>  1 file changed, 14 insertions(+), 5 deletions(-)\n>\n> diff --git a/sequencer.c b/sequencer.c\n> index cdafc2e0e8..b9295b5a02 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -1736,6 +1736,15 @@ static size_t subject_length(const char *body)\n>  \treturn blank_line ? len : i;\n>  }\n>\n> +static const char first_commit_msg_str[] =\n> +N_(\"This is the 1st commit message:\");\n> +static const char nth_commit_msg_fmt[] =\n> +N_(\"This is the commit message #%d:\");\n> +static const char skip_nth_commit_msg_fmt[] =\n> +N_(\"The commit message #%d will be skipped:\");\n> +static const char combined_commit_msg_str[] =\n> +N_(\"This is a combination of %d commits.\");\n> +\n\nTwo nit-picks here. The line break after the '=' is a little awkward,\nsince two of these lines are less than 80 characters combined, and the\nother two are just slightly longer than 80 characters. The other nitpick\nis that its typical to see 'char *foo' instead of 'char foo[]'.\n\nSo, I'd write these as:\n\n    static const char *first_commit_msg_str = N_(\"This is the 1st commit message:\");\n    static const char *nth_commit_msg_fmt = N_(\"This is the commit message #%d:\");\n    static const char *skip_nth_commit_msg_fmt = N_(\"The commit message #%d will be skipped:\");\n    static const char *combined_commit_msg_str = N_(\"This is a combination of %d commits.\");\n\nI also noticed that you suffix these with _fmt or _str depending on\nwhether or not there are arguments that get filled in later on. That\nmakes 'combined_commit_msg_str' labeled incorrectly (it should be\n'combined_commit_msg_fmt').\n\nI'm curious to see where down the road these messages will be used over\nagain, but I'm sure that that is coming in subsequent patch(es).\n\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n>  static void append_squash_message(struct strbuf *buf, const char *body,\n>  \t\t\t\t  struct replay_opts *opts)\n>  {\n> @@ -1745,7 +1754,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n>  \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n>  \t\tcommented_len = subject_length(body);\n>  \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n> -\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n> +\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n>  \t\t    ++opts->current_fixup_count + 1);\n\nThis and the three below uses are good, since they still translate\nthese messages. Nice.\n\nThanks,\nTaylor\n"},{"id":"414290","messageId":"xmqqv9c0wp2i.fsf@gitster.c.googlers.com","threadId":"54958","inReplyTo":"X/9GrVjBmnJUZcGn@nand.local","subject":"Re: [RFC PATCH 5/9] sequencer: use const variable for commit message comments","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-01-13T20:37:41Z","receivedAt":"2021-01-13T20:38:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Taylor Blau <me@ttaylorr.com> writes:\n\n> Two nit-picks here. The line break after the '=' is a little awkward,\n> since two of these lines are less than 80 characters combined, and the\n> other two are just slightly longer than 80 characters. The other nitpick\n> is that its typical to see 'char *foo' instead of 'char foo[]'.\n>\n> So, I'd write these as:\n>\n>     static const char *first_commit_msg_str = N_(\"This is the 1st commit message:\");\n>     static const char *nth_commit_msg_fmt = N_(\"This is the commit message #%d:\");\n>     static const char *skip_nth_commit_msg_fmt = N_(\"The commit message #%d will be skipped:\");\n>     static const char *combined_commit_msg_str = N_(\"This is a combination of %d commits.\");\n\nI actually am OK with []; it saves sizeof(char*) bytes from each of\nthe variable, doesn't it?\n\n> I also noticed that you suffix these with _fmt or _str depending on\n> whether or not there are arguments that get filled in later on. That\n> makes 'combined_commit_msg_str' labeled incorrectly (it should be\n> 'combined_commit_msg_fmt').\n\nGood eyes.\n\nThanks.\n"},{"id":"414335","messageId":"CAP8UFD3yhh+UO+pQ9Zr5Rwxy8ma1HENq5dNuani3qyJBYiBKkg@mail.gmail.com","threadId":"54958","inReplyTo":"xmqqv9c0wp2i.fsf@gitster.c.googlers.com","subject":"Re: [RFC PATCH 5/9] sequencer: use const variable for commit message comments","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-01-14T07:40:25Z","receivedAt":"2021-01-14T07:41:25Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Wed, Jan 13, 2021 at 9:37 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Taylor Blau <me@ttaylorr.com> writes:\n\n[...]\n\n> > The other nitpick\n> > is that its typical to see 'char *foo' instead of 'char foo[]'.\n> >\n> > So, I'd write these as:\n> >\n> >     static const char *first_commit_msg_str = N_(\"This is the 1st commit message:\");\n> >     static const char *nth_commit_msg_fmt = N_(\"This is the commit message #%d:\");\n> >     static const char *skip_nth_commit_msg_fmt = N_(\"The commit message #%d will be skipped:\");\n> >     static const char *combined_commit_msg_str = N_(\"This is a combination of %d commits.\");\n>\n> I actually am OK with []; it saves sizeof(char*) bytes from each of\n> the variable, doesn't it?\n\nYeah, that's my understanding too.\n"},{"id":"414339","messageId":"CAPSFM5ew583ZPZO9XUWxskQPsdSv520gKCM30GH2huhdTDxb2A@mail.gmail.com","threadId":"54958","inReplyTo":"X/8/WassxF7ujqjX@nand.local","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-14T08:12:06Z","receivedAt":"2021-01-14T08:13:15Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Thu, 14 Jan 2021 at 00:13, Taylor Blau <me@ttaylorr.com> wrote:\n>\n> On Fri, Jan 08, 2021 at 02:53:39PM +0530, Charvi Mendiratta wrote:\n> > From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >\n> > The file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\n> > commands, there's no point in writing it for squash commands as it is\n> > immediately deleted.\n> >\n> > Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> >  sequencer.c | 12 +++++++-----\n> >  1 file changed, 7 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 8909a46770..f888a7ed3b 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -1757,11 +1757,13 @@ static int update_squash_messages(struct repository *r,\n> >                       return error(_(\"could not read HEAD's commit message\"));\n> >\n> >               find_commit_subject(head_message, &body);\n> > -             if (write_message(body, strlen(body),\n> > -                               rebase_path_fixup_msg(), 0)) {\n> > -                     unuse_commit_buffer(head_commit, head_message);\n> > -                     return error(_(\"cannot write '%s'\"),\n> > -                                  rebase_path_fixup_msg());\n> > +             if (command == TODO_FIXUP) {\n> > +                     if (write_message(body, strlen(body),\n> > +                                       rebase_path_fixup_msg(), 0)) {\n> > +                             unuse_commit_buffer(head_commit, head_message);\n> > +                             return error(_(\"cannot write '%s'\"),\n> > +                                          rebase_path_fixup_msg());\n> > +                     }\n>\n> I'm nit-picking here, but would this be clearer instead as:\n>\n>     if (command == TODO_FIXUP && write_message(...) < 0) {\n>       unuse_commit_buffer(...);\n>       // ...\n>     }\n>\n> There are two changes there. One is two squash the two if-statements\n> together, and the latter is to add a check that 'write_message()'\n> returns an error. This explicit '< 0' checking was discussed recently in\n> another thread[1], and I think makes the conditional here read more\n> clearly.\n>\n\nOkay, I got this and will change it.\n\nThanks and Regards,\nCharvi\n\n> Thanks,\n> Taylor\n>\n> [1]: https://lore.kernel.org/git/xmqqlfcz8ggj.fsf@gitster.c.googlers.com/\n"},{"id":"414341","messageId":"CAPSFM5fuT0QAK9wJ_HuH3t=qThPx7Opwy0GrYieVntJ8A4ARMA@mail.gmail.com","threadId":"54958","inReplyTo":"X/9DdGnYo7RQz5CE@nand.local","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-14T08:27:57Z","receivedAt":"2021-01-14T08:28:57Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Thu, 14 Jan 2021 at 00:31, Taylor Blau <me@ttaylorr.com> wrote:\n>\n> On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n> > From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >\n> > When squashing commit messages the squash!/fixup! subjects are not of\n> > interest so comment them out to stop them becoming part of the final\n> > message.\n> >\n> > This change breaks a bunch of --autosquash tests which rely on the\n> > \"squash! <subject>\" line appearing in the final commit message. This is\n> > addressed by adding a second line to the commit message of the \"squash!\n> > ...\" commits and testing for that.\n> >\n> > Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> >  sequencer.c                  | 25 ++++++++++++++++++++++++-\n> >  t/t3415-rebase-autosquash.sh | 27 +++++++++++++--------------\n> >  t/t3900-i18n-commit.sh       |  4 ----\n> >  3 files changed, 37 insertions(+), 19 deletions(-)\n> >\n> > diff --git a/sequencer.c b/sequencer.c\n> > index 5062976d10..b050a9a212 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n> >       }\n> >  }\n> >\n> > +static size_t subject_length(const char *body)\n> > +{\n> > +     size_t i, len = 0;\n> > +     char c;\n> > +     int blank_line = 1;\n> > +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> > +             if (c == '\\n') {\n> > +                     if (blank_line)\n> > +                             return len;\n> > +                     len = i + 1;\n> > +                     blank_line = 1;\n> > +             } else if (!isspace(c)) {\n> > +                     blank_line = 0;\n> > +             }\n> > +     }\n> > +     return blank_line ? len : i;\n> > +}\n> > +\n>\n> OK, so this gets the length of the subject in \"body\", which is defined\n> as the run of characters before a newline and then a space character. So\n> \"foo bar\\n\\nbaz\" would return 7, but \"foo bar\\nbaz\" would return 11.\n>\n> Makes sense. (Apologies for stating the obvious here, I just had to read\n> this function to myself a couple of times to make sure that I understood\n> what it was doing.)\n>\n\nEarlier while testing patch, I also went through in the same way and\nnow got confirmed as you described here.\n\n> >  static void append_squash_message(struct strbuf *buf, const char *body,\n> >                                 struct replay_opts *opts)\n> >  {\n> > +     size_t commented_len = 0;\n> > +\n> >       unlink(rebase_path_fixup_msg());\n> > +     if (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> > +             commented_len = subject_length(body);\n> >       strbuf_addf(buf, \"\\n%c \", comment_line_char);\n> >       strbuf_addf(buf, _(\"This is the commit message #%d:\"),\n> >                   ++opts->current_fixup_count + 1);\n> >       strbuf_addstr(buf, \"\\n\\n\");\n> > -     strbuf_addstr(buf, body);\n> > +     strbuf_add_commented_lines(buf, body, commented_len);\n> > +     strbuf_addstr(buf, body + commented_len);\n>\n> Very nice; the subject gets commented when it starts with \"squash!\" or\n> \"fixup!\", but the body remains uncommented. Makes sense to me.\n>\n\nI agree and Thanks to Phillip, for the patch.\n\n> > @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n> >       git cat-file blob HEAD^:file1 >actual &&\n> >       test_cmp expect actual &&\n> >       git cat-file commit HEAD^ >commit &&\n> > -     grep squash commit >actual &&\n> > +     grep \"extra para\" commit >actual &&\n> >       test_line_count = 1 actual\n> >  '\n>\n> Worth checking that \"squash\" doesn't appear in an uncommented part of\n> actual? Or better yet, checking that \"# squash ...\" _does_ appear.\n>\n> I.e., that we would leave this as:\n>\n>     -   grep squash commit >actual &&\n>     +   grep \"^# squash\" commit >actual &&\n>     +   grep \"extra para\" commit >actual &&\n>\n> > @@ -342,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n> >       git cat-file blob HEAD^:file1 >actual &&\n> >       test_cmp expect actual &&\n> >       git cat-file commit HEAD^ >commit &&\n> > -     grep squash commit >actual &&\n> > -     test_line_count = 2 actual\n> > +     grep first commit >actual &&\n> > +     test_line_count = 3 actual\n> >  '\n>\n> Ditto.\n\nOkay, I will add it .\n\nThanks and Regards,\nCharvi\n\n>\n> Thanks,\n> Taylor\n"},{"id":"414343","messageId":"CAPSFM5dje9wi-aSmT+6+1jrxvB9+MHyQuRLY-zataWjy_UFdWA@mail.gmail.com","threadId":"54958","inReplyTo":"X/9GrVjBmnJUZcGn@nand.local","subject":"Re: [RFC PATCH 5/9] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-14T08:57:17Z","receivedAt":"2021-01-14T08:58:11Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Thu, 14 Jan 2021 at 00:44, Taylor Blau <me@ttaylorr.com> wrote:\n>\n> On Fri, Jan 08, 2021 at 02:53:43PM +0530, Charvi Mendiratta wrote:\n> > This makes it easier to use and reuse the comments.\n> >\n> > Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> > Mentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> >  sequencer.c | 19 ++++++++++++++-----\n> >  1 file changed, 14 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/sequencer.c b/sequencer.c\n> > index cdafc2e0e8..b9295b5a02 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -1736,6 +1736,15 @@ static size_t subject_length(const char *body)\n> >       return blank_line ? len : i;\n> >  }\n> >\n> > +static const char first_commit_msg_str[] =\n> > +N_(\"This is the 1st commit message:\");\n> > +static const char nth_commit_msg_fmt[] =\n> > +N_(\"This is the commit message #%d:\");\n> > +static const char skip_nth_commit_msg_fmt[] =\n> > +N_(\"The commit message #%d will be skipped:\");\n> > +static const char combined_commit_msg_str[] =\n> > +N_(\"This is a combination of %d commits.\");\n> > +\n>\n> Two nit-picks here. The line break after the '=' is a little awkward,\n> since two of these lines are less than 80 characters combined, and the\n> other two are just slightly longer than 80 characters. The other nitpick\n> is that its typical to see 'char *foo' instead of 'char foo[]'.\n>\n> So, I'd write these as:\n>\n>     static const char *first_commit_msg_str = N_(\"This is the 1st commit message:\");\n>     static const char *nth_commit_msg_fmt = N_(\"This is the commit message #%d:\");\n>     static const char *skip_nth_commit_msg_fmt = N_(\"The commit message #%d will be skipped:\");\n>     static const char *combined_commit_msg_str = N_(\"This is a combination of %d commits.\");\n>\n\nOkay, I will change it and write in the same line,\n\nAlso, I agree with Junio and Christian to use array instead of pointer\nhere as it will take the extra memory for pointer.\n\n> I also noticed that you suffix these with _fmt or _str depending on\n> whether or not there are arguments that get filled in later on. That\n> makes 'combined_commit_msg_str' labeled incorrectly (it should be\n> 'combined_commit_msg_fmt').\n>\n\nI admit, I was not aware about the difference of _fmt or _str but now I got\nthis and will change it.\n\n> I'm curious to see where down the road these messages will be used over\n> again, but I'm sure that that is coming in subsequent patch(es).\n>\n>  static void append_squash_message(struct strbuf *buf, const char *body,\n>                                   struct replay_opts *opts)\n> >  static void append_squash_message(struct strbuf *buf, const char *body,\n> >                                 struct replay_opts *opts)\n> >  {\n> > @@ -1745,7 +1754,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n> >       if (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> >               commented_len = subject_length(body);\n> >       strbuf_addf(buf, \"\\n%c \", comment_line_char);\n> > -     strbuf_addf(buf, _(\"This is the commit message #%d:\"),\n> > +     strbuf_addf(buf, _(nth_commit_msg_fmt),\n> >                   ++opts->current_fixup_count + 1);\n>\n> This and the three below uses are good, since they still translate\n> these messages. Nice.\n>\n\nThanks for the reviews,\n\nThanks and Regards,\nCharvi\n\n> Thanks,\n> Taylor\n"},{"id":"414345","messageId":"CAP8UFD2G-2kEbajYpi7kGn=E2HriTuhKJRgs-vEDvHC7WYCGQQ@mail.gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-7-charvi077@gmail.com","subject":"Re: [RFC PATCH 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-01-14T09:23:59Z","receivedAt":"2021-01-14T09:25:02Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Fri, Jan 8, 2021 at 10:26 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n\n> @@ -1740,34 +1746,177 @@ static const char first_commit_msg_str[] =\n>  N_(\"This is the 1st commit message:\");\n>  static const char nth_commit_msg_fmt[] =\n>  N_(\"This is the commit message #%d:\");\n> +static const char skip_first_commit_msg_str[] =\n> +N_(\"The 1st commit message will be skipped:\");\n>  static const char skip_nth_commit_msg_fmt[] =\n>  N_(\"The commit message #%d will be skipped:\");\n>  static const char combined_commit_msg_str[] =\n>  N_(\"This is a combination of %d commits.\");\n\n[...]\n\n> +static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n> +{\n> +       strbuf_setlen(buf1, 2);\n> +       strbuf_addf(buf1, nth_commit_msg_fmt, n);\n\nShould \"_(...)\" be used around \"nth_commit_msg_fmt\" here...\n\n> +       strbuf_addch(buf1, '\\n');\n> +       strbuf_setlen(buf2, 2);\n> +       strbuf_addf(buf2, skip_nth_commit_msg_fmt, n);\n\n...and around \"skip_nth_commit_msg_fmt\" here?\n\n> +       strbuf_addch(buf2, '\\n');\n> +}\n"},{"id":"414346","messageId":"CAPSFM5edZP90kYCf0fynpx+5oQ4pRuGBcrm2AmE5JKsXsS3fAQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD2G-2kEbajYpi7kGn=E2HriTuhKJRgs-vEDvHC7WYCGQQ@mail.gmail.com","subject":"Re: [RFC PATCH 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-14T09:45:42Z","receivedAt":"2021-01-14T09:46:37Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Christian,\n\nOn Thu, 14 Jan 2021 at 14:54, Christian Couder\n<christian.couder@gmail.com> wrote:\n>\n> On Fri, Jan 8, 2021 at 10:26 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n>\n> > @@ -1740,34 +1746,177 @@ static const char first_commit_msg_str[] =\n> >  N_(\"This is the 1st commit message:\");\n> >  static const char nth_commit_msg_fmt[] =\n> >  N_(\"This is the commit message #%d:\");\n> > +static const char skip_first_commit_msg_str[] =\n> > +N_(\"The 1st commit message will be skipped:\");\n> >  static const char skip_nth_commit_msg_fmt[] =\n> >  N_(\"The commit message #%d will be skipped:\");\n> >  static const char combined_commit_msg_str[] =\n> >  N_(\"This is a combination of %d commits.\");\n>\n> [...]\n>\n> > +static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n> > +{\n> > +       strbuf_setlen(buf1, 2);\n> > +       strbuf_addf(buf1, nth_commit_msg_fmt, n);\n>\n> Should \"_(...)\" be used around \"nth_commit_msg_fmt\" here...\n\n>\n> > +       strbuf_addch(buf1, '\\n');\n> > +       strbuf_setlen(buf2, 2);\n> > +       strbuf_addf(buf2, skip_nth_commit_msg_fmt, n);\n>\n> ...and around \"skip_nth_commit_msg_fmt\" here?\n>\n\nYes, I forgot to put  \"_(...)\" here for translation. I will add it, thanks.\n\nThanks and Regards,\nCharvi\n\n> > +       strbuf_addch(buf2, '\\n');\n> > +}\n"},{"id":"414347","messageId":"abc9334d-a9ec-a041-aa04-16cb4f01372a@gmail.com","threadId":"54958","inReplyTo":"CAPSFM5fuT0QAK9wJ_HuH3t=qThPx7Opwy0GrYieVntJ8A4ARMA@mail.gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-14T10:29:31Z","receivedAt":"2021-01-14T10:30:23Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Charvi and Taylor\n\nOn 14/01/2021 08:27, Charvi Mendiratta wrote:\n> On Thu, 14 Jan 2021 at 00:31, Taylor Blau <me@ttaylorr.com> wrote:\n>>\n>> On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n>>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>>\n>>> When squashing commit messages the squash!/fixup! subjects are not of\n>>> interest so comment them out to stop them becoming part of the final\n>>> message.\n>>>\n>>> This change breaks a bunch of --autosquash tests which rely on the\n>>> \"squash! <subject>\" line appearing in the final commit message. This is\n>>> addressed by adding a second line to the commit message of the \"squash!\n>>> ...\" commits and testing for that.\n>>>\n>>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n>>> ---\n>>>   sequencer.c                  | 25 ++++++++++++++++++++++++-\n>>>   t/t3415-rebase-autosquash.sh | 27 +++++++++++++--------------\n>>>   t/t3900-i18n-commit.sh       |  4 ----\n>>>   3 files changed, 37 insertions(+), 19 deletions(-)\n>>>\n>>> diff --git a/sequencer.c b/sequencer.c\n>>> index 5062976d10..b050a9a212 100644\n>>> --- a/sequencer.c\n>>> +++ b/sequencer.c\n>>> @@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n>>>        }\n>>>   }\n>>>\n>>> +static size_t subject_length(const char *body)\n>>> +{\n>>> +     size_t i, len = 0;\n>>> +     char c;\n>>> +     int blank_line = 1;\n>>> +     for (i = 0, c = body[i]; c; c = body[++i]) {\n>>> +             if (c == '\\n') {\n>>> +                     if (blank_line)\n>>> +                             return len;\n>>> +                     len = i + 1;\n>>> +                     blank_line = 1;\n>>> +             } else if (!isspace(c)) {\n>>> +                     blank_line = 0;\n>>> +             }\n>>> +     }\n>>> +     return blank_line ? len : i;\n>>> +}\n>>> +\n>>\n>> OK, so this gets the length of the subject in \"body\", which is defined\n>> as the run of characters before a newline and then a space character.\n\nThe length of the subject is the run of characters before a line \ncontaining only whitespace, \"hello\\n there\" would return 13 \"hello\\n \n\\nthere\" would return 5. Looking again at my code there must be a way of \nwriting that function that is easier to follow.\n\n>> So\n>> \"foo bar\\n\\nbaz\" would return 7, but \"foo bar\\nbaz\" would return 11.\n>>\n>> Makes sense. (Apologies for stating the obvious here, I just had to read\n>> this function to myself a couple of times to make sure that I understood\n>> what it was doing.)\n>>\n> \n> Earlier while testing patch, I also went through in the same way and\n> now got confirmed as you described here.\n> \n>>>   static void append_squash_message(struct strbuf *buf, const char *body,\n>>>                                  struct replay_opts *opts)\n>>>   {\n>>> +     size_t commented_len = 0;\n>>> +\n>>>        unlink(rebase_path_fixup_msg());\n>>> +     if (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n>>> +             commented_len = subject_length(body);\n>>>        strbuf_addf(buf, \"\\n%c \", comment_line_char);\n>>>        strbuf_addf(buf, _(\"This is the commit message #%d:\"),\n>>>                    ++opts->current_fixup_count + 1);\n>>>        strbuf_addstr(buf, \"\\n\\n\");\n>>> -     strbuf_addstr(buf, body);\n>>> +     strbuf_add_commented_lines(buf, body, commented_len);\n>>> +     strbuf_addstr(buf, body + commented_len);\n>>\n>> Very nice; the subject gets commented when it starts with \"squash!\" or\n>> \"fixup!\", but the body remains uncommented. Makes sense to me.\n>>\n> \n> I agree and Thanks to Phillip, for the patch.\n> \n>>> @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n>>>        git cat-file blob HEAD^:file1 >actual &&\n>>>        test_cmp expect actual &&\n>>>        git cat-file commit HEAD^ >commit &&\n>>> -     grep squash commit >actual &&\n>>> +     grep \"extra para\" commit >actual &&\n>>>        test_line_count = 1 actual\n>>>   '\n>>\n>> Worth checking that \"squash\" doesn't appear in an uncommented part of\n>> actual? Or better yet, checking that \"# squash ...\" _does_ appear.\n>>\n>> I.e., that we would leave this as:\n>>\n>>      -   grep squash commit >actual &&\n>>      +   grep \"^# squash\" commit >actual &&\n>>      +   grep \"extra para\" commit >actual &&\n\nThis test is checking the message that gets committed, not the contents \nof the file passed to the editor. I like the idea of checking that the \nsquash! line is indeed commented out, but we'd need to test it with\n\ngrep -v squash\n\nLooking at the changes to the tests in this commit it highlights the \nfact that I don't think we ever check exactly what the user sees in \ntheir editor. We do add such a test for the new `fixup -C` functionality \nin a later patch but perhaps we should improve the test coverage of the \nsquash message presented to the user before then.\n\nBest Wishes\n\nPhillip\n\n>>> @@ -342,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n>>>        git cat-file blob HEAD^:file1 >actual &&\n>>>        test_cmp expect actual &&\n>>>        git cat-file commit HEAD^ >commit &&\n>>> -     grep squash commit >actual &&\n>>> -     test_line_count = 2 actual\n>>> +     grep first commit >actual &&\n>>> +     test_line_count = 3 actual\n>>>   '\n>>\n>> Ditto.\n> \n> Okay, I will add it .\n> \n> Thanks and Regards,\n> Charvi\n> \n>>\n>> Thanks,\n>> Taylor\n\n"},{"id":"414350","messageId":"ac1691d6-e13e-2c04-b105-73a0645f4883@gmail.com","threadId":"54958","inReplyTo":"CAPSFM5ew583ZPZO9XUWxskQPsdSv520gKCM30GH2huhdTDxb2A@mail.gmail.com","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-14T10:46:23Z","receivedAt":"2021-01-14T10:47:25Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Taylor and Charvi\n\nOn 14/01/2021 08:12, Charvi Mendiratta wrote:\n> On Thu, 14 Jan 2021 at 00:13, Taylor Blau <me@ttaylorr.com> wrote:\n>>\n>> On Fri, Jan 08, 2021 at 02:53:39PM +0530, Charvi Mendiratta wrote:\n>>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>>\n>>> The file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\n>>> commands, there's no point in writing it for squash commands as it is\n>>> immediately deleted.\n>>>\n>>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n>>> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n>>> ---\n>>>   sequencer.c | 12 +++++++-----\n>>>   1 file changed, 7 insertions(+), 5 deletions(-)\n>>>\n>>> diff --git a/sequencer.c b/sequencer.c\n>>> index 8909a46770..f888a7ed3b 100644\n>>> --- a/sequencer.c\n>>> +++ b/sequencer.c\n>>> @@ -1757,11 +1757,13 @@ static int update_squash_messages(struct repository *r,\n>>>                        return error(_(\"could not read HEAD's commit message\"));\n>>>\n>>>                find_commit_subject(head_message, &body);\n>>> -             if (write_message(body, strlen(body),\n>>> -                               rebase_path_fixup_msg(), 0)) {\n>>> -                     unuse_commit_buffer(head_commit, head_message);\n>>> -                     return error(_(\"cannot write '%s'\"),\n>>> -                                  rebase_path_fixup_msg());\n>>> +             if (command == TODO_FIXUP) {\n>>> +                     if (write_message(body, strlen(body),\n>>> +                                       rebase_path_fixup_msg(), 0)) {\n>>> +                             unuse_commit_buffer(head_commit, head_message);\n>>> +                             return error(_(\"cannot write '%s'\"),\n>>> +                                          rebase_path_fixup_msg());\n>>> +                     }\n>>\n>> I'm nit-picking here, but would this be clearer instead as:\n>>\n>>      if (command == TODO_FIXUP && write_message(...) < 0) {\n>>        unuse_commit_buffer(...);\n>>        // ...\n>>      }\n>>\n>> There are two changes there. One is two squash the two if-statements\n>> together, and the latter is to add a check that 'write_message()'\n>> returns an error. This explicit '< 0' checking was discussed recently in\n>> another thread[1], and I think makes the conditional here read more\n>> clearly.\n\nI don't feel that strongly but the addition of '< 0' feels like it is \nadding an unrelated change to this commit. It also leaves a code base \nwhere most callers of `write_message()` do not check the sign of the \nreturn value but a couple do (there appears to be one that checks the \nsign already and a couple that completely ignore the return value). If \nwe want to standardize on always checking the sign of the return value \nof functions when checking for errors even when they never return a \npositive value then I think someone in favor of that change should \npropose a patch to the coding guidelines so it is clear what our policy \nis. When I see a '< 0`' check I tend to think the positive value has a \nnon-error meaning.\n\nBest Wishes\n\nPhillip\n\n> Okay, I got this and will change it.\n> \n> Thanks and Regards,\n> Charvi\n> \n>> Thanks,\n>> Taylor\n>>\n>> [1]: https://lore.kernel.org/git/xmqqlfcz8ggj.fsf@gitster.c.googlers.com/\n\n"},{"id":"414435","messageId":"CAPSFM5co06fdo=vqTMeHLtYyP37qucGVRtOiFsZBwiR1UOsm8Q@mail.gmail.com","threadId":"54958","inReplyTo":"abc9334d-a9ec-a041-aa04-16cb4f01372a@gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-15T08:35:48Z","receivedAt":"2021-01-15T08:36:41Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Phillip,\n\nOn Thu, 14 Jan 2021 at 15:59, Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Charvi and Taylor\n>\n> On 14/01/2021 08:27, Charvi Mendiratta wrote:\n> > On Thu, 14 Jan 2021 at 00:31, Taylor Blau <me@ttaylorr.com> wrote:\n> >>\n> >> On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n> >>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >>>\n> >>> When squashing commit messages the squash!/fixup! subjects are not of\n> >>> interest so comment them out to stop them becoming part of the final\n> >>> message.\n> >>>\n> >>> This change breaks a bunch of --autosquash tests which rely on the\n> >>> \"squash! <subject>\" line appearing in the final commit message. This is\n> >>> addressed by adding a second line to the commit message of the \"squash!\n> >>> ...\" commits and testing for that.\n> >>>\n> >>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >>> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> >>> ---\n> >>>   sequencer.c                  | 25 ++++++++++++++++++++++++-\n> >>>   t/t3415-rebase-autosquash.sh | 27 +++++++++++++--------------\n> >>>   t/t3900-i18n-commit.sh       |  4 ----\n> >>>   3 files changed, 37 insertions(+), 19 deletions(-)\n> >>>\n> >>> diff --git a/sequencer.c b/sequencer.c\n> >>> index 5062976d10..b050a9a212 100644\n> >>> --- a/sequencer.c\n> >>> +++ b/sequencer.c\n> >>> @@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n> >>>        }\n> >>>   }\n> >>>\n> >>> +static size_t subject_length(const char *body)\n> >>> +{\n> >>> +     size_t i, len = 0;\n> >>> +     char c;\n> >>> +     int blank_line = 1;\n> >>> +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> >>> +             if (c == '\\n') {\n> >>> +                     if (blank_line)\n> >>> +                             return len;\n> >>> +                     len = i + 1;\n> >>> +                     blank_line = 1;\n> >>> +             } else if (!isspace(c)) {\n> >>> +                     blank_line = 0;\n> >>> +             }\n> >>> +     }\n> >>> +     return blank_line ? len : i;\n> >>> +}\n> >>> +\n> >>\n> >> OK, so this gets the length of the subject in \"body\", which is defined\n> >> as the run of characters before a newline and then a space character.\n>\n> The length of the subject is the run of characters before a line\n> containing only whitespace, \"hello\\n there\" would return 13 \"hello\\n\n> \\nthere\" would return 5. Looking again at my code there must be a way of\n> writing that function that is easier to follow.\n>\n\nOkay. I will look into it once, thanks for explaining.\n\n> >> So\n> >> \"foo bar\\n\\nbaz\" would return 7, but \"foo bar\\nbaz\" would return 11.\n> >>\n> >> Makes sense. (Apologies for stating the obvious here, I just had to read\n> >> this function to myself a couple of times to make sure that I understood\n> >> what it was doing.)\n> >>\n> >\n> > Earlier while testing patch, I also went through in the same way and\n> > now got confirmed as you described here.\n> >\n> >>>   static void append_squash_message(struct strbuf *buf, const char *body,\n> >>>                                  struct replay_opts *opts)\n> >>>   {\n> >>> +     size_t commented_len = 0;\n> >>> +\n> >>>        unlink(rebase_path_fixup_msg());\n> >>> +     if (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> >>> +             commented_len = subject_length(body);\n> >>>        strbuf_addf(buf, \"\\n%c \", comment_line_char);\n> >>>        strbuf_addf(buf, _(\"This is the commit message #%d:\"),\n> >>>                    ++opts->current_fixup_count + 1);\n> >>>        strbuf_addstr(buf, \"\\n\\n\");\n> >>> -     strbuf_addstr(buf, body);\n> >>> +     strbuf_add_commented_lines(buf, body, commented_len);\n> >>> +     strbuf_addstr(buf, body + commented_len);\n> >>\n> >> Very nice; the subject gets commented when it starts with \"squash!\" or\n> >> \"fixup!\", but the body remains uncommented. Makes sense to me.\n> >>\n> >\n> > I agree and Thanks to Phillip, for the patch.\n> >\n> >>> @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n> >>>        git cat-file blob HEAD^:file1 >actual &&\n> >>>        test_cmp expect actual &&\n> >>>        git cat-file commit HEAD^ >commit &&\n> >>> -     grep squash commit >actual &&\n> >>> +     grep \"extra para\" commit >actual &&\n> >>>        test_line_count = 1 actual\n> >>>   '\n> >>\n> >> Worth checking that \"squash\" doesn't appear in an uncommented part of\n> >> actual? Or better yet, checking that \"# squash ...\" _does_ appear.\n> >>\n> >> I.e., that we would leave this as:\n> >>\n> >>      -   grep squash commit >actual &&\n> >>      +   grep \"^# squash\" commit >actual &&\n> >>      +   grep \"extra para\" commit >actual &&\n>\n> This test is checking the message that gets committed, not the contents\n> of the file passed to the editor. I like the idea of checking that the\n> squash! line is indeed commented out, but we'd need to test it with\n>\n> grep -v squash\n>\n> Looking at the changes to the tests in this commit it highlights the\n> fact that I don't think we ever check exactly what the user sees in\n> their editor. We do add such a test for the new `fixup -C` functionality\n> in a later patch but perhaps we should improve the test coverage of the\n> squash message presented to the user before then.\n>\n\nOkay and for checking \"squash\" I will add it in the above way.\n\nThanks and Regards,\nCharvi\n\n\n> Best Wishes\n>\n> Phillip\n>\n> >>> @@ -342,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n> >>>        git cat-file blob HEAD^:file1 >actual &&\n> >>>        test_cmp expect actual &&\n> >>>        git cat-file commit HEAD^ >commit &&\n> >>> -     grep squash commit >actual &&\n> >>> -     test_line_count = 2 actual\n> >>> +     grep first commit >actual &&\n> >>> +     test_line_count = 3 actual\n> >>>   '\n> >>\n> >> Ditto.\n> >\n> > Okay, I will add it .\n> >\n> > Thanks and Regards,\n> > Charvi\n> >\n> >>\n> >> Thanks,\n> >> Taylor\n>\n"},{"id":"414437","messageId":"CAPSFM5eBCVD9sx-AkA6Zr-PAq3JgTftcf2UhZBcBmK_00ff1+Q@mail.gmail.com","threadId":"54958","inReplyTo":"ac1691d6-e13e-2c04-b105-73a0645f4883@gmail.com","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-15T08:38:37Z","receivedAt":"2021-01-15T08:39:46Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Thu, 14 Jan 2021 at 16:16, Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Taylor and Charvi\n>\n> On 14/01/2021 08:12, Charvi Mendiratta wrote:\n> > On Thu, 14 Jan 2021 at 00:13, Taylor Blau <me@ttaylorr.com> wrote:\n> >>\n> >> On Fri, Jan 08, 2021 at 02:53:39PM +0530, Charvi Mendiratta wrote:\n> >>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >>>\n> >>> The file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\n> >>> commands, there's no point in writing it for squash commands as it is\n> >>> immediately deleted.\n> >>>\n> >>> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> >>> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> >>> ---\n> >>>   sequencer.c | 12 +++++++-----\n> >>>   1 file changed, 7 insertions(+), 5 deletions(-)\n> >>>\n> >>> diff --git a/sequencer.c b/sequencer.c\n> >>> index 8909a46770..f888a7ed3b 100644\n> >>> --- a/sequencer.c\n> >>> +++ b/sequencer.c\n> >>> @@ -1757,11 +1757,13 @@ static int update_squash_messages(struct repository *r,\n> >>>                        return error(_(\"could not read HEAD's commit message\"));\n> >>>\n> >>>                find_commit_subject(head_message, &body);\n> >>> -             if (write_message(body, strlen(body),\n> >>> -                               rebase_path_fixup_msg(), 0)) {\n> >>> -                     unuse_commit_buffer(head_commit, head_message);\n> >>> -                     return error(_(\"cannot write '%s'\"),\n> >>> -                                  rebase_path_fixup_msg());\n> >>> +             if (command == TODO_FIXUP) {\n> >>> +                     if (write_message(body, strlen(body),\n> >>> +                                       rebase_path_fixup_msg(), 0)) {\n> >>> +                             unuse_commit_buffer(head_commit, head_message);\n> >>> +                             return error(_(\"cannot write '%s'\"),\n> >>> +                                          rebase_path_fixup_msg());\n> >>> +                     }\n> >>\n> >> I'm nit-picking here, but would this be clearer instead as:\n> >>\n> >>      if (command == TODO_FIXUP && write_message(...) < 0) {\n> >>        unuse_commit_buffer(...);\n> >>        // ...\n> >>      }\n> >>\n> >> There are two changes there. One is two squash the two if-statements\n> >> together, and the latter is to add a check that 'write_message()'\n> >> returns an error. This explicit '< 0' checking was discussed recently in\n> >> another thread[1], and I think makes the conditional here read more\n> >> clearly.\n>\n> I don't feel that strongly but the addition of '< 0' feels like it is\n> adding an unrelated change to this commit. It also leaves a code base\n> where most callers of `write_message()` do not check the sign of the\n> return value but a couple do (there appears to be one that checks the\n> sign already and a couple that completely ignore the return value). If\n> we want to standardize on always checking the sign of the return value\n> of functions when checking for errors even when they never return a\n> positive value then I think someone in favor of that change should\n> propose a patch to the coding guidelines so it is clear what our policy\n> is. When I see a '< 0`' check I tend to think the positive value has a\n> non-error meaning.\n>\n\nOkay, I looked into the write_message(...) and agree that it does not return\na positive value and only returns non-zero for error case and zero for\nsuccess. So, for this patch maybe we can ignore checking '< 0' here and\nlater add another patch to make this function follow the convention of\n\"negative is error\".\n\nThanks and Regards,\nCharvi\n\n\n> Best Wishes\n>\n> Phillip\n>\n> > Okay, I got this and will change it.\n> >\n> > Thanks and Regards,\n> > Charvi\n> >\n> >> Thanks,\n> >> Taylor\n> >>\n> >> [1]: https://lore.kernel.org/git/xmqqlfcz8ggj.fsf@gitster.c.googlers.com/\n>\n"},{"id":"414438","messageId":"CAP8UFD3_RPrFQELiBp=QFgheQa8RhDYcwgLmG9Eb4fFKH4p+FA@mail.gmail.com","threadId":"54958","inReplyTo":"CAPSFM5co06fdo=vqTMeHLtYyP37qucGVRtOiFsZBwiR1UOsm8Q@mail.gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-01-15T08:44:54Z","receivedAt":"2021-01-15T08:46:05Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"Hi Charvi,\n\nOn Fri, Jan 15, 2021 at 9:35 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n\n> On Thu, 14 Jan 2021 at 15:59, Phillip Wood <phillip.wood123@gmail.com> wrote:\n\n> > On 14/01/2021 08:27, Charvi Mendiratta wrote:\n> > > On Thu, 14 Jan 2021 at 00:31, Taylor Blau <me@ttaylorr.com> wrote:\n> > >>\n> > >> On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n> > >>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\n> > >>> +static size_t subject_length(const char *body)\n> > >>> +{\n> > >>> +     size_t i, len = 0;\n> > >>> +     char c;\n> > >>> +     int blank_line = 1;\n> > >>> +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> > >>> +             if (c == '\\n') {\n> > >>> +                     if (blank_line)\n> > >>> +                             return len;\n> > >>> +                     len = i + 1;\n> > >>> +                     blank_line = 1;\n> > >>> +             } else if (!isspace(c)) {\n> > >>> +                     blank_line = 0;\n> > >>> +             }\n> > >>> +     }\n> > >>> +     return blank_line ? len : i;\n> > >>> +}\n> > >>\n> > >> OK, so this gets the length of the subject in \"body\", which is defined\n> > >> as the run of characters before a newline and then a space character.\n> >\n> > The length of the subject is the run of characters before a line\n> > containing only whitespace, \"hello\\n there\" would return 13 \"hello\\n\n> > \\nthere\" would return 5. Looking again at my code there must be a way of\n> > writing that function that is easier to follow.\n>\n> Okay. I will look into it once, thanks for explaining.\n\nYou may want to look at other places in the code where we deal with\nthe subject. For example there is find_commit_subject() in commit.c\nand find_trailer_start() in trailer.c that might have interesting code\nfor our purpose.\n\nBest,\nChristian.\n"},{"id":"414450","messageId":"CAPSFM5eiV-Kd3T7Ug9838UJVXKNPZ7x+C5UdRybu6wR0=sw4Ug@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD3_RPrFQELiBp=QFgheQa8RhDYcwgLmG9Eb4fFKH4p+FA@mail.gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-15T11:12:45Z","receivedAt":"2021-01-15T11:13:43Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Christian,\n\nOn Fri, 15 Jan 2021 at 14:15, Christian Couder\n<christian.couder@gmail.com> wrote:\n>\n> Hi Charvi,\n>\n> On Fri, Jan 15, 2021 at 9:35 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n>\n> > On Thu, 14 Jan 2021 at 15:59, Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> > > On 14/01/2021 08:27, Charvi Mendiratta wrote:\n> > > > On Thu, 14 Jan 2021 at 00:31, Taylor Blau <me@ttaylorr.com> wrote:\n> > > >>\n> > > >> On Fri, Jan 08, 2021 at 02:53:41PM +0530, Charvi Mendiratta wrote:\n> > > >>> From: Phillip Wood <phillip.wood@dunelm.org.uk>\n>\n> > > >>> +static size_t subject_length(const char *body)\n> > > >>> +{\n> > > >>> +     size_t i, len = 0;\n> > > >>> +     char c;\n> > > >>> +     int blank_line = 1;\n> > > >>> +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> > > >>> +             if (c == '\\n') {\n> > > >>> +                     if (blank_line)\n> > > >>> +                             return len;\n> > > >>> +                     len = i + 1;\n> > > >>> +                     blank_line = 1;\n> > > >>> +             } else if (!isspace(c)) {\n> > > >>> +                     blank_line = 0;\n> > > >>> +             }\n> > > >>> +     }\n> > > >>> +     return blank_line ? len : i;\n> > > >>> +}\n> > > >>\n> > > >> OK, so this gets the length of the subject in \"body\", which is defined\n> > > >> as the run of characters before a newline and then a space character.\n> > >\n> > > The length of the subject is the run of characters before a line\n> > > containing only whitespace, \"hello\\n there\" would return 13 \"hello\\n\n> > > \\nthere\" would return 5. Looking again at my code there must be a way of\n> > > writing that function that is easier to follow.\n> >\n> > Okay. I will look into it once, thanks for explaining.\n>\n> You may want to look at other places in the code where we deal with\n> the subject. For example there is find_commit_subject() in commit.c\n> and find_trailer_start() in trailer.c that might have interesting code\n> for our purpose.\n>\n\nThanks for the pointer, I will look at it.\n\nThanks and Regards,\nCharvi\n\n> Best,\n> Christian.\n"},{"id":"414458","messageId":"xmqqbldqt8rm.fsf@gitster.c.googlers.com","threadId":"54958","inReplyTo":"CAPSFM5eBCVD9sx-AkA6Zr-PAq3JgTftcf2UhZBcBmK_00ff1+Q@mail.gmail.com","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-01-15T17:22:37Z","receivedAt":"2021-01-15T17:23:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Charvi Mendiratta <charvi077@gmail.com> writes:\n\n> Okay, I looked into the write_message(...) and agree that it does not return\n> a positive value and only returns non-zero for error case and zero for\n> success. So, for this patch maybe we can ignore checking '< 0' here and\n> later add another patch to make this function follow the convention of\n> \"negative is error\".\n\nPlease don't.  There is a higher cognitive cost to readers when you write\n\n\tif (write_message(...)) {\n\nThe reader is forced to look at its implementation to see if it\nreturns positive in a non-error situation.\n\nIf you write it like so from the beginning\n\n\tif (write_message(...) < 0) {\n\nthe reader can trust that the code follows \"negative is an error\"\nconvention.  One fewer thing readers have to worry about.\n"},{"id":"414487","messageId":"CAPSFM5cq6kVM5tUWWKryFvmQBbNzOaOf-SR-Q4wRvs-4Cvc-fA@mail.gmail.com","threadId":"54958","inReplyTo":"xmqqbldqt8rm.fsf@gitster.c.googlers.com","subject":"Re: [RFC PATCH 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-16T04:49:21Z","receivedAt":"2021-01-16T04:50:15Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Junio,\n\nOn Fri, 15 Jan 2021 at 22:52, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Charvi Mendiratta <charvi077@gmail.com> writes:\n>\n> > Okay, I looked into the write_message(...) and agree that it does not return\n> > a positive value and only returns non-zero for error case and zero for\n> > success. So, for this patch maybe we can ignore checking '< 0' here and\n> > later add another patch to make this function follow the convention of\n> > \"negative is error\".\n>\n> Please don't.  There is a higher cognitive cost to readers when you write\n>\n>         if (write_message(...)) {\n>\n> The reader is forced to look at its implementation to see if it\n> returns positive in a non-error situation.\n>\n> If you write it like so from the beginning\n>\n>         if (write_message(...) < 0) {\n>\n> the reader can trust that the code follows \"negative is an error\"\n> convention.  One fewer thing readers have to worry about.\n\nI agree, earlier I was confused as there were many instances of\nwrite_message() without '< 0' in sequencer.c but considering the\nabove I completely agree to follow the convention.\n\nThanks and Regards,\nCharvi\n"},{"id":"414532","messageId":"CAPSFM5eZ=_yaeNmF_SnL2jx+Tz4HdgROF=SjhbL=UbB75eFHxA@mail.gmail.com","threadId":"54958","inReplyTo":"abc9334d-a9ec-a041-aa04-16cb4f01372a@gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-17T03:39:41Z","receivedAt":"2021-01-17T03:40:53Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Phillip and Taylor,\n\n> [...]\n> >>> @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n> >>>        git cat-file blob HEAD^:file1 >actual &&\n> >>>        test_cmp expect actual &&\n> >>>        git cat-file commit HEAD^ >commit &&\n> >>> -     grep squash commit >actual &&\n> >>> +     grep \"extra para\" commit >actual &&\n> >>>        test_line_count = 1 actual\n> >>>   '\n> >>\n> >> Worth checking that \"squash\" doesn't appear in an uncommented part of\n> >> actual? Or better yet, checking that \"# squash ...\" _does_ appear.\n> >>\n> >> I.e., that we would leave this as:\n> >>\n> >>      -   grep squash commit >actual &&\n> >>      +   grep \"^# squash\" commit >actual &&\n> >>      +   grep \"extra para\" commit >actual &&\n>\n> This test is checking the message that gets committed, not the contents\n> of the file passed to the editor. I like the idea of checking that the\n> squash! line is indeed commented out, but we'd need to test it with\n>\n> grep -v squash\n>\n\nIt seems to me that you suggest to use 'grep -v squash' instead of\ngrep \"^#squash\". So I added to check the test as here:\n\n             -   grep squash commit >actual &&\n             +   grep -v \"squash\" commit >actual &&\n             +   grep \"extra para\" commit >actual &&\n\n> Looking at the changes to the tests in this commit it highlights the\n> fact that I don't think we ever check exactly what the user sees in\n> their editor. We do add such a test for the new `fixup -C` functionality\n> in a later patch but perhaps we should improve the test coverage of the\n> squash message presented to the user before then.\n\nI agree and in this test  it's now just checking if the commit message body of\n\"squash!\" i.e  line \"extra para\", is added in commit message or not. So, I am\ndoubtful if the above is the right way to test whether squash! line is commented\nout or not , as \"grep \"extra para\" commit >actual &&\" will rewrite the\n'actual' file.\n\nThanks and Regards,\nCharvi\n"},{"id":"414609","messageId":"f2085c1b-c6aa-0183-e090-8b2da3cc57c0@gmail.com","threadId":"54958","inReplyTo":"CAPSFM5eZ=_yaeNmF_SnL2jx+Tz4HdgROF=SjhbL=UbB75eFHxA@mail.gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-18T18:29:26Z","receivedAt":"2021-01-18T18:36:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Charvi\n\nOn 17/01/2021 03:39, Charvi Mendiratta wrote:\n> Hi Phillip and Taylor,\n> \n>> [...]\n>>>>> @@ -224,7 +223,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n>>>>>         git cat-file blob HEAD^:file1 >actual &&\n>>>>>         test_cmp expect actual &&\n>>>>>         git cat-file commit HEAD^ >commit &&\n>>>>> -     grep squash commit >actual &&\n>>>>> +     grep \"extra para\" commit >actual &&\n>>>>>         test_line_count = 1 actual\n>>>>>    '\n>>>>\n>>>> Worth checking that \"squash\" doesn't appear in an uncommented part of\n>>>> actual? Or better yet, checking that \"# squash ...\" _does_ appear.\n>>>>\n>>>> I.e., that we would leave this as:\n>>>>\n>>>>       -   grep squash commit >actual &&\n>>>>       +   grep \"^# squash\" commit >actual &&\n>>>>       +   grep \"extra para\" commit >actual &&\n>>\n>> This test is checking the message that gets committed, not the contents\n>> of the file passed to the editor. I like the idea of checking that the\n>> squash! line is indeed commented out, but we'd need to test it with\n>>\n>> grep -v squash\n>>\n> \n> It seems to me that you suggest to use 'grep -v squash' instead of\n> grep \"^#squash\".\n\nThat's correct\n\n> So I added to check the test as here:\n> \n>               -   grep squash commit >actual &&\n>               +   grep -v \"squash\" commit >actual &&\n\nThere is no need to redirect the output of this one - we don't expect \nany output and the test will fail if there is so we want to see what the \noutput is.\n\n>               +   grep \"extra para\" commit >actual &&\n> \n>> Looking at the changes to the tests in this commit it highlights the\n>> fact that I don't think we ever check exactly what the user sees in\n>> their editor. We do add such a test for the new `fixup -C` functionality\n>> in a later patch but perhaps we should improve the test coverage of the\n>> squash message presented to the user before then.\n> \n> I agree and in this test  it's now just checking if the commit message body of\n> \"squash!\" i.e  line \"extra para\", is added in commit message or not. So, I am\n> doubtful if the above is the right way to test whether squash! line is commented\n> out or not , as \"grep \"extra para\" commit >actual &&\" will rewrite the\n> 'actual' file.\n\nThe test above gives us reassurance that \"squash! ...\" does not make it \ninto the commit message which is important. We'd want a separate test to \ncheck the message that is presented to the user however looking at patch \n7 the test 'sequence of fixup, fixup -C & squash --signoff works' checks \nthat a \"squash! ...\" subject line gets commented out so I wouldn't worry \nabout an additional test here\n\nBest Wishes\n\nPhillip\n\n> Thanks and Regards,\n> Charvi\n> \n\n"},{"id":"414653","messageId":"CAPSFM5dVbj-y=kRVhLC=9pfd3myjFP9R6-iih4CZiO3XSYO+sQ@mail.gmail.com","threadId":"54958","inReplyTo":"f2085c1b-c6aa-0183-e090-8b2da3cc57c0@gmail.com","subject":"Re: [RFC PATCH 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T04:08:40Z","receivedAt":"2021-01-19T04:12:15Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Phillip,\n\nOn Mon, 18 Jan 2021 at 23:59, Phillip Wood <phillip.wood123@gmail.com> wrote:\n> [...]\n> > So I added to check the test as here:\n> >\n> >               -   grep squash commit >actual &&\n> >               +   grep -v \"squash\" commit >actual &&\n>\n> There is no need to redirect the output of this one - we don't expect\n> any output and the test will fail if there is so we want to see what the\n> output is.\n>\n\nOkay,\n\n> >               +   grep \"extra para\" commit >actual &&\n> >\n> >> Looking at the changes to the tests in this commit it highlights the\n> >> fact that I don't think we ever check exactly what the user sees in\n> >> their editor. We do add such a test for the new `fixup -C` functionality\n> >> in a later patch but perhaps we should improve the test coverage of the\n> >> squash message presented to the user before then.\n> >\n> > I agree and in this test  it's now just checking if the commit message body of\n> > \"squash!\" i.e  line \"extra para\", is added in commit message or not. So, I am\n> > doubtful if the above is the right way to test whether squash! line is commented\n> > out or not , as \"grep \"extra para\" commit >actual &&\" will rewrite the\n> > 'actual' file.\n>\n> The test above gives us reassurance that \"squash! ...\" does not make it\n> into the commit message which is important. We'd want a separate test to\n> check the message that is presented to the user however looking at patch\n> 7 the test 'sequence of fixup, fixup -C & squash --signoff works' checks\n> that a \"squash! ...\" subject line gets commented out so I wouldn't worry\n> about an additional test here\n\nI agree, thanks for confirming.\n\nThanks and Regards,\nCharvi\n"},{"id":"414661","messageId":"20210119074102.21598-1-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 0/9][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:40:54Z","receivedAt":"2021-01-19T07:44:42Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This patch series adds fixup [-C|-c] options to interactive rebase. In\naddition to amending the contents of the commit as the `fixup` command\ndoes now, `fixup -C` replaces the commit message of the original commit\nwhich we are fixing up with the message of the fixup commit.\nAnd to edit the fixup commit message before committing, `fixup -c`\ncommand is used instead of `fixup -C`. This convention is similar to\nthe existing `merge` command in the interactive rebase, that also supports\n`-c` and `-C` options with similar meanings.\n\nThis patch series also changes `rebase -i --autosquash` to rearrange\ncommits whose message starts with \"amend!\" and replaces the pick\ncommand with `fixup -C`. The creation of \"amend!\" commits will be\nrebase -i: add options to fixup command added in another patch series.\n\nThis is done in reference to the issue opened by Dscho as here[1] and\nfurther discussed briefly[2]. Also, there is discussion[3] regarding the\nimplementation of reword! commit. The past patches of Phillip Wood’s\nwork[4], implements 'reword!' as 'amend!' in git rebase and these patches\nuses those as the initial base.\nAnd to avoid the extra command in the interactive rebase, this patch\nseries instead add options to the current fixup command in interactive\nrebase (fixup [-C | -c]) as discussed earlier[5].\n\nChanges from v1 :\n* added '< 0' to check that 'write_message()' returns an error\n* checks if squash! line commented out in t3415-rebase-autosquash.sh\n* removing line break and changing suffix from _str to _fmt in sequencer.c\n\n[1] https://github.com/gitgitgadget/git/issues/259\n[2] https://public-inbox.org/git/alpine.DEB.2.21.1.1710151754070.40514@virtualbox/\n[3] https://lore.kernel.org/git/95cc6fb2-d1bc-11de-febe-c2b5c78a6850@gmail.com/\n[4] https://github.com/phillipwood/git/commits/wip/rebase-amend\n[5] https://lore.kernel.org/git/29fc2f59-1cca-a3db-5586-bbd7b2e4806d@gmail.com/\n\n\nCharvi Mendiratta (6):\n  sequencer: pass todo_item to do_pick_commit()\n  sequencer: use const variable for commit message comments\n  rebase -i: add fixup [-C | -c] command\n  t3437: test script for fixup [-C|-c] options in interactive rebase\n  rebase -i: teach --autosquash to work with amend!\n  doc/git-rebase: add documentation for fixup [-C|-c] options\n\nPhillip Wood (3):\n  rebase -i: only write fixup-message when it's needed\n  sequencer: factor out code to append squash message\n  rebase -i: comment out squash!/fixup! subjects from squash message\n\n Documentation/git-rebase.txt    |  12 +-\n rebase-interactive.c            |   4 +-\n sequencer.c                     | 297 +++++++++++++++++++++++++++-----\n t/lib-rebase.sh                 |   4 +\n t/t3415-rebase-autosquash.sh    |  30 ++--\n t/t3437-rebase-fixup-options.sh | 202 ++++++++++++++++++++++\n t/t3437/expected-squash-message |  51 ++++++\n t/t3900-i18n-commit.sh          |   4 -\n 8 files changed, 543 insertions(+), 61 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-squash-message\n\n--\n2.29.0.rc1\n\n"},{"id":"414662","messageId":"20210119074102.21598-2-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:40:56Z","receivedAt":"2021-01-19T07:45:05Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThe file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\ncommands, there's no point in writing it for squash commands as it is\nimmediately deleted.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8909a46770..a59e0c84af 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1757,11 +1757,10 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (write_message(body, strlen(body),\n-\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n+\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n-\t\t\treturn error(_(\"cannot write '%s'\"),\n-\t\t\t\t     rebase_path_fixup_msg());\n+\t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-- \n2.29.0.rc1\n\n"},{"id":"414663","messageId":"20210119074102.21598-3-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 2/9] sequencer: factor out code to append squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:40:57Z","receivedAt":"2021-01-19T07:46:45Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis code is going to grow over the next two commits so move it to\nits own function.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex a59e0c84af..08cce40834 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,17 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static void append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t\t  struct replay_opts *opts)\n+{\n+\tunlink(rebase_path_fixup_msg());\n+\tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n+\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\t\t    ++opts->current_fixup_count + 1);\n+\tstrbuf_addstr(buf, \"\\n\\n\");\n+\tstrbuf_addstr(buf, body);\n+}\n+\n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n@@ -1779,12 +1790,7 @@ static int update_squash_messages(struct repository *r,\n \tfind_commit_subject(message, &body);\n \n \tif (command == TODO_SQUASH) {\n-\t\tunlink(rebase_path_fixup_msg());\n-\t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is the commit message #%d:\"),\n-\t\t\t    ++opts->current_fixup_count + 1);\n-\t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n-- \n2.29.0.rc1\n\n"},{"id":"414664","messageId":"20210119074102.21598-6-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 5/9] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:41:00Z","receivedAt":"2021-01-19T07:46:45Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This makes it easier to use and reuse the comments.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8a9adb6ff3..571000cf68 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1736,6 +1736,11 @@ static size_t subject_length(const char *body)\n \treturn blank_line ? len : i;\n }\n \n+static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n+static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n+static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n@@ -1745,7 +1750,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n \t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n-\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n@@ -1774,7 +1779,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\tbuf.buf : strchrnul(buf.buf, '\\n');\n \n \t\tstrbuf_addf(&header, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&header, _(\"This is a combination of %d commits.\"),\n+\t\tstrbuf_addf(&header, _(combined_commit_msg_fmt),\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n@@ -1798,9 +1803,9 @@ static int update_squash_messages(struct repository *r,\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is a combination of %d commits.\"), 2);\n+\t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(\"This is the 1st commit message:\"));\n+\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_addstr(&buf, body);\n \n@@ -1816,7 +1821,7 @@ static int update_squash_messages(struct repository *r,\n \t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n+\t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n-- \n2.29.0.rc1\n\n"},{"id":"414665","messageId":"20210119074102.21598-4-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:40:58Z","receivedAt":"2021-01-19T07:47:14Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen squashing commit messages the squash!/fixup! subjects are not of\ninterest so comment them out to stop them becoming part of the final\nmessage.\n\nThis change breaks a bunch of --autosquash tests which rely on the\n\"squash! <subject>\" line appearing in the final commit message. This is\naddressed by adding a second line to the commit message of the \"squash!\n...\" commits and testing for that.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                  | 25 ++++++++++++++++++++++++-\n t/t3415-rebase-autosquash.sh | 30 ++++++++++++++++--------------\n t/t3900-i18n-commit.sh       |  4 ----\n 3 files changed, 40 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 08cce40834..9acb9c333e 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,15 +1718,38 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static size_t subject_length(const char *body)\n+{\n+\tsize_t i, len = 0;\n+\tchar c;\n+\tint blank_line = 1;\n+\tfor (i = 0, c = body[i]; c; c = body[++i]) {\n+\t\tif (c == '\\n') {\n+\t\t\tif (blank_line)\n+\t\t\t\treturn len;\n+\t\t\tlen = i + 1;\n+\t\t\tblank_line = 1;\n+\t\t} else if (!isspace(c)) {\n+\t\t\tblank_line = 0;\n+\t\t}\n+\t}\n+\treturn blank_line ? len : i;\n+}\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n+\tsize_t commented_len = 0;\n+\n \tunlink(rebase_path_fixup_msg());\n+\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+\t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_addstr(buf, body);\n+\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_addstr(buf, body + commented_len);\n }\n \n static int update_squash_messages(struct repository *r,\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 7bab6000dc..551dc06bc3 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -81,8 +81,7 @@ test_auto_squash () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n-\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n \tgit rebase $2 -i HEAD^^^ &&\n@@ -139,7 +138,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag final-multisquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -192,7 +191,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-shasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -203,7 +202,8 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\tgrep -v \"squash\" commit &&\n+\tgrep \"extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -213,7 +213,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short=11 HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-longshasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -224,7 +224,8 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\tgrep -v \"squash\" commit &&\n+\tgrep \"extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -233,7 +234,7 @@ test_auto_commit_flags () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit --$1 first-commit &&\n+\tgit commit --$1 first-commit -m \"extra para for first\" &&\n \tgit tag final-commit-$1 &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -261,11 +262,11 @@ test_auto_fixup_fixup () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! first\" &&\n+\tgit commit -m \"$1! first\" -m \"extra para for first\" &&\n \techo 2 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! $2! first\" &&\n+\tgit commit -m \"$1! $2! first\" -m \"second extra para for first\" &&\n \tgit tag \"final-$1-$2\" &&\n \ttest_tick &&\n \t(\n@@ -326,12 +327,12 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para for first\" &&\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n \tsubject=$(git log -n 1 --format=%s HEAD~2) &&\n-\tgit commit -m \"squash! $subject\" &&\n+\tgit commit -m \"squash! $subject\" -m \"second extra para for first\" &&\n \tgit tag final-squash-instFmt &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -342,8 +343,9 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n-\ttest_line_count = 2 actual\n+\tgrep -v \"squash\" commit &&\n+\tgrep first commit >actual &&\n+\ttest_line_count = 3 actual\n '\n \n test_expect_success 'autosquash with empty custom instructionFormat' '\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex d277a9f4b7..bfab245eb3 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -226,10 +226,6 @@ test_commit_autosquash_multi_encoding () {\n \t\tgit rev-list HEAD >actual &&\n \t\ttest_line_count = 3 actual &&\n \t\ticonv -f $old -t UTF-8 \"$TEST_DIRECTORY\"/t3900/$msg >expect &&\n-\t\tif test $flag = squash; then\n-\t\t\tsubject=\"$(head -1 expect)\" &&\n-\t\t\tprintf \"\\nsquash! %s\\n\" \"$subject\" >>expect\n-\t\tfi &&\n \t\tgit cat-file commit HEAD^ >raw &&\n \t\t(sed \"1,/^$/d\" raw | iconv -f $new -t utf-8) >actual &&\n \t\ttest_cmp expect actual\n-- \n2.29.0.rc1\n\n"},{"id":"414666","messageId":"20210119074102.21598-5-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 4/9] sequencer: pass todo_item to do_pick_commit()","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:40:59Z","receivedAt":"2021-01-19T07:47:14Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"As an additional member of the structure todo_item will be required in\nfuture commits pass the complete structure.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 9acb9c333e..8a9adb6ff3 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1881,8 +1881,7 @@ static void record_in_rewritten(struct object_id *oid,\n }\n \n static int do_pick_commit(struct repository *r,\n-\t\t\t  enum todo_command command,\n-\t\t\t  struct commit *commit,\n+\t\t\t  struct todo_item *item,\n \t\t\t  struct replay_opts *opts,\n \t\t\t  int final_fixup, int *check_todo)\n {\n@@ -1895,6 +1894,8 @@ static int do_pick_commit(struct repository *r,\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res, unborn = 0, reword = 0, allow, drop_commit;\n+\tenum todo_command command = item->command;\n+\tstruct commit *commit = item->commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -4144,8 +4145,8 @@ static int pick_commits(struct repository *r,\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, reflog_message(opts,\n \t\t\t\t\tcommand_to_string(item->command), NULL),\n \t\t\t\t\t1);\n-\t\t\tres = do_pick_commit(r, item->command, item->commit,\n-\t\t\t\t\t     opts, is_final_fixup(todo_list),\n+\t\t\tres = do_pick_commit(r, item, opts,\n+\t\t\t\t\t     is_final_fixup(todo_list),\n \t\t\t\t\t     &check_todo);\n \t\t\tif (is_rebase_i(opts))\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);\n@@ -4607,11 +4608,14 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n+\tstruct todo_item item;\n+\n+\titem.command = opts->action == REPLAY_PICK ?\n+\t\t\tTODO_PICK : TODO_REVERT;\n+\titem.commit = cmit;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(r, opts->action == REPLAY_PICK ?\n-\t\t\t      TODO_PICK : TODO_REVERT, cmit, opts, 0,\n-\t\t\t      &check_todo);\n+\treturn do_pick_commit(r, &item, opts, 0, &check_todo);\n }\n \n int sequencer_pick_revisions(struct repository *r,\n-- \n2.29.0.rc1\n\n"},{"id":"414667","messageId":"20210119074102.21598-8-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:41:02Z","receivedAt":"2021-01-19T07:48:01Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n t/lib-rebase.sh                 |   4 +\n t/t3437-rebase-fixup-options.sh | 190 ++++++++++++++++++++++++++++++++\n t/t3437/expected-squash-message |  51 +++++++++\n 3 files changed, 245 insertions(+)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-squash-message\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex b72c051f47..e10e38060b 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -4,6 +4,7 @@\n #\n # - override the commit message with $FAKE_COMMIT_MESSAGE\n # - amend the commit message with $FAKE_COMMIT_AMEND\n+# - copy the original commit message to a file with $FAKE_MESSAGE_COPY\n # - check that non-commit messages have a certain line count with $EXPECT_COUNT\n # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT\n # - rewrite a rebase -i script as directed by $FAKE_LINES.\n@@ -33,6 +34,7 @@ set_fake_editor () {\n \t\t\texit\n \t\ttest -z \"$FAKE_COMMIT_MESSAGE\" || echo \"$FAKE_COMMIT_MESSAGE\" > \"$1\"\n \t\ttest -z \"$FAKE_COMMIT_AMEND\" || echo \"$FAKE_COMMIT_AMEND\" >> \"$1\"\n+\t\ttest -z \"$FAKE_MESSAGE_COPY\" || cat \"$1\" >\"$FAKE_MESSAGE_COPY\"\n \t\texit\n \t\t;;\n \tesac\n@@ -51,6 +53,8 @@ set_fake_editor () {\n \t\t\taction=\"$line\";;\n \t\texec_*|x_*|break|b)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n+\t\tmerge_*|fixup_*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\t\"#\")\n \t\t\techo '# comment' >> \"$1\";;\n \t\t\">\")\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nnew file mode 100755\nindex 0000000000..9e62d74249\n--- /dev/null\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -0,0 +1,190 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2018 Phillip Wood\n+#\n+\n+test_description='git rebase interactive fixup options\n+\n+This test checks the \"fixup [-C|-c]\" command of rebase interactive.\n+In addition to amending the contents of the commit, \"fixup -C\"\n+replaces the original commit message with the message of the fixup\n+commit. \"fixup -c\" also replaces the original message, but opens the\n+editor to allow the user to edit the message before committing.\n+'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+EMPTY=\"\"\n+\n+test_commit_message () {\n+\trev=\"$1\" && # commit or tag we want to test\n+\tfile=\"$2\" && # test against the content of a file\n+\tgit show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n+\tif test \"$2\" = -m\n+\tthen\n+\t\tstr=\"$3\" && # test against a string\n+\t\tprintf \"%s\\n\" \"$str\" >tmp-expected-message &&\n+\t\tfile=\"tmp-expected-message\"\n+\tfi\n+\ttest_cmp \"$file\" actual-message\n+}\n+\n+get_author () {\n+\trev=\"$1\" &&\n+\tgit log -1 --pretty=format:\"%an %ae\" \"$rev\"\n+}\n+\n+test_expect_success 'setup' '\n+\tcat >message <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tnew subject\n+\t\t${EMPTY}\n+\t\tnew\n+\t\tbody\n+\t\tEOF\n+\n+\tsed \"1,2d\" message >expected-message &&\n+\n+\ttest_commit A A &&\n+\ttest_commit B B &&\n+\tget_author HEAD >expected-author &&\n+\tORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n+\tORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n+\tGIT_AUTHOR_NAME=\"Amend Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n+\ttest_commit \"$(cat message)\" A A1 A1 &&\n+\ttest_commit A2 A &&\n+\ttest_commit A3 A &&\n+\tGIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n+\tGIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n+\tgit checkout -b conflicts-branch A &&\n+\ttest_commit conflicts A &&\n+\n+\tset_fake_editor &&\n+\tgit checkout -b branch B &&\n+\techo B1 >B &&\n+\ttest_tick &&\n+\tgit commit --fixup=HEAD -a &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\tEOF\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\tEOF\n+\techo B2 >B &&\n+\ttest_tick &&\n+\tFAKE_COMMIT_AMEND=\"edited squash\" git commit --squash=HEAD -a &&\n+\techo B3 >B &&\n+\ttest_tick &&\n+\tgit commit -a -F - <<-EOF &&\n+\t\tamend! amend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\t${EMPTY}\n+\t\tedited 3\n+\t\tEOF\n+\n+\tGIT_AUTHOR_NAME=\"Rebase Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"rebase.author@example.com\" &&\n+\tGIT_COMMITTER_NAME=\"Rebase Committer\" &&\n+\tGIT_COMMITTER_EMAIL=\"rebase.committer@example.com\"\n+'\n+\n+test_expect_success 'simple fixup -C works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD -m \"A2\"\n+'\n+\n+test_expect_success 'simple fixup -c works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tgit log -1 --pretty=format:%B >expected-fixup-message &&\n+\ttest_write_lines \"\" \"Modified A2\" >>expected-fixup-message &&\n+\tFAKE_LINES=\"1 fixup_-c 2\" \\\n+\t\tFAKE_COMMIT_AMEND=\"Modified A2\" \\\n+\t\tgit rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD expected-fixup-message\n+'\n+\n+test_expect_success 'fixup -C removes amend! from message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'fixup -C with conflicts gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n+\tgit checkout --theirs -- A &&\n+\tgit add A &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_cmp_rev HEAD^ conflicts &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_write_lines \"\" edited >>expected-message &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'skipping fixup -C after fixup gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup 2 fixup_-C 4\" git rebase -i A &&\n+\tgit reset --hard &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_commit_message HEAD -m \"B\"\n+'\n+\n+test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' '\n+\tgit checkout --detach branch &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4 squash 5 fixup_-C 6\" \\\n+\t\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n+test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout branch && git checkout --detach branch~2 &&\n+\tgit log -1 --pretty=format:%b >expected-message &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_done\ndiff --git a/t/t3437/expected-squash-message b/t/t3437/expected-squash-message\nnew file mode 100644\nindex 0000000000..ab2434f90e\n--- /dev/null\n+++ b/t/t3437/expected-squash-message\n@@ -0,0 +1,51 @@\n+# This is a combination of 6 commits.\n+# The 1st commit message will be skipped:\n+\n+# B\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# The commit message #2 will be skipped:\n+\n+# fixup! B\n+\n+# The commit message #3 will be skipped:\n+\n+# amend! B\n+#\n+# B\n+#\n+# edited 1\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #4:\n+\n+# amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #5:\n+\n+# squash! amend! amend! B\n+\n+edited squash\n+\n+# This is the commit message #6:\n+\n+# amend! amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+edited 3\n+squashed\n-- \n2.29.0.rc1\n\n"},{"id":"414668","messageId":"20210119074102.21598-9-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:41:03Z","receivedAt":"2021-01-19T07:48:11Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"If the commit subject starts with \"amend!\" then rearrange it like a\n\"fixup!\" commit and replace `pick` command with `fixup -C` command,\nwhich is used to fixup up the content if any and replaces the original\ncommit message with amend! commit's message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                     | 23 ++++++++++++++++-------\n t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n 2 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 3c0cd487f9..2a3f8d2fae 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5664,6 +5664,12 @@ static int subject2item_cmp(const void *fndata,\n \n define_commit_slab(commit_todo_item, struct todo_item *);\n \n+static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n+\treturn skip_prefix(subject, \"fixup! \", p) ||\n+\t       skip_prefix(subject, \"amend! \", p) ||\n+\t       skip_prefix(subject, \"squash! \", p);\n+}\n+\n /*\n  * Rearrange the todo list that has both \"pick commit-id msg\" and \"pick\n  * commit-id fixup!/squash! msg\" in it so that the latter is put immediately\n@@ -5722,15 +5728,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\tformat_subject(&buf, subject, \" \");\n \t\tsubject = subjects[i] = strbuf_detach(&buf, &subject_len);\n \t\tunuse_commit_buffer(item->commit, commit_buffer);\n-\t\tif ((skip_prefix(subject, \"fixup! \", &p) ||\n-\t\t     skip_prefix(subject, \"squash! \", &p))) {\n+\t\tif (skip_fixup_amend_squash(subject, &p)) {\n \t\t\tstruct commit *commit2;\n \n \t\t\tfor (;;) {\n \t\t\t\twhile (isspace(*p))\n \t\t\t\t\tp++;\n-\t\t\t\tif (!skip_prefix(p, \"fixup! \", &p) &&\n-\t\t\t\t    !skip_prefix(p, \"squash! \", &p))\n+\t\t\t\tif (!skip_fixup_amend_squash(p, &p))\n \t\t\t\t\tbreak;\n \t\t\t}\n \n@@ -5760,9 +5764,14 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t}\n \t\tif (i2 >= 0) {\n \t\t\trearranged = 1;\n-\t\t\ttodo_list->items[i].command =\n-\t\t\t\tstarts_with(subject, \"fixup!\") ?\n-\t\t\t\tTODO_FIXUP : TODO_SQUASH;\n+\t\t\tif (starts_with(subject, \"fixup!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t} else if (starts_with(subject, \"amend!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t\ttodo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;\n+\t\t\t} else {\n+\t\t\t\ttodo_list->items[i].command = TODO_SQUASH;\n+\t\t\t}\n \t\t\tif (tail[i2] < 0) {\n \t\t\t\tnext[i] = next[i2];\n \t\t\t\tnext[i2] = i;\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nindex 9e62d74249..532dc1c11b 100755\n--- a/t/t3437-rebase-fixup-options.sh\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -187,4 +187,16 @@ test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fix\n \ttest_commit_message HEAD expected-message\n '\n \n+test_expect_success 'fixup -C works upon --autosquash with amend!' '\n+\tgit checkout --detach branch &&\n+\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --autosquash \\\n+\t\t\t\t\t\t--signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n test_done\n-- \n2.29.0.rc1\n\n"},{"id":"414670","messageId":"20210119074102.21598-10-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:41:04Z","receivedAt":"2021-01-19T07:48:56Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n Documentation/git-rebase.txt | 12 +++++++++---\n 1 file changed, 9 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a0487b5cc5..776507e0cc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -887,9 +887,15 @@ If you want to fold two or more commits into one, replace the command\n \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n If the commits had different authors, the folded commit will be\n attributed to the author of the first commit.  The suggested commit\n-message for the folded commit is the concatenation of the commit\n-messages of the first commit and of those with the \"squash\" command,\n-but omits the commit messages of commits with the \"fixup\" command.\n+message for the folded commit is created as follows:\n+\n+ - It is made using the commit message of a commit with the \"fixup -C\"\n+   or \"fixup -c\" command. In the later case an editor is opened to edit\n+   the commit message.\n+ - Otherwise it's the concatenation of the commit messages of the first\n+   commit and of those with the \"squash\" command.\n+ - It omits the commit messages of commits with the \"fixup\"\n+   (without -C or -c) command.\n \n 'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n when a command fails due to merge errors. When you are done editing\n-- \n2.29.0.rc1\n\n"},{"id":"414671","messageId":"20210119074102.21598-7-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210108092345.2178-1-charvi077@gmail.com","subject":"[PATCH v2 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T07:41:01Z","receivedAt":"2021-01-19T07:48:56Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Add options to `fixup` command to fixup both the commit contents and\nmessage. `fixup -C` command is used to replace the original commit\nmessage and `fixup -c`, additionally allows to edit the commit message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n rebase-interactive.c |   4 +-\n sequencer.c          | 211 +++++++++++++++++++++++++++++++++++++++----\n 2 files changed, 195 insertions(+), 20 deletions(-)\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 762853bc7e..c3bd02adee 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n \"e, edit <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n-\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n+\"                   commit's log message. Use -C to replace with this\\n\"\n+\"                   commit message or -c to edit the commit message\\n\"\n \"x, exec <command> = run command (the rest of the line) using shell\\n\"\n \"b, break = stop here (continue rebase later with 'git rebase --continue')\\n\"\n \"d, drop <commit> = remove commit\\n\"\ndiff --git a/sequencer.c b/sequencer.c\nindex 571000cf68..3c0cd487f9 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+enum todo_item_flags {\n+\tTODO_EDIT_MERGE_MSG    = (1 << 0),\n+\tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n+\tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+};\n+\n static size_t subject_length(const char *body)\n {\n \tsize_t i, len = 0;\n@@ -1738,32 +1744,174 @@ static size_t subject_length(const char *body)\n \n static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_first_commit_msg_str[] = N_(\"The 1st commit message will be skipped:\");\n static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n \n-static void append_squash_message(struct strbuf *buf, const char *body,\n-\t\t\t\t  struct replay_opts *opts)\n+static int check_fixup_flag(enum todo_command command,\n+\t\t\t    enum todo_item_flags flag)\n+{\n+\treturn command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n+\t\t\t\t\t (flag & TODO_EDIT_FIXUP_MSG));\n+}\n+\n+/*\n+ * Wrapper around strbuf_add_commented_lines() which avoids double\n+ * commenting commit subjects.\n+ */\n+static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n+{\n+\tconst char *s = str;\n+\twhile (len > 0 && s[0] == comment_line_char) {\n+\t\tsize_t count;\n+\t\tconst char *n = memchr(s, '\\n', len);\n+\t\tif (!n)\n+\t\t\tcount = len;\n+\t\telse\n+\t\t\tcount = n - s + 1;\n+\t\tstrbuf_add(buf, s, count);\n+\t\ts += count;\n+\t\tlen -= count;\n+\t}\n+\tstrbuf_add_commented_lines(buf, s, len);\n+}\n+\n+/* Does the current fixup chain contain a squash command? */\n+static int seen_squash(struct replay_opts *opts)\n+{\n+\treturn starts_with(opts->current_fixups.buf, \"squash\") ||\n+\t\tstrstr(opts->current_fixups.buf, \"\\nsquash\");\n+}\n+\n+static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n {\n-\tsize_t commented_len = 0;\n+\tstrbuf_setlen(buf1, 2);\n+\tstrbuf_addf(buf1, _(nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf1, '\\n');\n+\tstrbuf_setlen(buf2, 2);\n+\tstrbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf2, '\\n');\n+}\n \n-\tunlink(rebase_path_fixup_msg());\n-\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+/*\n+ * Comment out any un-commented commit messages, updating the message comments\n+ * to say they will be skipped but do not comment out the empty lines that\n+ * surround commit messages and their comments.\n+ */\n+static void update_squash_message_for_fixup(struct strbuf *msg)\n+{\n+\tvoid (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;\n+\tstruct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tconst char *s, *start;\n+\tchar *orig_msg;\n+\tsize_t orig_msg_len;\n+\tint i = 1;\n+\n+\tstrbuf_addf(&buf1, \"# %s\\n\", _(first_commit_msg_str));\n+\tstrbuf_addf(&buf2, \"# %s\\n\", _(skip_first_commit_msg_str));\n+\ts = start = orig_msg = strbuf_detach(msg, &orig_msg_len);\n+\twhile (s) {\n+\t\tconst char *next;\n+\t\tsize_t off;\n+\t\tif (skip_prefix(s, buf1.buf, &next)) {\n+\t\t\t/*\n+\t\t\t * Copy the last message, preserving the blank line\n+\t\t\t * preceding the current line\n+\t\t\t */\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tif (off)\n+\t\t\t\tstrbuf_addch(msg, '\\n');\n+\t\t\t/*\n+\t\t\t * The next message needs to be commented out but the\n+\t\t\t * message header is already commented out so just copy\n+\t\t\t * it and the blank line that follows it.\n+\t\t\t */\n+\t\t\tstrbuf_addbuf(msg, &buf2);\n+\t\t\tif (*next == '\\n')\n+\t\t\t\tstrbuf_addch(msg, *next++);\n+\t\t\tstart = s = next;\n+\t\t\tcopy_lines = add_commented_lines;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else if (skip_prefix(s, buf2.buf, &next)) {\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tstart = s - off;\n+\t\t\ts = next;\n+\t\t\tcopy_lines = strbuf_add;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else {\n+\t\t\ts = strchr(s, '\\n');\n+\t\t\tif (s)\n+\t\t\t\ts++;\n+\t\t}\n+\t}\n+\tcopy_lines(msg, start, orig_msg_len - (start - orig_msg));\n+\tfree(orig_msg);\n+\tstrbuf_release(&buf1);\n+\tstrbuf_release(&buf2);\n+}\n+\n+static int append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t enum todo_command command, struct replay_opts *opts,\n+\t\t\t enum todo_item_flags flag)\n+{\n+\tconst char *fixup_msg;\n+\tsize_t commented_len = 0, fixup_off;\n+\t/*\n+\t * amend is non-interactive and not normally used with fixup!\n+\t * or squash! commits, so only comment out those subjects when\n+\t * squashing commit messages.\n+\t */\n+\tif (starts_with(body, \"amend!\") ||\n+\t    ((command == TODO_SQUASH || seen_squash(opts)) &&\n+\t     (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n \t\tcommented_len = subject_length(body);\n+\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n+\t/* buf->buf may be reallocated so store an offset into the buffer */\n+\tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n+\n+\t/* fixup -C after squash behaves like squash */\n+\tif (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n+\t\t/*\n+\t\t * We're replacing the commit message so we need to\n+\t\t * append the Signed-off-by: trailer if the user\n+\t\t * requested '--signoff'.\n+\t\t */\n+\t\tif (opts->signoff)\n+\t\t\tappend_signoff(buf, 0, 0);\n+\n+\t\tif ((command == TODO_FIXUP) &&\n+\t\t    (flag & TODO_REPLACE_FIXUP_MSG)) {\n+\t\t\tfixup_msg = skip_blank_lines(buf->buf + fixup_off);\n+\t\t\tif (write_message(fixup_msg, strlen(fixup_msg),\n+\t\t\t\t\trebase_path_fixup_msg(), 0) < 0)\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\trebase_path_fixup_msg());\n+\t\t} else {\n+\t\t\tunlink(rebase_path_fixup_msg());\n+\t\t}\n+\t} else  {\n+\t\tunlink(rebase_path_fixup_msg());\n+\t}\n+\n+\treturn 0;\n }\n \n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n-\t\t\t\t  struct replay_opts *opts)\n+\t\t\t\t  struct replay_opts *opts,\n+\t\t\t\t  enum todo_item_flags flag)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tint res;\n+\tint res = 0;\n \tconst char *message, *body;\n \tconst char *encoding = get_commit_output_encoding();\n \n@@ -1783,6 +1931,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n+\t\tif (check_fixup_flag(command, flag) && !seen_squash(opts))\n+\t\t\tupdate_squash_message_for_fixup(&buf);\n \t} else {\n \t\tstruct object_id head;\n \t\tstruct commit *head_commit;\n@@ -1796,18 +1946,22 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\tif (command == TODO_FIXUP && !flag && write_message(body, strlen(body),\n \t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n \t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n-\n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n+\t\tstrbuf_addstr(&buf, check_fixup_flag(command, flag) ?\n+\t\t\t      _(skip_first_commit_msg_str) :\n+\t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tif (check_fixup_flag(command, flag))\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, body);\n \n \t\tunuse_commit_buffer(head_commit, head_message);\n \t}\n@@ -1817,8 +1971,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tfind_commit_subject(message, &body);\n \n-\tif (command == TODO_SQUASH) {\n-\t\tappend_squash_message(&buf, body, opts);\n+\tif (command == TODO_SQUASH || check_fixup_flag(command, flag)) {\n+\t\tres = append_squash_message(&buf, body, command, opts, flag);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n@@ -1829,7 +1983,9 @@ static int update_squash_messages(struct repository *r,\n \t\treturn error(_(\"unknown command: %d\"), command);\n \tunuse_commit_buffer(commit, message);\n \n-\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);\n+\tif (!res)\n+\t\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(),\n+\t\t\t\t    0);\n \tstrbuf_release(&buf);\n \n \tif (!res) {\n@@ -2030,7 +2186,8 @@ static int do_pick_commit(struct repository *r,\n \tif (command == TODO_REWORD)\n \t\treword = 1;\n \telse if (is_fixup(command)) {\n-\t\tif (update_squash_messages(r, command, commit, opts))\n+\t\tif (update_squash_messages(r, command, commit,\n+\t\t\t\t\t   opts, item->flags))\n \t\t\treturn -1;\n \t\tflags |= AMEND_MSG;\n \t\tif (!final_fixup)\n@@ -2195,10 +2352,6 @@ static int read_and_refresh_cache(struct repository *r,\n \treturn 0;\n }\n \n-enum todo_item_flags {\n-\tTODO_EDIT_MERGE_MSG = 1\n-};\n-\n void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n@@ -2285,6 +2438,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n \t\treturn 0;\n \t}\n \n+\tif (item->command == TODO_FIXUP) {\n+\t\tif (skip_prefix(bol, \"-C\", &bol) &&\n+\t\t   (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_REPLACE_FIXUP_MSG;\n+\t\t} else if (skip_prefix(bol, \"-c\", &bol) &&\n+\t\t\t\t  (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_EDIT_FIXUP_MSG;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_MERGE) {\n \t\tif (skip_prefix(bol, \"-C\", &bol))\n \t\t\tbol += strspn(bol, \" \\t\");\n@@ -5291,6 +5456,14 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis\n \t\t\t\t\t  short_commit_name(item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n \n+\t\t\tif (item->command == TODO_FIXUP) {\n+\t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n+\t\t\t\telse if (item->flags & TODO_REPLACE_FIXUP_MSG) {\n+\t\t\t\t\tstrbuf_addstr(buf, \" -C\");\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_MERGE) {\n \t\t\t\tif (item->flags & TODO_EDIT_MERGE_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n-- \n2.29.0.rc1\n\n"},{"id":"414693","messageId":"CAPSFM5euGE_bUDPgdzx4-q5zYtkDymHdJP9rw-YkVVVzpOKWkw@mail.gmail.com","threadId":"54958","inReplyTo":"8fd2b72c-d1d0-98be-e6a5-fb7dc699d5d5@xiplink.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-19T17:13:10Z","receivedAt":"2021-01-19T18:28:51Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Marc,\n\nOn Tue, 19 Jan 2021 at 20:07, Marc Branchaud <marcnarc@xiplink.com> wrote:\n[...]\n> >   \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n> >   If the commits had different authors, the folded commit will be\n> >   attributed to the author of the first commit.  The suggested commit\n> > -message for the folded commit is the concatenation of the commit\n> > -messages of the first commit and of those with the \"squash\" command,\n> > -but omits the commit messages of commits with the \"fixup\" command.\n> > +message for the folded commit is created as follows:\n> > +\n> > + - It is made using the commit message of a commit with the \"fixup -C\"\n> > +   or \"fixup -c\" command. In the later case an editor is opened to edit\n> > +   the commit message.\n>\n> s/later/latter/\n>\n\nThanks, will fix it.\n\n> What happens if there is more than one \"fixup -C/-c\" command?\n>\n\nUpon running interactive rebase, in todo list if we use for example sequence of\ncommands like `fixup -C`, `fixup -C` , `fixup -C` then it will fixup\ncontent of all and\nfor commit message it will replace with the commit message of end `fixup -C`\n\nSimilarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\nthen also it will fixup\nup all the content and here it allow user to edit the message, so\nopens the editor once\nin this case and shows the commit msg of end `fixup -c` to edit and\nalso contains\ncommented commit messages of complete fixup chain. So, for any sequence of fixup\nchains `fixup -c` works as similar to the `squash` command.\n\nHope it explains the working.\n\nThanks and Regards,\nCharvi\n"},{"id":"414701","messageId":"8fd2b72c-d1d0-98be-e6a5-fb7dc699d5d5@xiplink.com","threadId":"54958","inReplyTo":"20210119074102.21598-10-charvi077@gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2021-01-19T14:37:48Z","receivedAt":"2021-01-19T18:42:58Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"Hi!\n\nOn 2021-01-19 2:41 a.m., Charvi Mendiratta wrote:\n> Mentored-by: Christian Couder <chriscool@tuxfamily.org>\n> Mentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 12 +++++++++---\n>   1 file changed, 9 insertions(+), 3 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index a0487b5cc5..776507e0cc 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -887,9 +887,15 @@ If you want to fold two or more commits into one, replace the command\n>   \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n>   If the commits had different authors, the folded commit will be\n>   attributed to the author of the first commit.  The suggested commit\n> -message for the folded commit is the concatenation of the commit\n> -messages of the first commit and of those with the \"squash\" command,\n> -but omits the commit messages of commits with the \"fixup\" command.\n> +message for the folded commit is created as follows:\n> +\n> + - It is made using the commit message of a commit with the \"fixup -C\"\n> +   or \"fixup -c\" command. In the later case an editor is opened to edit\n> +   the commit message.\n\ns/later/latter/\n\nWhat happens if there is more than one \"fixup -C/-c\" command?\n\nThanks for this work!\n\n\t\tM.\n\n> + - Otherwise it's the concatenation of the commit messages of the first\n> +   commit and of those with the \"squash\" command.\n> + - It omits the commit messages of commits with the \"fixup\"\n> +   (without -C or -c) command.\n>   \n>   'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n>   when a command fails due to merge errors. When you are done editing\n> \n"},{"id":"414732","messageId":"a9bc4d25-f2ec-6a8f-4969-7704f12d667b@xiplink.com","threadId":"54958","inReplyTo":"CAPSFM5euGE_bUDPgdzx4-q5zYtkDymHdJP9rw-YkVVVzpOKWkw@mail.gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2021-01-19T22:05:51Z","receivedAt":"2021-01-19T22:07:31Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"On 2021-01-19 12:13 p.m., Charvi Mendiratta wrote:\n> Hi Marc,\n> \n> On Tue, 19 Jan 2021 at 20:07, Marc Branchaud <marcnarc@xiplink.com> wrote:\n> [...]\n>>>    \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n>>>    If the commits had different authors, the folded commit will be\n>>>    attributed to the author of the first commit.  The suggested commit\n>>> -message for the folded commit is the concatenation of the commit\n>>> -messages of the first commit and of those with the \"squash\" command,\n>>> -but omits the commit messages of commits with the \"fixup\" command.\n>>> +message for the folded commit is created as follows:\n>>> +\n>>> + - It is made using the commit message of a commit with the \"fixup -C\"\n>>> +   or \"fixup -c\" command. In the later case an editor is opened to edit\n>>> +   the commit message.\n>>\n>> s/later/latter/\n>>\n> \n> Thanks, will fix it.\n> \n>> What happens if there is more than one \"fixup -C/-c\" command?\n>>\n> \n> Upon running interactive rebase, in todo list if we use for example sequence of\n> commands like `fixup -C`, `fixup -C` , `fixup -C` then it will fixup\n> content of all and\n> for commit message it will replace with the commit message of end `fixup -C`\n> \n> Similarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\n> then also it will fixup\n> up all the content and here it allow user to edit the message, so\n> opens the editor once\n> in this case and shows the commit msg of end `fixup -c` to edit and\n> also contains\n> commented commit messages of complete fixup chain. So, for any sequence of fixup\n> chains `fixup -c` works as similar to the `squash` command.\n> \n> Hope it explains the working.\n\nYes, that does explain things.\n\nI'm also under the impression that the \"fixup -C/-c\" commit's patch is \nstill incorporated into the folded commit.  Is that right?\n\nSo I think the documentation could be improved.  Assuming that a \"fixup \n-C/-c\" commit's patch is incorporated just like with plain \"fixup\", \nsomething like:\n\nThe suggested commit message for the folded commit is the concatenation \nof the first commit's message with those identified by \"squash\" \ncommands, omitting the messages of commits identified by \"fixup\" \ncommands, `unless` \"fixup -c\" is used.  In that case the suggested \ncommit message is `only` the message of the \"fixup -c\" commit, and an \neditor is opened allowing you to edit the message.  The contents (patch) \nof the \"fixup -c\" commit are still incorporated into the folded commit. \n  If there is more than one \"fixup -c\" commit, the message from the last \nlast one is used.  You can also use \"fixup -C\" to get the same behavior \nas \"fixup -c\" except without opening an editor.\n\nThanks!\n\n\t\tM.\n\n"},{"id":"414779","messageId":"CAPSFM5e8pKQ-HLuhONsChrkLb7Q6LxV7YbrF0RJx6TKOOy=rJQ@mail.gmail.com","threadId":"54958","inReplyTo":"a9bc4d25-f2ec-6a8f-4969-7704f12d667b@xiplink.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-20T07:10:15Z","receivedAt":"2021-01-20T07:11:12Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Wed, 20 Jan 2021 at 03:35, Marc Branchaud <marcnarc@xiplink.com> wrote:\n\n[...]\n> I'm also under the impression that the \"fixup -C/-c\" commit's patch is\n> still incorporated into the folded commit.  Is that right?\n>\n\nyes, it's still incorporated into the folded commit, as it just adds\noptions to the `fixup` command to replace or edit the commit message.\n\n> So I think the documentation could be improved.  Assuming that a \"fixup\n> -C/-c\" commit's patch is incorporated just like with plain \"fixup\",\n> something like:\n>\n> The suggested commit message for the folded commit is the concatenation\n> of the first commit's message with those identified by \"squash\"\n> commands, omitting the messages of commits identified by \"fixup\"\n> commands, `unless` \"fixup -c\" is used.  In that case the suggested\n> commit message is `only` the message of the \"fixup -c\" commit, and an\n> editor is opened allowing you to edit the message.  The contents (patch)\n> of the \"fixup -c\" commit are still incorporated into the folded commit.\n>   If there is more than one \"fixup -c\" commit, the message from the last\n> last one is used.  You can also use \"fixup -C\" to get the same behavior\n> as \"fixup -c\" except without opening an editor.\n>\n\nI agree, this is now more clear and explains for more than one `fixup\n[-C|-c]` or `squash` command also. Thanks for the suggestions, I will\nchange this in the next revision.\n\nThanks and Regards,\nCharvi\n"},{"id":"414787","messageId":"7c11da69-d2f1-0aab-80bc-d8ae8735f8ca@gmail.com","threadId":"54958","inReplyTo":"CAPSFM5euGE_bUDPgdzx4-q5zYtkDymHdJP9rw-YkVVVzpOKWkw@mail.gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-20T11:04:48Z","receivedAt":"2021-01-20T11:35:48Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Charvi\n\nOn 19/01/2021 17:13, Charvi Mendiratta wrote:\n> Hi Marc,\n> \n> On Tue, 19 Jan 2021 at 20:07, Marc Branchaud <marcnarc@xiplink.com> wrote:\n> [...]\n>>>    \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n>>>    If the commits had different authors, the folded commit will be\n>>>    attributed to the author of the first commit.  The suggested commit\n>>> -message for the folded commit is the concatenation of the commit\n>>> -messages of the first commit and of those with the \"squash\" command,\n>>> -but omits the commit messages of commits with the \"fixup\" command.\n>>> +message for the folded commit is created as follows:\n>>> +\n>>> + - It is made using the commit message of a commit with the \"fixup -C\"\n>>> +   or \"fixup -c\" command. In the later case an editor is opened to edit\n>>> +   the commit message.\n>>\n>> s/later/latter/\n>>\n> \n> Thanks, will fix it.\n> \n>> What happens if there is more than one \"fixup -C/-c\" command?\n>>\n> \n> Upon running interactive rebase, in todo list if we use for example sequence of\n> commands like `fixup -C`, `fixup -C` , `fixup -C` then it will fixup\n> content of all and\n> for commit message it will replace with the commit message of end `fixup -C`\n> \n> Similarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\n> then also it will fixup\n> up all the content and here it allow user to edit the message, so\n> opens the editor once\n\nIt is good that we only open the editor once in this case - I'd not \nthought about chains of `fixup -c` before reading this. Do we have a \ntest to verify that the editor is only opened once?\n\nBest Wishes\n\nPhillip\n\n> in this case and shows the commit msg of end `fixup -c` to edit and\n> also contains\n> commented commit messages of complete fixup chain. So, for any sequence of fixup\n> chains `fixup -c` works as similar to the `squash` command.\n> \n> Hope it explains the working.\n> \n> Thanks and Regards,\n> Charvi\n> \n"},{"id":"414789","messageId":"CAPSFM5f9JJk5xY-f2mNwHjZZfo-=LzSCpA2Q73T-ASGMxfqqeg@mail.gmail.com","threadId":"54958","inReplyTo":"7c11da69-d2f1-0aab-80bc-d8ae8735f8ca@gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-20T12:31:35Z","receivedAt":"2021-01-20T13:00:15Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Phillip,\n\nOn Wed, 20 Jan 2021 at 16:34, Phillip Wood <phillip.wood123@gmail.com> wrote:\n\n> >[...]\n> > Similarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\n> > then also it will fixup\n> > up all the content and here it allow user to edit the message, so\n> > opens the editor once\n>\n> It is good that we only open the editor once in this case - I'd not\n> thought about chains of `fixup -c` before reading this. Do we have a\n> test to verify that the editor is only opened once?\n>\n\nNo, we don't. But I also agree, it's a good idea to add a test for it.\nI think may be one sequence with 'fixup -C', 'fixup -c', 'fixup -c'\nand the other 'squash' , 'fixup -C', 'fixup -c', is sufficient for\ntesting. Or any other suggestions for testing it ?\n\nThanks and regards,\nCharvi\n"},{"id":"414801","messageId":"fda55ef5-ce37-67c0-f49b-fc2e5172853b@gmail.com","threadId":"54958","inReplyTo":"CAPSFM5f9JJk5xY-f2mNwHjZZfo-=LzSCpA2Q73T-ASGMxfqqeg@mail.gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-20T14:29:12Z","receivedAt":"2021-01-20T15:38:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Charvi\n\nOn 20/01/2021 12:31, Charvi Mendiratta wrote:\n> Hi Phillip,\n> \n> On Wed, 20 Jan 2021 at 16:34, Phillip Wood <phillip.wood123@gmail.com> wrote:\n> \n>>> [...]\n>>> Similarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\n>>> then also it will fixup\n>>> up all the content and here it allow user to edit the message, so\n>>> opens the editor once\n>>\n>> It is good that we only open the editor once in this case - I'd not\n>> thought about chains of `fixup -c` before reading this. Do we have a\n>> test to verify that the editor is only opened once?\n>>\n> \n> No, we don't. But I also agree, it's a good idea to add a test for it.\n> I think may be one sequence with 'fixup -C', 'fixup -c', 'fixup -c'\n> and the other 'squash' , 'fixup -C', 'fixup -c', is sufficient for\n> testing.\n\nThose are both good sequences to test. I think we should check 'fixup \n-c' 'fixup' as well - with 'squash' 'fixup' we open the editor after the \nfixup so the user can see all the changes that will be committed when \nthey edit the message, we should do the same for 'fixup -c' 'fixup'. \nAlso 'fixup -c' 'squash' might be worth testing as well.\n\nBest Wishes\n\nPhillip\n\n\n  Or any other suggestions for testing it ?\n> \n> Thanks and regards,\n> Charvi\n> \n"},{"id":"414808","messageId":"CAPSFM5eOVmL+6zLJ0xj5Y43vJzPVmPpfgSw_05CuAOMZgRrRHg@mail.gmail.com","threadId":"54958","inReplyTo":"fda55ef5-ce37-67c0-f49b-fc2e5172853b@gmail.com","subject":"Re: [PATCH v2 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-20T16:09:23Z","receivedAt":"2021-01-20T16:12:27Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Wed, 20 Jan 2021 at 19:59, Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> Hi Charvi\n>\n> On 20/01/2021 12:31, Charvi Mendiratta wrote:\n> > Hi Phillip,\n> >\n> > On Wed, 20 Jan 2021 at 16:34, Phillip Wood <phillip.wood123@gmail.com> wrote:\n> >\n> >>> [...]\n> >>> Similarly, if we have sequence like `fixup -c`, `fixup -c`, `fixup -c`\n> >>> then also it will fixup\n> >>> up all the content and here it allow user to edit the message, so\n> >>> opens the editor once\n> >>\n> >> It is good that we only open the editor once in this case - I'd not\n> >> thought about chains of `fixup -c` before reading this. Do we have a\n> >> test to verify that the editor is only opened once?\n> >>\n> >\n> > No, we don't. But I also agree, it's a good idea to add a test for it.\n> > I think may be one sequence with 'fixup -C', 'fixup -c', 'fixup -c'\n> > and the other 'squash' , 'fixup -C', 'fixup -c', is sufficient for\n> > testing.\n>\n> Those are both good sequences to test. I think we should check 'fixup\n> -c' 'fixup' as well - with 'squash' 'fixup' we open the editor after the\n> fixup so the user can see all the changes that will be committed when\n> they edit the message, we should do the same for 'fixup -c' 'fixup'.\n> Also 'fixup -c' 'squash' might be worth testing as well.\n>\n\nAgree, I will add these two test cases also and send the next revision of\npatches.\n\nThanks for reviews!\n\nThanks and Regards,\nCharvi\n"},{"id":"414875","messageId":"xmqqmtx3dq83.fsf@gitster.c.googlers.com","threadId":"54958","inReplyTo":"20210119074102.21598-4-charvi077@gmail.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-01-21T01:38:04Z","receivedAt":"2021-01-21T03:45:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Charvi Mendiratta <charvi077@gmail.com> writes:\n\n> +static size_t subject_length(const char *body)\n> +{\n> +\tsize_t i, len = 0;\n> +\tchar c;\n> +\tint blank_line = 1;\n> +\tfor (i = 0, c = body[i]; c; c = body[++i]) {\n> +\t\tif (c == '\\n') {\n> +\t\t\tif (blank_line)\n> +\t\t\t\treturn len;\n> +\t\t\tlen = i + 1;\n> +\t\t\tblank_line = 1;\n> +\t\t} else if (!isspace(c)) {\n> +\t\t\tblank_line = 0;\n> +\t\t}\n> +\t}\n> +\treturn blank_line ? len : i;\n> +}\n\nI cannot quite tell what this loop is trying to compute at the first\nglance.\n\n - If body[0] == '\\n', then i==0, c==LF, blank_line==1 and len==0\n   so len==0 is returned immediately.\n\n - If the first line has only SP, HT, CR, etc. whitespace,\n   blank_line stays 1 and at the end of the line when we see\n   c=='\\n', body[i] is pointing at that '\\n', blank_line is true, so\n   len is returned from the previous iteration (e.g. body=\"   \\n\"\n   returns 0)\n\n - If the first line has some non space, blank_line becomes false,\n   so at the end of that line when we see c=='\\n', body[i] is\n   pointing at that '\\n', len==i+1 becomes one past that LF and then\n   we reset blank_line to true??? and go on to the next line.\n\nSo when we see LF, if we have seen any non whitespace byte on that\nline, blank_line is false.  Only when we saw LF followed by zero or\nmore whitespace before seeing another LF, we return len that was set\nwhen we saw the previous LF (which is one past that LF).\n    \nSo... is this trying to find the first paragraph-break-looking line\nto find the end of the first paragraph.  OK.\n\nThere must be an easier-to-read way to write all this, though, I\nwould think (or don't we already have an existing code that is\nwaiting to be factored out?).\n\nIn any case, let's keep reading.\n\n>  static void append_squash_message(struct strbuf *buf, const char *body,\n>  \t\t\t\t  struct replay_opts *opts)\n>  {\n> +\tsize_t commented_len = 0;\n> +\n>  \tunlink(rebase_path_fixup_msg());\n> +\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> +\t\tcommented_len = subject_length(body);\n>  \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n>  \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n>  \t\t    ++opts->current_fixup_count + 1);\n>  \tstrbuf_addstr(buf, \"\\n\\n\");\n> -\tstrbuf_addstr(buf, body);\n> +\tstrbuf_add_commented_lines(buf, body, commented_len);\n\nAs add_commented_lines places the comment character at the beginning\nof each line, it is OK for body[0..commented_len) to contain more than\none lines.  Good.\n\n> +\tstrbuf_addstr(buf, body + commented_len);\n\nAnd we add everything after the beginning of the paragraph-break\nlooking line.  This code may add a line, immediately after the\nprevious \"commented out\" block, bunch of whitespaces and then a LF.\nIt will be cleaned up with stripspace most of the time, but\ndepending on the end-user settings, it may be left behind.  I am\nguessing that is what we want, but thought it would not hurt to\ndouble check.\n\n> diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\n> index 7bab6000dc..551dc06bc3 100755\n> --- a/t/t3415-rebase-autosquash.sh\n> +++ b/t/t3415-rebase-autosquash.sh\n> @@ -81,8 +81,7 @@ test_auto_squash () {\n>  \techo 1 >file1 &&\n>  \tgit add -u &&\n>  \ttest_tick &&\n> -\tgit commit -m \"squash! first\" &&\n> -\n> +\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n\nIt is not \"extra\"; that's the beginning of the \"body\" ;-).\n\n>  \tgit tag $1 &&\n>  \ttest_tick &&\n>  \tgit rebase $2 -i HEAD^^^ &&\n> @@ -139,7 +138,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n>  \techo 1 >file1 &&\n>  \tgit add -u &&\n>  \ttest_tick &&\n> -\tgit commit -m \"squash! first\" &&\n> +\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n>  \tgit tag final-multisquash &&\n>  \ttest_tick &&\n>  \tgit rebase --autosquash -i HEAD~4 &&\n> @@ -192,7 +191,7 @@ test_expect_success 'auto squash that matches a sha1' '\n>  \tgit add -u &&\n>  \ttest_tick &&\n>  \toid=$(git rev-parse --short HEAD^) &&\n> -\tgit commit -m \"squash! $oid\" &&\n> +\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n>  \tgit tag final-shasquash &&\n>  \ttest_tick &&\n>  \tgit rebase --autosquash -i HEAD^^^ &&\n> @@ -203,7 +202,8 @@ test_expect_success 'auto squash that matches a sha1' '\n>  \tgit cat-file blob HEAD^:file1 >actual &&\n>  \ttest_cmp expect actual &&\n>  \tgit cat-file commit HEAD^ >commit &&\n> -\tgrep squash commit >actual &&\n> +\tgrep -v \"squash\" commit &&\n\nThis says that the file must have at least one line that does not\nsay \"squash\" or the test is a failure.  It does not say \"there\nshould be no line that has \"squash\" on it\".  Intended?\n\n> +\tgrep \"extra para\" commit >actual &&\n\nI can tell that you want the \"extra para\" to still remain, but how\ndoes the grep that is not anchored guarantee that?  Perhaps look for\n\n\tgrep \"^extra para\" commit\n\nto ensure that you are not seeing a commented out but somehow failed\nto get stripspaced out?\n\n>  \ttest_line_count = 1 actual\n>  '\n\nThanks.\n"},{"id":"414901","messageId":"CAPSFM5cxTrvAq6j3yhzidWdr8P8-sYmd1-9tmsK4iXMKrC7TNA@mail.gmail.com","threadId":"54958","inReplyTo":"xmqqmtx3dq83.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-21T14:02:15Z","receivedAt":"2021-01-21T14:03:56Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Junio,\n\nOn Thu, 21 Jan 2021 at 07:08, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Charvi Mendiratta <charvi077@gmail.com> writes:\n>\n> > +static size_t subject_length(const char *body)\n> > +{\n> > +     size_t i, len = 0;\n> > +     char c;\n> > +     int blank_line = 1;\n> > +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> > +             if (c == '\\n') {\n> > +                     if (blank_line)\n> > +                             return len;\n> > +                     len = i + 1;\n> > +                     blank_line = 1;\n> > +             } else if (!isspace(c)) {\n> > +                     blank_line = 0;\n> > +             }\n> > +     }\n> > +     return blank_line ? len : i;\n> > +}\n>\n> I cannot quite tell what this loop is trying to compute at the first\n> glance.\n>\n\nOops, I think Phillip and Christian also pointed in the last revision\nto look for alternatives to make it easy. I mistook that point and\nforgot to look at it.\n\n>  - If body[0] == '\\n', then i==0, c==LF, blank_line==1 and len==0\n>    so len==0 is returned immediately.\n>\n>  - If the first line has only SP, HT, CR, etc. whitespace,\n>    blank_line stays 1 and at the end of the line when we see\n>    c=='\\n', body[i] is pointing at that '\\n', blank_line is true, so\n>    len is returned from the previous iteration (e.g. body=\"   \\n\"\n>    returns 0)\n>\n\nyes, it returns the same result as given in this example (But I am\nnot sure what you are taking \" SP, HT, CR, etc \" ? otherwise if its\nwhitespace, then its works the same).\n\n>  - If the first line has some non space, blank_line becomes false,\n>    so at the end of that line when we see c=='\\n', body[i] is\n>    pointing at that '\\n', len==i+1 becomes one past that LF and then\n>    we reset blank_line to true??? and go on to the next line.\n>\n> So when we see LF, if we have seen any non whitespace byte on that\n> line, blank_line is false.  Only when we saw LF followed by zero or\n> more whitespace before seeing another LF, we return len that was set\n> when we saw the previous LF (which is one past that LF).\n>\n> So... is this trying to find the first paragraph-break-looking line\n> to find the end of the first paragraph.  OK.\n>\n\nI followed and agreed with the above.\n\n> There must be an easier-to-read way to write all this, though, I\n> would think (or don't we already have an existing code that is\n> waiting to be factored out?).\n>\n\nI look into the code again and wonder if we can change this function like this :\n\nstatic int subject_length(const char *body)\n{\n               const char *p = body;\n               while (*p) {\n                if (*p == '\\n' && p[1] =='\\n') {\n                            break;\n                } else {\n                            p++;\n               }\n               }\n               return p - body;\n}\n\nI think checking again '\\n' will also serve the purpose as we separate\nthe commit message subject and its body with the newline. Also, this\nis also\ntrue that this function is only called when the message starts with\n(squash! or amend! or fixup!)\n\n> In any case, let's keep reading.\n>\n> >  static void append_squash_message(struct strbuf *buf, const char *body,\n> >                                 struct replay_opts *opts)\n> >  {\n> > +     size_t commented_len = 0;\n> > +\n> >       unlink(rebase_path_fixup_msg());\n> > +     if (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n> > +             commented_len = subject_length(body);\n> >       strbuf_addf(buf, \"\\n%c \", comment_line_char);\n> >       strbuf_addf(buf, _(\"This is the commit message #%d:\"),\n> >                   ++opts->current_fixup_count + 1);\n> >       strbuf_addstr(buf, \"\\n\\n\");\n> > -     strbuf_addstr(buf, body);\n> > +     strbuf_add_commented_lines(buf, body, commented_len);\n>\n> As add_commented_lines places the comment character at the beginning\n> of each line, it is OK for body[0..commented_len) to contain more than\n> one lines.  Good.\n>\n> > +     strbuf_addstr(buf, body + commented_len);\n>\n> And we add everything after the beginning of the paragraph-break\n> looking line.  This code may add a line, immediately after the\n> previous \"commented out\" block, bunch of whitespaces and then a LF.\n> It will be cleaned up with stripspace most of the time, but\n> depending on the end-user settings, it may be left behind.  I am\n> guessing that is what we want, but thought it would not hurt to\n> double check.\n>\n\nI agree this working does the same and comments out the subject of the\ncommit message starting with squash! or fixup! or amend!, upon\nsquashing the two or more commits.\n\n> > diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\n> > index 7bab6000dc..551dc06bc3 100755\n> > --- a/t/t3415-rebase-autosquash.sh\n> > +++ b/t/t3415-rebase-autosquash.sh\n> > @@ -81,8 +81,7 @@ test_auto_squash () {\n> >       echo 1 >file1 &&\n> >       git add -u &&\n> >       test_tick &&\n> > -     git commit -m \"squash! first\" &&\n> > -\n> > +     git commit -m \"squash! first\" -m \"extra para for first\" &&\n>\n> It is not \"extra\"; that's the beginning of the \"body\" ;-).\n>\n\nOkay, maybe we can use \"message body\" here.\n\n> >       git tag $1 &&\n> >       test_tick &&\n> >       git rebase $2 -i HEAD^^^ &&\n> > @@ -139,7 +138,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n> >       echo 1 >file1 &&\n> >       git add -u &&\n> >       test_tick &&\n> > -     git commit -m \"squash! first\" &&\n> > +     git commit -m \"squash! first\" -m \"extra para for first\" &&\n> >       git tag final-multisquash &&\n> >       test_tick &&\n> >       git rebase --autosquash -i HEAD~4 &&\n> > @@ -192,7 +191,7 @@ test_expect_success 'auto squash that matches a sha1' '\n> >       git add -u &&\n> >       test_tick &&\n> >       oid=$(git rev-parse --short HEAD^) &&\n> > -     git commit -m \"squash! $oid\" &&\n> > +     git commit -m \"squash! $oid\" -m \"extra para\" &&\n> >       git tag final-shasquash &&\n> >       test_tick &&\n> >       git rebase --autosquash -i HEAD^^^ &&\n> > @@ -203,7 +202,8 @@ test_expect_success 'auto squash that matches a sha1' '\n> >       git cat-file blob HEAD^:file1 >actual &&\n> >       test_cmp expect actual &&\n> >       git cat-file commit HEAD^ >commit &&\n> > -     grep squash commit >actual &&\n> > +     grep -v \"squash\" commit &&\n>\n> This says that the file must have at least one line that does not\n> say \"squash\" or the test is a failure.  It does not say \"there\n> should be no line that has \"squash\" on it\".  Intended?\n>\n\nOhh yes ..\n\n> > +     grep \"extra para\" commit >actual &&\n>\n> I can tell that you want the \"extra para\" to still remain, but how\n> does the grep that is not anchored guarantee that?\n\n.. but now I think to remove this `grep -v \"squash\" commit` as also\ndiscussed with Phillip earlier that in this test script we are not\nchecking for the commented commit message.\n\n> Perhaps look for\n>\n>         grep \"^extra para\" commit\n>\n> to ensure that you are not seeing a commented out but somehow failed\n> to get stripspaced out?\n>\nI am not sure, what does failing to get stripspaced mean?\n\nThanks for the review !\n\nThanks and Regards,\nCharvi\n"},{"id":"414905","messageId":"CAP8UFD3PRaiCiSfSMaX0FDrEcOz2xv3992meum7qnKve1rK6nw@mail.gmail.com","threadId":"54958","inReplyTo":"CAPSFM5cxTrvAq6j3yhzidWdr8P8-sYmd1-9tmsK4iXMKrC7TNA@mail.gmail.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-01-21T15:21:16Z","receivedAt":"2021-01-21T15:22:46Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Thu, Jan 21, 2021 at 3:02 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n>\n> Hi Junio,\n>\n> On Thu, 21 Jan 2021 at 07:08, Junio C Hamano <gitster@pobox.com> wrote:\n> >\n> > Charvi Mendiratta <charvi077@gmail.com> writes:\n> >\n> > > +static size_t subject_length(const char *body)\n> > > +{\n> > > +     size_t i, len = 0;\n> > > +     char c;\n> > > +     int blank_line = 1;\n> > > +     for (i = 0, c = body[i]; c; c = body[++i]) {\n> > > +             if (c == '\\n') {\n> > > +                     if (blank_line)\n> > > +                             return len;\n> > > +                     len = i + 1;\n> > > +                     blank_line = 1;\n> > > +             } else if (!isspace(c)) {\n> > > +                     blank_line = 0;\n> > > +             }\n> > > +     }\n> > > +     return blank_line ? len : i;\n> > > +}\n> >\n> > I cannot quite tell what this loop is trying to compute at the first\n> > glance.\n> >\n>\n> Oops, I think Phillip and Christian also pointed in the last revision\n> to look for alternatives to make it easy. I mistook that point and\n> forgot to look at it.\n\nYes, please take a look at find_commit_subject() in \"commit.c\".\n\n> > > +     grep \"extra para\" commit >actual &&\n> >\n> > I can tell that you want the \"extra para\" to still remain, but how\n> > does the grep that is not anchored guarantee that?\n>\n> .. but now I think to remove this `grep -v \"squash\" commit` as also\n> discussed with Phillip earlier that in this test script we are not\n> checking for the commented commit message.\n>\n> > Perhaps look for\n> >\n> >         grep \"^extra para\" commit\n> >\n> > to ensure that you are not seeing a commented out but somehow failed\n> > to get stripspaced out?\n> >\n> I am not sure, what does failing to get stripspaced mean?\n\nI think this refers to:\n\nhttps://git-scm.com/docs/git-stripspace\n\nBest,\nChristian.\n"},{"id":"414913","messageId":"3853a4a0-dca4-4d8c-a9da-6608a9385f38@gmail.com","threadId":"54958","inReplyTo":"CAP8UFD3PRaiCiSfSMaX0FDrEcOz2xv3992meum7qnKve1rK6nw@mail.gmail.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-01-21T16:58:11Z","receivedAt":"2021-01-21T16:59:27Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Christian and Charvi\n\nOn 21/01/2021 15:21, Christian Couder wrote:\n> On Thu, Jan 21, 2021 at 3:02 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n>>\n>> Hi Junio,\n>>\n>> On Thu, 21 Jan 2021 at 07:08, Junio C Hamano <gitster@pobox.com> wrote:\n>>>\n>>> Charvi Mendiratta <charvi077@gmail.com> writes:\n>>>\n>>>> +static size_t subject_length(const char *body)\n>>>> +{\n>>>> +     size_t i, len = 0;\n>>>> +     char c;\n>>>> +     int blank_line = 1;\n>>>> +     for (i = 0, c = body[i]; c; c = body[++i]) {\n>>>> +             if (c == '\\n') {\n>>>> +                     if (blank_line)\n>>>> +                             return len;\n>>>> +                     len = i + 1;\n>>>> +                     blank_line = 1;\n>>>> +             } else if (!isspace(c)) {\n>>>> +                     blank_line = 0;\n>>>> +             }\n>>>> +     }\n>>>> +     return blank_line ? len : i;\n>>>> +}\n>>>\n>>> I cannot quite tell what this loop is trying to compute at the first\n>>> glance.\n>>>\n>>\n>> Oops, I think Phillip and Christian also pointed in the last revision\n>> to look for alternatives to make it easy. I mistook that point and\n>> forgot to look at it.\n> \n> Yes, please take a look at find_commit_subject() in \"commit.c\".\n\nThat looks like it is taking the commit header and finding the start of \nthe message. We have just the message, I think we probably want to use \nformat_subject() in pretty.c which does what my hard to follow code does \nwith the option to replace newlines in the subject with another character.\n\nBest Wishes\n\nPhillip\n\n>>>> +     grep \"extra para\" commit >actual &&\n>>>\n>>> I can tell that you want the \"extra para\" to still remain, but how\n>>> does the grep that is not anchored guarantee that?\n>>\n>> .. but now I think to remove this `grep -v \"squash\" commit` as also\n>> discussed with Phillip earlier that in this test script we are not\n>> checking for the commented commit message.\n>>\n>>> Perhaps look for\n>>>\n>>>          grep \"^extra para\" commit\n>>>\n>>> to ensure that you are not seeing a commented out but somehow failed\n>>> to get stripspaced out?\n>>>\n>> I am not sure, what does failing to get stripspaced mean?\n> \n> I think this refers to:\n> \n> https://git-scm.com/docs/git-stripspace\n> \n> Best,\n> Christian.\n> \n"},{"id":"414924","messageId":"xmqqwnw6au1d.fsf@gitster.c.googlers.com","threadId":"54958","inReplyTo":"CAP8UFD3PRaiCiSfSMaX0FDrEcOz2xv3992meum7qnKve1rK6nw@mail.gmail.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-01-21T20:56:14Z","receivedAt":"2021-01-21T21:00:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n>> Oops, I think Phillip and Christian also pointed in the last revision\n>> to look for alternatives to make it easy. I mistook that point and\n>> forgot to look at it.\n>\n> Yes, please take a look at find_commit_subject() in \"commit.c\".\n\nYeah, it uses pretty.c::skip_blank_lines(), which is easy to use.\nso something like a loop that calls skip_blank_lines() to see if it\nreturns a differnt result (which means the argument we fed it was at\nthe beginning of a blank line, which is what this helper wants to\nreturn), and otherwise we advance by one line with strchrnul() and\nretry, perhaps.\n\n    while (*body) {\n\tchar *next = skip_blank_lines(body);\n\tif (next != body)\n\t    break; /* found a blank line */\n\tbody = strchrnul(body, '\\n');\n\tif (*body)\n\t    body++;\n    }\n    /* body has the answer */\n"},{"id":"415011","messageId":"CAPSFM5eOEQFDAhTateUOJt5XHY8dG8QtfjcXc-XEEZtmPmiG0g@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD3PRaiCiSfSMaX0FDrEcOz2xv3992meum7qnKve1rK6nw@mail.gmail.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-22T19:41:24Z","receivedAt":"2021-01-22T22:27:19Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi,\n\nOn Thu, 21 Jan 2021 at 20:51, Christian Couder\n<christian.couder@gmail.com> wrote:\n[...]\n> > > > +     grep \"extra para\" commit >actual &&\n> > >\n> > > I can tell that you want the \"extra para\" to still remain, but how\n> > > does the grep that is not anchored guarantee that?\n> >\n> > .. but now I think to remove this `grep -v \"squash\" commit` as also\n> > discussed with Phillip earlier that in this test script we are not\n> > checking for the commented commit message.\n> >\n> > > Perhaps look for\n> > >\n> > >         grep \"^extra para\" commit\n> > >\n> > > to ensure that you are not seeing a commented out but somehow failed\n> > > to get stripspaced out?\n> > >\n> > I am not sure, what does failing to get stripspaced mean?\n>\n> I think this refers to:\n>\n> https://git-scm.com/docs/git-stripspace\n>\n\nOkay, thanks for referring and also here in this test script - so that\nthe test does not fail\ndue to stripspace, it is using the `test_line_count` function. Also I\nagree with above\nso maybe it is right to just replace with:\n\ngrep \"^extra para\" commit &&\ngrep \"extra para\" commit >actual &&\n\nThanks and Regards,\nCharvi\n"},{"id":"415019","messageId":"CAPSFM5fUnVz7wuMJCULDGOWCzk=cxamqmXFYuCkF0m9rWTYELQ@mail.gmail.com","threadId":"54958","inReplyTo":"xmqqwnw6au1d.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v2 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-22T19:41:54Z","receivedAt":"2021-01-22T22:46:56Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Fri, 22 Jan 2021 at 02:26, Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Christian Couder <christian.couder@gmail.com> writes:\n>\n> >> Oops, I think Phillip and Christian also pointed in the last revision\n> >> to look for alternatives to make it easy. I mistook that point and\n> >> forgot to look at it.\n> >\n> > Yes, please take a look at find_commit_subject() in \"commit.c\".\n>\n> Yeah, it uses pretty.c::skip_blank_lines(), which is easy to use.\n> so something like a loop that calls skip_blank_lines() to see if it\n> returns a differnt result (which means the argument we fed it was at\n> the beginning of a blank line, which is what this helper wants to\n> return), and otherwise we advance by one line with strchrnul() and\n> retry, perhaps.\n>\n>     while (*body) {\n>         char *next = skip_blank_lines(body);\n>         if (next != body)\n>             break; /* found a blank line */\n>         body = strchrnul(body, '\\n');\n>         if (*body)\n>             body++;\n>     }\n>     /* body has the answer */\n\nThanks for all the pointers. I took time in looking into it, but now I got more\ncleared its actually looks for all the spaces in complete line which\nis considered\nas a blank line and above function explains it more clearly. I will\nupdate the \"subject\nlength\" function as the above way and send in the next revision.\n\nThanks and Regards,\nCharvi\n"},{"id":"415164","messageId":"20210124170405.30583-1-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210119074102.21598-1-charvi077@gmail.com","subject":"[PATCH v3 0/9][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:03:56Z","receivedAt":"2021-01-24T17:06:01Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This patch series adds fixup [-C|-c] options to interactive rebase. In\naddition to amending the contents of the commit as the `fixup` command\ndoes now, `fixup -C` replaces the commit message of the original commit\nwhich we are fixing up with the message of the fixup commit.\nAnd to edit the fixup commit message before committing, `fixup -c`\ncommand is used instead of `fixup -C`. This convention is similar to\nthe existing `merge` command in the interactive rebase, that also supports\n`-c` and `-C` options with similar meanings.\n\nThis patch series also changes `rebase -i --autosquash` to rearrange\ncommits whose message starts with \"amend!\" and replaces the pick\ncommand with `fixup -C`. The creation of \"amend!\" commits will be\nrebase -i: add options to fixup command added in another patch series.\n\nThis is done in reference to the issue opened by Dscho as here[1] and\nfurther discussed briefly[2]. Also, there is discussion[3] regarding the\nimplementation of reword! commit. The past patches of Phillip Wood’s\nwork[4], implements 'reword!' as 'amend!' in git rebase and these patches\nuses those as the initial base.\nAnd to avoid the extra command in the interactive rebase, this patch\nseries instead add options to the current fixup command in interactive\nrebase (fixup [-C | -c]) as discussed earlier[5].\n\nChanges from v2 :\n\n(Thanks to Junio C Hamano, Marc Branchaud, Christian Couder, Phillip Wood\nand Taylor Blau for the reviews and suggestions)\n\n* Updated the Documentation/git-rebase.txt\n* Added tests(t3437-rebase-fixup-options.sh) to check working of multiple\n  fixup -c in rebase -i and related changes in sequencer.c\n* Updated subject_length() function in sequencer.c and some corrections in\n  t3415-rebase-autosquash.sh\n\n[1] https://github.com/gitgitgadget/git/issues/259\n[2] https://public-inbox.org/git/alpine.DEB.2.21.1.1710151754070.40514@virtualbox/\n[3] https://lore.kernel.org/git/95cc6fb2-d1bc-11de-febe-c2b5c78a6850@gmail.com/\n[4] https://github.com/phillipwood/git/commits/wip/rebase-amend\n[5] https://lore.kernel.org/git/29fc2f59-1cca-a3db-5586-bbd7b2e4806d@gmail.com/\n\n\nCharvi Mendiratta (6):\n  sequencer: pass todo_item to do_pick_commit()\n  sequencer: use const variable for commit message comments\n  rebase -i: add fixup [-C | -c] command\n  t3437: test script for fixup [-C|-c] options in interactive rebase\n  rebase -i: teach --autosquash to work with amend!\n  doc/git-rebase: add documentation for fixup [-C|-c] options\n\nPhillip Wood (3):\n  rebase -i: only write fixup-message when it's needed\n  sequencer: factor out code to append squash message\n  rebase -i: comment out squash!/fixup! subjects from squash message\n\n Documentation/git-rebase.txt      |  14 +-\n rebase-interactive.c              |   4 +-\n sequencer.c                       | 295 ++++++++++++++++++++++++++----\n t/lib-rebase.sh                   |   4 +\n t/t3415-rebase-autosquash.sh      |  30 +--\n t/t3437-rebase-fixup-options.sh   | 225 +++++++++++++++++++++++\n t/t3437/expected-combined-message |  21 +++\n t/t3437/expected-squash-message   |  51 ++++++\n t/t3900-i18n-commit.sh            |   4 -\n 9 files changed, 587 insertions(+), 61 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n create mode 100644 t/t3437/expected-squash-message\n\n--\n2.29.0.rc1\n\n"},{"id":"415165","messageId":"20210124170405.30583-2-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:03:59Z","receivedAt":"2021-01-24T17:06:59Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThe file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\ncommands, there's no point in writing it for squash commands as it is\nimmediately deleted.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8909a46770..a59e0c84af 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1757,11 +1757,10 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (write_message(body, strlen(body),\n-\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n+\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n-\t\t\treturn error(_(\"cannot write '%s'\"),\n-\t\t\t\t     rebase_path_fixup_msg());\n+\t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-- \n2.29.0.rc1\n\n"},{"id":"415166","messageId":"20210124170405.30583-3-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 2/9] sequencer: factor out code to append squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:00Z","receivedAt":"2021-01-24T17:07:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis code is going to grow over the next two commits so move it to\nits own function.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex a59e0c84af..08cce40834 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,17 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static void append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t\t  struct replay_opts *opts)\n+{\n+\tunlink(rebase_path_fixup_msg());\n+\tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n+\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\t\t    ++opts->current_fixup_count + 1);\n+\tstrbuf_addstr(buf, \"\\n\\n\");\n+\tstrbuf_addstr(buf, body);\n+}\n+\n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n@@ -1779,12 +1790,7 @@ static int update_squash_messages(struct repository *r,\n \tfind_commit_subject(message, &body);\n \n \tif (command == TODO_SQUASH) {\n-\t\tunlink(rebase_path_fixup_msg());\n-\t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is the commit message #%d:\"),\n-\t\t\t    ++opts->current_fixup_count + 1);\n-\t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n-- \n2.29.0.rc1\n\n"},{"id":"415167","messageId":"20210124170405.30583-4-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:01Z","receivedAt":"2021-01-24T17:07:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen squashing commit messages the squash!/fixup! subjects are not of\ninterest so comment them out to stop them becoming part of the final\nmessage.\n\nThis change breaks a bunch of --autosquash tests which rely on the\n\"squash! <subject>\" line appearing in the final commit message. This is\naddressed by adding a second line to the commit message of the \"squash!\n...\" commits and testing for that.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                  | 21 ++++++++++++++++++++-\n t/t3415-rebase-autosquash.sh | 30 ++++++++++++++++--------------\n t/t3900-i18n-commit.sh       |  4 ----\n 3 files changed, 36 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 08cce40834..034149f24d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,15 +1718,34 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static size_t subject_length(const char *body)\n+{\n+\tconst char *p = body;\n+\twhile (*p) {\n+\t\tconst char *next = skip_blank_lines(p);\n+\t\tif (next != p)\n+\t\t\tbreak;\n+\t\tp = strchrnul(p, '\\n');\n+\t\tif (*p)\n+\t\t\tp++;\n+\t}\n+\treturn p - body;\n+}\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n+\tsize_t commented_len = 0;\n+\n \tunlink(rebase_path_fixup_msg());\n+\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+\t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_addstr(buf, body);\n+\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_addstr(buf, body + commented_len);\n }\n \n static int update_squash_messages(struct repository *r,\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex 7bab6000dc..a512335527 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -81,8 +81,7 @@ test_auto_squash () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n-\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n \tgit rebase $2 -i HEAD^^^ &&\n@@ -139,7 +138,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag final-multisquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -192,7 +191,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-shasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -203,7 +202,8 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep -v \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -213,7 +213,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short=11 HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-longshasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -224,7 +224,8 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep -v \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -233,7 +234,7 @@ test_auto_commit_flags () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit --$1 first-commit &&\n+\tgit commit --$1 first-commit -m \"extra para for first\" &&\n \tgit tag final-commit-$1 &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -261,11 +262,11 @@ test_auto_fixup_fixup () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! first\" &&\n+\tgit commit -m \"$1! first\" -m \"extra para for first\" &&\n \techo 2 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! $2! first\" &&\n+\tgit commit -m \"$1! $2! first\" -m \"second extra para for first\" &&\n \tgit tag \"final-$1-$2\" &&\n \ttest_tick &&\n \t(\n@@ -326,12 +327,12 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para for first\" &&\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n \tsubject=$(git log -n 1 --format=%s HEAD~2) &&\n-\tgit commit -m \"squash! $subject\" &&\n+\tgit commit -m \"squash! $subject\" -m \"second extra para for first\" &&\n \tgit tag final-squash-instFmt &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -342,8 +343,9 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n-\ttest_line_count = 2 actual\n+\t! grep -v \"squash\" commit &&\n+\tgrep first commit >actual &&\n+\ttest_line_count = 3 actual\n '\n \n test_expect_success 'autosquash with empty custom instructionFormat' '\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex d277a9f4b7..bfab245eb3 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -226,10 +226,6 @@ test_commit_autosquash_multi_encoding () {\n \t\tgit rev-list HEAD >actual &&\n \t\ttest_line_count = 3 actual &&\n \t\ticonv -f $old -t UTF-8 \"$TEST_DIRECTORY\"/t3900/$msg >expect &&\n-\t\tif test $flag = squash; then\n-\t\t\tsubject=\"$(head -1 expect)\" &&\n-\t\t\tprintf \"\\nsquash! %s\\n\" \"$subject\" >>expect\n-\t\tfi &&\n \t\tgit cat-file commit HEAD^ >raw &&\n \t\t(sed \"1,/^$/d\" raw | iconv -f $new -t utf-8) >actual &&\n \t\ttest_cmp expect actual\n-- \n2.29.0.rc1\n\n"},{"id":"415168","messageId":"20210124170405.30583-5-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 4/9] sequencer: pass todo_item to do_pick_commit()","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:02Z","receivedAt":"2021-01-24T17:07:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"As an additional member of the structure todo_item will be required in\nfuture commits pass the complete structure.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 034149f24d..09cbb17f87 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1877,8 +1877,7 @@ static void record_in_rewritten(struct object_id *oid,\n }\n \n static int do_pick_commit(struct repository *r,\n-\t\t\t  enum todo_command command,\n-\t\t\t  struct commit *commit,\n+\t\t\t  struct todo_item *item,\n \t\t\t  struct replay_opts *opts,\n \t\t\t  int final_fixup, int *check_todo)\n {\n@@ -1891,6 +1890,8 @@ static int do_pick_commit(struct repository *r,\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res, unborn = 0, reword = 0, allow, drop_commit;\n+\tenum todo_command command = item->command;\n+\tstruct commit *commit = item->commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -4140,8 +4141,8 @@ static int pick_commits(struct repository *r,\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, reflog_message(opts,\n \t\t\t\t\tcommand_to_string(item->command), NULL),\n \t\t\t\t\t1);\n-\t\t\tres = do_pick_commit(r, item->command, item->commit,\n-\t\t\t\t\t     opts, is_final_fixup(todo_list),\n+\t\t\tres = do_pick_commit(r, item, opts,\n+\t\t\t\t\t     is_final_fixup(todo_list),\n \t\t\t\t\t     &check_todo);\n \t\t\tif (is_rebase_i(opts))\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);\n@@ -4603,11 +4604,14 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n+\tstruct todo_item item;\n+\n+\titem.command = opts->action == REPLAY_PICK ?\n+\t\t\tTODO_PICK : TODO_REVERT;\n+\titem.commit = cmit;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(r, opts->action == REPLAY_PICK ?\n-\t\t\t      TODO_PICK : TODO_REVERT, cmit, opts, 0,\n-\t\t\t      &check_todo);\n+\treturn do_pick_commit(r, &item, opts, 0, &check_todo);\n }\n \n int sequencer_pick_revisions(struct repository *r,\n-- \n2.29.0.rc1\n\n"},{"id":"415169","messageId":"20210124170405.30583-6-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 5/9] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:03Z","receivedAt":"2021-01-24T17:07:34Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This makes it easier to use and reuse the comments.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 09cbb17f87..6d9a10afcf 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1732,6 +1732,11 @@ static size_t subject_length(const char *body)\n \treturn p - body;\n }\n \n+static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n+static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n+static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n@@ -1741,7 +1746,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n \t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n-\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n@@ -1770,7 +1775,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\tbuf.buf : strchrnul(buf.buf, '\\n');\n \n \t\tstrbuf_addf(&header, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&header, _(\"This is a combination of %d commits.\"),\n+\t\tstrbuf_addf(&header, _(combined_commit_msg_fmt),\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n@@ -1794,9 +1799,9 @@ static int update_squash_messages(struct repository *r,\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is a combination of %d commits.\"), 2);\n+\t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(\"This is the 1st commit message:\"));\n+\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_addstr(&buf, body);\n \n@@ -1812,7 +1817,7 @@ static int update_squash_messages(struct repository *r,\n \t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n+\t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n-- \n2.29.0.rc1\n\n"},{"id":"415170","messageId":"20210124170405.30583-7-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:04Z","receivedAt":"2021-01-24T17:07:42Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Add options to `fixup` command to fixup both the commit contents and\nmessage. `fixup -C` command is used to replace the original commit\nmessage and `fixup -c`, additionally allows to edit the commit message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n rebase-interactive.c |   4 +-\n sequencer.c          | 213 +++++++++++++++++++++++++++++++++++++++----\n 2 files changed, 197 insertions(+), 20 deletions(-)\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 762853bc7e..c3bd02adee 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n \"e, edit <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n-\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n+\"                   commit's log message. Use -C to replace with this\\n\"\n+\"                   commit message or -c to edit the commit message\\n\"\n \"x, exec <command> = run command (the rest of the line) using shell\\n\"\n \"b, break = stop here (continue rebase later with 'git rebase --continue')\\n\"\n \"d, drop <commit> = remove commit\\n\"\ndiff --git a/sequencer.c b/sequencer.c\nindex 6d9a10afcf..46e11d20e8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+enum todo_item_flags {\n+\tTODO_EDIT_MERGE_MSG    = (1 << 0),\n+\tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n+\tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+};\n+\n static size_t subject_length(const char *body)\n {\n \tconst char *p = body;\n@@ -1734,32 +1740,176 @@ static size_t subject_length(const char *body)\n \n static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_first_commit_msg_str[] = N_(\"The 1st commit message will be skipped:\");\n static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n \n-static void append_squash_message(struct strbuf *buf, const char *body,\n-\t\t\t\t  struct replay_opts *opts)\n+static int check_fixup_flag(enum todo_command command,\n+\t\t\t    enum todo_item_flags flag)\n+{\n+\treturn command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n+\t\t\t\t\t (flag & TODO_EDIT_FIXUP_MSG));\n+}\n+\n+/*\n+ * Wrapper around strbuf_add_commented_lines() which avoids double\n+ * commenting commit subjects.\n+ */\n+static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n+{\n+\tconst char *s = str;\n+\twhile (len > 0 && s[0] == comment_line_char) {\n+\t\tsize_t count;\n+\t\tconst char *n = memchr(s, '\\n', len);\n+\t\tif (!n)\n+\t\t\tcount = len;\n+\t\telse\n+\t\t\tcount = n - s + 1;\n+\t\tstrbuf_add(buf, s, count);\n+\t\ts += count;\n+\t\tlen -= count;\n+\t}\n+\tstrbuf_add_commented_lines(buf, s, len);\n+}\n+\n+/* Does the current fixup chain contain a squash command? */\n+static int seen_squash(struct replay_opts *opts)\n+{\n+\treturn starts_with(opts->current_fixups.buf, \"squash\") ||\n+\t\tstrstr(opts->current_fixups.buf, \"\\nsquash\");\n+}\n+\n+static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n {\n-\tsize_t commented_len = 0;\n+\tstrbuf_setlen(buf1, 2);\n+\tstrbuf_addf(buf1, _(nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf1, '\\n');\n+\tstrbuf_setlen(buf2, 2);\n+\tstrbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf2, '\\n');\n+}\n \n-\tunlink(rebase_path_fixup_msg());\n-\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+/*\n+ * Comment out any un-commented commit messages, updating the message comments\n+ * to say they will be skipped but do not comment out the empty lines that\n+ * surround commit messages and their comments.\n+ */\n+static void update_squash_message_for_fixup(struct strbuf *msg)\n+{\n+\tvoid (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;\n+\tstruct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tconst char *s, *start;\n+\tchar *orig_msg;\n+\tsize_t orig_msg_len;\n+\tint i = 1;\n+\n+\tstrbuf_addf(&buf1, \"# %s\\n\", _(first_commit_msg_str));\n+\tstrbuf_addf(&buf2, \"# %s\\n\", _(skip_first_commit_msg_str));\n+\ts = start = orig_msg = strbuf_detach(msg, &orig_msg_len);\n+\twhile (s) {\n+\t\tconst char *next;\n+\t\tsize_t off;\n+\t\tif (skip_prefix(s, buf1.buf, &next)) {\n+\t\t\t/*\n+\t\t\t * Copy the last message, preserving the blank line\n+\t\t\t * preceding the current line\n+\t\t\t */\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tif (off)\n+\t\t\t\tstrbuf_addch(msg, '\\n');\n+\t\t\t/*\n+\t\t\t * The next message needs to be commented out but the\n+\t\t\t * message header is already commented out so just copy\n+\t\t\t * it and the blank line that follows it.\n+\t\t\t */\n+\t\t\tstrbuf_addbuf(msg, &buf2);\n+\t\t\tif (*next == '\\n')\n+\t\t\t\tstrbuf_addch(msg, *next++);\n+\t\t\tstart = s = next;\n+\t\t\tcopy_lines = add_commented_lines;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else if (skip_prefix(s, buf2.buf, &next)) {\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tstart = s - off;\n+\t\t\ts = next;\n+\t\t\tcopy_lines = strbuf_add;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else {\n+\t\t\ts = strchr(s, '\\n');\n+\t\t\tif (s)\n+\t\t\t\ts++;\n+\t\t}\n+\t}\n+\tcopy_lines(msg, start, orig_msg_len - (start - orig_msg));\n+\tfree(orig_msg);\n+\tstrbuf_release(&buf1);\n+\tstrbuf_release(&buf2);\n+}\n+\n+static int append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t enum todo_command command, struct replay_opts *opts,\n+\t\t\t enum todo_item_flags flag)\n+{\n+\tconst char *fixup_msg;\n+\tsize_t commented_len = 0, fixup_off;\n+\t/*\n+\t * amend is non-interactive and not normally used with fixup!\n+\t * or squash! commits, so only comment out those subjects when\n+\t * squashing commit messages.\n+\t */\n+\tif (starts_with(body, \"amend!\") ||\n+\t    ((command == TODO_SQUASH || seen_squash(opts)) &&\n+\t     (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n \t\tcommented_len = subject_length(body);\n+\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n+\t/* buf->buf may be reallocated so store an offset into the buffer */\n+\tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n+\n+\t/* fixup -C after squash behaves like squash */\n+\tif (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n+\t\t/*\n+\t\t * We're replacing the commit message so we need to\n+\t\t * append the Signed-off-by: trailer if the user\n+\t\t * requested '--signoff'.\n+\t\t */\n+\t\tif (opts->signoff)\n+\t\t\tappend_signoff(buf, 0, 0);\n+\n+\t\tif ((command == TODO_FIXUP) &&\n+\t\t    (flag & TODO_REPLACE_FIXUP_MSG) &&\n+\t\t    (file_exists(rebase_path_fixup_msg()) ||\n+\t\t     !file_exists(rebase_path_squash_msg()))) {\n+\t\t\tfixup_msg = skip_blank_lines(buf->buf + fixup_off);\n+\t\t\tif (write_message(fixup_msg, strlen(fixup_msg),\n+\t\t\t\t\trebase_path_fixup_msg(), 0) < 0)\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\trebase_path_fixup_msg());\n+\t\t} else {\n+\t\t\tunlink(rebase_path_fixup_msg());\n+\t\t}\n+\t} else  {\n+\t\tunlink(rebase_path_fixup_msg());\n+\t}\n+\n+\treturn 0;\n }\n \n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n-\t\t\t\t  struct replay_opts *opts)\n+\t\t\t\t  struct replay_opts *opts,\n+\t\t\t\t  enum todo_item_flags flag)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tint res;\n+\tint res = 0;\n \tconst char *message, *body;\n \tconst char *encoding = get_commit_output_encoding();\n \n@@ -1779,6 +1929,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n+\t\tif (check_fixup_flag(command, flag) && !seen_squash(opts))\n+\t\t\tupdate_squash_message_for_fixup(&buf);\n \t} else {\n \t\tstruct object_id head;\n \t\tstruct commit *head_commit;\n@@ -1792,18 +1944,22 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\tif (command == TODO_FIXUP && !flag && write_message(body, strlen(body),\n \t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n \t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n-\n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n+\t\tstrbuf_addstr(&buf, check_fixup_flag(command, flag) ?\n+\t\t\t      _(skip_first_commit_msg_str) :\n+\t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tif (check_fixup_flag(command, flag))\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, body);\n \n \t\tunuse_commit_buffer(head_commit, head_message);\n \t}\n@@ -1813,8 +1969,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tfind_commit_subject(message, &body);\n \n-\tif (command == TODO_SQUASH) {\n-\t\tappend_squash_message(&buf, body, opts);\n+\tif (command == TODO_SQUASH || check_fixup_flag(command, flag)) {\n+\t\tres = append_squash_message(&buf, body, command, opts, flag);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n@@ -1825,7 +1981,9 @@ static int update_squash_messages(struct repository *r,\n \t\treturn error(_(\"unknown command: %d\"), command);\n \tunuse_commit_buffer(commit, message);\n \n-\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);\n+\tif (!res)\n+\t\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(),\n+\t\t\t\t    0);\n \tstrbuf_release(&buf);\n \n \tif (!res) {\n@@ -2026,7 +2184,8 @@ static int do_pick_commit(struct repository *r,\n \tif (command == TODO_REWORD)\n \t\treword = 1;\n \telse if (is_fixup(command)) {\n-\t\tif (update_squash_messages(r, command, commit, opts))\n+\t\tif (update_squash_messages(r, command, commit,\n+\t\t\t\t\t   opts, item->flags))\n \t\t\treturn -1;\n \t\tflags |= AMEND_MSG;\n \t\tif (!final_fixup)\n@@ -2191,10 +2350,6 @@ static int read_and_refresh_cache(struct repository *r,\n \treturn 0;\n }\n \n-enum todo_item_flags {\n-\tTODO_EDIT_MERGE_MSG = 1\n-};\n-\n void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n@@ -2281,6 +2436,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n \t\treturn 0;\n \t}\n \n+\tif (item->command == TODO_FIXUP) {\n+\t\tif (skip_prefix(bol, \"-C\", &bol) &&\n+\t\t   (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_REPLACE_FIXUP_MSG;\n+\t\t} else if (skip_prefix(bol, \"-c\", &bol) &&\n+\t\t\t\t  (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_EDIT_FIXUP_MSG;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_MERGE) {\n \t\tif (skip_prefix(bol, \"-C\", &bol))\n \t\t\tbol += strspn(bol, \" \\t\");\n@@ -5287,6 +5454,14 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis\n \t\t\t\t\t  short_commit_name(item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n \n+\t\t\tif (item->command == TODO_FIXUP) {\n+\t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n+\t\t\t\telse if (item->flags & TODO_REPLACE_FIXUP_MSG) {\n+\t\t\t\t\tstrbuf_addstr(buf, \" -C\");\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_MERGE) {\n \t\t\t\tif (item->flags & TODO_EDIT_MERGE_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n-- \n2.29.0.rc1\n\n"},{"id":"415171","messageId":"20210124170405.30583-8-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:05Z","receivedAt":"2021-01-24T17:07:52Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n t/lib-rebase.sh                   |   4 +\n t/t3437-rebase-fixup-options.sh   | 213 ++++++++++++++++++++++++++++++\n t/t3437/expected-combined-message |  21 +++\n t/t3437/expected-squash-message   |  51 +++++++\n 4 files changed, 289 insertions(+)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n create mode 100644 t/t3437/expected-squash-message\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex b72c051f47..e10e38060b 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -4,6 +4,7 @@\n #\n # - override the commit message with $FAKE_COMMIT_MESSAGE\n # - amend the commit message with $FAKE_COMMIT_AMEND\n+# - copy the original commit message to a file with $FAKE_MESSAGE_COPY\n # - check that non-commit messages have a certain line count with $EXPECT_COUNT\n # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT\n # - rewrite a rebase -i script as directed by $FAKE_LINES.\n@@ -33,6 +34,7 @@ set_fake_editor () {\n \t\t\texit\n \t\ttest -z \"$FAKE_COMMIT_MESSAGE\" || echo \"$FAKE_COMMIT_MESSAGE\" > \"$1\"\n \t\ttest -z \"$FAKE_COMMIT_AMEND\" || echo \"$FAKE_COMMIT_AMEND\" >> \"$1\"\n+\t\ttest -z \"$FAKE_MESSAGE_COPY\" || cat \"$1\" >\"$FAKE_MESSAGE_COPY\"\n \t\texit\n \t\t;;\n \tesac\n@@ -51,6 +53,8 @@ set_fake_editor () {\n \t\t\taction=\"$line\";;\n \t\texec_*|x_*|break|b)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n+\t\tmerge_*|fixup_*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\t\"#\")\n \t\t\techo '# comment' >> \"$1\";;\n \t\t\">\")\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nnew file mode 100755\nindex 0000000000..832971ffdb\n--- /dev/null\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -0,0 +1,213 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2018 Phillip Wood\n+#\n+\n+test_description='git rebase interactive fixup options\n+\n+This test checks the \"fixup [-C|-c]\" command of rebase interactive.\n+In addition to amending the contents of the commit, \"fixup -C\"\n+replaces the original commit message with the message of the fixup\n+commit. \"fixup -c\" also replaces the original message, but opens the\n+editor to allow the user to edit the message before committing.\n+'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+EMPTY=\"\"\n+\n+test_commit_message () {\n+\trev=\"$1\" && # commit or tag we want to test\n+\tfile=\"$2\" && # test against the content of a file\n+\tgit show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n+\tif test \"$2\" = -m\n+\tthen\n+\t\tstr=\"$3\" && # test against a string\n+\t\tprintf \"%s\\n\" \"$str\" >tmp-expected-message &&\n+\t\tfile=\"tmp-expected-message\"\n+\tfi\n+\ttest_cmp \"$file\" actual-message\n+}\n+\n+get_author () {\n+\trev=\"$1\" &&\n+\tgit log -1 --pretty=format:\"%an %ae\" \"$rev\"\n+}\n+\n+test_expect_success 'setup' '\n+\tcat >message <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tnew subject\n+\t\t${EMPTY}\n+\t\tnew\n+\t\tbody\n+\t\tEOF\n+\n+\tsed \"1,2d\" message >expected-message &&\n+\n+\ttest_commit A A &&\n+\ttest_commit B B &&\n+\tget_author HEAD >expected-author &&\n+\tORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n+\tORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n+\tGIT_AUTHOR_NAME=\"Amend Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n+\ttest_commit \"$(cat message)\" A A1 A1 &&\n+\ttest_commit A2 A &&\n+\ttest_commit A3 A &&\n+\tGIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n+\tGIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n+\tgit checkout -b conflicts-branch A &&\n+\ttest_commit conflicts A &&\n+\n+\tset_fake_editor &&\n+\tgit checkout -b branch B &&\n+\techo B1 >B &&\n+\ttest_tick &&\n+\tgit commit --fixup=HEAD -a &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\tEOF\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\tEOF\n+\techo B2 >B &&\n+\ttest_tick &&\n+\tFAKE_COMMIT_AMEND=\"edited squash\" git commit --squash=HEAD -a &&\n+\techo B3 >B &&\n+\ttest_tick &&\n+\tgit commit -a -F - <<-EOF &&\n+\t\tamend! amend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\t${EMPTY}\n+\t\tedited 3\n+\t\tEOF\n+\n+\tGIT_AUTHOR_NAME=\"Rebase Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"rebase.author@example.com\" &&\n+\tGIT_COMMITTER_NAME=\"Rebase Committer\" &&\n+\tGIT_COMMITTER_EMAIL=\"rebase.committer@example.com\"\n+'\n+\n+test_expect_success 'simple fixup -C works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD -m \"A2\"\n+'\n+\n+test_expect_success 'simple fixup -c works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tgit log -1 --pretty=format:%B >expected-fixup-message &&\n+\ttest_write_lines \"\" \"Modified A2\" >>expected-fixup-message &&\n+\tFAKE_LINES=\"1 fixup_-c 2\" \\\n+\t\tFAKE_COMMIT_AMEND=\"Modified A2\" \\\n+\t\tgit rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD expected-fixup-message\n+'\n+\n+test_expect_success 'fixup -C removes amend! from message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'fixup -C with conflicts gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n+\tgit checkout --theirs -- A &&\n+\tgit add A &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_cmp_rev HEAD^ conflicts &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_write_lines \"\" edited >>expected-message &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'skipping fixup -C after fixup gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup 2 fixup_-C 4\" git rebase -i A &&\n+\tgit reset --hard &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_commit_message HEAD -m \"B\"\n+'\n+\n+test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' '\n+\tgit checkout --detach branch &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4 squash 5 fixup_-C 6\" \\\n+\t\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n+test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout branch && git checkout --detach branch~2 &&\n+\tgit log -1 --pretty=format:%b >expected-message &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_expect_success 'multiple fixup -c opens editor once' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tbase=$(git rev-parse HEAD~4) &&\n+\tFAKE_COMMIT_MESSAGE=\"Modified-A3\" \\\n+\t\tFAKE_LINES=\"1 fixup_-C 2 fixup_-c 3 fixup_-c 4\" \\\n+\t\tEXPECT_HEADER_COUNT=4 \\\n+\t\tgit rebase -i $base &&\n+\ttest_cmp_rev $base HEAD^ &&\n+\ttest 1 = $(git show | grep Modified-A3 | wc -l)\n+'\n+\n+test_expect_success 'sequence squash, fixup & fixup -c gives combined message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tFAKE_LINES=\"1 squash 2 fixup 3 fixup_-c 4\" \\\n+\t\tFAKE_MESSAGE_COPY=actual-combined-message \\\n+\t\tgit -c commit.status=false rebase -i A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-combined-message\" \\\n+\t\tactual-combined-message &&\n+\ttest_cmp_rev HEAD^ A\n+'\n+\n+test_done\ndiff --git a/t/t3437/expected-combined-message b/t/t3437/expected-combined-message\nnew file mode 100644\nindex 0000000000..a26cfb2fa9\n--- /dev/null\n+++ b/t/t3437/expected-combined-message\n@@ -0,0 +1,21 @@\n+# This is a combination of 4 commits.\n+# This is the 1st commit message:\n+\n+B\n+\n+# This is the commit message #2:\n+\n+# amend! B\n+\n+new subject\n+\n+new\n+body\n+\n+# The commit message #3 will be skipped:\n+\n+# A2\n+\n+# This is the commit message #4:\n+\n+A3\ndiff --git a/t/t3437/expected-squash-message b/t/t3437/expected-squash-message\nnew file mode 100644\nindex 0000000000..ab2434f90e\n--- /dev/null\n+++ b/t/t3437/expected-squash-message\n@@ -0,0 +1,51 @@\n+# This is a combination of 6 commits.\n+# The 1st commit message will be skipped:\n+\n+# B\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# The commit message #2 will be skipped:\n+\n+# fixup! B\n+\n+# The commit message #3 will be skipped:\n+\n+# amend! B\n+#\n+# B\n+#\n+# edited 1\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #4:\n+\n+# amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #5:\n+\n+# squash! amend! amend! B\n+\n+edited squash\n+\n+# This is the commit message #6:\n+\n+# amend! amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+edited 3\n+squashed\n-- \n2.29.0.rc1\n\n"},{"id":"415172","messageId":"20210124170405.30583-9-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:06Z","receivedAt":"2021-01-24T17:07:58Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"If the commit subject starts with \"amend!\" then rearrange it like a\n\"fixup!\" commit and replace `pick` command with `fixup -C` command,\nwhich is used to fixup up the content if any and replaces the original\ncommit message with amend! commit's message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                     | 23 ++++++++++++++++-------\n t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n 2 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 46e11d20e8..d09ce446b6 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5662,6 +5662,12 @@ static int subject2item_cmp(const void *fndata,\n \n define_commit_slab(commit_todo_item, struct todo_item *);\n \n+static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n+\treturn skip_prefix(subject, \"fixup! \", p) ||\n+\t       skip_prefix(subject, \"amend! \", p) ||\n+\t       skip_prefix(subject, \"squash! \", p);\n+}\n+\n /*\n  * Rearrange the todo list that has both \"pick commit-id msg\" and \"pick\n  * commit-id fixup!/squash! msg\" in it so that the latter is put immediately\n@@ -5720,15 +5726,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\tformat_subject(&buf, subject, \" \");\n \t\tsubject = subjects[i] = strbuf_detach(&buf, &subject_len);\n \t\tunuse_commit_buffer(item->commit, commit_buffer);\n-\t\tif ((skip_prefix(subject, \"fixup! \", &p) ||\n-\t\t     skip_prefix(subject, \"squash! \", &p))) {\n+\t\tif (skip_fixup_amend_squash(subject, &p)) {\n \t\t\tstruct commit *commit2;\n \n \t\t\tfor (;;) {\n \t\t\t\twhile (isspace(*p))\n \t\t\t\t\tp++;\n-\t\t\t\tif (!skip_prefix(p, \"fixup! \", &p) &&\n-\t\t\t\t    !skip_prefix(p, \"squash! \", &p))\n+\t\t\t\tif (!skip_fixup_amend_squash(p, &p))\n \t\t\t\t\tbreak;\n \t\t\t}\n \n@@ -5758,9 +5762,14 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t}\n \t\tif (i2 >= 0) {\n \t\t\trearranged = 1;\n-\t\t\ttodo_list->items[i].command =\n-\t\t\t\tstarts_with(subject, \"fixup!\") ?\n-\t\t\t\tTODO_FIXUP : TODO_SQUASH;\n+\t\t\tif (starts_with(subject, \"fixup!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t} else if (starts_with(subject, \"amend!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t\ttodo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;\n+\t\t\t} else {\n+\t\t\t\ttodo_list->items[i].command = TODO_SQUASH;\n+\t\t\t}\n \t\t\tif (tail[i2] < 0) {\n \t\t\t\tnext[i] = next[i2];\n \t\t\t\tnext[i2] = i;\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nindex 832971ffdb..945df2555b 100755\n--- a/t/t3437-rebase-fixup-options.sh\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -210,4 +210,16 @@ test_expect_success 'sequence squash, fixup & fixup -c gives combined message' '\n \ttest_cmp_rev HEAD^ A\n '\n \n+test_expect_success 'fixup -C works upon --autosquash with amend!' '\n+\tgit checkout --detach branch &&\n+\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --autosquash \\\n+\t\t\t\t\t\t--signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n test_done\n-- \n2.29.0.rc1\n\n"},{"id":"415173","messageId":"20210124170405.30583-10-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v3 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-24T17:04:07Z","receivedAt":"2021-01-24T17:08:19Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Marc Branchaud <marcnarc@xiplink.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n Documentation/git-rebase.txt | 14 +++++++++++---\n 1 file changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a0487b5cc5..a6903419c4 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -887,9 +887,17 @@ If you want to fold two or more commits into one, replace the command\n \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n If the commits had different authors, the folded commit will be\n attributed to the author of the first commit.  The suggested commit\n-message for the folded commit is the concatenation of the commit\n-messages of the first commit and of those with the \"squash\" command,\n-but omits the commit messages of commits with the \"fixup\" command.\n+message for the folded commit is the concatenation of the first\n+commit's message with those identified by \"squash\" commands, omitting the\n+messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n+is used.  In that case the suggested commit message is only the message\n+of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n+the message.  The contents (patch) of the \"fixup -c\" commit are still\n+incorporated into the folded commit. If there is more than one \"fixup -c\"\n+commit, the message from the last last one is used.  You can also use\n+\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n+an editor.\n+\n \n 'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n when a command fails due to merge errors. When you are done editing\n-- \n2.29.0.rc1\n\n"},{"id":"415571","messageId":"20210129182050.26143-1-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210124170405.30583-1-charvi077@gmail.com","subject":"[PATCH v4 0/9][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:41Z","receivedAt":"2021-01-29T18:22:56Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This patch series adds fixup [-C|-c] options to interactive rebase. In\naddition to amending the contents of the commit as the `fixup` command\ndoes now, `fixup -C` replaces the commit message of the original commit\nwhich we are fixing up with the message of the fixup commit.\nAnd to edit the fixup commit message before committing, `fixup -c`\ncommand is used instead of `fixup -C`. This convention is similar to\nthe existing `merge` command in the interactive rebase, that also supports\n`-c` and `-C` options with similar meanings.\n\nThis patch series also changes `rebase -i --autosquash` to rearrange\ncommits whose message starts with \"amend!\" and replaces the pick\ncommand with `fixup -C`. The creation of \"amend!\" commits will be\nrebase -i: add options to fixup command added in another patch series.\n\nThis is done in reference to the issue opened by Dscho as here[1] and\nfurther discussed briefly[2]. Also, there is discussion[3] regarding the\nimplementation of reword! commit. The past patches of Phillip Wood’s\nwork[4], implements 'reword!' as 'amend!' in git rebase and these patches\nuses those as the initial base.\nAnd to avoid the extra command in the interactive rebase, this patch\nseries instead add options to the current fixup command in interactive\nrebase (fixup [-C | -c]) as discussed earlier[5].\n\nChanges from v2 :\n\n(Thanks to Junio C Hamano, Marc Branchaud, Christian Couder, Phillip Wood\nand Taylor Blau for the reviews and suggestions)\n\n* Updated the Documentation/git-rebase.txt\n* Added tests(t3437-rebase-fixup-options.sh) to check working of multiple\n  fixup -c in rebase -i and related changes in sequencer.c\n* Updated subject_length() function in sequencer.c and some corrections in\n  t3415-rebase-autosquash.sh\n\nChanges from v3 :\n\n* Corrected a small bug in t3415-rebase-autosquash.sh\n (Bymistake sent the patches of local branch, with error in test script in v3,\n corrected those in these patch series revision)\n\n[1] https://github.com/gitgitgadget/git/issues/259\n[2] https://public-inbox.org/git/alpine.DEB.2.21.1.1710151754070.40514@virtualbox/\n[3] https://lore.kernel.org/git/95cc6fb2-d1bc-11de-febe-c2b5c78a6850@gmail.com/\n[4] https://github.com/phillipwood/git/commits/wip/rebase-amend\n[5] https://lore.kernel.org/git/29fc2f59-1cca-a3db-5586-bbd7b2e4806d@gmail.com/\n\n\nCharvi Mendiratta (6):\n  sequencer: pass todo_item to do_pick_commit()\n  sequencer: use const variable for commit message comments\n  rebase -i: add fixup [-C | -c] command\n  t3437: test script for fixup [-C|-c] options in interactive rebase\n  rebase -i: teach --autosquash to work with amend!\n  doc/git-rebase: add documentation for fixup [-C|-c] options\n\nPhillip Wood (3):\n  rebase -i: only write fixup-message when it's needed\n  sequencer: factor out code to append squash message\n  rebase -i: comment out squash!/fixup! subjects from squash message\n\n Documentation/git-rebase.txt      |  14 +-\n rebase-interactive.c              |   4 +-\n sequencer.c                       | 295 ++++++++++++++++++++++++++----\n t/lib-rebase.sh                   |   4 +\n t/t3415-rebase-autosquash.sh      |  30 +--\n t/t3437-rebase-fixup-options.sh   | 225 +++++++++++++++++++++++\n t/t3437/expected-combined-message |  21 +++\n t/t3437/expected-squash-message   |  51 ++++++\n t/t3900-i18n-commit.sh            |   4 -\n 9 files changed, 587 insertions(+), 61 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n create mode 100644 t/t3437/expected-squash-message\n\n--\n2.29.0.rc1\n\n"},{"id":"415572","messageId":"20210129182050.26143-2-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 1/9] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:42Z","receivedAt":"2021-01-29T18:23:36Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThe file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\ncommands, there's no point in writing it for squash commands as it is\nimmediately deleted.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8909a46770..a59e0c84af 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1757,11 +1757,10 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (write_message(body, strlen(body),\n-\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n+\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n-\t\t\treturn error(_(\"cannot write '%s'\"),\n-\t\t\t\t     rebase_path_fixup_msg());\n+\t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-- \n2.29.0.rc1\n\n"},{"id":"415573","messageId":"20210129182050.26143-3-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 2/9] sequencer: factor out code to append squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:43Z","receivedAt":"2021-01-29T18:23:36Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis code is going to grow over the next two commits so move it to\nits own function.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex a59e0c84af..08cce40834 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,17 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static void append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t\t  struct replay_opts *opts)\n+{\n+\tunlink(rebase_path_fixup_msg());\n+\tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n+\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\t\t    ++opts->current_fixup_count + 1);\n+\tstrbuf_addstr(buf, \"\\n\\n\");\n+\tstrbuf_addstr(buf, body);\n+}\n+\n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n@@ -1779,12 +1790,7 @@ static int update_squash_messages(struct repository *r,\n \tfind_commit_subject(message, &body);\n \n \tif (command == TODO_SQUASH) {\n-\t\tunlink(rebase_path_fixup_msg());\n-\t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is the commit message #%d:\"),\n-\t\t\t    ++opts->current_fixup_count + 1);\n-\t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n-- \n2.29.0.rc1\n\n"},{"id":"415574","messageId":"20210129182050.26143-4-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 3/9] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:44Z","receivedAt":"2021-01-29T18:24:01Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen squashing commit messages the squash!/fixup! subjects are not of\ninterest so comment them out to stop them becoming part of the final\nmessage.\n\nThis change breaks a bunch of --autosquash tests which rely on the\n\"squash! <subject>\" line appearing in the final commit message. This is\naddressed by adding a second line to the commit message of the \"squash!\n...\" commits and testing for that.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                  | 21 ++++++++++++++++++++-\n t/t3415-rebase-autosquash.sh | 30 ++++++++++++++++--------------\n t/t3900-i18n-commit.sh       |  4 ----\n 3 files changed, 36 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 08cce40834..034149f24d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,15 +1718,34 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static size_t subject_length(const char *body)\n+{\n+\tconst char *p = body;\n+\twhile (*p) {\n+\t\tconst char *next = skip_blank_lines(p);\n+\t\tif (next != p)\n+\t\t\tbreak;\n+\t\tp = strchrnul(p, '\\n');\n+\t\tif (*p)\n+\t\t\tp++;\n+\t}\n+\treturn p - body;\n+}\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n+\tsize_t commented_len = 0;\n+\n \tunlink(rebase_path_fixup_msg());\n+\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+\t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_addstr(buf, body);\n+\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_addstr(buf, body + commented_len);\n }\n \n static int update_squash_messages(struct repository *r,\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex e7087befd4..78cc2260cc 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -84,8 +84,7 @@ test_auto_squash () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n-\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n \tgit rebase $2 -i HEAD^^^ &&\n@@ -142,7 +141,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag final-multisquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -195,7 +194,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-shasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -206,7 +205,8 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -216,7 +216,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short=11 HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-longshasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -227,7 +227,8 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -236,7 +237,7 @@ test_auto_commit_flags () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit --$1 first-commit &&\n+\tgit commit --$1 first-commit -m \"extra para for first\" &&\n \tgit tag final-commit-$1 &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -264,11 +265,11 @@ test_auto_fixup_fixup () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! first\" &&\n+\tgit commit -m \"$1! first\" -m \"extra para for first\" &&\n \techo 2 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! $2! first\" &&\n+\tgit commit -m \"$1! $2! first\" -m \"second extra para for first\" &&\n \tgit tag \"final-$1-$2\" &&\n \ttest_tick &&\n \t(\n@@ -329,12 +330,12 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para for first\" &&\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n \tsubject=$(git log -n 1 --format=%s HEAD~2) &&\n-\tgit commit -m \"squash! $subject\" &&\n+\tgit commit -m \"squash! $subject\" -m \"second extra para for first\" &&\n \tgit tag final-squash-instFmt &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -345,8 +346,9 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n-\ttest_line_count = 2 actual\n+\t! grep \"squash\" commit &&\n+\tgrep first commit >actual &&\n+\ttest_line_count = 3 actual\n '\n \n test_expect_success 'autosquash with empty custom instructionFormat' '\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex d277a9f4b7..bfab245eb3 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -226,10 +226,6 @@ test_commit_autosquash_multi_encoding () {\n \t\tgit rev-list HEAD >actual &&\n \t\ttest_line_count = 3 actual &&\n \t\ticonv -f $old -t UTF-8 \"$TEST_DIRECTORY\"/t3900/$msg >expect &&\n-\t\tif test $flag = squash; then\n-\t\t\tsubject=\"$(head -1 expect)\" &&\n-\t\t\tprintf \"\\nsquash! %s\\n\" \"$subject\" >>expect\n-\t\tfi &&\n \t\tgit cat-file commit HEAD^ >raw &&\n \t\t(sed \"1,/^$/d\" raw | iconv -f $new -t utf-8) >actual &&\n \t\ttest_cmp expect actual\n-- \n2.29.0.rc1\n\n"},{"id":"415575","messageId":"20210129182050.26143-7-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:47Z","receivedAt":"2021-01-29T18:24:33Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Add options to `fixup` command to fixup both the commit contents and\nmessage. `fixup -C` command is used to replace the original commit\nmessage and `fixup -c`, additionally allows to edit the commit message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n rebase-interactive.c |   4 +-\n sequencer.c          | 213 +++++++++++++++++++++++++++++++++++++++----\n 2 files changed, 197 insertions(+), 20 deletions(-)\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 762853bc7e..c3bd02adee 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n \"e, edit <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n-\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n+\"                   commit's log message. Use -C to replace with this\\n\"\n+\"                   commit message or -c to edit the commit message\\n\"\n \"x, exec <command> = run command (the rest of the line) using shell\\n\"\n \"b, break = stop here (continue rebase later with 'git rebase --continue')\\n\"\n \"d, drop <commit> = remove commit\\n\"\ndiff --git a/sequencer.c b/sequencer.c\nindex 6d9a10afcf..46e11d20e8 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+enum todo_item_flags {\n+\tTODO_EDIT_MERGE_MSG    = (1 << 0),\n+\tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n+\tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+};\n+\n static size_t subject_length(const char *body)\n {\n \tconst char *p = body;\n@@ -1734,32 +1740,176 @@ static size_t subject_length(const char *body)\n \n static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_first_commit_msg_str[] = N_(\"The 1st commit message will be skipped:\");\n static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n \n-static void append_squash_message(struct strbuf *buf, const char *body,\n-\t\t\t\t  struct replay_opts *opts)\n+static int check_fixup_flag(enum todo_command command,\n+\t\t\t    enum todo_item_flags flag)\n+{\n+\treturn command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n+\t\t\t\t\t (flag & TODO_EDIT_FIXUP_MSG));\n+}\n+\n+/*\n+ * Wrapper around strbuf_add_commented_lines() which avoids double\n+ * commenting commit subjects.\n+ */\n+static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n+{\n+\tconst char *s = str;\n+\twhile (len > 0 && s[0] == comment_line_char) {\n+\t\tsize_t count;\n+\t\tconst char *n = memchr(s, '\\n', len);\n+\t\tif (!n)\n+\t\t\tcount = len;\n+\t\telse\n+\t\t\tcount = n - s + 1;\n+\t\tstrbuf_add(buf, s, count);\n+\t\ts += count;\n+\t\tlen -= count;\n+\t}\n+\tstrbuf_add_commented_lines(buf, s, len);\n+}\n+\n+/* Does the current fixup chain contain a squash command? */\n+static int seen_squash(struct replay_opts *opts)\n+{\n+\treturn starts_with(opts->current_fixups.buf, \"squash\") ||\n+\t\tstrstr(opts->current_fixups.buf, \"\\nsquash\");\n+}\n+\n+static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n {\n-\tsize_t commented_len = 0;\n+\tstrbuf_setlen(buf1, 2);\n+\tstrbuf_addf(buf1, _(nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf1, '\\n');\n+\tstrbuf_setlen(buf2, 2);\n+\tstrbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf2, '\\n');\n+}\n \n-\tunlink(rebase_path_fixup_msg());\n-\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+/*\n+ * Comment out any un-commented commit messages, updating the message comments\n+ * to say they will be skipped but do not comment out the empty lines that\n+ * surround commit messages and their comments.\n+ */\n+static void update_squash_message_for_fixup(struct strbuf *msg)\n+{\n+\tvoid (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;\n+\tstruct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tconst char *s, *start;\n+\tchar *orig_msg;\n+\tsize_t orig_msg_len;\n+\tint i = 1;\n+\n+\tstrbuf_addf(&buf1, \"# %s\\n\", _(first_commit_msg_str));\n+\tstrbuf_addf(&buf2, \"# %s\\n\", _(skip_first_commit_msg_str));\n+\ts = start = orig_msg = strbuf_detach(msg, &orig_msg_len);\n+\twhile (s) {\n+\t\tconst char *next;\n+\t\tsize_t off;\n+\t\tif (skip_prefix(s, buf1.buf, &next)) {\n+\t\t\t/*\n+\t\t\t * Copy the last message, preserving the blank line\n+\t\t\t * preceding the current line\n+\t\t\t */\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tif (off)\n+\t\t\t\tstrbuf_addch(msg, '\\n');\n+\t\t\t/*\n+\t\t\t * The next message needs to be commented out but the\n+\t\t\t * message header is already commented out so just copy\n+\t\t\t * it and the blank line that follows it.\n+\t\t\t */\n+\t\t\tstrbuf_addbuf(msg, &buf2);\n+\t\t\tif (*next == '\\n')\n+\t\t\t\tstrbuf_addch(msg, *next++);\n+\t\t\tstart = s = next;\n+\t\t\tcopy_lines = add_commented_lines;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else if (skip_prefix(s, buf2.buf, &next)) {\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tstart = s - off;\n+\t\t\ts = next;\n+\t\t\tcopy_lines = strbuf_add;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else {\n+\t\t\ts = strchr(s, '\\n');\n+\t\t\tif (s)\n+\t\t\t\ts++;\n+\t\t}\n+\t}\n+\tcopy_lines(msg, start, orig_msg_len - (start - orig_msg));\n+\tfree(orig_msg);\n+\tstrbuf_release(&buf1);\n+\tstrbuf_release(&buf2);\n+}\n+\n+static int append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t enum todo_command command, struct replay_opts *opts,\n+\t\t\t enum todo_item_flags flag)\n+{\n+\tconst char *fixup_msg;\n+\tsize_t commented_len = 0, fixup_off;\n+\t/*\n+\t * amend is non-interactive and not normally used with fixup!\n+\t * or squash! commits, so only comment out those subjects when\n+\t * squashing commit messages.\n+\t */\n+\tif (starts_with(body, \"amend!\") ||\n+\t    ((command == TODO_SQUASH || seen_squash(opts)) &&\n+\t     (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n \t\tcommented_len = subject_length(body);\n+\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n+\t/* buf->buf may be reallocated so store an offset into the buffer */\n+\tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n+\n+\t/* fixup -C after squash behaves like squash */\n+\tif (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n+\t\t/*\n+\t\t * We're replacing the commit message so we need to\n+\t\t * append the Signed-off-by: trailer if the user\n+\t\t * requested '--signoff'.\n+\t\t */\n+\t\tif (opts->signoff)\n+\t\t\tappend_signoff(buf, 0, 0);\n+\n+\t\tif ((command == TODO_FIXUP) &&\n+\t\t    (flag & TODO_REPLACE_FIXUP_MSG) &&\n+\t\t    (file_exists(rebase_path_fixup_msg()) ||\n+\t\t     !file_exists(rebase_path_squash_msg()))) {\n+\t\t\tfixup_msg = skip_blank_lines(buf->buf + fixup_off);\n+\t\t\tif (write_message(fixup_msg, strlen(fixup_msg),\n+\t\t\t\t\trebase_path_fixup_msg(), 0) < 0)\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\trebase_path_fixup_msg());\n+\t\t} else {\n+\t\t\tunlink(rebase_path_fixup_msg());\n+\t\t}\n+\t} else  {\n+\t\tunlink(rebase_path_fixup_msg());\n+\t}\n+\n+\treturn 0;\n }\n \n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n-\t\t\t\t  struct replay_opts *opts)\n+\t\t\t\t  struct replay_opts *opts,\n+\t\t\t\t  enum todo_item_flags flag)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tint res;\n+\tint res = 0;\n \tconst char *message, *body;\n \tconst char *encoding = get_commit_output_encoding();\n \n@@ -1779,6 +1929,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n+\t\tif (check_fixup_flag(command, flag) && !seen_squash(opts))\n+\t\t\tupdate_squash_message_for_fixup(&buf);\n \t} else {\n \t\tstruct object_id head;\n \t\tstruct commit *head_commit;\n@@ -1792,18 +1944,22 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\tif (command == TODO_FIXUP && !flag && write_message(body, strlen(body),\n \t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n \t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n-\n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n+\t\tstrbuf_addstr(&buf, check_fixup_flag(command, flag) ?\n+\t\t\t      _(skip_first_commit_msg_str) :\n+\t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tif (check_fixup_flag(command, flag))\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, body);\n \n \t\tunuse_commit_buffer(head_commit, head_message);\n \t}\n@@ -1813,8 +1969,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tfind_commit_subject(message, &body);\n \n-\tif (command == TODO_SQUASH) {\n-\t\tappend_squash_message(&buf, body, opts);\n+\tif (command == TODO_SQUASH || check_fixup_flag(command, flag)) {\n+\t\tres = append_squash_message(&buf, body, command, opts, flag);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n@@ -1825,7 +1981,9 @@ static int update_squash_messages(struct repository *r,\n \t\treturn error(_(\"unknown command: %d\"), command);\n \tunuse_commit_buffer(commit, message);\n \n-\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);\n+\tif (!res)\n+\t\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(),\n+\t\t\t\t    0);\n \tstrbuf_release(&buf);\n \n \tif (!res) {\n@@ -2026,7 +2184,8 @@ static int do_pick_commit(struct repository *r,\n \tif (command == TODO_REWORD)\n \t\treword = 1;\n \telse if (is_fixup(command)) {\n-\t\tif (update_squash_messages(r, command, commit, opts))\n+\t\tif (update_squash_messages(r, command, commit,\n+\t\t\t\t\t   opts, item->flags))\n \t\t\treturn -1;\n \t\tflags |= AMEND_MSG;\n \t\tif (!final_fixup)\n@@ -2191,10 +2350,6 @@ static int read_and_refresh_cache(struct repository *r,\n \treturn 0;\n }\n \n-enum todo_item_flags {\n-\tTODO_EDIT_MERGE_MSG = 1\n-};\n-\n void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n@@ -2281,6 +2436,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n \t\treturn 0;\n \t}\n \n+\tif (item->command == TODO_FIXUP) {\n+\t\tif (skip_prefix(bol, \"-C\", &bol) &&\n+\t\t   (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_REPLACE_FIXUP_MSG;\n+\t\t} else if (skip_prefix(bol, \"-c\", &bol) &&\n+\t\t\t\t  (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_EDIT_FIXUP_MSG;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_MERGE) {\n \t\tif (skip_prefix(bol, \"-C\", &bol))\n \t\t\tbol += strspn(bol, \" \\t\");\n@@ -5287,6 +5454,14 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis\n \t\t\t\t\t  short_commit_name(item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n \n+\t\t\tif (item->command == TODO_FIXUP) {\n+\t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n+\t\t\t\telse if (item->flags & TODO_REPLACE_FIXUP_MSG) {\n+\t\t\t\t\tstrbuf_addstr(buf, \" -C\");\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_MERGE) {\n \t\t\t\tif (item->flags & TODO_EDIT_MERGE_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n-- \n2.29.0.rc1\n\n"},{"id":"415576","messageId":"20210129182050.26143-10-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:50Z","receivedAt":"2021-01-29T18:24:34Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Marc Branchaud <marcnarc@xiplink.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n Documentation/git-rebase.txt | 14 +++++++++++---\n 1 file changed, 11 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a0487b5cc5..a6903419c4 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -887,9 +887,17 @@ If you want to fold two or more commits into one, replace the command\n \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n If the commits had different authors, the folded commit will be\n attributed to the author of the first commit.  The suggested commit\n-message for the folded commit is the concatenation of the commit\n-messages of the first commit and of those with the \"squash\" command,\n-but omits the commit messages of commits with the \"fixup\" command.\n+message for the folded commit is the concatenation of the first\n+commit's message with those identified by \"squash\" commands, omitting the\n+messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n+is used.  In that case the suggested commit message is only the message\n+of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n+the message.  The contents (patch) of the \"fixup -c\" commit are still\n+incorporated into the folded commit. If there is more than one \"fixup -c\"\n+commit, the message from the last last one is used.  You can also use\n+\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n+an editor.\n+\n \n 'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n when a command fails due to merge errors. When you are done editing\n-- \n2.29.0.rc1\n\n"},{"id":"415577","messageId":"20210129182050.26143-8-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:48Z","receivedAt":"2021-01-29T18:25:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n t/lib-rebase.sh                   |   4 +\n t/t3437-rebase-fixup-options.sh   | 213 ++++++++++++++++++++++++++++++\n t/t3437/expected-combined-message |  21 +++\n t/t3437/expected-squash-message   |  51 +++++++\n 4 files changed, 289 insertions(+)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n create mode 100644 t/t3437/expected-squash-message\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex b72c051f47..e10e38060b 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -4,6 +4,7 @@\n #\n # - override the commit message with $FAKE_COMMIT_MESSAGE\n # - amend the commit message with $FAKE_COMMIT_AMEND\n+# - copy the original commit message to a file with $FAKE_MESSAGE_COPY\n # - check that non-commit messages have a certain line count with $EXPECT_COUNT\n # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT\n # - rewrite a rebase -i script as directed by $FAKE_LINES.\n@@ -33,6 +34,7 @@ set_fake_editor () {\n \t\t\texit\n \t\ttest -z \"$FAKE_COMMIT_MESSAGE\" || echo \"$FAKE_COMMIT_MESSAGE\" > \"$1\"\n \t\ttest -z \"$FAKE_COMMIT_AMEND\" || echo \"$FAKE_COMMIT_AMEND\" >> \"$1\"\n+\t\ttest -z \"$FAKE_MESSAGE_COPY\" || cat \"$1\" >\"$FAKE_MESSAGE_COPY\"\n \t\texit\n \t\t;;\n \tesac\n@@ -51,6 +53,8 @@ set_fake_editor () {\n \t\t\taction=\"$line\";;\n \t\texec_*|x_*|break|b)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n+\t\tmerge_*|fixup_*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\t\"#\")\n \t\t\techo '# comment' >> \"$1\";;\n \t\t\">\")\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nnew file mode 100755\nindex 0000000000..832971ffdb\n--- /dev/null\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -0,0 +1,213 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2018 Phillip Wood\n+#\n+\n+test_description='git rebase interactive fixup options\n+\n+This test checks the \"fixup [-C|-c]\" command of rebase interactive.\n+In addition to amending the contents of the commit, \"fixup -C\"\n+replaces the original commit message with the message of the fixup\n+commit. \"fixup -c\" also replaces the original message, but opens the\n+editor to allow the user to edit the message before committing.\n+'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+EMPTY=\"\"\n+\n+test_commit_message () {\n+\trev=\"$1\" && # commit or tag we want to test\n+\tfile=\"$2\" && # test against the content of a file\n+\tgit show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n+\tif test \"$2\" = -m\n+\tthen\n+\t\tstr=\"$3\" && # test against a string\n+\t\tprintf \"%s\\n\" \"$str\" >tmp-expected-message &&\n+\t\tfile=\"tmp-expected-message\"\n+\tfi\n+\ttest_cmp \"$file\" actual-message\n+}\n+\n+get_author () {\n+\trev=\"$1\" &&\n+\tgit log -1 --pretty=format:\"%an %ae\" \"$rev\"\n+}\n+\n+test_expect_success 'setup' '\n+\tcat >message <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tnew subject\n+\t\t${EMPTY}\n+\t\tnew\n+\t\tbody\n+\t\tEOF\n+\n+\tsed \"1,2d\" message >expected-message &&\n+\n+\ttest_commit A A &&\n+\ttest_commit B B &&\n+\tget_author HEAD >expected-author &&\n+\tORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n+\tORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n+\tGIT_AUTHOR_NAME=\"Amend Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n+\ttest_commit \"$(cat message)\" A A1 A1 &&\n+\ttest_commit A2 A &&\n+\ttest_commit A3 A &&\n+\tGIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n+\tGIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n+\tgit checkout -b conflicts-branch A &&\n+\ttest_commit conflicts A &&\n+\n+\tset_fake_editor &&\n+\tgit checkout -b branch B &&\n+\techo B1 >B &&\n+\ttest_tick &&\n+\tgit commit --fixup=HEAD -a &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\tEOF\n+\ttest_tick &&\n+\tgit commit --allow-empty -F - <<-EOF &&\n+\t\tamend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\tEOF\n+\techo B2 >B &&\n+\ttest_tick &&\n+\tFAKE_COMMIT_AMEND=\"edited squash\" git commit --squash=HEAD -a &&\n+\techo B3 >B &&\n+\ttest_tick &&\n+\tgit commit -a -F - <<-EOF &&\n+\t\tamend! amend! amend! B\n+\t\t${EMPTY}\n+\t\tB\n+\t\t${EMPTY}\n+\t\tedited 1\n+\t\t${EMPTY}\n+\t\tedited 2\n+\t\t${EMPTY}\n+\t\tedited 3\n+\t\tEOF\n+\n+\tGIT_AUTHOR_NAME=\"Rebase Author\" &&\n+\tGIT_AUTHOR_EMAIL=\"rebase.author@example.com\" &&\n+\tGIT_COMMITTER_NAME=\"Rebase Committer\" &&\n+\tGIT_COMMITTER_EMAIL=\"rebase.committer@example.com\"\n+'\n+\n+test_expect_success 'simple fixup -C works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD -m \"A2\"\n+'\n+\n+test_expect_success 'simple fixup -c works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tgit log -1 --pretty=format:%B >expected-fixup-message &&\n+\ttest_write_lines \"\" \"Modified A2\" >>expected-fixup-message &&\n+\tFAKE_LINES=\"1 fixup_-c 2\" \\\n+\t\tFAKE_COMMIT_AMEND=\"Modified A2\" \\\n+\t\tgit rebase -i B &&\n+\ttest_cmp_rev HEAD^ B &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD expected-fixup-message\n+'\n+\n+test_expect_success 'fixup -C removes amend! from message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tFAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'fixup -C with conflicts gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n+\tgit checkout --theirs -- A &&\n+\tgit add A &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_cmp_rev HEAD^ conflicts &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_write_lines \"\" edited >>expected-message &&\n+\ttest_commit_message HEAD expected-message &&\n+\tget_author HEAD >actual-author &&\n+\ttest_cmp expected-author actual-author\n+'\n+\n+test_expect_success 'skipping fixup -C after fixup gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup 2 fixup_-C 4\" git rebase -i A &&\n+\tgit reset --hard &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_commit_message HEAD -m \"B\"\n+'\n+\n+test_expect_success 'sequence of fixup, fixup -C & squash --signoff works' '\n+\tgit checkout --detach branch &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4 squash 5 fixup_-C 6\" \\\n+\t\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n+test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout branch && git checkout --detach branch~2 &&\n+\tgit log -1 --pretty=format:%b >expected-message &&\n+\tFAKE_LINES=\"1 fixup 2 fixup_-C 3 fixup_-C 4\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_expect_success 'multiple fixup -c opens editor once' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tbase=$(git rev-parse HEAD~4) &&\n+\tFAKE_COMMIT_MESSAGE=\"Modified-A3\" \\\n+\t\tFAKE_LINES=\"1 fixup_-C 2 fixup_-c 3 fixup_-c 4\" \\\n+\t\tEXPECT_HEADER_COUNT=4 \\\n+\t\tgit rebase -i $base &&\n+\ttest_cmp_rev $base HEAD^ &&\n+\ttest 1 = $(git show | grep Modified-A3 | wc -l)\n+'\n+\n+test_expect_success 'sequence squash, fixup & fixup -c gives combined message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tFAKE_LINES=\"1 squash 2 fixup 3 fixup_-c 4\" \\\n+\t\tFAKE_MESSAGE_COPY=actual-combined-message \\\n+\t\tgit -c commit.status=false rebase -i A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-combined-message\" \\\n+\t\tactual-combined-message &&\n+\ttest_cmp_rev HEAD^ A\n+'\n+\n+test_done\ndiff --git a/t/t3437/expected-combined-message b/t/t3437/expected-combined-message\nnew file mode 100644\nindex 0000000000..a26cfb2fa9\n--- /dev/null\n+++ b/t/t3437/expected-combined-message\n@@ -0,0 +1,21 @@\n+# This is a combination of 4 commits.\n+# This is the 1st commit message:\n+\n+B\n+\n+# This is the commit message #2:\n+\n+# amend! B\n+\n+new subject\n+\n+new\n+body\n+\n+# The commit message #3 will be skipped:\n+\n+# A2\n+\n+# This is the commit message #4:\n+\n+A3\ndiff --git a/t/t3437/expected-squash-message b/t/t3437/expected-squash-message\nnew file mode 100644\nindex 0000000000..ab2434f90e\n--- /dev/null\n+++ b/t/t3437/expected-squash-message\n@@ -0,0 +1,51 @@\n+# This is a combination of 6 commits.\n+# The 1st commit message will be skipped:\n+\n+# B\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# The commit message #2 will be skipped:\n+\n+# fixup! B\n+\n+# The commit message #3 will be skipped:\n+\n+# amend! B\n+#\n+# B\n+#\n+# edited 1\n+#\n+# Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #4:\n+\n+# amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+Signed-off-by: Rebase Committer <rebase.committer@example.com>\n+\n+# This is the commit message #5:\n+\n+# squash! amend! amend! B\n+\n+edited squash\n+\n+# This is the commit message #6:\n+\n+# amend! amend! amend! B\n+\n+B\n+\n+edited 1\n+\n+edited 2\n+\n+edited 3\n+squashed\n-- \n2.29.0.rc1\n\n"},{"id":"415578","messageId":"20210129182050.26143-5-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 4/9] sequencer: pass todo_item to do_pick_commit()","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:45Z","receivedAt":"2021-01-29T18:25:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"As an additional member of the structure todo_item will be required in\nfuture commits pass the complete structure.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 034149f24d..09cbb17f87 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1877,8 +1877,7 @@ static void record_in_rewritten(struct object_id *oid,\n }\n \n static int do_pick_commit(struct repository *r,\n-\t\t\t  enum todo_command command,\n-\t\t\t  struct commit *commit,\n+\t\t\t  struct todo_item *item,\n \t\t\t  struct replay_opts *opts,\n \t\t\t  int final_fixup, int *check_todo)\n {\n@@ -1891,6 +1890,8 @@ static int do_pick_commit(struct repository *r,\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res, unborn = 0, reword = 0, allow, drop_commit;\n+\tenum todo_command command = item->command;\n+\tstruct commit *commit = item->commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -4140,8 +4141,8 @@ static int pick_commits(struct repository *r,\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, reflog_message(opts,\n \t\t\t\t\tcommand_to_string(item->command), NULL),\n \t\t\t\t\t1);\n-\t\t\tres = do_pick_commit(r, item->command, item->commit,\n-\t\t\t\t\t     opts, is_final_fixup(todo_list),\n+\t\t\tres = do_pick_commit(r, item, opts,\n+\t\t\t\t\t     is_final_fixup(todo_list),\n \t\t\t\t\t     &check_todo);\n \t\t\tif (is_rebase_i(opts))\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);\n@@ -4603,11 +4604,14 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n+\tstruct todo_item item;\n+\n+\titem.command = opts->action == REPLAY_PICK ?\n+\t\t\tTODO_PICK : TODO_REVERT;\n+\titem.commit = cmit;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(r, opts->action == REPLAY_PICK ?\n-\t\t\t      TODO_PICK : TODO_REVERT, cmit, opts, 0,\n-\t\t\t      &check_todo);\n+\treturn do_pick_commit(r, &item, opts, 0, &check_todo);\n }\n \n int sequencer_pick_revisions(struct repository *r,\n-- \n2.29.0.rc1\n\n"},{"id":"415579","messageId":"20210129182050.26143-9-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:49Z","receivedAt":"2021-01-29T18:25:25Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"If the commit subject starts with \"amend!\" then rearrange it like a\n\"fixup!\" commit and replace `pick` command with `fixup -C` command,\nwhich is used to fixup up the content if any and replaces the original\ncommit message with amend! commit's message.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                     | 23 ++++++++++++++++-------\n t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n 2 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 46e11d20e8..d09ce446b6 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -5662,6 +5662,12 @@ static int subject2item_cmp(const void *fndata,\n \n define_commit_slab(commit_todo_item, struct todo_item *);\n \n+static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n+\treturn skip_prefix(subject, \"fixup! \", p) ||\n+\t       skip_prefix(subject, \"amend! \", p) ||\n+\t       skip_prefix(subject, \"squash! \", p);\n+}\n+\n /*\n  * Rearrange the todo list that has both \"pick commit-id msg\" and \"pick\n  * commit-id fixup!/squash! msg\" in it so that the latter is put immediately\n@@ -5720,15 +5726,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\tformat_subject(&buf, subject, \" \");\n \t\tsubject = subjects[i] = strbuf_detach(&buf, &subject_len);\n \t\tunuse_commit_buffer(item->commit, commit_buffer);\n-\t\tif ((skip_prefix(subject, \"fixup! \", &p) ||\n-\t\t     skip_prefix(subject, \"squash! \", &p))) {\n+\t\tif (skip_fixup_amend_squash(subject, &p)) {\n \t\t\tstruct commit *commit2;\n \n \t\t\tfor (;;) {\n \t\t\t\twhile (isspace(*p))\n \t\t\t\t\tp++;\n-\t\t\t\tif (!skip_prefix(p, \"fixup! \", &p) &&\n-\t\t\t\t    !skip_prefix(p, \"squash! \", &p))\n+\t\t\t\tif (!skip_fixup_amend_squash(p, &p))\n \t\t\t\t\tbreak;\n \t\t\t}\n \n@@ -5758,9 +5762,14 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)\n \t\t}\n \t\tif (i2 >= 0) {\n \t\t\trearranged = 1;\n-\t\t\ttodo_list->items[i].command =\n-\t\t\t\tstarts_with(subject, \"fixup!\") ?\n-\t\t\t\tTODO_FIXUP : TODO_SQUASH;\n+\t\t\tif (starts_with(subject, \"fixup!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t} else if (starts_with(subject, \"amend!\")) {\n+\t\t\t\ttodo_list->items[i].command = TODO_FIXUP;\n+\t\t\t\ttodo_list->items[i].flags = TODO_REPLACE_FIXUP_MSG;\n+\t\t\t} else {\n+\t\t\t\ttodo_list->items[i].command = TODO_SQUASH;\n+\t\t\t}\n \t\t\tif (tail[i2] < 0) {\n \t\t\t\tnext[i] = next[i2];\n \t\t\t\tnext[i2] = i;\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nindex 832971ffdb..945df2555b 100755\n--- a/t/t3437-rebase-fixup-options.sh\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -210,4 +210,16 @@ test_expect_success 'sequence squash, fixup & fixup -c gives combined message' '\n \ttest_cmp_rev HEAD^ A\n '\n \n+test_expect_success 'fixup -C works upon --autosquash with amend!' '\n+\tgit checkout --detach branch &&\n+\tFAKE_COMMIT_AMEND=squashed \\\n+\t\tFAKE_MESSAGE_COPY=actual-squash-message \\\n+\t\tgit -c commit.status=false rebase -ik --autosquash \\\n+\t\t\t\t\t\t--signoff A &&\n+\tgit diff-tree --exit-code --patch HEAD branch -- &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-squash-message\" \\\n+\t\tactual-squash-message\n+'\n+\n test_done\n-- \n2.29.0.rc1\n\n"},{"id":"415580","messageId":"20210129182050.26143-6-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v4 5/9] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-01-29T18:20:46Z","receivedAt":"2021-01-29T18:26:11Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This makes it easier to use and reuse the comments.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 09cbb17f87..6d9a10afcf 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1732,6 +1732,11 @@ static size_t subject_length(const char *body)\n \treturn p - body;\n }\n \n+static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n+static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n+static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n@@ -1741,7 +1746,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n \t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n-\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n@@ -1770,7 +1775,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\tbuf.buf : strchrnul(buf.buf, '\\n');\n \n \t\tstrbuf_addf(&header, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&header, _(\"This is a combination of %d commits.\"),\n+\t\tstrbuf_addf(&header, _(combined_commit_msg_fmt),\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n@@ -1794,9 +1799,9 @@ static int update_squash_messages(struct repository *r,\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is a combination of %d commits.\"), 2);\n+\t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(\"This is the 1st commit message:\"));\n+\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_addstr(&buf, body);\n \n@@ -1812,7 +1817,7 @@ static int update_squash_messages(struct repository *r,\n \t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n+\t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n-- \n2.29.0.rc1\n\n"},{"id":"415847","messageId":"CAPig+cQeBE7m8wf1e_soVrpvL3==u50MPyb90NwWLnFiUz1Byw@mail.gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-7-charvi077@gmail.com","subject":"Re: [PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-02T00:47:27Z","receivedAt":"2021-02-02T00:48:23Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Jan 29, 2021 at 1:24 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> Add options to `fixup` command to fixup both the commit contents and\n> message. `fixup -C` command is used to replace the original commit\n> message and `fixup -c`, additionally allows to edit the commit message.\n\nIn the cover letter for this series, you had this additional information:\n\n    This convention is similar to the existing `merge` command in the\n    interactive rebase, that also supports `-c` and `-C` options with\n    similar meanings.\n\nwhich helps to explain the choice of -c and -C. It might be nice to\ninclude that explanation in this commit message, as well (but not\nitself worth a re-roll).\n\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n> diff --git a/rebase-interactive.c b/rebase-interactive.c\n> @@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n>  \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n> -\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n> +\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n> +\"                   commit's log message. Use -C to replace with this\\n\"\n> +\"                   commit message or -c to edit the commit message\\n\"\n\nThis change jarringly introduces the first and only use of a period\nand capitalized word in the to-do help text. Perhaps instead say:\n\n    ... 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\nWhen `-c` says \"edit the commit message\" it's not clear what will be\nedited. The original's commit message? The replacement's message? A\ncombination of the two? If you can come up with a succinct way to word\nit such that it states more precisely what exactly will be edited, it\nwould be nice, but not necessarily worth a re-roll.\n\n> diff --git a/sequencer.c b/sequencer.c\n> @@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n> +enum todo_item_flags {\n> +       TODO_EDIT_MERGE_MSG    = (1 << 0),\n> +       TODO_REPLACE_FIXUP_MSG = (1 << 1),\n> +       TODO_EDIT_FIXUP_MSG    = (1 << 2),\n> +};\n\nI'm confused. These enumeration items are defined as bit flags,\nimplying that they may be combined, however...\n\n> @@ -1734,32 +1740,176 @@ static size_t subject_length(const char *body)\n> +static int check_fixup_flag(enum todo_command command,\n> +                           enum todo_item_flags flag)\n\n...here and elsewhere, you declare the argument as a strict\n`todo_item_flags` enum item rather than `unsigned` which is the\ntypical declaration when combining bit flag values. So, the picture\nthus far is confusing. Are the `todo_item_flags` values distinct\nunique values which will never be combined, or are they meant to be\ncombined?\n\n> +{\n> +       return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n> +                                        (flag & TODO_EDIT_FIXUP_MSG));\n> +}\n\nThis code adds to the confusion. In the function argument list, `flag`\nhas been declared as a single enum item, yet this code is treating\n`flag` as if it is a combination of bits. So, it's not clear what the\nintention is here. Is `flag` always going to be a specific enum item\nin this context or is it going to be a combination of bits? If it is\nonly ever going to be a distinct enum item, then one would expect this\ncode to be written like this:\n\n    return command == TODO_FIXUP &&\n        (flag == TODO_REPLACE_FIXUP_MSG ||\n        flag == TODO_EDIT_FIXUP_MSG);\n\nOtherwise, if `flag` will actually be a bag of bits, then the argument\nshould be declared as such:\n\n    static int check_fixup_flag(enum todo_command command,\n        unsigned flag)\n\nBy the way, the function name check_fixup_flag() doesn't necessarily\ndo a good job conveying the purpose of this function. Based upon the\nimplementation, I gather that it is checking whether the command is a\n\"fixup\" command, so perhaps the name could reflect that. Perhaps\nis_fixup() or something?\n\n> +static int append_squash_message(struct strbuf *buf, const char *body,\n> +                        enum todo_command command, struct replay_opts *opts,\n> +                        enum todo_item_flags flag)\n> +{\n> +       /*\n> +        * amend is non-interactive and not normally used with fixup!\n> +        * or squash! commits, so only comment out those subjects when\n> +        * squashing commit messages.\n> +        */\n> +       if (starts_with(body, \"amend!\") ||\n> +           ((command == TODO_SQUASH || seen_squash(opts)) &&\n> +            (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n>                 commented_len = subject_length(body);\n\nI understand from the cover letter that \"amend!\" is being added by\nthis series, however, no patch up to this point, nor this patch\nitself, adds \"amend!\" functionality, so it's surprising to see it\nbeing tested here. As a reader, I would expect code/comments related\nto \"amend!\" to be added in the patch which actually introduces\n\"amend!\" rather than doing it here.\n\n> +       /* fixup -C after squash behaves like squash */\n> +       if (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n> +               if (opts->signoff)\n> +                       append_signoff(buf, 0, 0);\n> +\n> +               if ((command == TODO_FIXUP) &&\n> +                   (flag & TODO_REPLACE_FIXUP_MSG) &&\n> +                   (file_exists(rebase_path_fixup_msg()) ||\n> +                    !file_exists(rebase_path_squash_msg()))) {\n\nIs the expression `command == TODO_FIXUP` redundant here considering\nthat the only way we got this far is if check_fixup_flag() returned\ntrue, in which case we know that command is TODO_FIXUP? Or am I\nmissing something?\n\n> @@ -2281,6 +2436,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n> +       if (item->command == TODO_FIXUP) {\n> +               if (skip_prefix(bol, \"-C\", &bol) &&\n> +                  (*bol == ' ' || *bol == '\\t')) {\n> +                       bol += strspn(bol, \" \\t\");\n> +                       item->flags |= TODO_REPLACE_FIXUP_MSG;\n> +               } else if (skip_prefix(bol, \"-c\", &bol) &&\n> +                                 (*bol == ' ' || *bol == '\\t')) {\n> +                       bol += strspn(bol, \" \\t\");\n> +                       item->flags |= TODO_EDIT_FIXUP_MSG;\n> +               }\n> +       }\n\nI was wondering if the above could be rephrased like this to avoid the\nrepetition:\n\n    if (bol[0] == '-' && tolower(bol[1]) == 'c' &&\n        (bol[2] == ' ' || bol[2] == '\\t') {\n        item->flags |= bol[1] == 'C' ?\n            TODO_REPLACE_FIXUP_MSG :\n            TODO_EDIT_FIXUP_MSG;\n        bol += 2 + strspn(bol + 2, \" \\t\");\n    }\n\nbut perhaps it's too magical and ugly.\n"},{"id":"415854","messageId":"CAPig+cQO_uHurPn3N-k-UwBFgvx2x8Bx2Uy+=sQxhmj3E6rt7Q@mail.gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-8-charvi077@gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-02T02:01:24Z","receivedAt":"2021-02-02T02:02:24Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> Mentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n> diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\n> @@ -51,6 +53,8 @@ set_fake_editor () {\n>                 exec_*|x_*|break|b)\n>                         echo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n> +               merge_*|fixup_*)\n> +                       action=$(echo \"$line\" | sed 's/_/ /g');;\n\nWhat is \"merge_\" doing here? It doesn't seem to be used by this patch.\n\nThe function comment above this code may also need to be updated to\nreflect this change.\n\n> diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\n> @@ -0,0 +1,213 @@\n> +#!/bin/sh\n> +#\n> +# Copyright (c) 2018 Phillip Wood\n\nDid Phillip write this script? Is this patch based upon an old patch from him?\n\n> +test_commit_message () {\n> +       rev=\"$1\" && # commit or tag we want to test\n> +       file=\"$2\" && # test against the content of a file\n> +       git show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n> +       if test \"$2\" = -m\n> +       then\n> +               str=\"$3\" && # test against a string\n> +               printf \"%s\\n\" \"$str\" >tmp-expected-message &&\n> +               file=\"tmp-expected-message\"\n> +       fi\n> +       test_cmp \"$file\" actual-message\n> +}\n\nBy embedding comments in the function itself explaining $1, $2, and\n$3, anyone who adds tests to this script in the future is forced to\nread the function implementation to understand how to call it. Adding\nfunction documentation can remove that burden. For instance:\n\n    # test_commit_message <rev> -m <msg>\n    # test_commit_message <rev> <path>\n    #    Verify that the commit message of <rev> matches\n    #    <msg> or the content of <path>.\n    test_commit_message ()  {\n        ...\n    }\n\nThe implementation of test_commit_message() is a bit hard to follow.\nIt might be simpler to write it more concisely and directly like this:\n\n    git show --no-patch --pretty=format:%B \"$1\" >actual &&\n    case \"$2\" in\n    -m) echo \"$3\" >expect && test_cmp expect actual ;;\n    *) test_cmp \"$2\" actual ;;\n    esac\n\n> +test_expect_success 'setup' '\n> +       cat >message <<-EOF &&\n> +               amend! B\n> +               ${EMPTY}\n> +               new subject\n> +               ${EMPTY}\n> +               new\n> +               body\n> +               EOF\n\nStyle nit: In Git test scripts, the here-doc body and EOF are indented\nthe same amount as the command which opened the here-doc:\n\n    cat >message <<-EOF &&\n    amend! B\n    ...\n    body\n    EOF\n\nAlso, `$EMPTY` is perfectly fine; no need to write it as `${EMPTY}`.\n\n> +       ORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n> +       ORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n> +       GIT_AUTHOR_NAME=\"Amend Author\" &&\n> +       GIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n> +       test_commit \"$(cat message)\" A A1 A1 &&\n> +       test_commit A2 A &&\n> +       test_commit A3 A &&\n> +       GIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n> +       GIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n\nAre the timestamps of these commits meaningful in this context? If\nnot, another way to do this would be to assign the new author\nname/email values in a subshell so that the values do not need to be\nrestored manually. For instance:\n\n    (\n        GIT_AUTHOR_NAME=\"Amend Author\" &&\n        GIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n        test_commit \"$(cat message)\" A A1 A1 &&\n        test_commit A2 A &&\n        test_commit A3 A\n    ) &&\n\nIt's a matter of taste whether or not that is preferable, though.\n\n> +       echo B1 >B &&\n> +       test_tick &&\n> +       git commit --fixup=HEAD -a &&\n> +       test_tick &&\n\nSame question about whether the commit timestamps have any\nsignificance in these tests. If not, then these test_tick() calls\nmislead the reader into thinking that the timestamps are significant,\nthus it would make sense to drop them.\n\n> +test_expect_success 'simple fixup -C works' '\n> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> +       git checkout --detach A2 &&\n> +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n\nI see that you mirrored the implementation of FAKE_LINES handling of\n\"exec\" here for \"fixup\", but the cases are quite different. The\nargument to \"exec\" is arbitrary and can have any number of spaces\nembedded in it, which conflicts with the meaning of spaces in\nFAKE_LINES, which separate the individual commands in FAKE_LINES.\nConsequently, \"_\" was chosen as a placeholder in \"exec\" to mean\n\"space\".\n\nHowever, \"fixup\" is a very different beast. Its arguments are not\narbitrary at all, so there isn't a good reason to mirror the choice of\n\"_\" to represent a space, which leads to rather unsightly tokens such\nas \"fixup_-C\". It would work just as well to use simpler tokens such\nas \"fixup-C\" and \"fixup-c\", in which case t/lib-rebase.sh might parse\nthem like this (note that I also dropped `g` from the `sed` action):\n\n    fixup-*)\n        action=$(echo \"$line\" | sed 's/-/ -/');;\n\nIn fact, the recognized set of options following \"fixup\" is so small,\nthat you could even get by with simpler tokens \"fixupC\" and \"fixupc\":\n\n    fixupC)\n        action=\"fixup -C\";;\n    fixupc)\n        actions=\"fixup -c\";;\n\nThough it's subjective whether or not \"fixupC\" and \"fixupc\" are nicer\nthan \"fixup-C\" and \"fixup-c\", respectively.\n\n> +test_expect_success 'fixup -C removes amend! from message' '\n> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> +       git checkout --detach A1 &&\n> +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n> +       test_cmp_rev HEAD^ A &&\n> +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> +       test_commit_message HEAD expected-message &&\n> +       get_author HEAD >actual-author &&\n> +       test_cmp expected-author actual-author\n> +'\n\nThis test seems out of place. I would expect to see it added in the\npatch which adds \"amend!\" functionality.\n\nAlternatively, if the intention really is to support \"amend!\" this\nearly in the series in [6/9], then the commit message of [6/9] should\ntalk about it.\n\n> +test_expect_success 'fixup -C with conflicts gives correct message' '\n> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n\nIs there a reason this isn't written as:\n\n    test_when_finished \"reset_rebase\" &&\n\nwhich is more common? Is there something non-obvious which makes\nreset_rebase() inappropriate in these tests?\n\n> +       git checkout --detach A1 &&\n> +       test_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n> +       git checkout --theirs -- A &&\n> +       git add A &&\n> +       FAKE_COMMIT_AMEND=edited git rebase --continue &&\n> +       test_cmp_rev HEAD^ conflicts &&\n> +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> +       test_write_lines \"\" edited >>expected-message &&\n\nIt feels clunky and fragile for this test to be changing\n\"expected-message\" which was created in the \"setup\" test and used\nunaltered up to this point. If the content of \"expected-message\" is\nreally going to change from test to test (as I see it changes again in\na later test), then it would be easier to reason about the behavior if\neach test gives \"expected-message\" the precise content it should have\nin that local context. As it is currently implemented, it's too\ndifficult to follow along and remember the value of \"expected-message\"\nfrom test to test. It also makes it difficult to extend tests or add\nnew tests in between existing tests without negatively impacting other\ntests. If each test sets up \"expected-message\" to the precise content\nneeded by the test, then both those problems go away.\n\n> +test_expect_success 'multiple fixup -c opens editor once' '\n> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> +       git checkout --detach A3 &&\n> +       base=$(git rev-parse HEAD~4) &&\n> +       FAKE_COMMIT_MESSAGE=\"Modified-A3\" \\\n> +               FAKE_LINES=\"1 fixup_-C 2 fixup_-c 3 fixup_-c 4\" \\\n> +               EXPECT_HEADER_COUNT=4 \\\n> +               git rebase -i $base &&\n> +       test_cmp_rev $base HEAD^ &&\n> +       test 1 = $(git show | grep Modified-A3 | wc -l)\n> +'\n\nThese days, we would phrase the last part of the test as:\n\n    git show > raw &&\n    grep Modified-A3 raw >out &&\n    test_line_count = 1 out\n"},{"id":"415876","messageId":"CAPig+cTyK_OPixAnJQc_cO4vHzA++hfyfGEA7uZBK3ukCWD0PA@mail.gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-9-charvi077@gmail.com","subject":"Re: [PATCH v4 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-02T03:20:31Z","receivedAt":"2021-02-02T03:21:26Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> If the commit subject starts with \"amend!\" then rearrange it like a\n> \"fixup!\" commit and replace `pick` command with `fixup -C` command,\n> which is used to fixup up the content if any and replaces the original\n> commit message with amend! commit's message.\n>\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n>  sequencer.c                     | 23 ++++++++++++++++-------\n>  t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n>  2 files changed, 28 insertions(+), 7 deletions(-)\n\nIs this new behavior of recognizing \"amend!\" in the subject documented\nanywhere? I checked the documentation patch [9/9] but didn't see any\nmention of it.\n\n> diff --git a/sequencer.c b/sequencer.c\n> @@ -5662,6 +5662,12 @@ static int subject2item_cmp(const void *fndata,\n> +static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n> +       return skip_prefix(subject, \"fixup! \", p) ||\n> +              skip_prefix(subject, \"amend! \", p) ||\n> +              skip_prefix(subject, \"squash! \", p);\n> +}\n\nWhile the function name skip_fixup_amend_squash() may be accurate, it\nwon't scale well. What happens when additional fixup-like prefixes are\nadded in the future? Does the function name get extended to name them,\nas well? How about choosing a more generic, yet still meaningful,\nfunction name which doesn't suffer from this scaling problem. Perhaps\nskip_fixupish() or fix_squashlike() or something.\n\nAlso, making this function `inline` seems like a case of premature optimization.\n"},{"id":"415877","messageId":"f3e2b9ce-3dfe-e33a-6149-ca23397b1690@sunshineco.com","threadId":"54958","inReplyTo":"20210129182050.26143-10-charvi077@gmail.com","subject":"Re: [PATCH v4 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-02T03:23:57Z","receivedAt":"2021-02-02T03:24:57Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On 1/29/21 1:20 PM, Charvi Mendiratta wrote:\n> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> ---\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> @@ -887,9 +887,17 @@ If you want to fold two or more commits into one, replace the command\n>   If the commits had different authors, the folded commit will be\n>   attributed to the author of the first commit.  The suggested commit\n> -message for the folded commit is the concatenation of the commit\n> -messages of the first commit and of those with the \"squash\" command,\n> -but omits the commit messages of commits with the \"fixup\" command.\n> +message for the folded commit is the concatenation of the first\n> +commit's message with those identified by \"squash\" commands, omitting the\n> +messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n> +is used.  In that case the suggested commit message is only the message\n> +of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n> +the message.  The contents (patch) of the \"fixup -c\" commit are still\n> +incorporated into the folded commit. If there is more than one \"fixup -c\"\n> +commit, the message from the last last one is used.  You can also use\n\nErm, s/last last/last/ or even better s/last last/final/\n\n> +\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n> +an editor.\n> +\n>   \n>   'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n>   when a command fails due to merge errors. When you are done editing\n\nIt seems like an extra blank line sneaked in between the updated \nparagraph and the paragraph which follows it.\n"},{"id":"415912","messageId":"CAP8UFD2m18ZemGMkfzFhO1TUrMjNOGuQCqP1KVnRK7JEngeuog@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cQO_uHurPn3N-k-UwBFgvx2x8Bx2Uy+=sQxhmj3E6rt7Q@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-02-02T10:02:04Z","receivedAt":"2021-02-02T10:03:18Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Tue, Feb 2, 2021 at 3:01 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > Mentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> > diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\n> > @@ -51,6 +53,8 @@ set_fake_editor () {\n> >                 exec_*|x_*|break|b)\n> >                         echo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n> > +               merge_*|fixup_*)\n> > +                       action=$(echo \"$line\" | sed 's/_/ /g');;\n>\n> What is \"merge_\" doing here? It doesn't seem to be used by this patch.\n\nYeah, it's not used, but it might be a good thing to add this for\nconsistency while at it.\n\n> The function comment above this code may also need to be updated to\n> reflect this change.\n\nYeah, good suggestion.\n\n> > diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\n> > @@ -0,0 +1,213 @@\n> > +#!/bin/sh\n> > +#\n> > +# Copyright (c) 2018 Phillip Wood\n>\n> Did Phillip write this script? Is this patch based upon an old patch from him?\n\nYeah, it might be a good idea to add a \"Based-on-patch-by: Phillip ...\"\n\n> > +test_commit_message () {\n> > +       rev=\"$1\" && # commit or tag we want to test\n> > +       file=\"$2\" && # test against the content of a file\n> > +       git show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n> > +       if test \"$2\" = -m\n> > +       then\n> > +               str=\"$3\" && # test against a string\n> > +               printf \"%s\\n\" \"$str\" >tmp-expected-message &&\n> > +               file=\"tmp-expected-message\"\n> > +       fi\n> > +       test_cmp \"$file\" actual-message\n> > +}\n>\n> By embedding comments in the function itself explaining $1, $2, and\n> $3, anyone who adds tests to this script in the future is forced to\n> read the function implementation to understand how to call it. Adding\n> function documentation can remove that burden. For instance:\n>\n>     # test_commit_message <rev> -m <msg>\n>     # test_commit_message <rev> <path>\n>     #    Verify that the commit message of <rev> matches\n>     #    <msg> or the content of <path>.\n>     test_commit_message ()  {\n>         ...\n>     }\n\nGood suggestion.\n\n> The implementation of test_commit_message() is a bit hard to follow.\n> It might be simpler to write it more concisely and directly like this:\n>\n>     git show --no-patch --pretty=format:%B \"$1\" >actual &&\n>     case \"$2\" in\n>     -m) echo \"$3\" >expect && test_cmp expect actual ;;\n\nI think we try to avoid many commands on the same line.\n\n>     *) test_cmp \"$2\" actual ;;\n>     esac\n\nIn general I am not sure that using $1, $2, $3 directly makes things\neasier to understand, but yeah, with the function documentation that\nyou suggest, it might be better to write the function using them\ndirectly.\n\n> > +test_expect_success 'setup' '\n> > +       cat >message <<-EOF &&\n> > +               amend! B\n> > +               ${EMPTY}\n> > +               new subject\n> > +               ${EMPTY}\n> > +               new\n> > +               body\n> > +               EOF\n>\n> Style nit: In Git test scripts, the here-doc body and EOF are indented\n> the same amount as the command which opened the here-doc:\n\nI don't think we are very consistent with this and I didn't find\nanything about this in CodingGuidelines.\n\nIn t0008 and t0021 for example, the indentation is more like:\n\n     cat >message <<-EOF &&\n          amend! B\n          ...\n          body\n     EOF\n\nand I like this style, as it seems clearer than the other styles.\n\n[...]\n\n> > +test_expect_success 'simple fixup -C works' '\n> > +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> > +       git checkout --detach A2 &&\n> > +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n>\n> I see that you mirrored the implementation of FAKE_LINES handling of\n> \"exec\" here for \"fixup\", but the cases are quite different. The\n> argument to \"exec\" is arbitrary and can have any number of spaces\n> embedded in it, which conflicts with the meaning of spaces in\n> FAKE_LINES, which separate the individual commands in FAKE_LINES.\n> Consequently, \"_\" was chosen as a placeholder in \"exec\" to mean\n> \"space\".\n>\n> However, \"fixup\" is a very different beast. Its arguments are not\n> arbitrary at all, so there isn't a good reason to mirror the choice of\n> \"_\" to represent a space, which leads to rather unsightly tokens such\n> as \"fixup_-C\". It would work just as well to use simpler tokens such\n> as \"fixup-C\" and \"fixup-c\", in which case t/lib-rebase.sh might parse\n> them like this (note that I also dropped `g` from the `sed` action):\n>\n>     fixup-*)\n>         action=$(echo \"$line\" | sed 's/-/ -/');;\n\nI agree that \"fixup\" arguments are not arbitrary at all, but I think\nit makes things simpler to just use one way to encode spaces instead\nof many different ways.\n\n> In fact, the recognized set of options following \"fixup\" is so small,\n> that you could even get by with simpler tokens \"fixupC\" and \"fixupc\":\n>\n>     fixupC)\n>         action=\"fixup -C\";;\n>     fixupc)\n>         actions=\"fixup -c\";;\n>\n> Though it's subjective whether or not \"fixupC\" and \"fixupc\" are nicer\n> than \"fixup-C\" and \"fixup-c\", respectively.\n\nI don't think this would scale nicely when the number of options grows\nfor both \"fixup\" and \"merge\".\n\n> > +test_expect_success 'fixup -C removes amend! from message' '\n> > +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> > +       git checkout --detach A1 &&\n> > +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n> > +       test_cmp_rev HEAD^ A &&\n> > +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> > +       test_commit_message HEAD expected-message &&\n> > +       get_author HEAD >actual-author &&\n> > +       test_cmp expected-author actual-author\n> > +'\n>\n> This test seems out of place. I would expect to see it added in the\n> patch which adds \"amend!\" functionality.\n>\n> Alternatively, if the intention really is to support \"amend!\" this\n> early in the series in [6/9], then the commit message of [6/9] should\n> talk about it.\n\nYeah, I think it might be better to just remove everything related to\n\"amend!\" in this series and put it into the next one.\n\n[...]\n\n> > +       git checkout --detach A1 &&\n> > +       test_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n> > +       git checkout --theirs -- A &&\n> > +       git add A &&\n> > +       FAKE_COMMIT_AMEND=edited git rebase --continue &&\n> > +       test_cmp_rev HEAD^ conflicts &&\n> > +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> > +       test_write_lines \"\" edited >>expected-message &&\n>\n> It feels clunky and fragile for this test to be changing\n> \"expected-message\" which was created in the \"setup\" test and used\n> unaltered up to this point. If the content of \"expected-message\" is\n> really going to change from test to test (as I see it changes again in\n> a later test), then it would be easier to reason about the behavior if\n> each test gives \"expected-message\" the precise content it should have\n> in that local context. As it is currently implemented, it's too\n> difficult to follow along and remember the value of \"expected-message\"\n> from test to test. It also makes it difficult to extend tests or add\n> new tests in between existing tests without negatively impacting other\n> tests. If each test sets up \"expected-message\" to the precise content\n> needed by the test, then both those problems go away.\n\nYeah, perhaps the global \"expected-message\" could be renamed for\nexample \"global-expected-message\", and tests which need a specific one\ncould prepare and use a custom \"expected-message\" (maybe named\n\"custom-expected-message\") without ever changing\n\"global-expected-message\".\n\nThanks for your review!\n"},{"id":"415923","messageId":"CAPSFM5fZHZDnmRD2GzwPVKwBjogKD=GJbC7e=6aQSbu_iXBdNw@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cQeBE7m8wf1e_soVrpvL3==u50MPyb90NwWLnFiUz1Byw@mail.gmail.com","subject":"Re: [PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-02T15:29:12Z","receivedAt":"2021-02-02T15:32:29Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Eric,\n\nOn Tue, 2 Feb 2021 at 06:17, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Jan 29, 2021 at 1:24 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > Add options to `fixup` command to fixup both the commit contents and\n> > message. `fixup -C` command is used to replace the original commit\n> > message and `fixup -c`, additionally allows to edit the commit message.\n>\n> In the cover letter for this series, you had this additional information:\n>\n>     This convention is similar to the existing `merge` command in the\n>     interactive rebase, that also supports `-c` and `-C` options with\n>     similar meanings.\n>\n> which helps to explain the choice of -c and -C. It might be nice to\n> include that explanation in this commit message, as well (but not\n> itself worth a re-roll).\n>\n\nAgree, I will include this in the commit message.\n\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> > diff --git a/rebase-interactive.c b/rebase-interactive.c\n> > @@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n> >  \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n> > -\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n> > +\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n> > +\"                   commit's log message. Use -C to replace with this\\n\"\n> > +\"                   commit message or -c to edit the commit message\\n\"\n>\n> This change jarringly introduces the first and only use of a period\n> and capitalized word in the to-do help text. Perhaps instead say:\n>\n>     ... 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>\n\nOkay, I will change it.\n\n> When `-c` says \"edit the commit message\" it's not clear what will be\n> edited. The original's commit message? The replacement's message? A\n> combination of the two? If you can come up with a succinct way to word\n> it such that it states more precisely what exactly will be edited, it\n> would be nice, but not necessarily worth a re-roll.\n>\n\nHere the editor shows the commented out commit message of original commit and\nthe replacement commit message (of fixup -c commit) is not commented out.\n\nSo maybe s/edit the commit message/edit this commit message  is better.\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > @@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n> > +enum todo_item_flags {\n> > +       TODO_EDIT_MERGE_MSG    = (1 << 0),\n> > +       TODO_REPLACE_FIXUP_MSG = (1 << 1),\n> > +       TODO_EDIT_FIXUP_MSG    = (1 << 2),\n> > +};\n>\n> I'm confused. These enumeration items are defined as bit flags,\n> implying that they may be combined, however...\n>\n> > @@ -1734,32 +1740,176 @@ static size_t subject_length(const char *body)\n> > +static int check_fixup_flag(enum todo_command command,\n> > +                           enum todo_item_flags flag)\n>\n> ...here and elsewhere, you declare the argument as a strict\n> `todo_item_flags` enum item rather than `unsigned` which is the\n> typical declaration when combining bit flag values. So, the picture\n> thus far is confusing. Are the `todo_item_flags` values distinct\n> unique values which will never be combined, or are they meant to be\n> combined?\n>\n> > +{\n> > +       return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n> > +                                        (flag & TODO_EDIT_FIXUP_MSG));\n> > +}\n>\n> This code adds to the confusion. In the function argument list, `flag`\n> has been declared as a single enum item, yet this code is treating\n> `flag` as if it is a combination of bits. So, it's not clear what the\n> intention is here. Is `flag` always going to be a specific enum item\n> in this context or is it going to be a combination of bits? If it is\n> only ever going to be a distinct enum item, then one would expect this\n> code to be written like this:\n>\n>     return command == TODO_FIXUP &&\n>         (flag == TODO_REPLACE_FIXUP_MSG ||\n>         flag == TODO_EDIT_FIXUP_MSG);\n>\n> Otherwise, if `flag` will actually be a bag of bits, then the argument\n> should be declared as such:\n>\n>     static int check_fixup_flag(enum todo_command command,\n>         unsigned flag)\n>\n\nI admit it resulted in a bit of confusion. Here, its true that flag is always\ngoing to be specific enum item( as command can be merge -c, fixup -c, or\nfixup -C ) and I combined the bag of bits to denote\nthe specific enum item. So, maybe we can go with the first method?\n\n> By the way, the function name check_fixup_flag() doesn't necessarily\n> do a good job conveying the purpose of this function. Based upon the\n> implementation, I gather that it is checking whether the command is a\n> \"fixup\" command, so perhaps the name could reflect that. Perhaps\n> is_fixup() or something?\n>\n\nAgree, here it's checking if the command is fixup and the flag value (\nwhich implies either user has given command fixup -c or fixup -C )\nSo, I wonder if we can write is_fixup_flag() ?\n\n> > +static int append_squash_message(struct strbuf *buf, const char *body,\n> > +                        enum todo_command command, struct replay_opts *opts,\n> > +                        enum todo_item_flags flag)\n> > +{\n> > +       /*\n> > +        * amend is non-interactive and not normally used with fixup!\n> > +        * or squash! commits, so only comment out those subjects when\n> > +        * squashing commit messages.\n> > +        */\n> > +       if (starts_with(body, \"amend!\") ||\n> > +           ((command == TODO_SQUASH || seen_squash(opts)) &&\n> > +            (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))))\n> >                 commented_len = subject_length(body);\n>\n> I understand from the cover letter that \"amend!\" is being added by\n> this series, however, no patch up to this point, nor this patch\n> itself, adds \"amend!\" functionality, so it's surprising to see it\n> being tested here. As a reader, I would expect code/comments related\n> to \"amend!\" to be added in the patch which actually introduces\n> \"amend!\" rather than doing it here.\n>\n\nThis patch series does not include the implementation of amend! commit.\nI think to avoid the confusion I will remove this part from this patch series\nand add it in the next patch series for amend! commit.\n\n> > +       /* fixup -C after squash behaves like squash */\n> > +       if (check_fixup_flag(command, flag) && !seen_squash(opts)) {\n> > +               if (opts->signoff)\n> > +                       append_signoff(buf, 0, 0);\n> > +\n> > +               if ((command == TODO_FIXUP) &&\n> > +                   (flag & TODO_REPLACE_FIXUP_MSG) &&\n> > +                   (file_exists(rebase_path_fixup_msg()) ||\n> > +                    !file_exists(rebase_path_squash_msg()))) {\n>\n> Is the expression `command == TODO_FIXUP` redundant here considering\n> that the only way we got this far is if check_fixup_flag() returned\n> true, in which case we know that command is TODO_FIXUP? Or am I\n> missing something?\n\nYes, it implies the same.\n\n>\n> > @@ -2281,6 +2436,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n> > +       if (item->command == TODO_FIXUP) {\n> > +               if (skip_prefix(bol, \"-C\", &bol) &&\n> > +                  (*bol == ' ' || *bol == '\\t')) {\n> > +                       bol += strspn(bol, \" \\t\");\n> > +                       item->flags |= TODO_REPLACE_FIXUP_MSG;\n> > +               } else if (skip_prefix(bol, \"-c\", &bol) &&\n> > +                                 (*bol == ' ' || *bol == '\\t')) {\n> > +                       bol += strspn(bol, \" \\t\");\n> > +                       item->flags |= TODO_EDIT_FIXUP_MSG;\n> > +               }\n> > +       }\n>\n> I was wondering if the above could be rephrased like this to avoid the\n> repetition:\n>\n>     if (bol[0] == '-' && tolower(bol[1]) == 'c' &&\n>         (bol[2] == ' ' || bol[2] == '\\t') {\n>         item->flags |= bol[1] == 'C' ?\n>             TODO_REPLACE_FIXUP_MSG :\n>             TODO_EDIT_FIXUP_MSG;\n>         bol += 2 + strspn(bol + 2, \" \\t\");\n>     }\n>\n> but perhaps it's too magical and ugly.\n\nI agree, this [tolower(bol[1]) == 'c'] is actually doing all the\nmagic, but I am not\nsure if we should change it or not ? As in the source code just after\nthis code we\nare checking in a similar way for the 'merge' command. So, maybe implementing\nin a similar way is easier to read ?\n\nThanks and Regards,\nCharvi\n"},{"id":"415924","messageId":"CAPSFM5cRcVYfNSnm_-FyRRJc4mnh-t2BaSbhd7nE3uz-zv=+vQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cTyK_OPixAnJQc_cO4vHzA++hfyfGEA7uZBK3ukCWD0PA@mail.gmail.com","subject":"Re: [PATCH v4 8/9] rebase -i: teach --autosquash to work with amend!","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-02T15:29:45Z","receivedAt":"2021-02-02T15:32:58Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Tue, 2 Feb 2021 at 08:50, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > If the commit subject starts with \"amend!\" then rearrange it like a\n> > \"fixup!\" commit and replace `pick` command with `fixup -C` command,\n> > which is used to fixup up the content if any and replaces the original\n> > commit message with amend! commit's message.\n> >\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> >  sequencer.c                     | 23 ++++++++++++++++-------\n> >  t/t3437-rebase-fixup-options.sh | 12 ++++++++++++\n> >  2 files changed, 28 insertions(+), 7 deletions(-)\n>\n> Is this new behavior of recognizing \"amend!\" in the subject documented\n> anywhere? I checked the documentation patch [9/9] but didn't see any\n> mention of it.\n>\n\nNo this patch series does not include that but included in the patch series of\namend! commit implementation that is not sent to the mailing list yet.\n(Apology for the confusion)\n\n> > diff --git a/sequencer.c b/sequencer.c\n> > @@ -5662,6 +5662,12 @@ static int subject2item_cmp(const void *fndata,\n> > +static inline int skip_fixup_amend_squash(const char *subject, const char **p) {\n> > +       return skip_prefix(subject, \"fixup! \", p) ||\n> > +              skip_prefix(subject, \"amend! \", p) ||\n> > +              skip_prefix(subject, \"squash! \", p);\n> > +}\n>\n> While the function name skip_fixup_amend_squash() may be accurate, it\n> won't scale well. What happens when additional fixup-like prefixes are\n> added in the future? Does the function name get extended to name them,\n> as well? How about choosing a more generic, yet still meaningful,\n> function name which doesn't suffer from this scaling problem. Perhaps\n> skip_fixupish() or fix_squashlike() or something.\n>\n\nI agree completely, and will change the function name  to skip_fixupish().\n\n> Also, making this function `inline` seems like a case of premature optimization.\n\nOkay, will remove `inline`.\n\nThanks and Regards,\nCharvi\n"},{"id":"415925","messageId":"CAPSFM5f_=-MFUnZtt9KKLBcd56L_m3SZ8OZr5xjUwG3zgo+7pQ@mail.gmail.com","threadId":"54958","inReplyTo":"f3e2b9ce-3dfe-e33a-6149-ca23397b1690@sunshineco.com","subject":"Re: [PATCH v4 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-02T15:30:18Z","receivedAt":"2021-02-02T15:32:59Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Tue, 2 Feb 2021 at 08:53, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On 1/29/21 1:20 PM, Charvi Mendiratta wrote:\n> > Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n> > ---\n> > diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> > @@ -887,9 +887,17 @@ If you want to fold two or more commits into one, replace the command\n> >   If the commits had different authors, the folded commit will be\n> >   attributed to the author of the first commit.  The suggested commit\n> > -message for the folded commit is the concatenation of the commit\n> > -messages of the first commit and of those with the \"squash\" command,\n> > -but omits the commit messages of commits with the \"fixup\" command.\n> > +message for the folded commit is the concatenation of the first\n> > +commit's message with those identified by \"squash\" commands, omitting the\n> > +messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n> > +is used.  In that case the suggested commit message is only the message\n> > +of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n> > +the message.  The contents (patch) of the \"fixup -c\" commit are still\n> > +incorporated into the folded commit. If there is more than one \"fixup -c\"\n> > +commit, the message from the last last one is used.  You can also use\n>\n> Erm, s/last last/last/ or even better s/last last/final/\n>\n\nOkay, I will correct it as s/last last/final\n\n> > +\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n> > +an editor.\n> > +\n> >\n> >   'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n> >   when a command fails due to merge errors. When you are done editing\n>\n> It seems like an extra blank line sneaked in between the updated\n> paragraph and the paragraph which follows it.\n\nOkay, I will remove it. Thanks for all the reviews!\n\nThanks and Regards,\nCharvi\n"},{"id":"415926","messageId":"CAPSFM5dWLLa2HVVDyh+_vW-Kv=8wn-MOz7YUOXUr=hqn0jumQQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD2m18ZemGMkfzFhO1TUrMjNOGuQCqP1KVnRK7JEngeuog@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-02T15:31:24Z","receivedAt":"2021-02-02T15:35:12Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi,\n\nOn Tue, 2 Feb 2021 at 15:32, Christian Couder\n<christian.couder@gmail.com> wrote:\n[...]\n> > The function comment above this code may also need to be updated to\n> > reflect this change.\n>\n> Yeah, good suggestion.\n>\n\nOkay, I will add that .\n\n> > > diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\n> > > @@ -0,0 +1,213 @@\n> > > +#!/bin/sh\n> > > +#\n> > > +# Copyright (c) 2018 Phillip Wood\n> >\n> > Did Phillip write this script? Is this patch based upon an old patch from him?\n>\n> Yeah, it might be a good idea to add a \"Based-on-patch-by: Phillip ...\"\n>\n\nOops, I forgot to add the trailer in this patch and will add it.\n\n> > > +test_commit_message () {\n> > > +       rev=\"$1\" && # commit or tag we want to test\n> > > +       file=\"$2\" && # test against the content of a file\n> > > +       git show --no-patch --pretty=format:%B \"$rev\" >actual-message &&\n> > > +       if test \"$2\" = -m\n> > > +       then\n> > > +               str=\"$3\" && # test against a string\n> > > +               printf \"%s\\n\" \"$str\" >tmp-expected-message &&\n> > > +               file=\"tmp-expected-message\"\n> > > +       fi\n> > > +       test_cmp \"$file\" actual-message\n> > > +}\n> >\n> > By embedding comments in the function itself explaining $1, $2, and\n> > $3, anyone who adds tests to this script in the future is forced to\n> > read the function implementation to understand how to call it. Adding\n> > function documentation can remove that burden. For instance:\n> >\n> >     # test_commit_message <rev> -m <msg>\n> >     # test_commit_message <rev> <path>\n> >     #    Verify that the commit message of <rev> matches\n> >     #    <msg> or the content of <path>.\n> >     test_commit_message ()  {\n> >         ...\n> >     }\n>\n> Good suggestion.\n>\n\nAgree, I will add the comments.\n\n> > The implementation of test_commit_message() is a bit hard to follow.\n> > It might be simpler to write it more concisely and directly like this:\n> >\n> >     git show --no-patch --pretty=format:%B \"$1\" >actual &&\n> >     case \"$2\" in\n> >     -m) echo \"$3\" >expect && test_cmp expect actual ;;\n>\n> I think we try to avoid many commands on the same line.\n>\n> >     *) test_cmp \"$2\" actual ;;\n> >     esac\n>\n> In general I am not sure that using $1, $2, $3 directly makes things\n> easier to understand, but yeah, with the function documentation that\n> you suggest, it might be better to write the function using them\n> directly.\n>\n\nOkay, I will update it.\n\n[...]\n> > > +test_expect_success 'fixup -C removes amend! from message' '\n> > > +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> > > +       git checkout --detach A1 &&\n> > > +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n> > > +       test_cmp_rev HEAD^ A &&\n> > > +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> > > +       test_commit_message HEAD expected-message &&\n> > > +       get_author HEAD >actual-author &&\n> > > +       test_cmp expected-author actual-author\n> > > +'\n> >\n> > This test seems out of place. I would expect to see it added in the\n> > patch which adds \"amend!\" functionality.\n> >\n> > Alternatively, if the intention really is to support \"amend!\" this\n> > early in the series in [6/9], then the commit message of [6/9] should\n> > talk about it.\n>\n> Yeah, I think it might be better to just remove everything related to\n> \"amend!\" in this series and put it into the next one.\n>\n\nAgree. Eric pointed at other patches also for amend! commit.\nSo I also admit that to avoid confusion, I will remove all these amend! part and\nwill add to other patch series.\n\n> [...]\n>\n> > > +       git checkout --detach A1 &&\n> > > +       test_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n> > > +       git checkout --theirs -- A &&\n> > > +       git add A &&\n> > > +       FAKE_COMMIT_AMEND=edited git rebase --continue &&\n> > > +       test_cmp_rev HEAD^ conflicts &&\n> > > +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n> > > +       test_write_lines \"\" edited >>expected-message &&\n> >\n> > It feels clunky and fragile for this test to be changing\n> > \"expected-message\" which was created in the \"setup\" test and used\n> > unaltered up to this point. If the content of \"expected-message\" is\n> > really going to change from test to test (as I see it changes again in\n> > a later test), then it would be easier to reason about the behavior if\n> > each test gives \"expected-message\" the precise content it should have\n> > in that local context. As it is currently implemented, it's too\n> > difficult to follow along and remember the value of \"expected-message\"\n> > from test to test. It also makes it difficult to extend tests or add\n> > new tests in between existing tests without negatively impacting other\n> > tests. If each test sets up \"expected-message\" to the precise content\n> > needed by the test, then both those problems go away.\n>\n\nI agree with it ...\n\n> Yeah, perhaps the global \"expected-message\" could be renamed for\n> example \"global-expected-message\", and tests which need a specific one\n> could prepare and use a custom \"expected-message\" (maybe named\n> \"custom-expected-message\") without ever changing\n> \"global-expected-message\".\n>\n\n... Okay, I will change it.\n\nThanks Eric and Christian for the suggestions and reviews. I will\ninclude all the changes\nin the next revision.\n\nThanks and Regards,\nCharvi\n"},{"id":"415941","messageId":"2f680005-db11-aaa9-9197-58d3ecf679dd@xiplink.com","threadId":"54958","inReplyTo":"f3e2b9ce-3dfe-e33a-6149-ca23397b1690@sunshineco.com","subject":"Re: [PATCH v4 9/9] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2021-02-02T14:12:27Z","receivedAt":"2021-02-02T17:27:57Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"On 2021-02-01 10:23 p.m., Eric Sunshine wrote:\n> On 1/29/21 1:20 PM, Charvi Mendiratta wrote:\n>> Signed-off-by: Charvi Mendiratta <charvi077@gmail.com>\n>> ---\n>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>> @@ -887,9 +887,17 @@ If you want to fold two or more commits into one, \n>> replace the command\n>>   If the commits had different authors, the folded commit will be\n>>   attributed to the author of the first commit.  The suggested commit\n>> -message for the folded commit is the concatenation of the commit\n>> -messages of the first commit and of those with the \"squash\" command,\n>> -but omits the commit messages of commits with the \"fixup\" command.\n>> +message for the folded commit is the concatenation of the first\n>> +commit's message with those identified by \"squash\" commands, omitting \n>> the\n>> +messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n>> +is used.  In that case the suggested commit message is only the message\n>> +of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n>> +the message.  The contents (patch) of the \"fixup -c\" commit are still\n>> +incorporated into the folded commit. If there is more than one \"fixup \n>> -c\"\n>> +commit, the message from the last last one is used.  You can also use\n> \n> Erm, s/last last/last/ or even better s/last last/final/\n\nI like \"final\", personally.\n\n\t\tM.\n\n>> +\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n>> +an editor.\n>> +\n>>   'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n>>   when a command fails due to merge errors. When you are done editing\n> \n> It seems like an extra blank line sneaked in between the updated \n> paragraph and the paragraph which follows it.\n"},{"id":"416026","messageId":"CAPig+cRxmFr_Sbwdf4OFMr8Vp1q6O6J7AbgYAD5cgdD--hgDuw@mail.gmail.com","threadId":"54958","inReplyTo":"CAPSFM5fZHZDnmRD2GzwPVKwBjogKD=GJbC7e=6aQSbu_iXBdNw@mail.gmail.com","subject":"Re: [PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-03T05:05:31Z","receivedAt":"2021-02-03T05:06:39Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Feb 2, 2021 at 10:29 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> On Tue, 2 Feb 2021 at 06:17, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > When `-c` says \"edit the commit message\" it's not clear what will be\n> > edited. The original's commit message? The replacement's message? A\n> > combination of the two? If you can come up with a succinct way to word\n> > it such that it states more precisely what exactly will be edited, it\n> > would be nice, but not necessarily worth a re-roll.\n>\n> Here the editor shows the commented out commit message of original commit and\n> the replacement commit message (of fixup -c commit) is not commented out.\n>\n> So maybe s/edit the commit message/edit this commit message  is better.\n\nYes, that would be clearer and is just as succinct.\n\n> > This code adds to the confusion. In the function argument list, `flag`\n> > has been declared as a single enum item, yet this code is treating\n> > `flag` as if it is a combination of bits. So, it's not clear what the\n> > intention is here. Is `flag` always going to be a specific enum item\n> > in this context or is it going to be a combination of bits? If it is\n> > only ever going to be a distinct enum item, then one would expect this\n> > code to be written like this:\n> >\n> >     return command == TODO_FIXUP &&\n> >         (flag == TODO_REPLACE_FIXUP_MSG ||\n> >         flag == TODO_EDIT_FIXUP_MSG);\n>\n> I admit it resulted in a bit of confusion. Here, its true that flag is always\n> going to be specific enum item( as command can be merge -c, fixup -c, or\n> fixup -C ) and I combined the bag of bits to denote\n> the specific enum item. So, maybe we can go with the first method?\n\nSounds fine. It would clarify the intent.\n\n> > By the way, the function name check_fixup_flag() doesn't necessarily\n> > do a good job conveying the purpose of this function. Based upon the\n> > implementation, I gather that it is checking whether the command is a\n> > \"fixup\" command, so perhaps the name could reflect that. Perhaps\n> > is_fixup() or something?\n>\n> Agree, here it's checking if the command is fixup and the flag value (\n> which implies either user has given command fixup -c or fixup -C )\n> So, I wonder if we can write is_fixup_flag() ?\n\nReasonable.\n\n> > I was wondering if the above could be rephrased like this to avoid the\n> > repetition:\n> > [...]\n> > but perhaps it's too magical and ugly.\n>\n> I agree, this [tolower(bol[1]) == 'c'] is actually doing all the\n> magic, but I am not\n> sure if we should change it or not ? As in the source code just after\n> this code we\n> are checking in a similar way for the 'merge' command. So, maybe implementing\n> in a similar way is easier to read ?\n\nKeeping it similar to nearby code makes sense.\n"},{"id":"416029","messageId":"CAPig+cSBVG0AdyqXH2mZp6Ohrcb8_ec1Mm_vGbQM4zWT_7yYxQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD2m18ZemGMkfzFhO1TUrMjNOGuQCqP1KVnRK7JEngeuog@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-03T05:44:40Z","receivedAt":"2021-02-03T05:45:38Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Tue, Feb 2, 2021 at 5:02 AM Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Tue, Feb 2, 2021 at 3:01 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > > +               merge_*|fixup_*)\n> > > +                       action=$(echo \"$line\" | sed 's/_/ /g');;\n> >\n> > What is \"merge_\" doing here? It doesn't seem to be used by this patch.\n>\n> Yeah, it's not used, but it might be a good thing to add this for\n> consistency while at it.\n\nIt confuses readers (as it did to me), causing them to waste\nbrain-cycles trying to figure out why it's present. Thus, it would be\nbetter to add it when it's actually needed. The waste of brain-cycles\nand time is especially important on a project like Git for which\nreviewers and reviewer time are limited resources.\n\n> > > +# Copyright (c) 2018 Phillip Wood\n> >\n> > Did Phillip write this script? Is this patch based upon an old patch from him?\n>\n> Yeah, it might be a good idea to add a \"Based-on-patch-by: Phillip ...\"\n\nAgreed.\n\n> > The implementation of test_commit_message() is a bit hard to follow.\n> > It might be simpler to write it more concisely and directly like this:\n> >\n> >     git show --no-patch --pretty=format:%B \"$1\" >actual &&\n> >     case \"$2\" in\n> >     -m) echo \"$3\" >expect && test_cmp expect actual ;;\n>\n> I think we try to avoid many commands on the same line.\n\nFor something this minor, it's not likely to matter but, of course, it\ncould be split over two lines:\n\n    -m) echo \"$3\" >expect &&\n        test_cmp expect actual ;;\n\n> >     *) test_cmp \"$2\" actual ;;\n> >     esac\n>\n> In general I am not sure that using $1, $2, $3 directly makes things\n> easier to understand, but yeah, with the function documentation that\n> you suggest, it might be better to write the function using them\n> directly.\n\nThe direct $1, $2, etc. was just an example. It's certainly possible\nto give them names even in the rewritten code I presented. One good\nreason, however, for just using $1, $2, etc. is that $2 is not well\ndefined; sometimes it's a switch (\"-m\") and sometimes its a pathname,\nso it's hard to invent a suitable variable name for it. Also, this\nfunction becomes so simple (in the rewritten version) that explicit\nvariable names don't add a lot of value (the cognitive load is quite\nlow because the function is so short).\n\n> > Style nit: In Git test scripts, the here-doc body and EOF are indented\n> > the same amount as the command which opened the here-doc:\n>\n> I don't think we are very consistent with this and I didn't find\n> anything about this in CodingGuidelines.\n>\n> In t0008 and t0021 for example, the indentation is more like:\n>\n>      cat >message <<-EOF &&\n>           amend! B\n>           ...\n>           body\n>      EOF\n>\n> and I like this style, as it seems clearer than the other styles.\n\nI performed a quick survey of the heredoc styles in the tests. Here\nare the results[1] of my analysis on the 'seen' branch:\n\ntotal-heredocs=4128\n\nsame-indent=3053 (<<EOF & body & EOF share indent)\n\n    cat >expect <<-\\EOF\n    body\n    EOF\n\nbody-eof-indented=24 (body & EOF indented)\n\n    cat >expect <<-\\EOF\n        body\n        EOF\n\nbody-indented=735 (body indented; EOF not)\n\n    cat >expect <<-\\EOF\n        body\n    EOF\n\nleft-margin=316 (<<EOF indented; body & EOF not)\n\n        cat >expect <<\\EOF\n    body\n    EOF\n\nSo, the indentation recommended in my review -- with 3053 instances\nout of 4128 heredocs -- is by far the most prevalent in the project.\n\n[1]: Note that there is a miniscule amount of inaccuracy in the\nnumbers because there are a few cases in which heredocs contain other\nheredocs, and some scripts build heredocs piecemeal when constructing\nother scripts, and I didn't bother making my analysis script handle\nthose few cases. The inaccuracy is tiny, thus not meaningful to the\noverall picture.\n\n> > I see that you mirrored the implementation of FAKE_LINES handling of\n> > \"exec\" here for \"fixup\", but the cases are quite different. The\n> > argument to \"exec\" is arbitrary and can have any number of spaces\n> > embedded in it, which conflicts with the meaning of spaces in\n> > FAKE_LINES, which separate the individual commands in FAKE_LINES.\n> > Consequently, \"_\" was chosen as a placeholder in \"exec\" to mean\n> > \"space\".\n> >\n> > However, \"fixup\" is a very different beast. Its arguments are not\n> > arbitrary at all, so there isn't a good reason to mirror the choice of\n> > \"_\" to represent a space, which leads to rather unsightly tokens such\n> > as \"fixup_-C\". It would work just as well to use simpler tokens such\n> > as \"fixup-C\" and \"fixup-c\", in which case t/lib-rebase.sh might parse\n> > them like this (note that I also dropped `g` from the `sed` action):\n> >\n> >     fixup-*)\n> >         action=$(echo \"$line\" | sed 's/-/ -/');;\n>\n> I agree that \"fixup\" arguments are not arbitrary at all, but I think\n> it makes things simpler to just use one way to encode spaces instead\n> of many different ways.\n\nIs that the intention here, though? Is the idea that some day `fixup`\nwill accept arbitrary arguments thus needs to encode spaces? If not,\nthen mirroring the treatment given to `exec` confuses readers into\nthinking that it will/should accept arbitrary arguments. I brought\nthis up in my review specifically because it was confusing to a person\n(me) new to this topic and reading the patches for the first time. The\nmore specific and exact the code can be, the less likely it will\nconfuse readers in the future.\n\nAnyhow, it's a minor point, not worth expending a lot of time discussing.\n\n> > It feels clunky and fragile for this test to be changing\n> > \"expected-message\" which was created in the \"setup\" test and used\n> > unaltered up to this point. If the content of \"expected-message\" is\n> > really going to change from test to test (as I see it changes again in\n> > a later test), then it would be easier to reason about the behavior if\n> > each test gives \"expected-message\" the precise content it should have\n> > in that local context. As it is currently implemented, it's too\n> > difficult to follow along and remember the value of \"expected-message\"\n> > from test to test. It also makes it difficult to extend tests or add\n> > new tests in between existing tests without negatively impacting other\n> > tests. If each test sets up \"expected-message\" to the precise content\n> > needed by the test, then both those problems go away.\n>\n> Yeah, perhaps the global \"expected-message\" could be renamed for\n> example \"global-expected-message\", and tests which need a specific one\n> could prepare and use a custom \"expected-message\" (maybe named\n> \"custom-expected-message\") without ever changing\n> \"global-expected-message\".\n\nThat would be fine, though I wondered while reviewing the patch if a\nglobal \"expect-message\" file was even needed since it didn't seem like\nvery many tests used it (but I didn't spend a lot of time counting the\nexact number of tests due to the high cognitive load tracing how that\nfile might mutate as it passed through each test).\n\nAnother really good reason for avoiding having later tests depend upon\nmutations from earlier tests, if possible, is that it makes it easier\nto run tests selectively with --run or GIT_SKIP_TESTS.\n"},{"id":"416115","messageId":"CAPSFM5fLi-U3zVcXFip_kgchHSXiEUF9nngO2nSf31kAEBkq1w@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cRxmFr_Sbwdf4OFMr8Vp1q6O6J7AbgYAD5cgdD--hgDuw@mail.gmail.com","subject":"Re: [PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T00:00:50Z","receivedAt":"2021-02-04T00:02:00Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Wed, 3 Feb 2021 at 10:35, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> > >     return command == TODO_FIXUP &&\n> > >         (flag == TODO_REPLACE_FIXUP_MSG ||\n> > >         flag == TODO_EDIT_FIXUP_MSG);\n> >\n> > I admit it resulted in a bit of confusion. Here, its true that flag is always\n> > going to be specific enum item( as command can be merge -c, fixup -c, or\n> > fixup -C ) and I combined the bag of bits to denote\n> > the specific enum item. So, maybe we can go with the first method?\n>\n> Sounds fine. It would clarify the intent.\n>\n\n(Apology for confusion) After, looking again at the source code, as we are using\nthe flag element of  the structure todo_item of in sequencer.h. So, I\nthink right\nway is to let it be in binary only and change type from 'enum todo_item_flag' to\n'unsigned' , as you suggested below (better than first method) :\n\nOtherwise, if `flag` will actually be a bag of bits, then the argument\nshould be declared as such:\n\n    static int check_fixup_flag(enum todo_command command,\n        unsigned flag)\n\n> > Agree, here it's checking if the command is fixup and the flag value (\n> > which implies either user has given command fixup -c or fixup -C )\n> > So, I wonder if we can write is_fixup_flag() ?\n>\n> Reasonable.\n>\n[...]\n> > I agree, this [tolower(bol[1]) == 'c'] is actually doing all the\n> > magic, but I am not\n> > sure if we should change it or not ? As in the source code just after\n> > this code we\n> > are checking in a similar way for the 'merge' command. So, maybe implementing\n> > in a similar way is easier to read ?\n>\n> Keeping it similar to nearby code makes sense.\n\nThanks for confirming!\n\nThanks and Regards,\nCharvi\n"},{"id":"416116","messageId":"CAPSFM5d=9yV6TrmuZoJX7SMHpKNUdO=n7f-DJN1q4i__hUChSQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cSBVG0AdyqXH2mZp6Ohrcb8_ec1Mm_vGbQM4zWT_7yYxQ@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T00:01:58Z","receivedAt":"2021-02-04T00:05:41Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Wed, 3 Feb 2021 at 11:14, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> > > What is \"merge_\" doing here? It doesn't seem to be used by this patch.\n> >\n> > Yeah, it's not used, but it might be a good thing to add this for\n> > consistency while at it.\n>\n> It confuses readers (as it did to me), causing them to waste\n> brain-cycles trying to figure out why it's present. Thus, it would be\n> better to add it when it's actually needed. The waste of brain-cycles\n> and time is especially important on a project like Git for which\n> reviewers and reviewer time are limited resources.\n>\n\nOkay, I will remove \"merge_\" from this patch series and maybe later will make\nseparate patch for it and also adding its tests and updating\nt3430-rebase-merges.sh\n\n> > > > +# Copyright (c) 2018 Phillip Wood\n> > >\n> > > Did Phillip write this script? Is this patch based upon an old patch from him?\n> >\n> > Yeah, it might be a good idea to add a \"Based-on-patch-by: Phillip ...\"\n>\n> Agreed.\n>\n> > > The implementation of test_commit_message() is a bit hard to follow.\n> > > It might be simpler to write it more concisely and directly like this:\n> > >\n> > >     git show --no-patch --pretty=format:%B \"$1\" >actual &&\n> > >     case \"$2\" in\n> > >     -m) echo \"$3\" >expect && test_cmp expect actual ;;\n> >\n> > I think we try to avoid many commands on the same line.\n>\n> For something this minor, it's not likely to matter but, of course, it\n> could be split over two lines:\n>\n>     -m) echo \"$3\" >expect &&\n>         test_cmp expect actual ;;\n>\n> > >     *) test_cmp \"$2\" actual ;;\n> > >     esac\n> >\n> > In general I am not sure that using $1, $2, $3 directly makes things\n> > easier to understand, but yeah, with the function documentation that\n> > you suggest, it might be better to write the function using them\n> > directly.\n>\n> The direct $1, $2, etc. was just an example. It's certainly possible\n> to give them names even in the rewritten code I presented. One good\n> reason, however, for just using $1, $2, etc. is that $2 is not well\n> defined; sometimes it's a switch (\"-m\") and sometimes its a pathname,\n> so it's hard to invent a suitable variable name for it. Also, this\n> function becomes so simple (in the rewritten version) that explicit\n> variable names don't add a lot of value (the cognitive load is quite\n> low because the function is so short).\n>\n\nAgree, and will update it.\n\n> > > Style nit: In Git test scripts, the here-doc body and EOF are indented\n> > > the same amount as the command which opened the here-doc:\n> >\n> > I don't think we are very consistent with this and I didn't find\n> > anything about this in CodingGuidelines.\n> >\n> > In t0008 and t0021 for example, the indentation is more like:\n> >\n> >      cat >message <<-EOF &&\n> >           amend! B\n> >           ...\n> >           body\n> >      EOF\n> >\n> > and I like this style, as it seems clearer than the other styles.\n>\n> I performed a quick survey of the heredoc styles in the tests. Here\n> are the results[1] of my analysis on the 'seen' branch:\n>\n> total-heredocs=4128\n>\n> same-indent=3053 (<<EOF & body & EOF share indent)\n>\n>     cat >expect <<-\\EOF\n>     body\n>     EOF\n>\n> body-eof-indented=24 (body & EOF indented)\n>\n>     cat >expect <<-\\EOF\n>         body\n>         EOF\n>\n> body-indented=735 (body indented; EOF not)\n>\n>     cat >expect <<-\\EOF\n>         body\n>     EOF\n>\n> left-margin=316 (<<EOF indented; body & EOF not)\n>\n>         cat >expect <<\\EOF\n>     body\n>     EOF\n>\n> So, the indentation recommended in my review -- with 3053 instances\n> out of 4128 heredocs -- is by far the most prevalent in the project.\n>\n> [1]: Note that there is a miniscule amount of inaccuracy in the\n> numbers because there are a few cases in which heredocs contain other\n> heredocs, and some scripts build heredocs piecemeal when constructing\n> other scripts, and I didn't bother making my analysis script handle\n> those few cases. The inaccuracy is tiny, thus not meaningful to the\n> overall picture.\n>\n\nOkay, will update the indentation.\n\n[...]\n> > >     fixup-*)\n> > >         action=$(echo \"$line\" | sed 's/-/ -/');;\n> >\n> > I agree that \"fixup\" arguments are not arbitrary at all, but I think\n> > it makes things simpler to just use one way to encode spaces instead\n> > of many different ways.\n>\n> Is that the intention here, though? Is the idea that some day `fixup`\n> will accept arbitrary arguments thus needs to encode spaces? If not,\n> then mirroring the treatment given to `exec` confuses readers into\n> thinking that it will/should accept arbitrary arguments. I brought\n> this up in my review specifically because it was confusing to a person\n> (me) new to this topic and reading the patches for the first time. The\n> more specific and exact the code can be, the less likely it will\n> confuse readers in the future.\n>\n\nI also agree that fixup will not accept arbitrary arguments, So I think to\ngo with the method using fixup-*) (as suggested above).\n\n[...]\n> > Yeah, perhaps the global \"expected-message\" could be renamed for\n> > example \"global-expected-message\", and tests which need a specific one\n> > could prepare and use a custom \"expected-message\" (maybe named\n> > \"custom-expected-message\") without ever changing\n> > \"global-expected-message\".\n>\n> That would be fine, though I wondered while reviewing the patch if a\n> global \"expect-message\" file was even needed since it didn't seem like\n> very many tests used it (but I didn't spend a lot of time counting the\n> exact number of tests due to the high cognitive load tracing how that\n> file might mutate as it passed through each test).\n>\n> Another really good reason for avoiding having later tests depend upon\n> mutations from earlier tests, if possible, is that it makes it easier\n> to run tests selectively with --run or GIT_SKIP_TESTS.\n\nAgree, also for this patch series I think to remove all tests for\namend!, change the\ntest setup and will take care this time to remove the test dependency\n(in case of expected-message).\n\nThanks and Regards,\nCharvi\n"},{"id":"416120","messageId":"CAPig+cROYr0H80ZosNUQe_mxVaRtwgqirtNxFPr2a8tnenvwwQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAPSFM5fLi-U3zVcXFip_kgchHSXiEUF9nngO2nSf31kAEBkq1w@mail.gmail.com","subject":"Re: [PATCH v4 6/9] rebase -i: add fixup [-C | -c] command","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-04T00:14:50Z","receivedAt":"2021-02-04T00:15:47Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Feb 3, 2021 at 7:01 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > > I admit it resulted in a bit of confusion. Here, its true that flag is always\n> > > going to be specific enum item( as command can be merge -c, fixup -c, or\n> > > fixup -C ) and I combined the bag of bits to denote\n> > > the specific enum item. So, maybe we can go with the first method?\n> >\n> > Sounds fine. It would clarify the intent.\n>\n> (Apology for confusion) After, looking again at the source code, as we are using\n> the flag element of  the structure todo_item of in sequencer.h. So, I\n> think right\n> way is to let it be in binary only and change type from 'enum todo_item_flag' to\n> 'unsigned' , as you suggested below (better than first method) :\n\nThat would be fine, as well. Thanks.\n"},{"id":"416147","messageId":"54d1ef0f-6a50-b2cb-3ac6-c313cf9dd2f3@gmail.com","threadId":"54958","inReplyTo":"CAPig+cQO_uHurPn3N-k-UwBFgvx2x8Bx2Uy+=sQxhmj3E6rt7Q@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2021-02-04T10:46:56Z","receivedAt":"2021-02-04T10:47:52Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Eric\n\nThanks for taking such a close look at this series.\n\nOn 02/02/2021 02:01, Eric Sunshine wrote:\n> On Fri, Jan 29, 2021 at 1:25 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> [...] \n>> +       ORIG_AUTHOR_NAME=\"$GIT_AUTHOR_NAME\" &&\n>> +       ORIG_AUTHOR_EMAIL=\"$GIT_AUTHOR_EMAIL\" &&\n>> +       GIT_AUTHOR_NAME=\"Amend Author\" &&\n>> +       GIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n>> +       test_commit \"$(cat message)\" A A1 A1 &&\n>> +       test_commit A2 A &&\n>> +       test_commit A3 A &&\n>> +       GIT_AUTHOR_NAME=\"$ORIG_AUTHOR_NAME\" &&\n>> +       GIT_AUTHOR_EMAIL=\"$ORIG_AUTHOR_EMAIL\" &&\n> \n> Are the timestamps of these commits meaningful in this context? \n\nI think we want to ensure that the timestamp of the commits created with \nthe different author are different from the previous commits. We ought \nto be checking that the author date of the rebased commit matches the \nauthor date of the original commit and not the author date of the fixup \ncommit created with the different author.\n\n> If not, another way to do this would be to assign the new author\n> name/email values in a subshell so that the values do not need to be\n> restored manually. For instance:\n> \n>      (\n>          GIT_AUTHOR_NAME=\"Amend Author\" &&\n>          GIT_AUTHOR_EMAIL=\"amend@example.com\" &&\n>          test_commit \"$(cat message)\" A A1 A1 &&\n>          test_commit A2 A &&\n>          test_commit A3 A\n>      ) &&\n> \n> It's a matter of taste whether or not that is preferable, though.\n> \n>> +       echo B1 >B &&\n>> +       test_tick &&\n>> +       git commit --fixup=HEAD -a &&\n>> +       test_tick &&\n> \n> Same question about whether the commit timestamps have any\n> significance in these tests.\n\nSame answer as above - we want different author dates so we can check \nthe original author date is not modified.\n\nI'm not sure that we are actually checking the dates yet though it looks \nlike we only check the author name and email at the moment.\n\nBest Wishes\n\nPhillip\n\n> If not, then these test_tick() calls\n> mislead the reader into thinking that the timestamps are significant,\n> thus it would make sense to drop them.\n> \n>> +test_expect_success 'simple fixup -C works' '\n>> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n>> +       git checkout --detach A2 &&\n>> +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i B &&\n> \n> I see that you mirrored the implementation of FAKE_LINES handling of\n> \"exec\" here for \"fixup\", but the cases are quite different. The\n> argument to \"exec\" is arbitrary and can have any number of spaces\n> embedded in it, which conflicts with the meaning of spaces in\n> FAKE_LINES, which separate the individual commands in FAKE_LINES.\n> Consequently, \"_\" was chosen as a placeholder in \"exec\" to mean\n> \"space\".\n> \n> However, \"fixup\" is a very different beast. Its arguments are not\n> arbitrary at all, so there isn't a good reason to mirror the choice of\n> \"_\" to represent a space, which leads to rather unsightly tokens such\n> as \"fixup_-C\". It would work just as well to use simpler tokens such\n> as \"fixup-C\" and \"fixup-c\", in which case t/lib-rebase.sh might parse\n> them like this (note that I also dropped `g` from the `sed` action):\n> \n>      fixup-*)\n>          action=$(echo \"$line\" | sed 's/-/ -/');;\n> \n> In fact, the recognized set of options following \"fixup\" is so small,\n> that you could even get by with simpler tokens \"fixupC\" and \"fixupc\":\n> \n>      fixupC)\n>          action=\"fixup -C\";;\n>      fixupc)\n>          actions=\"fixup -c\";;\n> \n> Though it's subjective whether or not \"fixupC\" and \"fixupc\" are nicer\n> than \"fixup-C\" and \"fixup-c\", respectively.\n> \n>> +test_expect_success 'fixup -C removes amend! from message' '\n>> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n>> +       git checkout --detach A1 &&\n>> +       FAKE_LINES=\"1 fixup_-C 2\" git rebase -i A &&\n>> +       test_cmp_rev HEAD^ A &&\n>> +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n>> +       test_commit_message HEAD expected-message &&\n>> +       get_author HEAD >actual-author &&\n>> +       test_cmp expected-author actual-author\n>> +'\n> \n> This test seems out of place. I would expect to see it added in the\n> patch which adds \"amend!\" functionality.\n> \n> Alternatively, if the intention really is to support \"amend!\" this\n> early in the series in [6/9], then the commit message of [6/9] should\n> talk about it.\n> \n>> +test_expect_success 'fixup -C with conflicts gives correct message' '\n>> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n> \n> Is there a reason this isn't written as:\n> \n>      test_when_finished \"reset_rebase\" &&\n> \n> which is more common? Is there something non-obvious which makes\n> reset_rebase() inappropriate in these tests?\n> \n>> +       git checkout --detach A1 &&\n>> +       test_must_fail env FAKE_LINES=\"1 fixup_-C 2\" git rebase -i conflicts &&\n>> +       git checkout --theirs -- A &&\n>> +       git add A &&\n>> +       FAKE_COMMIT_AMEND=edited git rebase --continue &&\n>> +       test_cmp_rev HEAD^ conflicts &&\n>> +       test_cmp_rev HEAD^{tree} A1^{tree} &&\n>> +       test_write_lines \"\" edited >>expected-message &&\n> \n> It feels clunky and fragile for this test to be changing\n> \"expected-message\" which was created in the \"setup\" test and used\n> unaltered up to this point. If the content of \"expected-message\" is\n> really going to change from test to test (as I see it changes again in\n> a later test), then it would be easier to reason about the behavior if\n> each test gives \"expected-message\" the precise content it should have\n> in that local context. As it is currently implemented, it's too\n> difficult to follow along and remember the value of \"expected-message\"\n> from test to test. It also makes it difficult to extend tests or add\n> new tests in between existing tests without negatively impacting other\n> tests. If each test sets up \"expected-message\" to the precise content\n> needed by the test, then both those problems go away.\n> \n>> +test_expect_success 'multiple fixup -c opens editor once' '\n>> +       test_when_finished \"test_might_fail git rebase --abort\" &&\n>> +       git checkout --detach A3 &&\n>> +       base=$(git rev-parse HEAD~4) &&\n>> +       FAKE_COMMIT_MESSAGE=\"Modified-A3\" \\\n>> +               FAKE_LINES=\"1 fixup_-C 2 fixup_-c 3 fixup_-c 4\" \\\n>> +               EXPECT_HEADER_COUNT=4 \\\n>> +               git rebase -i $base &&\n>> +       test_cmp_rev $base HEAD^ &&\n>> +       test 1 = $(git show | grep Modified-A3 | wc -l)\n>> +'\n> \n> These days, we would phrase the last part of the test as:\n> \n>      git show > raw &&\n>      grep Modified-A3 raw >out &&\n>      test_line_count = 1 out\n> \n\n"},{"id":"416151","messageId":"CAPig+cRt3+CfGVKMTroCsLMLM+LxhM7ioLV=2-AAMU9MGzquaA@mail.gmail.com","threadId":"54958","inReplyTo":"54d1ef0f-6a50-b2cb-3ac6-c313cf9dd2f3@gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-04T16:14:02Z","receivedAt":"2021-02-04T16:16:29Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Feb 4, 2021 at 5:47 AM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> On 02/02/2021 02:01, Eric Sunshine wrote:\n> > Are the timestamps of these commits meaningful in this context?\n>\n> I think we want to ensure that the timestamp of the commits created with\n> the different author are different from the previous commits. We ought\n> to be checking that the author date of the rebased commit matches the\n> author date of the original commit and not the author date of the fixup\n> commit created with the different author.\n\nSuch date-checking would indeed make sense and would remove any\npotential confusion a reader might have concerning the manual\ntest_tick() calls. (It's not super important, but I still lean toward\ndropping the test_tick() calls until they are actually needed simply\nto avoid confusing readers. I asked about it in my review since their\npurpose was unclear and I was genuinely wondering if I was overlooking\nthe reason for their presence. Future readers of the code may\nexperience the same puzzlement without necessarily having ready access\nto the original author of the code from whom to receive an answer.)\n"},{"id":"416167","messageId":"20210204190507.26487-1-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210129182050.26143-1-charvi077@gmail.com","subject":"[PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:04:59Z","receivedAt":"2021-02-04T19:06:48Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This patch series adds fixup [-C|-c] options to interactive rebase. In\naddition to amending the contents of the commit as the `fixup` command\ndoes now, `fixup -C` replaces the commit message of the original commit\nwhich we are fixing up with the message of the fixup commit.\nAnd to edit the fixup commit message before committing, `fixup -c`\ncommand is used instead of `fixup -C`. This convention is similar to\nthe existing `merge` command in the interactive rebase, that also supports\n`-c` and `-C` options with similar meanings.\n\nAlso, `fixup -C` is intended to support amend! commit upon --autosquash\nand it's working will be added in another patch series with the implementation\nof amend! commit.\n\nChanges from v4 :\n(Thanks to Eric Sunshine, Christian Couder and Phillip Wood for suggestions\n and reviews)\n\nThe major change in this version is to remove the working of `fixup -C`\nwith amend! commit and will include in the another patch series, in order\nto avoid the confusion. So there are following changes :\n* removed the patch (rebase -i : teach --autosquash to work with amend!)\n* updated the test script (t3437-*.sh), changed the test setup and removed\n  two tests.\n\n  Earlier every test includes the commit message having subject starting\n  with amend! So, now it includes a setup of different branch for testing\n  fixup with options and also updated all the tests.\n  Removed the test - \"skip fixup -C removes amend! from message\" and also\n  \"sequence of fixup, fixup -C & squash --signoff works\" as I think it would\n  be better to test this also in the branch with amend! commit with different\n  author. (Will add these tests with amend! commit implementation)\n\n* changed the flag type from enum todo_item_flags to unsigned\n* Removed amend! conditions from sequencer.c and\n* Replaced fixup_-* with fixup-* in lib-rebase.sh\n* fixup a small nit in Documentation\n\nCharvi Mendiratta (5):\n  sequencer: pass todo_item to do_pick_commit()\n  sequencer: use const variable for commit message comments\n  rebase -i: add fixup [-C | -c] command\n  t3437: test script for fixup [-C|-c] options in interactive rebase\n  doc/git-rebase: add documentation for fixup [-C|-c] options\n\nPhillip Wood (3):\n  rebase -i: only write fixup-message when it's needed\n  sequencer: factor out code to append squash message\n  rebase -i: comment out squash!/fixup! subjects from squash message\n\n Documentation/git-rebase.txt      |  13 +-\n rebase-interactive.c              |   4 +-\n sequencer.c                       | 270 ++++++++++++++++++++++++++----\n t/lib-rebase.sh                   |   8 +-\n t/t3415-rebase-autosquash.sh      |  30 ++--\n t/t3437-rebase-fixup-options.sh   | 133 +++++++++++++++\n t/t3437/expected-combined-message |  19 +++\n t/t3900-i18n-commit.sh            |   4 -\n 8 files changed, 425 insertions(+), 56 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n\n--\n2.29.0.rc1\n\n"},{"id":"416168","messageId":"20210204190507.26487-2-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 1/8] rebase -i: only write fixup-message when it's needed","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:00Z","receivedAt":"2021-02-04T19:06:52Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThe file \"$GIT_DIR/rebase-merge/fixup-message\" is only used for fixup\ncommands, there's no point in writing it for squash commands as it is\nimmediately deleted.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 8909a46770..a59e0c84af 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1757,11 +1757,10 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (write_message(body, strlen(body),\n-\t\t\t\t  rebase_path_fixup_msg(), 0)) {\n+\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n-\t\t\treturn error(_(\"cannot write '%s'\"),\n-\t\t\t\t     rebase_path_fixup_msg());\n+\t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-- \n2.29.0.rc1\n\n"},{"id":"416169","messageId":"20210204190507.26487-4-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 3/8] rebase -i: comment out squash!/fixup! subjects from squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:02Z","receivedAt":"2021-02-04T19:07:35Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nWhen squashing commit messages the squash!/fixup! subjects are not of\ninterest so comment them out to stop them becoming part of the final\nmessage.\n\nThis change breaks a bunch of --autosquash tests which rely on the\n\"squash! <subject>\" line appearing in the final commit message. This is\naddressed by adding a second line to the commit message of the \"squash!\n...\" commits and testing for that.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c                  | 21 ++++++++++++++++++++-\n t/t3415-rebase-autosquash.sh | 30 ++++++++++++++++--------------\n t/t3900-i18n-commit.sh       |  4 ----\n 3 files changed, 36 insertions(+), 19 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 08cce40834..034149f24d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,15 +1718,34 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static size_t subject_length(const char *body)\n+{\n+\tconst char *p = body;\n+\twhile (*p) {\n+\t\tconst char *next = skip_blank_lines(p);\n+\t\tif (next != p)\n+\t\t\tbreak;\n+\t\tp = strchrnul(p, '\\n');\n+\t\tif (*p)\n+\t\t\tp++;\n+\t}\n+\treturn p - body;\n+}\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n+\tsize_t commented_len = 0;\n+\n \tunlink(rebase_path_fixup_msg());\n+\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+\t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_addstr(buf, body);\n+\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_addstr(buf, body + commented_len);\n }\n \n static int update_squash_messages(struct repository *r,\ndiff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh\nindex e7087befd4..78cc2260cc 100755\n--- a/t/t3415-rebase-autosquash.sh\n+++ b/t/t3415-rebase-autosquash.sh\n@@ -84,8 +84,7 @@ test_auto_squash () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n-\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag $1 &&\n \ttest_tick &&\n \tgit rebase $2 -i HEAD^^^ &&\n@@ -142,7 +141,7 @@ test_expect_success 'auto squash that matches 2 commits' '\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"squash! first\" &&\n+\tgit commit -m \"squash! first\" -m \"extra para for first\" &&\n \tgit tag final-multisquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -195,7 +194,7 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-shasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -206,7 +205,8 @@ test_expect_success 'auto squash that matches a sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -216,7 +216,7 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short=11 HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para\" &&\n \tgit tag final-longshasquash &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -227,7 +227,8 @@ test_expect_success 'auto squash that matches longer sha1' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n+\t! grep \"squash\" commit &&\n+\tgrep \"^extra para\" commit >actual &&\n \ttest_line_count = 1 actual\n '\n \n@@ -236,7 +237,7 @@ test_auto_commit_flags () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit --$1 first-commit &&\n+\tgit commit --$1 first-commit -m \"extra para for first\" &&\n \tgit tag final-commit-$1 &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD^^^ &&\n@@ -264,11 +265,11 @@ test_auto_fixup_fixup () {\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! first\" &&\n+\tgit commit -m \"$1! first\" -m \"extra para for first\" &&\n \techo 2 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n-\tgit commit -m \"$1! $2! first\" &&\n+\tgit commit -m \"$1! $2! first\" -m \"second extra para for first\" &&\n \tgit tag \"final-$1-$2\" &&\n \ttest_tick &&\n \t(\n@@ -329,12 +330,12 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit add -u &&\n \ttest_tick &&\n \toid=$(git rev-parse --short HEAD^) &&\n-\tgit commit -m \"squash! $oid\" &&\n+\tgit commit -m \"squash! $oid\" -m \"extra para for first\" &&\n \techo 1 >file1 &&\n \tgit add -u &&\n \ttest_tick &&\n \tsubject=$(git log -n 1 --format=%s HEAD~2) &&\n-\tgit commit -m \"squash! $subject\" &&\n+\tgit commit -m \"squash! $subject\" -m \"second extra para for first\" &&\n \tgit tag final-squash-instFmt &&\n \ttest_tick &&\n \tgit rebase --autosquash -i HEAD~4 &&\n@@ -345,8 +346,9 @@ test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '\n \tgit cat-file blob HEAD^:file1 >actual &&\n \ttest_cmp expect actual &&\n \tgit cat-file commit HEAD^ >commit &&\n-\tgrep squash commit >actual &&\n-\ttest_line_count = 2 actual\n+\t! grep \"squash\" commit &&\n+\tgrep first commit >actual &&\n+\ttest_line_count = 3 actual\n '\n \n test_expect_success 'autosquash with empty custom instructionFormat' '\ndiff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh\nindex d277a9f4b7..bfab245eb3 100755\n--- a/t/t3900-i18n-commit.sh\n+++ b/t/t3900-i18n-commit.sh\n@@ -226,10 +226,6 @@ test_commit_autosquash_multi_encoding () {\n \t\tgit rev-list HEAD >actual &&\n \t\ttest_line_count = 3 actual &&\n \t\ticonv -f $old -t UTF-8 \"$TEST_DIRECTORY\"/t3900/$msg >expect &&\n-\t\tif test $flag = squash; then\n-\t\t\tsubject=\"$(head -1 expect)\" &&\n-\t\t\tprintf \"\\nsquash! %s\\n\" \"$subject\" >>expect\n-\t\tfi &&\n \t\tgit cat-file commit HEAD^ >raw &&\n \t\t(sed \"1,/^$/d\" raw | iconv -f $new -t utf-8) >actual &&\n \t\ttest_cmp expect actual\n-- \n2.29.0.rc1\n\n"},{"id":"416170","messageId":"20210204190507.26487-8-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 7/8] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:06Z","receivedAt":"2021-02-04T19:08:06Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Original-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n t/lib-rebase.sh                   |   8 +-\n t/t3437-rebase-fixup-options.sh   | 133 ++++++++++++++++++++++++++++++\n t/t3437/expected-combined-message |  19 +++++\n 3 files changed, 158 insertions(+), 2 deletions(-)\n create mode 100755 t/t3437-rebase-fixup-options.sh\n create mode 100644 t/t3437/expected-combined-message\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex b72c051f47..d9afed7b47 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -4,6 +4,7 @@\n #\n # - override the commit message with $FAKE_COMMIT_MESSAGE\n # - amend the commit message with $FAKE_COMMIT_AMEND\n+# - copy the original commit message to a file with $FAKE_MESSAGE_COPY\n # - check that non-commit messages have a certain line count with $EXPECT_COUNT\n # - check the commit count in the commit message header with $EXPECT_HEADER_COUNT\n # - rewrite a rebase -i script as directed by $FAKE_LINES.\n@@ -14,8 +15,8 @@\n #       specified line.\n #\n #   \"<cmd> <lineno>\" -- add a line with the specified command\n-#       (\"pick\", \"squash\", \"fixup\", \"edit\", \"reword\" or \"drop\") and the\n-#       SHA1 taken from the specified line.\n+#       (\"pick\", \"squash\", \"fixup\"|\"fixup-C\"|\"fixup-c\", \"edit\", \"reword\" or \"drop\")\n+#       and the SHA1 taken from the specified line.\n #\n #   \"exec_cmd_with_args\" -- add an \"exec cmd with args\" line.\n #\n@@ -33,6 +34,7 @@ set_fake_editor () {\n \t\t\texit\n \t\ttest -z \"$FAKE_COMMIT_MESSAGE\" || echo \"$FAKE_COMMIT_MESSAGE\" > \"$1\"\n \t\ttest -z \"$FAKE_COMMIT_AMEND\" || echo \"$FAKE_COMMIT_AMEND\" >> \"$1\"\n+\t\ttest -z \"$FAKE_MESSAGE_COPY\" || cat \"$1\" >\"$FAKE_MESSAGE_COPY\"\n \t\texit\n \t\t;;\n \tesac\n@@ -51,6 +53,8 @@ set_fake_editor () {\n \t\t\taction=\"$line\";;\n \t\texec_*|x_*|break|b)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n+\t\tfixup-*)\n+\t\t\taction=$(echo \"$line\" | sed 's/-/ -/');;\n \t\t\"#\")\n \t\t\techo '# comment' >> \"$1\";;\n \t\t\">\")\ndiff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh\nnew file mode 100755\nindex 0000000000..c2875803af\n--- /dev/null\n+++ b/t/t3437-rebase-fixup-options.sh\n@@ -0,0 +1,133 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2018 Phillip Wood\n+#\n+\n+test_description='git rebase interactive fixup options\n+\n+This test checks the \"fixup [-C|-c]\" command of rebase interactive.\n+In addition to amending the contents of the commit, \"fixup -C\"\n+replaces the original commit message with the message of the fixup\n+commit. \"fixup -c\" also replaces the original message, but opens the\n+editor to allow the user to edit the message before committing.\n+'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+EMPTY=\"\"\n+\n+# test_commit_message <rev> -m <msg>\n+# test_commit_message <rev> <path>\n+# Verify that the commit message of <rev> matches\n+# <msg> or the content of <path>.\n+test_commit_message () {\n+\tgit show --no-patch --pretty=format:%B \"$1\" >actual &&\n+\tcase \"$2\" in\n+\t-m) echo \"$3\" >expect &&\n+\t    test_cmp expect actual ;;\n+\t*) test_cmp \"$2\" actual ;;\n+\tesac\n+}\n+\n+test_expect_success 'setup' '\n+\tcat >message <<-EOF &&\n+\tnew subject\n+\t$EMPTY\n+\tnew\n+\tbody\n+\tEOF\n+\ttest_commit A A &&\n+\ttest_commit B B &&\n+\n+\tset_fake_editor &&\n+\tgit checkout -b test-branch &&\n+\ttest_commit \"$(cat message)\" A A1 A1 &&\n+\ttest_commit A2 A &&\n+\ttest_commit A3 A &&\n+\tgit checkout -b conflicts-branch A &&\n+\ttest_commit conflicts A\n+'\n+\n+test_expect_success 'simple fixup -C works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tgit log -1 --pretty=format:%B >expected-message &&\n+\tFAKE_LINES=\"1 fixup-C 2 \" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_expect_success 'simple fixup -c works' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A2 &&\n+\tgit log -1 --pretty=format:%B HEAD~ >expected-message &&\n+\ttest_write_lines \"\" \"Modified A1\" >>expected-message &&\n+\tFAKE_LINES=\"1 fixup-c 2 3\" \\\n+\t\tFAKE_COMMIT_AMEND=\"Modified A1\" \\\n+\t\tgit rebase -i A &&\n+\ttest_cmp_rev HEAD^{tree} A2^{tree} &&\n+\ttest_commit_message HEAD~ expected-message\n+'\n+\n+test_expect_success 'fixup -C with conflicts gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A1 &&\n+\tgit log -1 --pretty=format:%B HEAD >expected-message &&\n+\ttest_write_lines \"\" \"edited\" >>expected-message &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup-C 2\" git rebase -i conflicts &&\n+\tgit checkout --theirs -- A &&\n+\tgit add A &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_cmp_rev HEAD^ conflicts &&\n+\ttest_cmp_rev HEAD^{tree} A1^{tree} &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_expect_success 'skipping fixup -C after fixup gives correct message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\ttest_must_fail env FAKE_LINES=\"1 fixup 2 fixup-C 4\" git rebase -i A &&\n+\tgit reset --hard &&\n+\tFAKE_COMMIT_AMEND=edited git rebase --continue &&\n+\ttest_commit_message HEAD -m \"B\"\n+'\n+\n+test_expect_success 'first fixup -C commented out in sequence fixup fixup -C fixup -C' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tgit log -1 --pretty=format:%B >expected-message &&\n+\tFAKE_LINES=\"1 fixup 2 fixup-C 3 fixup-C 4\" git rebase -i A &&\n+\ttest_cmp_rev HEAD^ A &&\n+\ttest_commit_message HEAD expected-message\n+'\n+\n+test_expect_success 'multiple fixup -c opens editor once' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tbase=$(git rev-parse HEAD~4) &&\n+\tFAKE_COMMIT_MESSAGE=\"Modified-A3\" \\\n+\t\tFAKE_LINES=\"1 fixup-C 2 fixup-c 3 fixup-c 4\" \\\n+\t\tEXPECT_HEADER_COUNT=4 \\\n+\t\tgit rebase -i $base &&\n+\ttest_commit_message HEAD -m \"Modified-A3\" &&\n+\ttest_cmp_rev $base HEAD^ &&\n+\tgit show > raw &&\n+\tgrep Modified-A3 raw >out &&\n+\ttest_line_count = 1 out\n+'\n+\n+test_expect_success 'sequence squash, fixup & fixup -c gives combined message' '\n+\ttest_when_finished \"test_might_fail git rebase --abort\" &&\n+\tgit checkout --detach A3 &&\n+\tFAKE_LINES=\"1 squash 2 fixup 3 fixup-c 4\" \\\n+\t\tFAKE_MESSAGE_COPY=actual-combined-message \\\n+\t\tgit -c commit.status=false rebase -i A &&\n+\ttest_i18ncmp \"$TEST_DIRECTORY/t3437/expected-combined-message\" \\\n+\t\tactual-combined-message &&\n+\ttest_cmp_rev HEAD^ A\n+'\n+\n+test_done\ndiff --git a/t/t3437/expected-combined-message b/t/t3437/expected-combined-message\nnew file mode 100644\nindex 0000000000..d21bd1b6bb\n--- /dev/null\n+++ b/t/t3437/expected-combined-message\n@@ -0,0 +1,19 @@\n+# This is a combination of 4 commits.\n+# This is the 1st commit message:\n+\n+B\n+\n+# This is the commit message #2:\n+\n+new subject\n+\n+new\n+body\n+\n+# The commit message #3 will be skipped:\n+\n+# A2\n+\n+# This is the commit message #4:\n+\n+A3\n-- \n2.29.0.rc1\n\n"},{"id":"416171","messageId":"20210204190507.26487-7-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 6/8] rebase -i: add fixup [-C | -c] command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:05Z","receivedAt":"2021-02-04T19:08:06Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Add options to `fixup` command to fixup both the commit contents and\nmessage. `fixup -C` command is used to replace the original commit\nmessage and `fixup -c`, additionally allows to edit the commit message.\n\nThis convention is similar to the existing `merge` command in the\ninteractive rebase, that also supports `-c` and `-C` options with\nsimilar meanings.\n\nOriginal-patch-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n rebase-interactive.c |   4 +-\n sequencer.c          | 211 +++++++++++++++++++++++++++++++++++++++----\n 2 files changed, 195 insertions(+), 20 deletions(-)\n\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 762853bc7e..13e7a6c475 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -44,7 +44,9 @@ void append_todo_help(int command_count,\n \"r, reword <commit> = use commit, but edit the commit message\\n\"\n \"e, edit <commit> = use commit, but stop for amending\\n\"\n \"s, squash <commit> = use commit, but meld into previous commit\\n\"\n-\"f, fixup <commit> = like \\\"squash\\\", but discard this commit's log message\\n\"\n+\"f, fixup [-C | -c] <commit> = like \\\"squash\\\", but discard this\\n\"\n+\"                   commit's log message; use -C to replace with this\\n\"\n+\"                   commit message or -c to edit this commit message\\n\"\n \"x, exec <command> = run command (the rest of the line) using shell\\n\"\n \"b, break = stop here (continue rebase later with 'git rebase --continue')\\n\"\n \"d, drop <commit> = remove commit\\n\"\ndiff --git a/sequencer.c b/sequencer.c\nindex 6d9a10afcf..324fc5698a 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,12 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+enum todo_item_flags {\n+\tTODO_EDIT_MERGE_MSG    = (1 << 0),\n+\tTODO_REPLACE_FIXUP_MSG = (1 << 1),\n+\tTODO_EDIT_FIXUP_MSG    = (1 << 2),\n+};\n+\n static size_t subject_length(const char *body)\n {\n \tconst char *p = body;\n@@ -1734,32 +1740,174 @@ static size_t subject_length(const char *body)\n \n static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_first_commit_msg_str[] = N_(\"The 1st commit message will be skipped:\");\n static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n \n-static void append_squash_message(struct strbuf *buf, const char *body,\n-\t\t\t\t  struct replay_opts *opts)\n+static int is_fixup_flag(enum todo_command command, unsigned flag)\n+{\n+\treturn command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||\n+\t\t\t\t\t (flag & TODO_EDIT_FIXUP_MSG));\n+}\n+\n+/*\n+ * Wrapper around strbuf_add_commented_lines() which avoids double\n+ * commenting commit subjects.\n+ */\n+static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n+{\n+\tconst char *s = str;\n+\twhile (len > 0 && s[0] == comment_line_char) {\n+\t\tsize_t count;\n+\t\tconst char *n = memchr(s, '\\n', len);\n+\t\tif (!n)\n+\t\t\tcount = len;\n+\t\telse\n+\t\t\tcount = n - s + 1;\n+\t\tstrbuf_add(buf, s, count);\n+\t\ts += count;\n+\t\tlen -= count;\n+\t}\n+\tstrbuf_add_commented_lines(buf, s, len);\n+}\n+\n+/* Does the current fixup chain contain a squash command? */\n+static int seen_squash(struct replay_opts *opts)\n+{\n+\treturn starts_with(opts->current_fixups.buf, \"squash\") ||\n+\t\tstrstr(opts->current_fixups.buf, \"\\nsquash\");\n+}\n+\n+static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n)\n {\n-\tsize_t commented_len = 0;\n+\tstrbuf_setlen(buf1, 2);\n+\tstrbuf_addf(buf1, _(nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf1, '\\n');\n+\tstrbuf_setlen(buf2, 2);\n+\tstrbuf_addf(buf2, _(skip_nth_commit_msg_fmt), n);\n+\tstrbuf_addch(buf2, '\\n');\n+}\n \n-\tunlink(rebase_path_fixup_msg());\n-\tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n+/*\n+ * Comment out any un-commented commit messages, updating the message comments\n+ * to say they will be skipped but do not comment out the empty lines that\n+ * surround commit messages and their comments.\n+ */\n+static void update_squash_message_for_fixup(struct strbuf *msg)\n+{\n+\tvoid (*copy_lines)(struct strbuf *, const void *, size_t) = strbuf_add;\n+\tstruct strbuf buf1 = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tconst char *s, *start;\n+\tchar *orig_msg;\n+\tsize_t orig_msg_len;\n+\tint i = 1;\n+\n+\tstrbuf_addf(&buf1, \"# %s\\n\", _(first_commit_msg_str));\n+\tstrbuf_addf(&buf2, \"# %s\\n\", _(skip_first_commit_msg_str));\n+\ts = start = orig_msg = strbuf_detach(msg, &orig_msg_len);\n+\twhile (s) {\n+\t\tconst char *next;\n+\t\tsize_t off;\n+\t\tif (skip_prefix(s, buf1.buf, &next)) {\n+\t\t\t/*\n+\t\t\t * Copy the last message, preserving the blank line\n+\t\t\t * preceding the current line\n+\t\t\t */\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tif (off)\n+\t\t\t\tstrbuf_addch(msg, '\\n');\n+\t\t\t/*\n+\t\t\t * The next message needs to be commented out but the\n+\t\t\t * message header is already commented out so just copy\n+\t\t\t * it and the blank line that follows it.\n+\t\t\t */\n+\t\t\tstrbuf_addbuf(msg, &buf2);\n+\t\t\tif (*next == '\\n')\n+\t\t\t\tstrbuf_addch(msg, *next++);\n+\t\t\tstart = s = next;\n+\t\t\tcopy_lines = add_commented_lines;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else if (skip_prefix(s, buf2.buf, &next)) {\n+\t\t\toff = (s > start + 1 && s[-2] == '\\n') ? 1 : 0;\n+\t\t\tcopy_lines(msg, start, s - start - off);\n+\t\t\tstart = s - off;\n+\t\t\ts = next;\n+\t\t\tcopy_lines = strbuf_add;\n+\t\t\tupdate_comment_bufs(&buf1, &buf2, ++i);\n+\t\t} else {\n+\t\t\ts = strchr(s, '\\n');\n+\t\t\tif (s)\n+\t\t\t\ts++;\n+\t\t}\n+\t}\n+\tcopy_lines(msg, start, orig_msg_len - (start - orig_msg));\n+\tfree(orig_msg);\n+\tstrbuf_release(&buf1);\n+\tstrbuf_release(&buf2);\n+}\n+\n+static int append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t enum todo_command command, struct replay_opts *opts,\n+\t\t\t unsigned flag)\n+{\n+\tconst char *fixup_msg;\n+\tsize_t commented_len = 0, fixup_off;\n+\t/*\n+\t * fixup -C is non-interactive and not normally used with fixup!\n+\t * or squash! commits, so only comment out those subjects when\n+\t * squashing commit messages.\n+\t */\n+\tif ((command == TODO_SQUASH || seen_squash(opts)) &&\n+\t    (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\")))\n \t\tcommented_len = subject_length(body);\n+\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n+\t/* buf->buf may be reallocated so store an offset into the buffer */\n+\tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n+\n+\t/* fixup -C after squash behaves like squash */\n+\tif (is_fixup_flag(command, flag) && !seen_squash(opts)) {\n+\t\t/*\n+\t\t * We're replacing the commit message so we need to\n+\t\t * append the Signed-off-by: trailer if the user\n+\t\t * requested '--signoff'.\n+\t\t */\n+\t\tif (opts->signoff)\n+\t\t\tappend_signoff(buf, 0, 0);\n+\n+\t\tif ((command == TODO_FIXUP) &&\n+\t\t    (flag & TODO_REPLACE_FIXUP_MSG) &&\n+\t\t    (file_exists(rebase_path_fixup_msg()) ||\n+\t\t     !file_exists(rebase_path_squash_msg()))) {\n+\t\t\tfixup_msg = skip_blank_lines(buf->buf + fixup_off);\n+\t\t\tif (write_message(fixup_msg, strlen(fixup_msg),\n+\t\t\t\t\trebase_path_fixup_msg(), 0) < 0)\n+\t\t\t\treturn error(_(\"cannot write '%s'\"),\n+\t\t\t\t\trebase_path_fixup_msg());\n+\t\t} else {\n+\t\t\tunlink(rebase_path_fixup_msg());\n+\t\t}\n+\t} else  {\n+\t\tunlink(rebase_path_fixup_msg());\n+\t}\n+\n+\treturn 0;\n }\n \n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n-\t\t\t\t  struct replay_opts *opts)\n+\t\t\t\t  struct replay_opts *opts,\n+\t\t\t\t  unsigned flag)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n-\tint res;\n+\tint res = 0;\n \tconst char *message, *body;\n \tconst char *encoding = get_commit_output_encoding();\n \n@@ -1779,6 +1927,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n+\t\tif (is_fixup_flag(command, flag) && !seen_squash(opts))\n+\t\t\tupdate_squash_message_for_fixup(&buf);\n \t} else {\n \t\tstruct object_id head;\n \t\tstruct commit *head_commit;\n@@ -1792,18 +1942,22 @@ static int update_squash_messages(struct repository *r,\n \t\t\treturn error(_(\"could not read HEAD's commit message\"));\n \n \t\tfind_commit_subject(head_message, &body);\n-\t\tif (command == TODO_FIXUP && write_message(body, strlen(body),\n+\t\tif (command == TODO_FIXUP && !flag && write_message(body, strlen(body),\n \t\t\t\t\t\t\trebase_path_fixup_msg(), 0) < 0) {\n \t\t\tunuse_commit_buffer(head_commit, head_message);\n \t\t\treturn error(_(\"cannot write '%s'\"), rebase_path_fixup_msg());\n \t\t}\n-\n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n+\t\tstrbuf_addstr(&buf, is_fixup_flag(command, flag) ?\n+\t\t\t      _(skip_first_commit_msg_str) :\n+\t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tif (is_fixup_flag(command, flag))\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\telse\n+\t\t\tstrbuf_addstr(&buf, body);\n \n \t\tunuse_commit_buffer(head_commit, head_message);\n \t}\n@@ -1813,8 +1967,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t     oid_to_hex(&commit->object.oid));\n \tfind_commit_subject(message, &body);\n \n-\tif (command == TODO_SQUASH) {\n-\t\tappend_squash_message(&buf, body, opts);\n+\tif (command == TODO_SQUASH || is_fixup_flag(command, flag)) {\n+\t\tres = append_squash_message(&buf, body, command, opts, flag);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n@@ -1825,7 +1979,9 @@ static int update_squash_messages(struct repository *r,\n \t\treturn error(_(\"unknown command: %d\"), command);\n \tunuse_commit_buffer(commit, message);\n \n-\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(), 0);\n+\tif (!res)\n+\t\tres = write_message(buf.buf, buf.len, rebase_path_squash_msg(),\n+\t\t\t\t    0);\n \tstrbuf_release(&buf);\n \n \tif (!res) {\n@@ -2026,7 +2182,8 @@ static int do_pick_commit(struct repository *r,\n \tif (command == TODO_REWORD)\n \t\treword = 1;\n \telse if (is_fixup(command)) {\n-\t\tif (update_squash_messages(r, command, commit, opts))\n+\t\tif (update_squash_messages(r, command, commit,\n+\t\t\t\t\t   opts, item->flags))\n \t\t\treturn -1;\n \t\tflags |= AMEND_MSG;\n \t\tif (!final_fixup)\n@@ -2191,10 +2348,6 @@ static int read_and_refresh_cache(struct repository *r,\n \treturn 0;\n }\n \n-enum todo_item_flags {\n-\tTODO_EDIT_MERGE_MSG = 1\n-};\n-\n void todo_list_release(struct todo_list *todo_list)\n {\n \tstrbuf_release(&todo_list->buf);\n@@ -2281,6 +2434,18 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,\n \t\treturn 0;\n \t}\n \n+\tif (item->command == TODO_FIXUP) {\n+\t\tif (skip_prefix(bol, \"-C\", &bol) &&\n+\t\t   (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_REPLACE_FIXUP_MSG;\n+\t\t} else if (skip_prefix(bol, \"-c\", &bol) &&\n+\t\t\t\t  (*bol == ' ' || *bol == '\\t')) {\n+\t\t\tbol += strspn(bol, \" \\t\");\n+\t\t\titem->flags |= TODO_EDIT_FIXUP_MSG;\n+\t\t}\n+\t}\n+\n \tif (item->command == TODO_MERGE) {\n \t\tif (skip_prefix(bol, \"-C\", &bol))\n \t\t\tbol += strspn(bol, \" \\t\");\n@@ -5287,6 +5452,14 @@ static void todo_list_to_strbuf(struct repository *r, struct todo_list *todo_lis\n \t\t\t\t\t  short_commit_name(item->commit) :\n \t\t\t\t\t  oid_to_hex(&item->commit->object.oid);\n \n+\t\t\tif (item->command == TODO_FIXUP) {\n+\t\t\t\tif (item->flags & TODO_EDIT_FIXUP_MSG)\n+\t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n+\t\t\t\telse if (item->flags & TODO_REPLACE_FIXUP_MSG) {\n+\t\t\t\t\tstrbuf_addstr(buf, \" -C\");\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (item->command == TODO_MERGE) {\n \t\t\t\tif (item->flags & TODO_EDIT_MERGE_MSG)\n \t\t\t\t\tstrbuf_addstr(buf, \" -c\");\n-- \n2.29.0.rc1\n\n"},{"id":"416172","messageId":"20210204190507.26487-3-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 2/8] sequencer: factor out code to append squash message","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:01Z","receivedAt":"2021-02-04T19:08:06Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"From: Phillip Wood <phillip.wood@dunelm.org.uk>\n\nThis code is going to grow over the next two commits so move it to\nits own function.\n\nSigned-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 ++++++++++++------\n 1 file changed, 12 insertions(+), 6 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex a59e0c84af..08cce40834 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1718,6 +1718,17 @@ static int is_pick_or_similar(enum todo_command command)\n \t}\n }\n \n+static void append_squash_message(struct strbuf *buf, const char *body,\n+\t\t\t\t  struct replay_opts *opts)\n+{\n+\tunlink(rebase_path_fixup_msg());\n+\tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n+\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\t\t    ++opts->current_fixup_count + 1);\n+\tstrbuf_addstr(buf, \"\\n\\n\");\n+\tstrbuf_addstr(buf, body);\n+}\n+\n static int update_squash_messages(struct repository *r,\n \t\t\t\t  enum todo_command command,\n \t\t\t\t  struct commit *commit,\n@@ -1779,12 +1790,7 @@ static int update_squash_messages(struct repository *r,\n \tfind_commit_subject(message, &body);\n \n \tif (command == TODO_SQUASH) {\n-\t\tunlink(rebase_path_fixup_msg());\n-\t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is the commit message #%d:\"),\n-\t\t\t    ++opts->current_fixup_count + 1);\n-\t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_addstr(&buf, body);\n+\t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n \t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n-- \n2.29.0.rc1\n\n"},{"id":"416173","messageId":"20210204190507.26487-6-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 5/8] sequencer: use const variable for commit message comments","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:04Z","receivedAt":"2021-02-04T19:09:00Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"This makes it easier to use and reuse the comments.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Taylor Blau <me@ttaylorr.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 15 ++++++++++-----\n 1 file changed, 10 insertions(+), 5 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 09cbb17f87..6d9a10afcf 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1732,6 +1732,11 @@ static size_t subject_length(const char *body)\n \treturn p - body;\n }\n \n+static const char first_commit_msg_str[] = N_(\"This is the 1st commit message:\");\n+static const char nth_commit_msg_fmt[] = N_(\"This is the commit message #%d:\");\n+static const char skip_nth_commit_msg_fmt[] = N_(\"The commit message #%d will be skipped:\");\n+static const char combined_commit_msg_fmt[] = N_(\"This is a combination of %d commits.\");\n+\n static void append_squash_message(struct strbuf *buf, const char *body,\n \t\t\t\t  struct replay_opts *opts)\n {\n@@ -1741,7 +1746,7 @@ static void append_squash_message(struct strbuf *buf, const char *body,\n \tif (starts_with(body, \"squash!\") || starts_with(body, \"fixup!\"))\n \t\tcommented_len = subject_length(body);\n \tstrbuf_addf(buf, \"\\n%c \", comment_line_char);\n-\tstrbuf_addf(buf, _(\"This is the commit message #%d:\"),\n+\tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n \tstrbuf_add_commented_lines(buf, body, commented_len);\n@@ -1770,7 +1775,7 @@ static int update_squash_messages(struct repository *r,\n \t\t\tbuf.buf : strchrnul(buf.buf, '\\n');\n \n \t\tstrbuf_addf(&header, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&header, _(\"This is a combination of %d commits.\"),\n+\t\tstrbuf_addf(&header, _(combined_commit_msg_fmt),\n \t\t\t    opts->current_fixup_count + 2);\n \t\tstrbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len);\n \t\tstrbuf_release(&header);\n@@ -1794,9 +1799,9 @@ static int update_squash_messages(struct repository *r,\n \t\t}\n \n \t\tstrbuf_addf(&buf, \"%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"This is a combination of %d commits.\"), 2);\n+\t\tstrbuf_addf(&buf, _(combined_commit_msg_fmt), 2);\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addstr(&buf, _(\"This is the 1st commit message:\"));\n+\t\tstrbuf_addstr(&buf, _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_addstr(&buf, body);\n \n@@ -1812,7 +1817,7 @@ static int update_squash_messages(struct repository *r,\n \t\tappend_squash_message(&buf, body, opts);\n \t} else if (command == TODO_FIXUP) {\n \t\tstrbuf_addf(&buf, \"\\n%c \", comment_line_char);\n-\t\tstrbuf_addf(&buf, _(\"The commit message #%d will be skipped:\"),\n+\t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n-- \n2.29.0.rc1\n\n"},{"id":"416174","messageId":"20210204190507.26487-9-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 8/8] doc/git-rebase: add documentation for fixup [-C|-c] options","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:07Z","receivedAt":"2021-02-04T19:09:00Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Mentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nReviewed-by: Marc Branchaud <marcnarc@xiplink.com>\nReviewed-by: Eric Sunshine <sunshine@sunshineco.com>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n Documentation/git-rebase.txt | 13 ++++++++++---\n 1 file changed, 10 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a0487b5cc5..97a8d2e1aa 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -887,9 +887,16 @@ If you want to fold two or more commits into one, replace the command\n \"pick\" for the second and subsequent commits with \"squash\" or \"fixup\".\n If the commits had different authors, the folded commit will be\n attributed to the author of the first commit.  The suggested commit\n-message for the folded commit is the concatenation of the commit\n-messages of the first commit and of those with the \"squash\" command,\n-but omits the commit messages of commits with the \"fixup\" command.\n+message for the folded commit is the concatenation of the first\n+commit's message with those identified by \"squash\" commands, omitting the\n+messages of commits identified by \"fixup\" commands, unless \"fixup -c\"\n+is used.  In that case the suggested commit message is only the message\n+of the \"fixup -c\" commit, and an editor is opened allowing you to edit\n+the message.  The contents (patch) of the \"fixup -c\" commit are still\n+incorporated into the folded commit. If there is more than one \"fixup -c\"\n+commit, the message from the final one is used.  You can also use\n+\"fixup -C\" to get the same behavior as \"fixup -c\" except without opening\n+an editor.\n \n 'git rebase' will stop when \"pick\" has been replaced with \"edit\" or\n when a command fails due to merge errors. When you are done editing\n-- \n2.29.0.rc1\n\n"},{"id":"416175","messageId":"20210204190507.26487-5-charvi077@gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"[PATCH v5 4/8] sequencer: pass todo_item to do_pick_commit()","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:05:03Z","receivedAt":"2021-02-04T19:09:00Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"As an additional member of the structure todo_item will be required in\nfuture commits pass the complete structure.\n\nMentored-by: Christian Couder <chriscool@tuxfamily.org>\nMentored-by: Phillip Wood <phillip.wood@dunelm.org.uk>\nSigned-off-by: Charvi Mendiratta <charvi077@gmail.com>\n---\n sequencer.c | 18 +++++++++++-------\n 1 file changed, 11 insertions(+), 7 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex 034149f24d..09cbb17f87 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -1877,8 +1877,7 @@ static void record_in_rewritten(struct object_id *oid,\n }\n \n static int do_pick_commit(struct repository *r,\n-\t\t\t  enum todo_command command,\n-\t\t\t  struct commit *commit,\n+\t\t\t  struct todo_item *item,\n \t\t\t  struct replay_opts *opts,\n \t\t\t  int final_fixup, int *check_todo)\n {\n@@ -1891,6 +1890,8 @@ static int do_pick_commit(struct repository *r,\n \tstruct commit_message msg = { NULL, NULL, NULL, NULL };\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res, unborn = 0, reword = 0, allow, drop_commit;\n+\tenum todo_command command = item->command;\n+\tstruct commit *commit = item->commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -4140,8 +4141,8 @@ static int pick_commits(struct repository *r,\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, reflog_message(opts,\n \t\t\t\t\tcommand_to_string(item->command), NULL),\n \t\t\t\t\t1);\n-\t\t\tres = do_pick_commit(r, item->command, item->commit,\n-\t\t\t\t\t     opts, is_final_fixup(todo_list),\n+\t\t\tres = do_pick_commit(r, item, opts,\n+\t\t\t\t\t     is_final_fixup(todo_list),\n \t\t\t\t\t     &check_todo);\n \t\t\tif (is_rebase_i(opts))\n \t\t\t\tsetenv(GIT_REFLOG_ACTION, prev_reflog_action, 1);\n@@ -4603,11 +4604,14 @@ static int single_pick(struct repository *r,\n \t\t       struct replay_opts *opts)\n {\n \tint check_todo;\n+\tstruct todo_item item;\n+\n+\titem.command = opts->action == REPLAY_PICK ?\n+\t\t\tTODO_PICK : TODO_REVERT;\n+\titem.commit = cmit;\n \n \tsetenv(GIT_REFLOG_ACTION, action_name(opts), 0);\n-\treturn do_pick_commit(r, opts->action == REPLAY_PICK ?\n-\t\t\t      TODO_PICK : TODO_REVERT, cmit, opts, 0,\n-\t\t\t      &check_todo);\n+\treturn do_pick_commit(r, &item, opts, 0, &check_todo);\n }\n \n int sequencer_pick_revisions(struct repository *r,\n-- \n2.29.0.rc1\n\n"},{"id":"416177","messageId":"CAPSFM5eYMRuWoYaVFn9+5kZ16DoaLZ_8Pqu5hScbu9H0twXXiQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cQO_uHurPn3N-k-UwBFgvx2x8Bx2Uy+=sQxhmj3E6rt7Q@mail.gmail.com","subject":"Re: [PATCH v4 7/9] t3437: test script for fixup [-C|-c] options in interactive rebase","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-04T19:12:42Z","receivedAt":"2021-02-04T19:14:03Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi Eric,\n\n> > +test_expect_success 'fixup -C with conflicts gives correct message' '\n> > +       test_when_finished \"test_might_fail git rebase --abort\" &&\n>\n> Is there a reason this isn't written as:\n>\n>     test_when_finished \"reset_rebase\" &&\n>\n> which is more common? Is there something non-obvious which makes\n> reset_rebase() inappropriate in these tests?\n>\n\nI missed this earlier, but I confirmed before sending next version that as\nreset_rebase() removes the untracked files so we could not use this as otherwise\nit removes the fake-editor.sh file and will be required to set a fake\neditor for every\ntest and also removes other untracked files which may be used to debug.\nSo, I think it's okay with:\ntest_when_finished \"test_might_fail git rebase --abort\"\n\nThanks and regards,\nCharvi\n"},{"id":"416246","messageId":"CAPig+cTj5erQ6GoikwU7aeJTH0+QCC2SqkSuZ_T=n0LVxf1pBQ@mail.gmail.com","threadId":"54958","inReplyTo":"20210204190507.26487-1-charvi077@gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-05T07:30:06Z","receivedAt":"2021-02-05T07:31:32Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Feb 4, 2021 at 2:05 PM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> Changes from v4 :\n> (Thanks to Eric Sunshine, Christian Couder and Phillip Wood for suggestions\n>  and reviews)\n\nThanks for working on this and re-rolling. Unfortunately, it seems\nthat v4 already landed in Junio's `next` branch which means that he\nwon't be replacing v4 wholesale as would have been the case if it was\nstill in the `seen` branch. Once patches are in `next`, improvements\nare made by building changes atop them (incrementally) rather than\nreplacing them. Whether or not it makes sense for you to spend time\nre-doing these patches as incremental changes is not clear. In fact...\n\n> The major change in this version is to remove the working of `fixup -C`\n> with amend! commit and will include in the another patch series, in order\n> to avoid the confusion. So there are following changes :\n> * removed the patch (rebase -i : teach --autosquash to work with amend!)\n> * updated the test script (t3437-*.sh), changed the test setup and removed\n>   two tests.\n>\n>   Earlier every test includes the commit message having subject starting\n>   with amend! So, now it includes a setup of different branch for testing\n>   fixup with options and also updated all the tests.\n>   Removed the test - \"skip fixup -C removes amend! from message\" and also\n>   \"sequence of fixup, fixup -C & squash --signoff works\" as I think it would\n>   be better to test this also in the branch with amend! commit with different\n>   author. (Will add these tests with amend! commit implementation)\n\nDespite these being nice cleanups to the standalone series, I'm not\nsure it's worth spending your time creating new patches to undo these\nfrom `next`. Removing them only to add them back later is not\nnecessarily going to help \"unconfuse\" someone reading the commits in\nthe permanent project history.\n\n> * changed the flag type from enum todo_item_flags to unsigned\n> * Replaced fixup_-* with fixup-* in lib-rebase.sh\n> * fixup a small nit in Documentation\n\nThese changes are still worthwhile and can easily be done\nincrementally atop what is already in next, I would think.\n\nAnyhow, use your best judgment to decide how much work to devote to this.\n"},{"id":"416250","messageId":"CAPSFM5f0Jk03tWCTerZP1JhcMHG4MXjVSZjPKm2uzQYc+cOwsw@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cTj5erQ6GoikwU7aeJTH0+QCC2SqkSuZ_T=n0LVxf1pBQ@mail.gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-05T09:42:44Z","receivedAt":"2021-02-05T09:46:46Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"Hi,\n\nOn Fri, 5 Feb 2021 at 13:00, Eric Sunshine <sunshine@sunshineco.com> wrote:\n[...]\n> Thanks for working on this and re-rolling. Unfortunately, it seems\n> that v4 already landed in Junio's `next` branch which means that he\n> won't be replacing v4 wholesale as would have been the case if it was\n> still in the `seen` branch. Once patches are in `next`, improvements\n> are made by building changes atop them (incrementally) rather than\n> replacing them. Whether or not it makes sense for you to spend time\n> re-doing these patches as incremental changes is not clear. In fact...\n>\n\nOkay, I admit I was not aware of this, before.\n\n> > The major change in this version is to remove the working of `fixup -C`\n> > with amend! commit and will include in the another patch series, in order\n> > to avoid the confusion. So there are following changes :\n> > * removed the patch (rebase -i : teach --autosquash to work with amend!)\n> > * updated the test script (t3437-*.sh), changed the test setup and removed\n> >   two tests.\n> >\n> >   Earlier every test includes the commit message having subject starting\n> >   with amend! So, now it includes a setup of different branch for testing\n> >   fixup with options and also updated all the tests.\n> >   Removed the test - \"skip fixup -C removes amend! from message\" and also\n> >   \"sequence of fixup, fixup -C & squash --signoff works\" as I think it would\n> >   be better to test this also in the branch with amend! commit with different\n> >   author. (Will add these tests with amend! commit implementation)\n>\n> Despite these being nice cleanups to the standalone series, I'm not\n> sure it's worth spending your time creating new patches to undo these\n> from `next`. Removing them only to add them back later is not\n> necessarily going to help \"unconfuse\" someone reading the commits in\n> the permanent project history.\n>\n\nYes, I was also thinking that let's not remove the working of `fixup -C` with\namend! commit as it's true that it is intended to work like that way.\n\n> > * changed the flag type from enum todo_item_flags to unsigned\n> > * Replaced fixup_-* with fixup-* in lib-rebase.sh\n> > * fixup a small nit in Documentation\n>\n> These changes are still worthwhile and can easily be done\n> incrementally atop what is already in next, I would think.\n>\n\nI agree, these fixes are required. So, I am not sure but now to do these\nfixup shall I send another patch cleaning this patch series(v4) and rebase the\npatch on the 'next' branch ? Is it the right way ?\n\nThanks and Regards,\nCharvi\n"},{"id":"416273","messageId":"CAP8UFD0VpgT=mTydWQRmqo9TFQvdfDiXuA1TcwAqG1BtXXdKxA@mail.gmail.com","threadId":"54958","inReplyTo":"CAPSFM5f0Jk03tWCTerZP1JhcMHG4MXjVSZjPKm2uzQYc+cOwsw@mail.gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Christian Couder","fromEmail":"christian.couder@gmail.com","sentAt":"2021-02-05T18:25:27Z","receivedAt":"2021-02-05T18:29:32Z","isPatch":true,"sender":{"key":"christian.couder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/208954?v=4"},"body":"On Fri, Feb 5, 2021 at 10:42 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n\n> On Fri, 5 Feb 2021 at 13:00, Eric Sunshine <sunshine@sunshineco.com> wrote:\n\n> > > * changed the flag type from enum todo_item_flags to unsigned\n> > > * Replaced fixup_-* with fixup-* in lib-rebase.sh\n> > > * fixup a small nit in Documentation\n> >\n> > These changes are still worthwhile and can easily be done\n> > incrementally atop what is already in next, I would think.\n>\n> I agree, these fixes are required. So, I am not sure but now to do these\n> fixup shall I send another patch cleaning this patch series(v4) and rebase the\n> patch on the 'next' branch ? Is it the right way ?\n\nYeah, I think you can send each of the above 3 changes in a different\npatch on top of the 'next' branch. That would create a new 3 patch\nlong series, which you should give a new name and not consider v5 of\nthe previous patch series.\n\nBest,\nChristian.\n"},{"id":"416275","messageId":"CAPig+cR44eisWjbcsSiTyHqVKeqPKXMnc=-9BEjK5MFxPUBFkQ@mail.gmail.com","threadId":"54958","inReplyTo":"CAP8UFD0VpgT=mTydWQRmqo9TFQvdfDiXuA1TcwAqG1BtXXdKxA@mail.gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2021-02-05T18:56:48Z","receivedAt":"2021-02-05T19:09:36Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Feb 5, 2021 at 1:25 PM Christian Couder\n<christian.couder@gmail.com> wrote:\n> On Fri, Feb 5, 2021 at 10:42 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > On Fri, 5 Feb 2021 at 13:00, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > > These changes are still worthwhile and can easily be done\n> > > incrementally atop what is already in next, I would think.\n> >\n> > I agree, these fixes are required. So, I am not sure but now to do these\n> > fixup shall I send another patch cleaning this patch series(v4) and rebase the\n> > patch on the 'next' branch ? Is it the right way ?\n>\n> Yeah, I think you can send each of the above 3 changes in a different\n> patch on top of the 'next' branch. That would create a new 3 patch\n> long series, which you should give a new name and not consider v5 of\n> the previous patch series.\n\nYes, whatever issues from my reviews seem worth fixing atop the\nexisting v4 can be included in this new patch series. (I think there\nmay have been a few things beyond the three listed in the v5 cover\nletter, but I didn't bother doing a full audit of my review emails, so\nI could be wrong.) As Christian said, just make it a new series,\nthough be sure to build it atop your v4 rather than building it atop\n\"next\". (The problem with building atop \"next\" is that your series\nthen gets held hostage by _every_ series already in \"next\", which\nmakes it nearly impossible for your series to graduate to \"master\"\nsince it can't graduate until every other existing series in \"next\"\ngraduates to \"master\".) The one other important thing is to mention in\nthe cover letter that your new series is built atop \"cm/rebase-i\",\nwhich lets Junio know where to place the new series when he picks it\nup (and also lets reviewers know where to apply it if they want to\ntest it themselves).\n"},{"id":"416276","messageId":"xmqqmtwi1g6u.fsf@gitster.c.googlers.com","threadId":"54958","inReplyTo":"CAP8UFD0VpgT=mTydWQRmqo9TFQvdfDiXuA1TcwAqG1BtXXdKxA@mail.gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-02-05T19:13:13Z","receivedAt":"2021-02-05T19:15:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Christian Couder <christian.couder@gmail.com> writes:\n\n> On Fri, Feb 5, 2021 at 10:42 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n>\n>> On Fri, 5 Feb 2021 at 13:00, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n>> > > * changed the flag type from enum todo_item_flags to unsigned\n>> > > * Replaced fixup_-* with fixup-* in lib-rebase.sh\n>> > > * fixup a small nit in Documentation\n>> >\n>> > These changes are still worthwhile and can easily be done\n>> > incrementally atop what is already in next, I would think.\n>>\n>> I agree, these fixes are required. So, I am not sure but now to do these\n>> fixup shall I send another patch cleaning this patch series(v4) and rebase the\n>> patch on the 'next' branch ? Is it the right way ?\n>\n> Yeah, I think you can send each of the above 3 changes in a different\n> patch on top of the 'next' branch. That would create a new 3 patch\n> long series, which you should give a new name and not consider v5 of\n> the previous patch series.\n\nCorrect, except that it shouldn't be on top of the 'next' branch.\n\nPlease \"git log --first-parent --oneline master..next\" to find the\ntip of what got merged, and build on top of that instead.  I.e.\n\n    $ git show -s --oneline \\\n\t\"origin/next^{/ branch 'cm/rebase-i' into }\"\n    4f9aa6cec3 Merge branch 'cm/rebase-i' into next\n    $ git checkout -b my-follow-up-topic 4f9aa6cec3^2\n    ... work work work ...\n\nThat is what we mean by \"after getting merged to 'next', the topic\ngets polished incrementally\".\n\nAlternatively, you can have branches from the broken-out repository\nhandy, e.g.\n\n    $ git remote add brokenout https://github.com/gitster/git\n\nand you'd find the topic as I see it like so:\n\n    $ git fetch brokenout\n    $ git log --oneline brokenout/master..brokenout/cm/rebase-i\n\nHTH; thanks.\n\n\n\n\n"},{"id":"416332","messageId":"CAPSFM5fbryEsikVNzuYOtnrhXEyNMfx5HH8rGGYjXDS8jAVipw@mail.gmail.com","threadId":"54958","inReplyTo":"CAPig+cR44eisWjbcsSiTyHqVKeqPKXMnc=-9BEjK5MFxPUBFkQ@mail.gmail.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-06T05:36:52Z","receivedAt":"2021-02-06T05:38:17Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Sat, 6 Feb 2021 at 00:27, Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Feb 5, 2021 at 1:25 PM Christian Couder\n> <christian.couder@gmail.com> wrote:\n> > On Fri, Feb 5, 2021 at 10:42 AM Charvi Mendiratta <charvi077@gmail.com> wrote:\n> > > On Fri, 5 Feb 2021 at 13:00, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > > > These changes are still worthwhile and can easily be done\n> > > > incrementally atop what is already in next, I would think.\n> > >\n> > > I agree, these fixes are required. So, I am not sure but now to do these\n> > > fixup shall I send another patch cleaning this patch series(v4) and rebase the\n> > > patch on the 'next' branch ? Is it the right way ?\n> >\n> > Yeah, I think you can send each of the above 3 changes in a different\n> > patch on top of the 'next' branch. That would create a new 3 patch\n> > long series, which you should give a new name and not consider v5 of\n> > the previous patch series.\n>\n> Yes, whatever issues from my reviews seem worth fixing atop the\n> existing v4 can be included in this new patch series. (I think there\n> may have been a few things beyond the three listed in the v5 cover\n> letter, but I didn't bother doing a full audit of my review emails, so\n> I could be wrong.) As Christian said, just make it a new series,\n> though be sure to build it atop your v4 rather than building it atop\n> \"next\". (The problem with building atop \"next\" is that your series\n> then gets held hostage by _every_ series already in \"next\", which\n> makes it nearly impossible for your series to graduate to \"master\"\n> since it can't graduate until every other existing series in \"next\"\n> graduates to \"master\".) The one other important thing is to mention in\n> the cover letter that your new series is built atop \"cm/rebase-i\",\n> which lets Junio know where to place the new series when he picks it\n> up (and also lets reviewers know where to apply it if they want to\n> test it themselves).\n\nGot it, Thanks !\n"},{"id":"416333","messageId":"CAPSFM5c0yi=c6=q07X=0NBPiNn87eCq26CGwigwtyRRx2F9+mw@mail.gmail.com","threadId":"54958","inReplyTo":"xmqqmtwi1g6u.fsf@gitster.c.googlers.com","subject":"Re: [PATCH v5 0/8][Outreachy] rebase -i: add options to fixup command","fromName":"Charvi Mendiratta","fromEmail":"charvi077@gmail.com","sentAt":"2021-02-06T05:37:57Z","receivedAt":"2021-02-06T05:39:17Z","isPatch":true,"sender":{"key":"charvi077@gmail.com","avatar":"https://avatars.githubusercontent.com/u/32788121?v=4"},"body":"On Sat, 6 Feb 2021 at 00:43, Junio C Hamano <gitster@pobox.com> wrote:\n[...]\n> Correct, except that it shouldn't be on top of the 'next' branch.\n>\n> Please \"git log --first-parent --oneline master..next\" to find the\n> tip of what got merged, and build on top of that instead.  I.e.\n>\n>     $ git show -s --oneline \\\n>         \"origin/next^{/ branch 'cm/rebase-i' into }\"\n>     4f9aa6cec3 Merge branch 'cm/rebase-i' into next\n>     $ git checkout -b my-follow-up-topic 4f9aa6cec3^2\n>     ... work work work ...\n>\n> That is what we mean by \"after getting merged to 'next', the topic\n> gets polished incrementally\".\n>\n> Alternatively, you can have branches from the broken-out repository\n> handy, e.g.\n>\n>     $ git remote add brokenout https://github.com/gitster/git\n>\n> and you'd find the topic as I see it like so:\n>\n>     $ git fetch brokenout\n>     $ git log --oneline brokenout/master..brokenout/cm/rebase-i\n>\n\nGot it, thanks all for guiding. I will update soon.\n\nThanks and Regards,\nCharvi\n"}]}