{"thread":{"id":"36962","subject":"[RFC PATCH 0/7] rebase -i: Implement `reword` and `squash` in terms of `do_pick`","startedAt":"2014-06-19T03:28:18Z","lastAt":"2014-09-21T16:59:40Z","messageCount":148,"participants":["Fabian Ruch","Michael Haggerty","Junio C Hamano","Andrew Wong","Chris Webb","Thomas Rast","Jeff King","Matthieu Moy","Peter Krefting","Eric Sunshine","Phil Hord"],"isPatch":true,"patchVersion":1,"patchTotal":7},"messages":[{"id":"244617","messageId":"53A258D2.7080806@gmail.com","threadId":"36962","inReplyTo":null,"subject":"[RFC PATCH 0/7] rebase -i: Implement `reword` and `squash` in terms of `do_pick`","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-06-19T03:28:18Z","receivedAt":"2014-06-19T03:28:18Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nThis patch series is part of the undertaking to add command line options\nto to-do list commands. The goal is to be able to write something\nsimilar to\n\n    pick --reset-author --signoff a Some changes\n    pick                          b Some more changes\n    squash --no-edit              c Ack Some more changes.\n\nThe first submission to the mailing list adds options parsing to\n`do_pick` and reimplements the current set of to-do list commands in\nterms[1] of a parametrized `do_pick`. It neither adds new commands to\nto-do lists nor exposes the command line options feature to the user.\nStill it makes the implementation of `do_next` slightly more\nstraight-forward and the function `do_pick` behave more like an internal\ngit-cherry-pick.\n\nThe patches try to accomplish one thing at a time but are not standalone\nin the sense that each of them constitutes a frame only in which a\nsubsequent patch can express its one thing. For instance, only\ncommitting once and not dying in `do_pick` are things specific to\nimplementing `squash` in terms of `do_pick` but presented as separate\npatches so that their correctness can be discussed independently.\n\nThe last patch contains some notes about when to run the post-rewrite\nhook, something I could not figure out myself.\n\nThanks for your time,\n   Fabian\n\n[1] pick, reword, squash, fixup\n\nFabian Ruch (7):\n  rebase -i: Make option handling in pick_one more flexible\n  rebase -i: Teach do_pick the option --edit\n  rebase -i: Stop on root commits with empty log messages\n  rebase -i: Commit only once when rewriting picks\n  rebase -i: Do not die in do_pick\n  rebase -i: Prepare for squash in terms of do_pick --amend\n  rebase -i: Teach do_pick the options --amend and --file\n\n git-rebase--interactive.sh    | 194 +++++++++++++++++++++++++++++++-----------\n t/t3404-rebase-interactive.sh |   8 ++\n t/t3412-rebase-root.sh        |  39 +++++++++\n 3 files changed, 193 insertions(+), 48 deletions(-)\n\n-- \n2.0.0\n"},{"id":"245317","messageId":"cover.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"53A258D2.7080806@gmail.com","subject":"[PATCH RFC v2 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:52Z","receivedAt":"2014-07-02T17:47:52Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nthis reroll applies the comments from Eric, Junio and Michael. In\nparticular,\n\n * It turned out that `pick_one` does not need option handling at all\n   and the option-like argument `-n` determines whether `pick_one` or\n   `do_pick` creates the replay commit. The latter happens if the\n   task wants to rewrite the commit being picked (f.i., for the\n   purpose of editing the log message or resetting the authorship).\n\n   `do_pick` still seems to require a flexible parsing of options,\n   i.e. a relatively expensive loop, since it receives the\n   whitelisted user-supplied options. Unsupported and unknown options\n   are treated as an \"unknown command\" error.\n\n * The `do_pick` options are documented in the same order they are\n   listed in the function signature. Moreover, it is mentioned which\n   options rewrite commits being picked.\n\n * The test cases output differing actual values as changes to the\n   expected values and not the other way around. Moreover, the failed\n   rebases are not cleaned up until the respective test succeeds.\n\nTwo stages (and two sub-stages) can be identified in the rerolled\npatch series:\n\n 1. Route primary to-do list commands through `do_pick`\n\n     a. Implement reword in terms of do_pick (5/19)\n     b. Implement squash in terms of do_pick (14/19)\n\n 2. Add user options to main commands\n\n    Enable options --signoff, --reset-author for pick, reword (19/19)\n\nThe last stage was added in this reroll. It enables the parsing of\nline options for to-do list commands, which is still restricted to\noptions without arguments because it is unclear how spaces can be\nparsed as characters rather than separators where needed. For\ninstance, if we were to support\n\n    pick --author=\"A U Thor\" fa1afe1 Some changes\n\nthen read(1) would hand us the tokens `--author=\"A`, `U` and `Thor\"`\ninstead of `--author=A U Thor`, which we would want to relay to\n`do_pick`. Interpreting the shell quoting would help. However,\neval(1) seems to disqualify itself as an interpreter because the\nto-do list entry could potentially contain any shell command line.\nThis could be both a security and a usability issue. For this reason,\nthe patch series still hasn't graduated from being RFC.\n\n   Fabian\n\nFabian Ruch (19):\n  rebase -i: Failed reword prints redundant error message\n  rebase -i: reword complains about empty commit despite --keep-empty\n  rebase -i: reword executes pre-commit hook on interim commit\n  rebase -i: Teach do_pick the option --edit\n  rebase -i: Implement reword in terms of do_pick\n  rebase -i: Stop on root commits with empty log messages\n  rebase -i: The replay of root commits is not shown with --verbose\n  rebase -i: Root commits are replayed with an unnecessary option\n  rebase -i: Commit only once when rewriting picks\n  rebase -i: Do not die in do_pick\n  rebase -i: Teach do_pick the option --amend\n  rebase -i: Teach do_pick the option --file\n  rebase -i: Prepare for squash in terms of do_pick --amend\n  rebase -i: Implement squash in terms of do_pick\n  rebase -i: Explicitly distinguish replay commands and exec tasks\n  rebase -i: Parse to-do list command line options\n  rebase -i: Teach do_pick the option --reset-author\n  rebase -i: Teach do_pick the option --signoff\n  rebase -i: Enable options --signoff, --reset-author for pick, reword\n\n git-rebase--interactive.sh    | 277 ++++++++++++++++++++++++++++++++++--------\n t/t3404-rebase-interactive.sh |   8 ++\n t/t3412-rebase-root.sh        |  39 ++++++\n 3 files changed, 273 insertions(+), 51 deletions(-)\n\n-- \n2.0.0\n"},{"id":"245318","messageId":"10d7fae199e4d8adec537aa377177de652badc07.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:53Z","receivedAt":"2014-07-02T17:47:53Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If the edited log\nmessage is empty or is found ill-formatted by one of the commit\nhooks, git-rebase--interactive prints three error messages to the\nconsole.\n\n    1. The git-commit output, which contains all the output from hook\n       scripts.\n    2. A rebase diagnosis saying at which task on the to-do list it\n       got stuck.\n    3. Generic presumptions about what could have triggered the\n       error.\n\nThe third message contains redundant information and does not add any\nenlightenment either, which makes the output unnecessarily longish\nand different from the other command's output. For instance, this is\nwhat the output looks like if the log message is empty (contains\nduplicate Signed-off-by lines).\n\n    (1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by lines.)\n    (2.) Could not amend commit after successfully picking fa1afe1... Some change\n    (3.) This is most likely due to an empty commit message, or the pre-commit hook\n         failed. If the pre-commit hook failed, you may need to resolve the issue before\n         you are able to reword the commit.\n\nDiscard the third message.\n\nIt is true that a failed hook script might not output any diagnosis\nbut then the generic message is not of much help either. Since this\nlack of information affects the built-in git commands for commit,\nmerge and cherry-pick first, the solution would be to keep track of\nthe failed hooks in their output so that the user knows which of her\nhooks require improvement.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 7e1eda0..e733d7f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -506,9 +506,6 @@ do_next () {\n \t\tdo_pick $sha1 \"$rest\"\n \t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n-\t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n-\t\t\twarn \"you are able to reword the commit.\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\n \t\trecord_in_rewritten $sha1\n-- \n2.0.0\n"},{"id":"245319","messageId":"b7ee74ddb785f0e087b30ca6be11723ca199fa03.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 02/19] rebase -i: reword complains about empty commit despite --keep-empty","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:54Z","receivedAt":"2014-07-02T17:47:54Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If `--keep-empty` is\npassed as option to git-rebase--interactive, empty commits ought to\nbe replayed without complaints. However, if the users chooses to\nreword an empty commit by changing the respective to-do list entry\nfrom\n\n    pick fa1afe1 Empty commit\n\nto\n\n    reword fa1afe1 Empty commit\n\n, then git-rebase--interactive suddenly fails to replay the empty\ncommit. This is especially counterintuitive because `reword` is\nthought of as a `pick` that alters the log message in some way but\nnothing more and the unchanged to-do list entry would not fail.\n\nHandle `reword` by cherry-picking the named commit and editing the\nlog message using\n\n    git commit --allow-empty --amend\n\ninstead of\n\n    git commit --amend.\n\nAdd test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 2 +-\n t/t3404-rebase-interactive.sh | 8 ++++++++\n 2 files changed, 9 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e733d7f..689400e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8197ed2..9931143 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,14 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+test_expect_success 'rebase --keep-empty' '\n+\tgit checkout emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 reword 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 6 actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.0.0\n"},{"id":"245320","messageId":"12171cf0323b3d10b12b02e3b7d42ff4b7964724.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:55Z","receivedAt":"2014-07-02T17:47:55Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. This happens in two\nsteps. Firstly, the named commit is cherry-picked. Secondly, the\ncommit created in the first step is amended using an unchanged index\nto edit the log message. The pre-commit hook is meant to verify the\nchanges introduced by a commit (for instance, catching inserted\ntrailing white space). Since the committed tree is not changed\nbetween the two steps, do not execute the pre-commit hook in the\nsecond step.\n\nSpecify the git-commit option `--no-verify` to disable the pre-commit\nhook when editing the log message. Because `--no-verify` also skips\nthe commit-msg hook, execute the hook from within\ngit-rebase--interactive after the commit is created. Fortunately, the\ncommit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\ngit-commit terminates. Caveat: In case the commit-msg hook finds the\nnew log message ill-formatted, the user is only notified of the\nfailed commit-msg hook but the log message is used for the commit\nanyway. git-commit ought to offer more fine-grained control over\nwhich hooks are executed.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 17 +++++++++++++----\n 1 file changed, 13 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 689400e..b50770d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,10 +504,19 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\texit_with_patch $sha1 1\n-\t\t}\n+\t\t# TODO: Work around the fact that git-commit lets us\n+\t\t# disable either both the pre-commit and the commit-msg\n+\t\t# hook or none. Disable the pre-commit hook because the\n+\t\t# tree is left unchanged but run the commit-msg hook\n+\t\t# from here because the log message is altered.\n+\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n+\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\t\tthen\n+\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\t\tfi || {\n+\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n+\t\t\t\texit_with_patch $sha1 1\n+\t\t\t}\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n-- \n2.0.0\n"},{"id":"245321","messageId":"f674c404c004899bd19b79e585831839550ca44a.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 04/19] rebase -i: Teach do_pick the option --edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:56Z","receivedAt":"2014-07-02T17:47:56Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`. To cater for\nthe different pick behaviours (like `reword`), `do_pick` accepts\nseveral options not only from the git-cherry-pick but also the\ngit-commit interface. Add the common option `--edit` to let the user\nedit the log message of the named commit.\n\nLoop over `$@` to parse the `do_pick` arguments. Assign the local\nvariable `edit` if one of the options is `--edit` so that the\nremainder of `do_pick` can easily check whether the client code asked\nto edit the commit message. If one of the options is unknown, mention\nit on the console and `die`. Break the loop on the first non-option\nand do some sanity checking to ensure that there exactly two\nnon-options, which are interpreted by the remainder as `<commit>` and\n`<title>` like before.\n\n`do_pick` ought to act as a wrapper around `cherry-pick`.\nUnfortunately, it cannot just forward `--edit` to the `cherry-pick`\ncommand line. The assembled command line is executed within a command\nsubstitution for controlling the verbosity of `rebase--interactive`.\nPassing `--edit` would either hang the terminal or clutter the\nsubstituted command output with control sequences. Execute the\n`reword` code from `do_next` instead if the option `--edit` is\nspecified.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 52 insertions(+)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b50770d..e06d9b6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -461,7 +461,42 @@ record_in_rewritten() {\n \tesac\n }\n \n+# Apply the changes introduced by the given commit to the current head.\n+#\n+# do_pick [--edit] <commit> <title>\n+#\n+# Wrapper around git-cherry-pick.\n+#\n+# -e, --edit\n+#     After picking <commit>, open an editor and let the user edit the\n+#     commit message. The editor contents becomes the commit message of\n+#     the new head. This creates a fresh commit.\n+#\n+# <commit>\n+#     The commit to cherry-pick.\n+#\n+# <title>\n+#     The commit message title of <commit>. Used for information\n+#     purposes only.\n do_pick () {\n+\tedit=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-e|--edit)\n+\t\t\tedit=y\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n \t\t# Set the correct commit message and author info on the\n@@ -483,6 +518,23 @@ do_pick () {\n \t\tpick_one $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n+\n+\tif test -n \"$edit\"\n+\tthen\n+\t\t# TODO: Work around the fact that git-commit lets us\n+\t\t# disable either both the pre-commit and the commit-msg\n+\t\t# hook or none. Disable the pre-commit hook because the\n+\t\t# tree is left unchanged but run the commit-msg hook\n+\t\t# from here because the log message is altered.\n+\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n+\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\t\tthen\n+\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\t\tfi || {\n+\t\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n+\t\t\t\texit_with_patch $1 1\n+\t\t\t}\n+\tfi\n }\n \n do_next () {\n-- \n2.0.0\n"},{"id":"245323","messageId":"a82fd64f943d4b59a01509ae52fc2d7a05d51f4a.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 05/19] rebase -i: Implement reword in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:57Z","receivedAt":"2014-07-02T17:47:57Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If one thinks of `pick`\nentries as scheduled `cherry-pick` command lines, then `reword`\nbecomes an alias for the command line `cherry-pick --edit`. The\nporcelain `rebase--interactive` defines a function `do_pick` for\nprocessing the `pick` entries on to-do lists. Reimplement `reword` in\nterms of `do_pick --edit`.\n\nIf the user picks a commit using the to-do list line\n\n    reword fa1afe1 Some change\n\nexecute the command `do_pick --edit fa1afe1 \"Some change\"` which\ncarries out exactly the same steps as the case arm for `reword` in\n`do_next` so far.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 15 +--------------\n 1 file changed, 1 insertion(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e06d9b6..4c875d5 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -555,20 +555,7 @@ do_next () {\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n-\t\t# TODO: Work around the fact that git-commit lets us\n-\t\t# disable either both the pre-commit and the commit-msg\n-\t\t# hook or none. Disable the pre-commit hook because the\n-\t\t# tree is left unchanged but run the commit-msg hook\n-\t\t# from here because the log message is altered.\n-\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n-\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n-\t\t\tthen\n-\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\t\tfi || {\n-\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\t\texit_with_patch $sha1 1\n-\t\t\t}\n+\t\tdo_pick --edit $sha1 \"$rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n-- \n2.0.0\n"},{"id":"245324","messageId":"00ca9dc0d1750301aa22c2bb78976b141233cef3.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:58Z","receivedAt":"2014-07-02T17:47:58Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the\nerroneous option `--allow-empty-message`. If the root commit has an\nempty log message, the replay of this commit should fail and the\nrebase should be interrupted like for any other commit that is on the\nto-do list and has an empty commit message. Remove the option.\n\nThe option might have been introduced by copy-and-paste of the first\npart of the command line which initializes the authorship of the\nsentinel commit. Indeed, the sentinel commit has an empty log message\nand this should not trigger a failure, which is why the option\n`--allow-empty-message` is correctly specified here.\n\nAdd test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh |  2 +-\n t/t3412-rebase-root.sh     | 39 +++++++++++++++++++++++++++++++++++++++\n 2 files changed, 40 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4c875d5..0af96f2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -510,7 +510,7 @@ do_pick () {\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n-\t\t\tgit commit --allow-empty --allow-empty-message \\\n+\t\t\tgit commit --allow-empty \\\n \t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 0b52105..9867705 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -278,4 +278,43 @@ test_expect_success 'rebase -i -p --root with conflict (second part)' '\n \ttest_cmp expect-conflict-p out\n '\n \n+test_expect_success 'stop rebase --root on empty root log message' '\n+\t# create a root commit with a non-empty tree so that rebase does\n+\t# not fail because of an empty commit, and an empty log message\n+\techo root-commit >file &&\n+\tgit add file &&\n+\ttree=$(git write-tree) &&\n+\troot=$(git commit-tree $tree </dev/null) &&\n+\tgit checkout -b no-message-root-commit $root &&\n+\t# do not ff because otherwise neither the patch nor the message\n+\t# are looked at and checked for emptiness\n+\ttest_when_finished git rebase --abort &&\n+\ttest_must_fail env EDITOR=true git rebase -i --force-rebase --root &&\n+\techo root-commit >file.expected &&\n+\ttest_cmp file.expected file\n+'\n+\n+test_expect_success 'stop rebase --root on empty child log message' '\n+\t# create a root commit with a non-empty tree and provide a log\n+\t# message so that rebase does not fail until the root commit is\n+\t# successfully replayed\n+\techo root-commit >file &&\n+\tgit add file &&\n+\ttree=$(git write-tree) &&\n+\troot=$(git commit-tree $tree -m root-commit) &&\n+\tgit checkout -b no-message-child-commit $root &&\n+\t# create a child commit with a non-empty patch so that rebase\n+\t# does not fail because of an empty commit, but an empty log\n+\t# message\n+\techo child-commit >file &&\n+\tgit add file &&\n+\tgit commit --allow-empty-message --no-edit &&\n+\t# do not ff because otherwise neither the patch nor the message\n+\t# are looked at and checked for emptiness\n+\ttest_when_finished git rebase --abort &&\n+\ttest_must_fail env EDITOR=true git rebase -i --force-rebase --root &&\n+\techo child-commit >file.expected &&\n+\ttest_cmp file.expected file\n+'\n+\n test_done\n-- \n2.0.0\n"},{"id":"245326","messageId":"b1ecef042cd18a0251199429e4efb969b085d5fe.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 07/19] rebase -i: The replay of root commits is not shown with --verbose","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:47:59Z","receivedAt":"2014-07-02T17:47:59Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the\nerroneous option `-q` which suppresses the commit summary message.\nHowever, git-rebase--interactive tends to tell the user about the\ncommits it creates, if she wishes (cf. command line option\n`--verbose`). The code parts handling non-root commits or squash\ncommits all output commit summary messages. Do not make the replay of\nroot commits an exception. Remove the option.\n\nIt is OK to suppress the commit summary when git-commit is used to\ninitialize the authorship of the sentinel commit because the\nexistence of this additional commit is a detail of\ngit-rebase--interactive's implementation. The option `-q` was\nprobably introduced as a copy-and-paste error stemming from that part\nof the root commit handling code.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0af96f2..ff04d5d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\tgit commit --allow-empty \\\n-\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.0\n"},{"id":"245327","messageId":"606af9e165c447b59076046a4d84aecf8b4cd2b0.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:00Z","receivedAt":"2014-07-02T17:48:00Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the\neffectless option `-C`. It is used to reuse commit message and\nauthorship from the named commit but the commit being amended here,\nwhich is the sentinel commit, already carries the authorship and log\nmessage of the processed commit. Note that the committer email and\ncommit date fields do not match the root commit either way. Remove\nthe option. However, `-C` (other than `-c`) does not invoke the\neditor and the `--amend` option invokes it by default. Disable editor\ninvocation again by specifying `--no-edit`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ff04d5d..17836d5 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\tgit commit --allow-empty \\\n-\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.0\n"},{"id":"245322","messageId":"778d3832309bc21f74301926844cacc862ce9bb2.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 09/19] rebase -i: Commit only once when rewriting picks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:01Z","receivedAt":"2014-07-02T17:48:01Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The options passed to `do_pick` determine whether the picked commit\nwill be rewritten or not. If the commit gets rewritten, because the\nuser requested to edit the commit message for instance, let\n`pick_one` merely apply the changes introduced by the commit and do\nnot commit the resulting tree yet. If the commit is replayed as is,\nleave it to `pick_one` to recreate the commit (possibly by\nfast-forwarding the head). This makes it easier to combine git-commit\noptions like `--edit` and `--amend` in `do_pick` because\ngit-cherry-pick does not support `--amend`.\n\nIn the case of `--edit`, do not `exit_with_patch` but assign\n`rewrite` to pick the changes with `-n`. If the pick conflicts, no\ncommit is created which we would have to amend when continuing the\nrebase. To complete the pick after the conflicts are resolved the\nuser just resumes with `git rebase --continue`.\n\ngit-commit lets the user edit the commit log message by default. We\ndo not want that for the rewriting git-commit command line because\nthe default behaviour of git-cherry-pick is exactly the opposite.\nPass `--no-edit` when rewriting a picked commit. An explicit `--edit`\npassed to `do_pick` (for instance, when reword is executed) enables\nthe editor launch again.\n\nIf `rebase--interactive` is used to rebase a complete branch onto\nsome head, `rebase` creates a sentinel commit that requires special\ntreatment by `do_pick`. Do not finalize the pick here either because\nits commit message can be altered as for any other pick. Since the\norphaned root commit gets a temporary parent, it is always rewritten.\nSafely use the rewrite infrastructure of `do_pick` to create the\nfinal commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 55 +++++++++++++++++++++++++++-------------------\n 1 file changed, 33 insertions(+), 22 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 17836d5..46b2db1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -63,7 +63,8 @@ msgnum=\"$state_dir\"/msgnum\n author_script=\"$state_dir\"/author-script\n \n # When an \"edit\" rebase command is being processed, the SHA1 of the\n-# commit to be edited is recorded in this file.  When \"git rebase\n+# commit to be edited is recorded in this file.  The same happens when\n+# rewriting a commit fails, for instance \"reword\".  When \"git rebase\n # --continue\" is executed, if there are any staged changes then they\n # will be amended to the HEAD commit, but only provided the HEAD\n # commit is still the commit to be edited.  When any other rebase\n@@ -479,12 +480,15 @@ record_in_rewritten() {\n #     The commit message title of <commit>. Used for information\n #     purposes only.\n do_pick () {\n-\tedit=\n+\trewrite=\n+\trewrite_amend=\n+\trewrite_edit=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n \t\t-e|--edit)\n-\t\t\tedit=y\n+\t\t\trewrite=y\n+\t\t\trewrite_edit=y\n \t\t\t;;\n \t\t-*)\n \t\t\tdie \"do_pick: unrecognized option -- $1\"\n@@ -499,6 +503,10 @@ do_pick () {\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n+\t\trewrite=y\n+\t\trewrite_amend=y\n+\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\n \t\t# Set the correct commit message and author info on the\n \t\t# sentinel root before cherry-picking the original changes\n \t\t# without committing (-n).  Finally, update the sentinel again\n@@ -509,31 +517,34 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 &&\n-\t\t\tgit commit --allow-empty \\\n-\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n-\t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tpick_one -n $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-\t\tpick_one $1 ||\n+\t\tpick_one ${rewrite:+-n} $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n \n-\tif test -n \"$edit\"\n+\tif test -n \"$rewrite\"\n \tthen\n-\t\t# TODO: Work around the fact that git-commit lets us\n-\t\t# disable either both the pre-commit and the commit-msg\n-\t\t# hook or none. Disable the pre-commit hook because the\n-\t\t# tree is left unchanged but run the commit-msg hook\n-\t\t# from here because the log message is altered.\n-\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n-\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n-\t\t\tthen\n-\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\t\tfi || {\n-\t\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n-\t\t\t\texit_with_patch $1 1\n-\t\t\t}\n+\t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n+\t\t\t   ${rewrite_amend:+--amend} \\\n+\t\t\t   ${rewrite_edit:+--edit} \\\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\tfi\n+\n+\t# TODO: Work around the fact that git-commit lets us\n+\t# disable either both the pre-commit and the commit-msg\n+\t# hook or none. Disable the pre-commit hook because the\n+\t# tree is left unchanged but run the commit-msg hook\n+\t# from here because the log message is altered.\n+\tif test -n \"$rewrite_edit\"\n+\tthen\n+\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\tthen\n+\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\tfi ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n \tfi\n }\n \n-- \n2.0.0\n"},{"id":"245325","messageId":"50ca26dbebbc291af5110770665c283375345bbd.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 10/19] rebase -i: Do not die in do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:02Z","receivedAt":"2014-07-02T17:48:02Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Since `do_pick` might be executed in a sub-shell (a modified author\nenvironment for instance), calling `die` in `do_pick` has no effect\nbut exiting the sub-shell with a failure exit status. The\ngit-rebase--interactive script is not terminated. Moreover, if\n`do_pick` is called while a squash or fixup is in effect,\n`die_with_patch` will discard `$squash_msg` as commit message.\nLastly, after a `die` in `do_pick` `do_next` has no chance to\nreschedule tasks that failed before changes could be applied.\n\nIndicate an error in `do_pick` using return statements and properly\nkill the script at the call sites. Although possible in principle,\nthe issued error messages are no more indicating whether `do_pick`\nfailed while applying or while committing the changes. This reduces\ncode complexity at the call site and does not matter from a user's\npoint of view because a glance at the index reveals whether there are\nconflicts or not and in-depth troubleshooting is still possible using\nthe `--verbose` option.\n\nRemove the commit message title argument from `do_pick`'s interface,\nwhich has become unused.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 46b2db1..0070b3e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit> <title>\n+# do_pick [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -476,9 +476,11 @@ record_in_rewritten() {\n # <commit>\n #     The commit to cherry-pick.\n #\n-# <title>\n-#     The commit message title of <commit>. Used for information\n-#     purposes only.\n+# The return value is 1 if applying the changes resulted in a conflict\n+# and 2 if the specified arguments were incorrect. If the changes could\n+# be applied successfully but creating the commit failed, a value\n+# greater than 2 is returned. No commit is created in either case and\n+# the index is left with the (conflicting) changes in place.\n do_pick () {\n \trewrite=\n \trewrite_amend=\n@@ -491,7 +493,8 @@ do_pick () {\n \t\t\trewrite_edit=y\n \t\t\t;;\n \t\t-*)\n-\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\twarn \"do_pick: unrecognized option -- $1\"\n+\t\t\treturn 2\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n@@ -499,7 +502,11 @@ do_pick () {\n \t\tesac\n \t\tshift\n \tdone\n-\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\tif test $# -ne 1\n+\tthen\n+\t\twarn \"do_pick: wrong number of arguments\"\n+\t\treturn 2\n+\tfi\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n@@ -517,11 +524,9 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\t\tpick_one -n $1 || return 1\n \telse\n-\t\tpick_one ${rewrite:+-n} $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n \tif test -n \"$rewrite\"\n@@ -529,8 +534,7 @@ do_pick () {\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n-\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n \t# TODO: Work around the fact that git-commit lets us\n@@ -543,8 +547,7 @@ do_pick () {\n \t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n \t\tthen\n \t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\tfi ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\tfi || return 3\n \tfi\n }\n \n@@ -559,21 +562,21 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 \"$rest\"\n+\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.0\n"},{"id":"245333","messageId":"def85097bcd50006ad39dc274f900f33ecc010e5.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 11/19] rebase -i: Teach do_pick the option --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:03Z","receivedAt":"2014-07-02T17:48:03Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list commands `pick`, `reword`\nand `edit`. To cater for the different pick behaviours (like\n`squash`), `do_pick` accepts several options not only from the\ngit-cherry-pick but also the git-commit interface.\n\nAdd the option `--amend` from the git-commit interface to the options\npool of `do_pick`. It creates a new commit for the changes introduced\nby the picked commit and the previous one. The previous commit is\nthen replaced with the new commit. If no other options are specified,\nthe log message of the previous commit is used.\n\nBe careful when `--amend` is used to pick a root commit because HEAD\nmight point to the sentinel commit but there is still nothing to\namend. Be sure to initialize `amend` so that commits are squashed\neven when git-rebase--interactive is interrupted for resolving\nconflicts. It is not a mistake to do the initialization regardless of\nany conflicts because `amend` is always cleared before the next to-do\nitem is processed.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 18 +++++++++++++++++-\n 1 file changed, 17 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0070b3e..046d358 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,16 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit>\n+# do_pick [--amend] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --amend\n+#     After picking <commit>, replace the current head commit with a new\n+#     commit that also introduces the changes of <commit>.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -488,6 +494,16 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--amend)\n+\t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse --verify HEAD\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: nothing to amend\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_amend=y\n+\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n-- \n2.0.0\n"},{"id":"245336","messageId":"b9979c769e293d032cf7a3c173ec06f87f8fc8e8.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 12/19] rebase -i: Teach do_pick the option --file","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:04Z","receivedAt":"2014-07-02T17:48:04Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`, `reword` and\n`edit`. To cater for the different pick behaviours (like `squash`),\n`do_pick` accepts several options not only from the git-cherry-pick\nbut also the git-commit interface.\n\nAdd the option `--file` from the git-commit interface to the options\npool of `do_pick`. It expects an argument itself which is interpreted\nas a file path and takes the commit message from the given file. If\n`--file` is passed to `do_pick`, assign the given file path to the\nlocal variable `rewrite_message` and relay the option\n\n    --file \"$rewrite_message\"\n\nto the git-commit command line which creates the commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 20 +++++++++++++++++++-\n 1 file changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 046d358..47e3edf 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--edit] <commit>\n+# do_pick [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -474,6 +474,12 @@ record_in_rewritten() {\n #\n #     _This is not a git-cherry-pick option._\n #\n+# -F <file>, --file <file>\n+#     Take the commit message from the given file. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -491,6 +497,7 @@ do_pick () {\n \trewrite=\n \trewrite_amend=\n \trewrite_edit=\n+\trewrite_message=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n@@ -504,6 +511,16 @@ do_pick () {\n \t\t\trewrite_amend=y\n \t\t\tgit rev-parse --verify HEAD >\"$amend\"\n \t\t\t;;\n+\t\t-F|--file)\n+\t\t\tif test $# -eq 0\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: option --file specified but no <file> given\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_message=$2\n+\t\t\tshift\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n@@ -550,6 +567,7 @@ do_pick () {\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n+\t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n-- \n2.0.0\n"},{"id":"245334","messageId":"9b5c502a106a23c35caf78b4331278ac3c2ad3c9.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 13/19] rebase -i: Prepare for squash in terms of do_pick --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:05Z","receivedAt":"2014-07-02T17:48:05Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Rewrite `squash` and `fixup` handling in `do_next` using the sequence\n\n    pick_one\n    commit\n\nin order to test the correctness of a single `do_squash` or\nparameterised `do_pick` and make the subsequent patch reimplementing\n`squash` in terms of such a single function more readable.\n\nDo not call `rm -f \"$GIT_DIR\"/MERGE_MSG` since it has no effect on\nthe state after git-rebase--interactive terminates. The option `-F`\nmakes git-commit ignore `MERGE_MSG` for the log message. If\ngit-commit succeeds, `MERGE_MSG` is removed, and if it fails,\n`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.\nIn summary, removing `MERGE_MSG` neither influences the squash commit\nmessage nor the file state after git-commit returns.\n\nMoreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch\n`$squash_msg` so that it is correct to execute `pick_one` immediately\nbefore git-commit.\n\nMight be squashed into the subsequent commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 21 +++++++++++++++------\n 1 file changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 47e3edf..37800be 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -633,15 +633,15 @@ do_next () {\n \t\tauthor_script_content=$(get_author_ident_from_commit HEAD)\n \t\techo \"$author_script_content\" > \"$author_script\"\n \t\teval \"$author_script_content\"\n-\t\tif ! pick_one -n $sha1\n-\t\tthen\n-\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\tdie_failed_squash $sha1 \"$rest\"\n-\t\tfi\n \t\tcase \"$(peek_next_command)\" in\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n+\t\t\tif ! pick_one -n $sha1\n+\t\t\tthen\n+\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\tfi\n \t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n@@ -650,12 +650,21 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n-- \n2.0.0\n"},{"id":"245335","messageId":"aef64805e4209549739f5a066426a4909d701388.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 14/19] rebase -i: Implement squash in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:06Z","receivedAt":"2014-07-02T17:48:06Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `squash` and its close relative `fixup` replay\nthe changes of a commit like `pick` but do not recreate the commit.\nInstead they replace the previous commit with a new commit that also\nintroduces the changes of the squashed commit. This is roughly like\ncherry-picking without committing and using git-commit to amend the\nprevious commit.\n\nThe to-do list\n\n    pick   a Some changes\n    squash b Some more changes\n\ngets translated into the sequence of git commands\n\n    git cherry-pick a\n    git cherry-pick -n b\n    git commit --amend\n\nand if git-cherry-pick supported `--amend` this would look even more\nlike the to-do list it is based on\n\n    git cherry-pick a\n    git cherry-pick --amend b.\n\nSince `do_pick` takes care of `pick` entries and the above suggests\n`squash` as an alias for `pick --amend`, reimplement `squash` in\nterms of `do_pick --amend`. Introduce `$squash_msg` as the commit\nmessage via the `--file` option. When the last commit of a squash\nseries is processed, the user is asked to review the log message.\nPass `--edit` as additional option in this case. The only difference\nin the options passed to git-commit and `do_pick` is the omitted\n`--no-verify`. However, `do_pick` does not execute the verification\nhooks anyway because it solely replays commits and assumes that they\nhave been verified before.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 30 ++++++------------------------\n 1 file changed, 6 insertions(+), 24 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 37800be..008f3a0 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -637,37 +637,19 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tif ! pick_one -n $sha1\n-\t\t\tthen\n-\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\tfi\n-\t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n-\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\tdo_with_author do_pick --amend -F \"$squash_msg\" $sha1 \\\n+\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\t;;\n \t\t*)\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$fixup_msg\" $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n \t\t\t;;\n-- \n2.0.0\n"},{"id":"245328","messageId":"07e5f295c0042e78ba83ffb66925e3f09988ae3c.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 15/19] rebase -i: Explicitly distinguish replay commands and exec tasks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:07Z","receivedAt":"2014-07-02T17:48:07Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"There are two kinds of to-do list commands available. One kind\nreplays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that\nis) and the other executes a shell command (`exec`). We will call the\nfirst kind replay commands.\n\nThe two kinds of tasks are scheduled using different line formats.\nReplay commands expect a commit hash argument following the command\nname and exec concatenates all arguments to assemble a command line.\n\nAdhere to the distinction of formats by not trying to parse the\n`sha1` field unless we are dealing with a replay command. Move the\nreplay command handling code to a new function `do_replay` which\nassumes the first argument to be a commit hash and make no more such\nassumptions in `do_next`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 008f3a0..9de7441 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -585,13 +585,12 @@ do_pick () {\n \tfi\n }\n \n-do_next () {\n-\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest < \"$todo\"\n+do_replay () {\n+\tcommand=$1\n+\tsha1=$2\n+\trest=$3\n+\n \tcase \"$command\" in\n-\t\"$comment_char\"*|''|noop)\n-\t\tmark_action_done\n-\t\t;;\n \tpick|p)\n \t\tcomment_for_reflog pick\n \n@@ -656,6 +655,28 @@ do_next () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\twarn \"Unknown command: $command\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+}\n+\n+do_next () {\n+\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\tread -r command sha1 rest <\"$todo\"\n+\n+\tcase \"$command\" in\n+\t\"$comment_char\"*|''|noop)\n+\t\tmark_action_done\n+\t\t;;\n \tx|\"exec\")\n \t\tread -r command rest < \"$todo\"\n \t\tmark_action_done\n@@ -695,14 +716,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\twarn \"Unknown command: $command $sha1 $rest\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n+\t\tdo_replay $command $sha1 \"$rest\"\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n-- \n2.0.0\n"},{"id":"245332","messageId":"e6e472630dd3dd08316ab0b07eb488da437c6c7c.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 16/19] rebase -i: Parse to-do list command line options","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:08Z","receivedAt":"2014-07-02T17:48:08Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Read in to-do list lines as\n\n    command args\n\ninstead of\n\n    command sha1 rest\n\nso that to-do list command lines can specify additional arguments\napart from the commit hash and the log message title, which become\nthe non-options in `args`. Loop over `args`, put all options (an\nargument beginning with a dash) in `opts`, stop the loop on the first\nnon-option and assign it to `sha1`. The loop does not know the\noptions it parses so that options that take an argument themselves\nare not supported at the moment. Neither are options that contain\nspaces because the shell expansion of `args` in `do_next` interprets\nwhite space characters as argument separator, that is a command line\nlike\n\n    pick --author \"A U Thor\" fa1afe1 Some change\n\nis parsed as the pick command\n\n    pick --author\n\nand the commit hash\n\n    \"A\n\nwhich obviously results in an unknown revision error. For the sake of\ncompleteness, in the example above the message title variable `rest`\nis assigned the string 'U Thor\" fa1afe1 Some change' (without the\nsingle quotes).\n\nPrint an error message for unknown or unsupported command line\noptions, which means an error for all specified options at the\nmoment. Cleanly break the `do_next` loop by assigning the special\nvalue 'unknown' to the local variable `command`, which triggers the\nunknown command case in `do_cmd`.\n\nThe to-do list is also parsed when the commit hashes are translated\nbetween long and short format before and after the to-do list is\nedited. Apply the same procedure as in `do_cmd` with the exception\nthat we only care about where the options stop and the commit hash\nbegins. Do not reject any options when transforming the commit\nhashes.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 49 ++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 41 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 9de7441..2119d00 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -587,8 +587,26 @@ do_pick () {\n \n do_replay () {\n \tcommand=$1\n-\tsha1=$2\n-\trest=$3\n+\tshift\n+\n+\topts=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-*)\n+\t\t\twarn \"Unknown option: $1\"\n+\t\t\tcommand=unknown\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\topts=\"$opts $(git rev-parse --sq-quote \"$1\")\"\n+\t\tshift\n+\tdone\n+\tsha1=$1\n+\tshift\n+\trest=$*\n \n \tcase \"$command\" in\n \tpick|p)\n@@ -671,7 +689,7 @@ do_replay () {\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest <\"$todo\"\n+\tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n \t\"$comment_char\"*|''|noop)\n@@ -716,7 +734,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\tdo_replay $command $sha1 \"$rest\"\n+\t\tdo_replay $command $args\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n@@ -796,19 +814,34 @@ skip_unnecessary_picks () {\n }\n \n transform_todo_ids () {\n-\twhile read -r command rest\n+\twhile read -r command args\n \tdo\n \t\tcase \"$command\" in\n \t\t\"$comment_char\"* | exec)\n \t\t\t# Be careful for oddball commands like 'exec'\n \t\t\t# that do not have a SHA-1 at the beginning of $rest.\n+\t\t\tnewargs=\\ $args\n \t\t\t;;\n \t\t*)\n-\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" ${rest%% *}) &&\n-\t\t\trest=\"$sha1 ${rest#* }\"\n+\t\t\tnewargs=\n+\t\t\tsha1=\n+\t\t\tfor arg in $args\n+\t\t\tdo\n+\t\t\t\tcase \"$arg\" in\n+\t\t\t\t-*)\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\ttest -z \"$sha1\" &&\n+\t\t\t\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" $arg) &&\n+\t\t\t\t\t\targ=$sha1\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone\n \t\t\t;;\n \t\tesac\n-\t\tprintf '%s\\n' \"$command${rest:+ }$rest\"\n+\t\tprintf '%s\\n' \"$command$newargs\"\n \tdone <\"$todo\" >\"$todo.new\" &&\n \tmv -f \"$todo.new\" \"$todo\"\n }\n-- \n2.0.0\n"},{"id":"245330","messageId":"baceb6e5770c530d938f497dd07ebb37efd518e1.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 17/19] rebase -i: Teach do_pick the option --reset-author","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:09Z","receivedAt":"2014-07-02T17:48:09Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement many of the to-do list commands.\nEventually, the complete `do_pick` interface will be exposed to the\nuser in some form or another and those commands will become simple\naliases for the `do_pick` options now used to implement them.\n\nAdd the git-commit option `--reset-author` to the options pool of\n`do_pick`. It rewrites the author date and name of the picked commit\nto match the committer date and name.\n\nIf `--reset-author` is passed to `do_pick`, set the `rewrite` flag\nand relay the option to the git-commit command line which creates the\nfinal commit. If `--amend` is not passed as well, the fresh\nauthorship effect is achieved by the mere fact that we are creating a\nnew commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 23 ++++++++++++++++++++++-\n 1 file changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2119d00..a9fcb76 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,18 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --reset-author\n+#     Pretend the changes were made for the first time. Declare that the\n+#     authorship of the resulting commit now belongs to the committer.\n+#     This also renews the author timestamp. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # --amend\n #     After picking <commit>, replace the current head commit with a new\n #     commit that also introduces the changes of <commit>.\n@@ -501,6 +509,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--reset-author)\n+\t\t\trewrite=y\n+\t\t\trewrite_author=y\n+\t\t\t;;\n \t\t--amend)\n \t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse --verify HEAD\n \t\t\tthen\n@@ -562,12 +574,21 @@ do_pick () {\n \t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n+\tif test -n \"$rewrite_author\" && test -z \"$rewrite_amend\"\n+\tthen\n+\t\t# keep rewrite flag to create a new commit, rewrite\n+\t\t# without --reset-author though because it can only be\n+\t\t# used with -C, -c or --amend\n+\t\trewrite_author=\n+\tfi\n+\n \tif test -n \"$rewrite\"\n \tthen\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n+\t\t\t   ${rewrite_author:+--reset-author} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n-- \n2.0.0\n"},{"id":"245331","messageId":"b55f924521f19fbdc0b2d9525b2929a4422893ea.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 18/19] rebase -i: Teach do_pick the option --signoff","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:10Z","receivedAt":"2014-07-02T17:48:10Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is currently used to implement most of the to-do list commands\nand offers additional options that will eventually find their way\nonto to-do lists.\n\nTo extend the repertoire of available options, add the git-commit and\ngit-cherry-pick option `--signoff` to the `do_pick` interface. It\nappends a Signed-off-by: line using the committer identity to the log\nmessage of the picked commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 12 +++++++++++-\n 1 file changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a9fcb76..bb258bb 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,15 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--signoff] [--reset-author] [--amend] [--file <file>]\n+#         [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# -s, --signoff\n+#     Insert a Signed-off-by: line using the committer identity at the\n+#     end of the commit log message. This creates a fresh commit.\n+#\n # --reset-author\n #     Pretend the changes were made for the first time. Declare that the\n #     authorship of the resulting commit now belongs to the committer.\n@@ -509,6 +514,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t-s|--signoff)\n+\t\t\trewrite=y\n+\t\t\trewrite_signoff=y\n+\t\t\t;;\n \t\t--reset-author)\n \t\t\trewrite=y\n \t\t\trewrite_author=y\n@@ -585,6 +594,7 @@ do_pick () {\n \tif test -n \"$rewrite\"\n \tthen\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n+\t\t\t   ${rewrite_signoff:+--signoff} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n-- \n2.0.0\n"},{"id":"245329","messageId":"ee5fc98420753a03a1f559ae824a2c13ee2aa49b.1404323078.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"[PATCH RFC v2 19/19] rebase -i: Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-02T17:48:11Z","receivedAt":"2014-07-02T17:48:11Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"pick and reword are atomic to-do list commands in the sense that they\nopen a new task which is closed after the respective command is\ncompleted. squash and fixup are not atomic. They create a new task\nwhich is not completed until the last squash or fixup is processed.\n\nLift the general unknown option blockade for the pick and reword\ncommands. If `do_cmd` comes across one of the options `--signoff` and\n`--reset-author` while parsing a to-do entry and the scheduled\ncommand is either `pick` or `reword`, relay the option to `do_pick`.\n\nThe `do_pick` options `--gpg-sign` and `--file` are not yet supported\nbecause `do_cmd` cannot handle option arguments and options with\nspaces at the moment. It is true that edit is one of the atomic\ncommands but it displays hash information when the rebase is stopped\nand some options rewrite the picked commit which alters that\ninformation. squash and fixup still do not accept user options as the\ninterplay of `--reset-author` and the author script are yet to be\ndetermined.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex bb258bb..c34a9a7 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -624,6 +624,16 @@ do_replay () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--signoff|--reset-author)\n+\t\t\tcase \"$command\" in\n+\t\t\tpick|reword)\n+\t\t\t\t;;\n+\t\t\t*)\n+\t\t\t\twarn \"Unsupported option: $1\"\n+\t\t\t\tcommand=unknown\n+\t\t\t\t;;\n+\t\t\tesac\n+\t\t\t;;\n \t\t-*)\n \t\t\twarn \"Unknown option: $1\"\n \t\t\tcommand=unknown\n@@ -644,21 +654,24 @@ do_replay () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick --edit $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.0\n"},{"id":"245370","messageId":"53B53172.4030803@alum.mit.edu","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2014-07-03T10:33:22Z","receivedAt":"2014-07-03T10:33:22Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 07/02/2014 07:47 PM, Fabian Ruch wrote:\n> [...]\n>  2. Add user options to main commands\n> \n>     Enable options --signoff, --reset-author for pick, reword (19/19)\n> \n> The last stage was added in this reroll. It enables the parsing of\n> line options for to-do list commands, which is still restricted to\n> options without arguments because it is unclear how spaces can be\n> parsed as characters rather than separators where needed. For\n> instance, if we were to support\n> \n>     pick --author=\"A U Thor\" fa1afe1 Some changes\n> \n> then read(1) would hand us the tokens `--author=\"A`, `U` and `Thor\"`\n> instead of `--author=A U Thor`, which we would want to relay to\n> `do_pick`. Interpreting the shell quoting would help. However,\n> eval(1) seems to disqualify itself as an interpreter because the\n> to-do list entry could potentially contain any shell command line.\n> This could be both a security and a usability issue. For this reason,\n> the patch series still hasn't graduated from being RFC.\n> [...]\n\nIt is not required that a patch series solves all of the problems in the\nuniverse.  If these patches implements some useful features robustly,\nand if there is no reason to expect that future enhancements will\nrequire the user interface to be changed in a backwards-compatible way,\nthen there is no reason that this patch series has to be held as an RFC\nhostage to some hypothetical future.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"245550","messageId":"xmqqtx6r8uem.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"10d7fae199e4d8adec537aa377177de652badc07.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T20:31:13Z","receivedAt":"2014-07-08T20:31:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> The to-do list command `reword` replays a commit like `pick` but lets\n> the user also edit the commit's log message. If the edited log\n> message is empty or is found ill-formatted by one of the commit\n> hooks, git-rebase--interactive prints three error messages to the\n> console.\n>\n>     1. The git-commit output, which contains all the output from hook\n>        scripts.\n>     2. A rebase diagnosis saying at which task on the to-do list it\n>        got stuck.\n>     3. Generic presumptions about what could have triggered the\n>        error.\n>\n> The third message contains redundant information and does not add any\n> enlightenment either, which makes the output unnecessarily longish\n> and different from the other command's output. For instance, this is\n> what the output looks like if the log message is empty (contains\n> duplicate Signed-off-by lines).\n>\n>     (1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by lines.)\n>     (2.) Could not amend commit after successfully picking fa1afe1... Some change\n>     (3.) This is most likely due to an empty commit message, or the pre-commit hook\n>          failed. If the pre-commit hook failed, you may need to resolve the issue before\n>          you are able to reword the commit.\n>\n> Discard the third message.\n>\n> It is true that a failed hook script might not output any diagnosis...\n\nI think the message originally came from 0becb3e4 (rebase -i:\ninterrupt rebase when \"commit --amend\" failed during \"reword\",\n2011-11-30); it seems that the primary point of the change was to\nmake sure it exits and the warning message may not have been well\nthought out, but before discarding the result of somebody else's\nwork, it may not be a bad idea to ask just in case you may have\noverlooked something (Andrew Wong Cc'ed).\n\n\n\n\n\n> but then the generic message is not of much help either. Since this\n> lack of information affects the built-in git commands for commit,\n> merge and cherry-pick first, the solution would be to keep track of\n> the failed hooks in their output so that the user knows which of her\n> hooks require improvement.\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh | 3 ---\n>  1 file changed, 3 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 7e1eda0..e733d7f 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -506,9 +506,6 @@ do_next () {\n>  \t\tdo_pick $sha1 \"$rest\"\n>  \t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n>  \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n> -\t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n> -\t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n> -\t\t\twarn \"you are able to reword the commit.\"\n>  \t\t\texit_with_patch $sha1 1\n>  \t\t}\n>  \t\trecord_in_rewritten $sha1\n"},{"id":"245551","messageId":"xmqqpphf8u3x.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"b7ee74ddb785f0e087b30ca6be11723ca199fa03.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 02/19] rebase -i: reword complains about empty commit despite --keep-empty","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T20:37:38Z","receivedAt":"2014-07-08T20:37:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Subject: rebase -i: reword complains about empty commit despite --keep-empty\n\nI had to read the title and then the log twice before understanding\nthat the above is not \"change the complaint message\" (i.e. \"reword\ncomplaints\" spelled incorrectly) but is a description of the current\nbehaviour (i.e. \"the command complains when 'reword' is used on an\nempty commit\") that is not accompanied by an evaluation (\"ok, it\ncomplains; are you saying it is a good thing or a bad thing?\") or an\naction (\"if it is a bad thing, what are you doing about it?\").\n\nPerhaps\n\n\trebase -i: allow rewording an empty commit\n\nor something?\n\n> The to-do list command `reword` replays a commit like `pick` but lets\n> the user also edit the commit's log message. If `--keep-empty` is\n> passed as option to git-rebase--interactive, empty commits ought to\n> be replayed without complaints. However, if the users chooses to\n> reword an empty commit by changing the respective to-do list entry\n> from\n>\n>     pick fa1afe1 Empty commit\n>\n> to\n>\n>     reword fa1afe1 Empty commit\n>\n> , then git-rebase--interactive suddenly fails to replay the empty\n> commit. This is especially counterintuitive because `reword` is\n> thought of as a `pick` that alters the log message in some way but\n> nothing more and the unchanged to-do list entry would not fail.\n>\n> Handle `reword` by cherry-picking the named commit and editing the\n> log message using\n>\n>     git commit --allow-empty --amend\n>\n> instead of\n>\n>     git commit --amend.\n>\n> Add test.\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh    | 2 +-\n>  t/t3404-rebase-interactive.sh | 8 ++++++++\n>  2 files changed, 9 insertions(+), 1 deletion(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index e733d7f..689400e 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -504,7 +504,7 @@ do_next () {\n>  \n>  \t\tmark_action_done\n>  \t\tdo_pick $sha1 \"$rest\"\n> -\t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n> +\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n>  \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n>  \t\t\texit_with_patch $sha1 1\n>  \t\t}\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index 8197ed2..9931143 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -75,6 +75,14 @@ test_expect_success 'rebase --keep-empty' '\n>  \ttest_line_count = 6 actual\n>  '\n>  \n> +test_expect_success 'rebase --keep-empty' '\n> +\tgit checkout emptybranch &&\n> +\tset_fake_editor &&\n> +\tFAKE_LINES=\"1 reword 2\" git rebase --keep-empty -i HEAD~2 &&\n> +\tgit log --oneline >actual &&\n> +\ttest_line_count = 6 actual\n> +'\n> +\n>  test_expect_success 'rebase -i with the exec command' '\n>  \tgit checkout master &&\n>  \t(\n"},{"id":"245552","messageId":"xmqqlhs38tub.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"12171cf0323b3d10b12b02e3b7d42ff4b7964724.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T20:43:24Z","receivedAt":"2014-07-08T20:43:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> The to-do list command `reword` replays a commit like `pick` but lets\n> the user also edit the commit's log message. This happens in two\n> steps. Firstly, the named commit is cherry-picked. Secondly, the\n> commit created in the first step is amended using an unchanged index\n> to edit the log message. The pre-commit hook is meant to verify the\n> changes introduced by a commit (for instance, catching inserted\n> trailing white space). Since the committed tree is not changed\n> between the two steps, do not execute the pre-commit hook in the\n> second step.\n\nIt is not like the second step is built as a child commit of the\nresult from the first step, recording the same tree without any\nchange.  Why is it a good thing not to run the pre-commit hook (or\nother hooks for that matter)?  After all, the result of the second\nstep is what is recorded in the final history; it just feels wrong\nnot to test that one, even if it were a good idea to test only once.\n\n> Specify the git-commit option `--no-verify` to disable the pre-commit\n> hook when editing the log message. Because `--no-verify` also skips\n> the commit-msg hook, execute the hook from within\n> git-rebase--interactive after the commit is created. Fortunately, the\n> commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\n> git-commit terminates. Caveat: In case the commit-msg hook finds the\n> new log message ill-formatted, the user is only notified of the\n> failed commit-msg hook but the log message is used for the commit\n> anyway. git-commit ought to offer more fine-grained control over\n> which hooks are executed.\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh | 17 +++++++++++++----\n>  1 file changed, 13 insertions(+), 4 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 689400e..b50770d 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -504,10 +504,19 @@ do_next () {\n>  \n>  \t\tmark_action_done\n>  \t\tdo_pick $sha1 \"$rest\"\n> -\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n> -\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n> -\t\t\texit_with_patch $sha1 1\n> -\t\t}\n> +\t\t# TODO: Work around the fact that git-commit lets us\n> +\t\t# disable either both the pre-commit and the commit-msg\n> +\t\t# hook or none. Disable the pre-commit hook because the\n> +\t\t# tree is left unchanged but run the commit-msg hook\n> +\t\t# from here because the log message is altered.\n> +\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n> +\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n> +\t\t\tthen\n> +\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n> +\t\t\tfi || {\n> +\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n> +\t\t\t\texit_with_patch $sha1 1\n> +\t\t\t}\n>  \t\trecord_in_rewritten $sha1\n>  \t\t;;\n>  \tedit|e)\n"},{"id":"245553","messageId":"xmqqha2r8trc.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"cover.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T20:45:11Z","receivedAt":"2014-07-08T20:45:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Fabian Ruch (19):\n>   rebase -i: Failed reword prints redundant error message\n>   rebase -i: reword complains about empty commit despite --keep-empty\n>   rebase -i: reword executes pre-commit hook on interim commit\n>   rebase -i: Teach do_pick the option --edit\n>   rebase -i: Implement reword in terms of do_pick\n>   rebase -i: Stop on root commits with empty log messages\n>   rebase -i: The replay of root commits is not shown with --verbose\n>   rebase -i: Root commits are replayed with an unnecessary option\n>   rebase -i: Commit only once when rewriting picks\n>   rebase -i: Do not die in do_pick\n>   rebase -i: Teach do_pick the option --amend\n>   rebase -i: Teach do_pick the option --file\n>   rebase -i: Prepare for squash in terms of do_pick --amend\n>   rebase -i: Implement squash in terms of do_pick\n>   rebase -i: Explicitly distinguish replay commands and exec tasks\n>   rebase -i: Parse to-do list command line options\n>   rebase -i: Teach do_pick the option --reset-author\n>   rebase -i: Teach do_pick the option --signoff\n>   rebase -i: Enable options --signoff, --reset-author for pick, reword\n\nAfter \"rebase -i:\", some begin with lowercase and many begin with\ncapital, which makes the short-log output look distracting.\n"},{"id":"245559","messageId":"xmqq8uo38p28.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"00ca9dc0d1750301aa22c2bb78976b141233cef3.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T22:26:39Z","receivedAt":"2014-07-08T22:26:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> The command line used to recreate root commits specifies the\n> erroneous option `--allow-empty-message`. If the root commit has an\n> empty log message, the replay of this commit should fail and the\n> rebase should be interrupted like for any other commit that is on the\n> to-do list and has an empty commit message. Remove the option.\n>\n> The option might have been introduced by copy-and-paste of the first\n> part of the command line which initializes the authorship of the\n> sentinel commit. Indeed, the sentinel commit has an empty log message\n> and this should not trigger a failure, which is why the option\n> `--allow-empty-message` is correctly specified here.\n\nThe first \"commit --amend\" uses -C \"$1\" to give the amended result\nnot just the authorship but also the log message taken from \"$1\".\nIf we are allowing a commit without any message to be used as \"$1\",\nI think --allow-empty-message needs to be there.  If \"$1\" requires\nthe option here, why doesn't the second one, that records the\nupdated tree with the metainformation taken from the same commit\n\"$1\" can successfully commit without the option?\n\nPuzzled...\n\n> Add test.\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh |  2 +-\n>  t/t3412-rebase-root.sh     | 39 +++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 40 insertions(+), 1 deletion(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 4c875d5..0af96f2 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -510,7 +510,7 @@ do_pick () {\n>  \t\tgit commit --allow-empty --allow-empty-message --amend \\\n>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>  \t\t\tpick_one -n $1 &&\n> -\t\t\tgit commit --allow-empty --allow-empty-message \\\n> +\t\t\tgit commit --allow-empty \\\n>  \t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\n> index 0b52105..9867705 100755\n> --- a/t/t3412-rebase-root.sh\n> +++ b/t/t3412-rebase-root.sh\n> @@ -278,4 +278,43 @@ test_expect_success 'rebase -i -p --root with conflict (second part)' '\n>  \ttest_cmp expect-conflict-p out\n>  '\n>  \n> +test_expect_success 'stop rebase --root on empty root log message' '\n> +\t# create a root commit with a non-empty tree so that rebase does\n> +\t# not fail because of an empty commit, and an empty log message\n> +\techo root-commit >file &&\n> +\tgit add file &&\n> +\ttree=$(git write-tree) &&\n> +\troot=$(git commit-tree $tree </dev/null) &&\n> +\tgit checkout -b no-message-root-commit $root &&\n> +\t# do not ff because otherwise neither the patch nor the message\n> +\t# are looked at and checked for emptiness\n> +\ttest_when_finished git rebase --abort &&\n> +\ttest_must_fail env EDITOR=true git rebase -i --force-rebase --root &&\n> +\techo root-commit >file.expected &&\n> +\ttest_cmp file.expected file\n> +'\n> +\n> +test_expect_success 'stop rebase --root on empty child log message' '\n> +\t# create a root commit with a non-empty tree and provide a log\n> +\t# message so that rebase does not fail until the root commit is\n> +\t# successfully replayed\n> +\techo root-commit >file &&\n> +\tgit add file &&\n> +\ttree=$(git write-tree) &&\n> +\troot=$(git commit-tree $tree -m root-commit) &&\n> +\tgit checkout -b no-message-child-commit $root &&\n> +\t# create a child commit with a non-empty patch so that rebase\n> +\t# does not fail because of an empty commit, but an empty log\n> +\t# message\n> +\techo child-commit >file &&\n> +\tgit add file &&\n> +\tgit commit --allow-empty-message --no-edit &&\n> +\t# do not ff because otherwise neither the patch nor the message\n> +\t# are looked at and checked for emptiness\n> +\ttest_when_finished git rebase --abort &&\n> +\ttest_must_fail env EDITOR=true git rebase -i --force-rebase --root &&\n> +\techo child-commit >file.expected &&\n> +\ttest_cmp file.expected file\n> +'\n> +\n>  test_done\n"},{"id":"245560","messageId":"xmqq4myr8oxz.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"b1ecef042cd18a0251199429e4efb969b085d5fe.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 07/19] rebase -i: The replay of root commits is not shown with --verbose","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T22:29:12Z","receivedAt":"2014-07-08T22:29:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> The command line used to recreate root commits specifies the\n> erroneous option `-q` which suppresses the commit summary message.\n> However, git-rebase--interactive tends to tell the user about the\n> commits it creates, if she wishes (cf. command line option\n> `--verbose`). The code parts handling non-root commits or squash\n> commits all output commit summary messages. Do not make the replay of\n> root commits an exception. Remove the option.\n>\n> It is OK to suppress the commit summary when git-commit is used to\n> initialize the authorship of the sentinel commit because the\n> existence of this additional commit is a detail of\n> git-rebase--interactive's implementation. The option `-q` was\n> probably introduced as a copy-and-paste error stemming from that part\n> of the root commit handling code.\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n\nThis one I can buy; there is no reason to drop \"-q\" from both (which\nwould give us the same thing twice and the one before the \"pick_one\n-n\" runs is not the final one anyway) and the later one that records\nthe updated tree would be the one to report what it did.\n\n>  git-rebase--interactive.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 0af96f2..ff04d5d 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -511,7 +511,7 @@ do_pick () {\n>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>  \t\t\tpick_one -n $1 &&\n>  \t\t\tgit commit --allow-empty \\\n> -\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n> +\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n>  \telse\n"},{"id":"245561","messageId":"xmqqzjgj7a88.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"606af9e165c447b59076046a4d84aecf8b4cd2b0.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-08T22:32:23Z","receivedAt":"2014-07-08T22:32:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> The command line used to recreate root commits specifies the\n> effectless option `-C`. It is used to reuse commit message and\n> authorship from the named commit but the commit being amended here,\n> which is the sentinel commit, already carries the authorship and log\n> message of the processed commit. Note that the committer email and\n> commit date fields do not match the root commit either way. Remove\n> the option. However, `-C` (other than `-c`) does not invoke the\n> editor and the `--amend` option invokes it by default. Disable editor\n> invocation again by specifying `--no-edit`.\n\nI'd say this is a no-value change, in the sense that it can be\nwritten either way for the same effect and if the original were\nwritten with \"--amend --no-edit\" then there would be no reason to\nchange it to \"-C $1\" because such a change would also be equally a\nno-value change.\n\nWhat exactly are we gaining?  Performance?  Correctness?\n\n\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index ff04d5d..17836d5 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -511,7 +511,7 @@ do_pick () {\n>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>  \t\t\tpick_one -n $1 &&\n>  \t\t\tgit commit --allow-empty \\\n> -\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n> +\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n>  \telse\n"},{"id":"245638","messageId":"53BD6917.7070700@gmail.com","threadId":"36962","inReplyTo":"xmqqha2r8trc.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-09T16:08:55Z","receivedAt":"2014-07-09T16:08:55Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"On 07/08/2014 10:45 PM, Junio C Hamano wrote:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> Fabian Ruch (19):\n>>   rebase -i: Failed reword prints redundant error message\n>>   rebase -i: reword complains about empty commit despite --keep-empty\n>>   rebase -i: reword executes pre-commit hook on interim commit\n>>   rebase -i: Teach do_pick the option --edit\n>>   rebase -i: Implement reword in terms of do_pick\n>>   rebase -i: Stop on root commits with empty log messages\n>>   rebase -i: The replay of root commits is not shown with --verbose\n>>   rebase -i: Root commits are replayed with an unnecessary option\n>>   rebase -i: Commit only once when rewriting picks\n>>   rebase -i: Do not die in do_pick\n>>   rebase -i: Teach do_pick the option --amend\n>>   rebase -i: Teach do_pick the option --file\n>>   rebase -i: Prepare for squash in terms of do_pick --amend\n>>   rebase -i: Implement squash in terms of do_pick\n>>   rebase -i: Explicitly distinguish replay commands and exec tasks\n>>   rebase -i: Parse to-do list command line options\n>>   rebase -i: Teach do_pick the option --reset-author\n>>   rebase -i: Teach do_pick the option --signoff\n>>   rebase -i: Enable options --signoff, --reset-author for pick, reword\n> \n> After \"rebase -i:\", some begin with lowercase and many begin with\n> capital, which makes the short-log output look distracting.\n\nThe ones that begin with lower-case letters are the ones that begin with\nthe command name \"reword\". All first lines are typed in lower case now.\n\nSorry for the noise.\n\n   Fabian\n"},{"id":"245642","messageId":"53BD83C0.20607@gmail.com","threadId":"36962","inReplyTo":"xmqqpphf8u3x.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 02/19] rebase -i: reword complains about empty commit despite --keep-empty","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-09T18:02:40Z","receivedAt":"2014-07-09T18:02:40Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Junio C Hamano writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> Subject: rebase -i: reword complains about empty commit despite --keep-empty\n> \n> I had to read the title and then the log twice before understanding\n> that the above is not \"change the complaint message\" (i.e. \"reword\n> complaints\" spelled incorrectly) but is a description of the current\n> behaviour (i.e. \"the command complains when 'reword' is used on an\n> empty commit\") that is not accompanied by an evaluation (\"ok, it\n> complains; are you saying it is a good thing or a bad thing?\") or an\n> action (\"if it is a bad thing, what are you doing about it?\").\n> \n> Perhaps\n> \n> \trebase -i: allow rewording an empty commit\n> \n> or something?\n\nI thought \"...despite --keep-empty\" would already imply that \"reword\ncomplains about empty commit\" is not supposed to happen, the action\nwould have been obvious. However, I understand that --keep-empty is\nfirst of all concerned with which commits of $upstream...$orig_head end\nup on the initial to-do list and the git-rebase manual page doesn't\nmention that it picks commits using the --allow-empty option. It is\nsimply a necessity of a script not to complain about something it put on\nthe to-do list itself.\n\nThe subject reads now\n\n    rebase -i: allow rewording an empty commit without complaints\n\ntrying to convey that this is not a new feature but a bug fix.\n\n   Fabian\n"},{"id":"245683","messageId":"53BE5D0D.8090308@gmail.com","threadId":"36962","inReplyTo":"xmqq8uo38p28.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-10T09:29:49Z","receivedAt":"2014-07-10T09:29:49Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> The command line used to recreate root commits specifies the\n>> erroneous option `--allow-empty-message`. If the root commit has an\n>> empty log message, the replay of this commit should fail and the\n>> rebase should be interrupted like for any other commit that is on the\n>> to-do list and has an empty commit message. Remove the option.\n>>\n>> The option might have been introduced by copy-and-paste of the first\n>> part of the command line which initializes the authorship of the\n>> sentinel commit. Indeed, the sentinel commit has an empty log message\n>> and this should not trigger a failure, which is why the option\n>> `--allow-empty-message` is correctly specified here.\n> \n> The first \"commit --amend\" uses -C \"$1\" to give the amended result\n> not just the authorship but also the log message taken from \"$1\".\n> If we are allowing a commit without any message to be used as \"$1\",\n> I think --allow-empty-message needs to be there.  If \"$1\" requires\n> the option here, why doesn't the second one, that records the\n> updated tree with the metainformation taken from the same commit\n> \"$1\" can successfully commit without the option?\n\n(I realize now that the emptiness of the sentinel log message is\nirrelevant to the success of the first \"commit --amend\" since we are\namending using -C. I'll rewrite the second paragraph of the patch\ndescription.)\n\nThe first \"commit --amend\" requires --allow-empty-message because we do\nnot want to fail without the authorship or log message of $1 being in\nplace. It's not a matter of allowing or disallowing empty log messages yet.\n\ngit-rebase--interactive can come across an empty log message in three\ndifferent ways, which are, depicted as to-do list tasks, the following.\n\n 1) pick --ff $1\n 2) pick --no-ff $1\n 3) reword $1\n\nThis patch is concerned with consistency in the second case.\ngit-rebase--root does not handle the first case yet and the third case\nis handled somewhere else in the script independent of the first two.\n\nThe --root option handling was added to the script as a special case\nlater in the revision history. It's that option handling which\nintroduced the inconsistency that non-fast-forwards of commits with\nempty log messages succeed if they are root commits but have always\nfailed otherwise.\n\nYour reply suggests that git-rebase--interactive was wrong from the\nbeginning and that the replay of commits without any message should be\nallowed. This would reconcile the first case with the second. In fact,\nsince neither of them alters the changes introduced by $1 or its log\nmessage, it might be incorrect to complain about a missing message in\nthe first place.\n\nDo you want me to replace this patch with a patch\n\n    rebase -i: Always allow picking of commits with empty log messages\n\nthat makes git-rebase--interactive cherry-pick commits using\n--allow-empty-message? The script would still abort an empty reword with\nthe new patch and the user could then still force the empty log message\nwith \"git commit --amend --allow-empty-message\".\n\n   Fabian\n\n> Puzzled...\n> \n>> Add test.\n>>\n>> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n>> ---\n>>  git-rebase--interactive.sh |  2 +-\n>>  t/t3412-rebase-root.sh     | 39 +++++++++++++++++++++++++++++++++++++++\n>>  2 files changed, 40 insertions(+), 1 deletion(-)\n>>\n>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>> index 4c875d5..0af96f2 100644\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -510,7 +510,7 @@ do_pick () {\n>>  \t\tgit commit --allow-empty --allow-empty-message --amend \\\n>>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>>  \t\t\tpick_one -n $1 &&\n>> -\t\t\tgit commit --allow-empty --allow-empty-message \\\n>> +\t\t\tgit commit --allow-empty \\\n>>  \t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n>>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n"},{"id":"245691","messageId":"CADgNjakNQKbA8fYJqz7n-C9aPoZdfxX+N9Xuq1irJ_ajB8Yt_w@mail.gmail.com","threadId":"36962","inReplyTo":"xmqqtx6r8uem.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message","fromName":"Andrew Wong","fromEmail":"andrew.kw.w@gmail.com","sentAt":"2014-07-10T14:30:50Z","receivedAt":"2014-07-10T14:30:50Z","isPatch":true,"sender":{"key":"andrew.kw.w@gmail.com","avatar":"https://avatars.githubusercontent.com/u/489311?v=4"},"body":"On Tue, Jul 8, 2014 at 4:31 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> It is true that a failed hook script might not output any diagnosis...\n>\n> I think the message originally came from 0becb3e4 (rebase -i:\n> interrupt rebase when \"commit --amend\" failed during \"reword\",\n> 2011-11-30); it seems that the primary point of the change was to\n> make sure it exits and the warning message may not have been well\n> thought out, but before discarding the result of somebody else's\n> work, it may not be a bad idea to ask just in case you may have\n> overlooked something (Andrew Wong Cc'ed).\n>\n>\n>\n>\n>\n>> but then the generic message is not of much help either. Since this\n>> lack of information affects the built-in git commands for commit,\n>> merge and cherry-pick first, the solution would be to keep track of\n>> the failed hooks in their output so that the user knows which of her\n>> hooks require improvement.\n\nSince \"git commit\" already prints out error messages for failing due\nto empty commit message, the third message is really about giving\nhints in the case where pre-commit fails. We could probably assume\nthat pre-commit would also print out error messages. So I'd be fine\nwith removing the third message. But I wonder if we need to explain\nthat the user needs to run \"git rebase --continue\" to resume the\nrebase?\n"},{"id":"245692","messageId":"53BEC0BC.6030600@gmail.com","threadId":"36962","inReplyTo":"CADgNjakNQKbA8fYJqz7n-C9aPoZdfxX+N9Xuq1irJ_ajB8Yt_w@mail.gmail.com","subject":"Re: [PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-10T16:35:08Z","receivedAt":"2014-07-10T16:35:08Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Andrew,\n\nthanks for your review and sorry that I forgot to cc the bug fix to you.\n\nAndrew Wong writes:\n> On Tue, Jul 8, 2014 at 4:31 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Fabian Ruch <bafain@gmail.com> writes:\n>>> It is true that a failed hook script might not output any diagnosis...\n>>\n>> I think the message originally came from 0becb3e4 (rebase -i:\n>> interrupt rebase when \"commit --amend\" failed during \"reword\",\n>> 2011-11-30); it seems that the primary point of the change was to\n>> make sure it exits and the warning message may not have been well\n>> thought out, but before discarding the result of somebody else's\n>> work, it may not be a bad idea to ask just in case you may have\n>> overlooked something (Andrew Wong Cc'ed).\n>>\n>>> but then the generic message is not of much help either. Since this\n>>> lack of information affects the built-in git commands for commit,\n>>> merge and cherry-pick first, the solution would be to keep track of\n>>> the failed hooks in their output so that the user knows which of her\n>>> hooks require improvement.\n> \n> Since \"git commit\" already prints out error messages for failing due\n> to empty commit message, the third message is really about giving\n> hints in the case where pre-commit fails. We could probably assume\n> that pre-commit would also print out error messages. So I'd be fine\n> with removing the third message. But I wonder if we need to explain\n> that the user needs to run \"git rebase --continue\" to resume the\n> rebase?\n\nThat is still taken care of by exit_with_patch here. When called in the\nerror case, it prints\n\n    You can amend the commit now, with\n\n    \tgit commit --amend\n\n    Once you are satisfied with your changes, run\n\n    \tgit rebase --continue\n\nto standard error. I might have overlooked this in one of the later\npatches though.\n\n   Fabian\n"},{"id":"245695","messageId":"xmqqmwch883q.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"53BE5D0D.8090308@gmail.com","subject":"Re: [PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T16:57:29Z","receivedAt":"2014-07-10T16:57:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> ...\n> Do you want me to replace this patch with a patch\n>\n>     rebase -i: Always allow picking of commits with empty log messages\n>\n> that makes git-rebase--interactive cherry-pick commits using\n> --allow-empty-message?\n\nI do not \"want\" any particular behaviour change.  I wanted you to\nclarify what changed behaviour you are trying to implement and why,\nand that was why I was asking these questions.\n"},{"id":"245696","messageId":"CADgNjanVFEBwbgL8O6U04fpmsDi+UFcRH4PPvy7LyrFYsnDr-g@mail.gmail.com","threadId":"36962","inReplyTo":"53BEC0BC.6030600@gmail.com","subject":"Re: [PATCH RFC v2 01/19] rebase -i: Failed reword prints redundant error message","fromName":"Andrew Wong","fromEmail":"andrew.kw.w@gmail.com","sentAt":"2014-07-10T17:04:55Z","receivedAt":"2014-07-10T17:04:55Z","isPatch":true,"sender":{"key":"andrew.kw.w@gmail.com","avatar":"https://avatars.githubusercontent.com/u/489311?v=4"},"body":"On Thu, Jul 10, 2014 at 12:35 PM, Fabian Ruch <bafain@gmail.com> wrote:\n> That is still taken care of by exit_with_patch here.\n\nOh, that's right. Ok, go ahead and remove the third warning then. Thanks!\n"},{"id":"245698","messageId":"xmqqion586g6.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"53BE5D0D.8090308@gmail.com","subject":"Re: [PATCH RFC v2 06/19] rebase -i: Stop on root commits with empty log messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T17:33:13Z","receivedAt":"2014-07-10T17:33:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Your reply suggests that git-rebase--interactive was wrong from the\n> beginning and that the replay of commits without any message should be\n> allowed. This would reconcile the first case with the second. In fact,\n> since neither of them alters the changes introduced by $1 or its log\n> message, it might be incorrect to complain about a missing message in\n> the first place.\n> ...\n> Do you want me to replace this patch with a patch\n\nNow you explained your line of thought more clearly and I have\nthought about it a bit more, I think I agree with the conclusion of\nthe above.\n\nAn alternative may be to teach a new option --allow-empty-message to\nrebase to allow people to replay/reproduce an existing history with\ncommits without any message, and uniformly tighten to refuse replaying\na commit without message by default.  But I am not sure if that is a\ngood direction to go.  Doesn't \"rebase\" without \"-i\" by default replay\na commit without message faithfully?  It might be debatable to allow\na commit that we would normally would flag as suspicious (i.e. no\nchange relative to its parent, or no log message) when replaying\nwith \"reword\" or \"edit\", but when replaying with \"pick\", \"rebase -i\"\nshould behave just like \"rebase\" without interactive.\n\nThanks.\n"},{"id":"245707","messageId":"xmqq1ttt7zib.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"07e5f295c0042e78ba83ffb66925e3f09988ae3c.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 15/19] rebase -i: Explicitly distinguish replay commands and exec tasks","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-10T20:03:08Z","receivedAt":"2014-07-10T20:03:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> There are two kinds of to-do list commands available. One kind\n> replays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that\n> is) and the other executes a shell command (`exec`). We will call the\n> first kind replay commands.\n>\n> The two kinds of tasks are scheduled using different line formats.\n> Replay commands expect a commit hash argument following the command\n> name and exec concatenates all arguments to assemble a command line.\n>\n> Adhere to the distinction of formats by not trying to parse the\n> `sha1` field unless we are dealing with a replay command. Move the\n> replay command handling code to a new function `do_replay` which\n> assumes the first argument to be a commit hash and make no more such\n> assumptions in `do_next`.\n\nIn do_next(), we used read the first line of the insn sheet into\nthree variables, assuming the common case of handling one of the\nreplay commands, and (somewhat wastefully) re-read the same line\ninto two variables when we realize that the command was \"exec\".\n\nAfter you split do_replay() out of do_next() with this patch, we\nseem to do exactly the same thing.\n\nWhat exactly is the problem this change wants to fix?\n\nPuzzled...\n\n\n>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh | 42 ++++++++++++++++++++++++++++--------------\n>  1 file changed, 28 insertions(+), 14 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 008f3a0..9de7441 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -585,13 +585,12 @@ do_pick () {\n>  \tfi\n>  }\n>  \n> -do_next () {\n> -\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n> -\tread -r command sha1 rest < \"$todo\"\n> +do_replay () {\n> +\tcommand=$1\n> +\tsha1=$2\n> +\trest=$3\n> +\n>  \tcase \"$command\" in\n> -\t\"$comment_char\"*|''|noop)\n> -\t\tmark_action_done\n> -\t\t;;\n>  \tpick|p)\n>  \t\tcomment_for_reflog pick\n>  \n> @@ -656,6 +655,28 @@ do_next () {\n>  \t\tesac\n>  \t\trecord_in_rewritten $sha1\n>  \t\t;;\n> +\t*)\n> +\t\tread -r command <\"$todo\"\n> +\t\twarn \"Unknown command: $command\"\n> +\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n> +\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n> +\t\tthen\n> +\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n> +\t\telse\n> +\t\t\tdie \"$fixtodo\"\n> +\t\tfi\n> +\t\t;;\n> +\tesac\n> +}\n> +\n> +do_next () {\n> +\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n> +\tread -r command sha1 rest <\"$todo\"\n> +\n> +\tcase \"$command\" in\n> +\t\"$comment_char\"*|''|noop)\n> +\t\tmark_action_done\n> +\t\t;;\n>  \tx|\"exec\")\n>  \t\tread -r command rest < \"$todo\"\n>  \t\tmark_action_done\n> @@ -695,14 +716,7 @@ do_next () {\n>  \t\tfi\n>  \t\t;;\n>  \t*)\n> -\t\twarn \"Unknown command: $command $sha1 $rest\"\n> -\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n> -\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n> -\t\tthen\n> -\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n> -\t\telse\n> -\t\t\tdie \"$fixtodo\"\n> -\t\tfi\n> +\t\tdo_replay $command $sha1 \"$rest\"\n>  \t\t;;\n>  \tesac\n>  \ttest -s \"$todo\" && return\n"},{"id":"245778","messageId":"53BFEA9C.6010203@gmail.com","threadId":"36962","inReplyTo":"b1ecef042cd18a0251199429e4efb969b085d5fe.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 07/19] rebase -i: The replay of root commits is not shown with --verbose","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-11T13:46:04Z","receivedAt":"2014-07-11T13:46:04Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Chris,\n\nyou're the original author of the code touched by this patch. Is the\nsecond -q option really a simple copy-and-paste of the first or am I\noverlooking something here? I'd like to confirm this as, in retrospect,\nI feel a bit uncertain about the hasty claim in the log message.\n\nKind regards,\n   Fabian\n\nFabian Ruch writes:\n> The command line used to recreate root commits specifies the\n> erroneous option `-q` which suppresses the commit summary message.\n> However, git-rebase--interactive tends to tell the user about the\n> commits it creates, if she wishes (cf. command line option\n> `--verbose`). The code parts handling non-root commits or squash\n> commits all output commit summary messages. Do not make the replay of\n> root commits an exception. Remove the option.\n> \n> It is OK to suppress the commit summary when git-commit is used to\n> initialize the authorship of the sentinel commit because the\n> existence of this additional commit is a detail of\n> git-rebase--interactive's implementation. The option `-q` was\n> probably introduced as a copy-and-paste error stemming from that part\n> of the root commit handling code.\n> \n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n>  git-rebase--interactive.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n> \n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 0af96f2..ff04d5d 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -511,7 +511,7 @@ do_pick () {\n>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>  \t\t\tpick_one -n $1 &&\n>  \t\t\tgit commit --allow-empty \\\n> -\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n> +\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n>  \telse\n"},{"id":"245948","messageId":"53C266DC.4050408@gmail.com","threadId":"36962","inReplyTo":"xmqqlhs38tub.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-13T11:00:44Z","receivedAt":"2014-07-13T11:00:44Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> The to-do list command `reword` replays a commit like `pick` but lets\n>> the user also edit the commit's log message. This happens in two\n>> steps. Firstly, the named commit is cherry-picked. Secondly, the\n>> commit created in the first step is amended using an unchanged index\n>> to edit the log message. The pre-commit hook is meant to verify the\n>> changes introduced by a commit (for instance, catching inserted\n>> trailing white space). Since the committed tree is not changed\n>> between the two steps, do not execute the pre-commit hook in the\n>> second step.\n> \n> It is not like the second step is built as a child commit of the\n> result from the first step, recording the same tree without any\n> change.  Why is it a good thing not to run the pre-commit hook (or\n> other hooks for that matter)?  After all, the result of the second\n> step is what is recorded in the final history; it just feels wrong\n> not to test that one, even if it were a good idea to test only once.\n\nif I understand correctly, the tree of the (amended) commit isn't tested\nat all by git-rebase--interactive because git-cherry-pick, and therefore\npick_one, commits with both the pre-commit and commit-msg hook disabled\n(see the \"git commit -n\" command line being built in\nsequencer.c#run_git_commit since revision 9fa4db5).\n\nThe \"commit --amend\" we are concerned with here amends using an\nuntouched tree so that the history ought to record exactly the same\ntrees as prior to \"commit --amend\". If git-cherry-pick was testing the\ntree, then it would be unnecessary to test the tree a second time. Since\ngit-cherry-pick is not testing as of yet, testing and possibly rejecting\na tree in the second step would actually be wrong. I totally neglected\nto look for a test case when I submitted this patch, so I'd like to\nsupply one late now:\n\n> test_expect_success 'reword a commit violating pre-commit' '\n> \tmkdir -p .git/hooks &&\n> \tPRE_COMMIT=.git/hooks/pre-commit &&\n> \tcat >\"$PRE_COMMIT\" <<EOF\n> #!/bin/sh\n> echo running pre-commit\n> exit 1\n> EOF\n> \tchmod +x \"$PRE_COMMIT\" &&\n> \ttest_must_fail test_commit file &&\n> \ttest_commit --no-verify file &&\n> \tset_fake_editor &&\n> \tFAKE_LINES=\"pick 1\" git rebase -i HEAD^ &&\n> \tFAKE_LINES=\"pick 1\" git rebase -i --no-ff HEAD^ &&\n> \tFAKE_LINES=\"reword 1\" git rebase -i HEAD^\n> '\n\n(This addition to t3404-rebase--interactive.sh is based on the test case\n\"rebase a commit violating pre-commit\"; \"test_commit --no-verify\" will\nbe implemented the obvious way.)\n\nIn both cases, it's correct to disable the pre-commit hook when editing\nthe log message and it just makes sense to test changes where you make\nthem. Unfortunately, it is not obvious that \"git commit --amend\" merely\nedits the log message rather than committing a new tree.\n\nFor what it's worth, if we were to create an empty child commit and\nsquash it into the parent instead of amending immediately, then\ngit-rebase--interactive would disable tree verification in the second\nstep as well. This behaviour was introduced by commit c5b09fe. Although\nthe change seems to have been triggered by something completely\ndifferent back then, the correctness criterion remains the same, i.e.\nrecording previously committed trees.\n\nBest regards,\n   Fabian\n\n>> Specify the git-commit option `--no-verify` to disable the pre-commit\n>> hook when editing the log message. Because `--no-verify` also skips\n>> the commit-msg hook, execute the hook from within\n>> git-rebase--interactive after the commit is created. Fortunately, the\n>> commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\n>> git-commit terminates. Caveat: In case the commit-msg hook finds the\n>> new log message ill-formatted, the user is only notified of the\n>> failed commit-msg hook but the log message is used for the commit\n>> anyway. git-commit ought to offer more fine-grained control over\n>> which hooks are executed.\n>>\n>> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n>> ---\n>>  git-rebase--interactive.sh | 17 +++++++++++++----\n>>  1 file changed, 13 insertions(+), 4 deletions(-)\n>>\n>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>> index 689400e..b50770d 100644\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -504,10 +504,19 @@ do_next () {\n>>  \n>>  \t\tmark_action_done\n>>  \t\tdo_pick $sha1 \"$rest\"\n>> -\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n>> -\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n>> -\t\t\texit_with_patch $sha1 1\n>> -\t\t}\n>> +\t\t# TODO: Work around the fact that git-commit lets us\n>> +\t\t# disable either both the pre-commit and the commit-msg\n>> +\t\t# hook or none. Disable the pre-commit hook because the\n>> +\t\t# tree is left unchanged but run the commit-msg hook\n>> +\t\t# from here because the log message is altered.\n>> +\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n>> +\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n>> +\t\t\tthen\n>> +\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n>> +\t\t\tfi || {\n>> +\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n>> +\t\t\t\texit_with_patch $sha1 1\n>> +\t\t\t}\n>>  \t\trecord_in_rewritten $sha1\n>>  \t\t;;\n>>  \tedit|e)\n"},{"id":"246044","messageId":"C27412B4-3289-4776-974A-4E7B69DA5786@arachsys.com","threadId":"36962","inReplyTo":"53BFEA9C.6010203@gmail.com","subject":"Re: [PATCH RFC v2 07/19] rebase -i: The replay of root commits is not shown with --verbose","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2014-07-15T09:29:48Z","receivedAt":"2014-07-15T09:29:48Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Fabian Ruch <bafain@gmail.com> wrote:\n\n> you're the original author of the code touched by this patch. Is the\n> second -q option really a simple copy-and-paste of the first or am I\n> overlooking something here? I'd like to confirm this as, in retrospect,\n> I feel a bit uncertain about the hasty claim in the log message.\n\nIt was a while ago and I don't remember the details of this patch I'm\nafraid, but your rationale here looks sensible to me. I tend to find git too\nnoisy by default rather than too quiet, so it wouldn't surprise me if I\nnever thought to try the --verbose version.\n\nCheers,\n\nChris.\n"},{"id":"246289","messageId":"53C8E5E8.4090509@gmail.com","threadId":"36962","inReplyTo":"xmqqzjgj7a88.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-18T09:16:24Z","receivedAt":"2014-07-18T09:16:24Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> The command line used to recreate root commits specifies the\n>> effectless option `-C`. It is used to reuse commit message and\n>> authorship from the named commit but the commit being amended here,\n>> which is the sentinel commit, already carries the authorship and log\n>> message of the processed commit. Note that the committer email and\n>> commit date fields do not match the root commit either way. Remove\n>> the option. However, `-C` (other than `-c`) does not invoke the\n>> editor and the `--amend` option invokes it by default. Disable editor\n>> invocation again by specifying `--no-edit`.\n> \n> I'd say this is a no-value change, in the sense that it can be\n> written either way for the same effect and if the original were\n> written with \"--amend --no-edit\" then there would be no reason to\n> change it to \"-C $1\" because such a change would also be equally a\n> no-value change.\n> \n> What exactly are we gaining?  Performance?  Correctness?\n\nI submitted this change separately from the next (\"rebase -i: Commit\nonly once when rewriting picks\") for the following reasons, at least I\nthought they were.\n\nIt makes the next patch easier to understand because the finalising\ncommand line \"git commit --allow-empty --amend --no-post-rewrite -n\n--no-edit\" seems to be simply moved to the end of do_pick. Substituting\n--no-edit for -C there would make that log message overly long and the\nparagraph saying why this substitution is correct would be distracting\n(it's a little unfortunate that there is this special case in the first\nplace). While the resulting history stays the same of course, it might\nbe confusing to someone reading the code that the log message gets\nreplaced with itself.\n\nI know the last point is rather weak but aren't the two patches and log\nmessages easier to read?\n\n   Fabian\n\n>> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n>> ---\n>>  git-rebase--interactive.sh | 2 +-\n>>  1 file changed, 1 insertion(+), 1 deletion(-)\n>>\n>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>> index ff04d5d..17836d5 100644\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -511,7 +511,7 @@ do_pick () {\n>>  \t\t\t   --no-post-rewrite -n -q -C $1 &&\n>>  \t\t\tpick_one -n $1 &&\n>>  \t\t\tgit commit --allow-empty \\\n>> -\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n>> +\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n>>  \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>>  \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n>>  \telse\n"},{"id":"246305","messageId":"87zjg63m0h.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"53BD6917.7070700@gmail.com","subject":"Re: [PATCH RFC v2 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-07-18T12:10:54Z","receivedAt":"2014-07-18T12:10:54Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> On 07/08/2014 10:45 PM, Junio C Hamano wrote:\n>> Fabian Ruch <bafain@gmail.com> writes:\n>>> Fabian Ruch (19):\n>>>   rebase -i: Failed reword prints redundant error message\n>>>   rebase -i: reword complains about empty commit despite --keep-empty\n>>>   rebase -i: reword executes pre-commit hook on interim commit\n>>>   rebase -i: Teach do_pick the option --edit\n>>>   rebase -i: Implement reword in terms of do_pick\n>>>   rebase -i: Stop on root commits with empty log messages\n>>>   rebase -i: The replay of root commits is not shown with --verbose\n>>>   rebase -i: Root commits are replayed with an unnecessary option\n>>>   rebase -i: Commit only once when rewriting picks\n>>>   rebase -i: Do not die in do_pick\n>>>   rebase -i: Teach do_pick the option --amend\n>>>   rebase -i: Teach do_pick the option --file\n>>>   rebase -i: Prepare for squash in terms of do_pick --amend\n>>>   rebase -i: Implement squash in terms of do_pick\n>>>   rebase -i: Explicitly distinguish replay commands and exec tasks\n>>>   rebase -i: Parse to-do list command line options\n>>>   rebase -i: Teach do_pick the option --reset-author\n>>>   rebase -i: Teach do_pick the option --signoff\n>>>   rebase -i: Enable options --signoff, --reset-author for pick, reword\n>> \n>> After \"rebase -i:\", some begin with lowercase and many begin with\n>> capital, which makes the short-log output look distracting.\n>\n> The ones that begin with lower-case letters are the ones that begin with\n> the command name \"reword\". All first lines are typed in lower case now.\n\nYou could spell it 'reword' (with the quotes), which also disambiguates\nthe command from the verb.\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"246317","messageId":"xmqq7g3aobib.fsf@gitster.dls.corp.google.com","threadId":"36962","inReplyTo":"53C8E5E8.4090509@gmail.com","subject":"Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-07-18T16:52:12Z","receivedAt":"2014-07-18T16:52:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> It makes the next patch easier to understand because the finalising\n> command line \"git commit --allow-empty --amend --no-post-rewrite -n\n> --no-edit\" seems to be simply moved to the end of do_pick. Substituting\n> --no-edit for -C there would make that log message overly long ...\n\nAnd the reason why the same \"-C $1\" is not used and \"--no-edit\" is used\nin the final version that is moved to the end of do_pick is...?\n"},{"id":"246392","messageId":"53CAB593.5040306@gmail.com","threadId":"36962","inReplyTo":"xmqq7g3aobib.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH RFC v2 08/19] rebase -i: Root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-19T18:14:43Z","receivedAt":"2014-07-19T18:14:43Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Junio,\n\nJunio C Hamano writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> It makes the next patch easier to understand because the finalising\n>> command line \"git commit --allow-empty --amend --no-post-rewrite -n\n>> --no-edit\" seems to be simply moved to the end of do_pick. Substituting\n>> --no-edit for -C there would make that log message overly long ...\n> \n> And the reason why the same \"-C $1\" is not used and \"--no-edit\" is used\n> in the final version that is moved to the end of do_pick is...?\n\nThe finalising command line is executed by do_pick to rewrite $1 when it\nis being replayed.\n\nFor instance, one purpose of rewriting is amending the current head with\nthe changes introduced by $1. In this case, we don't want the log\nmessage of $1 to be the final log message. Another purpose of rewriting\nis using a text file or a string as log message, which would be defeated\nby \"-C $1\" as well.\n\nIt's true that, by the time the next patch is introduced, do_pick\ndoesn't yet implement either rewriting mechanism (they are both used to\nthread \"squash\" through do_pick later on) but these considerations\nsuggest that \"-C $1\" might not be what we want to use to disable the log\nmessage editor.\n\n   Fabian\n"},{"id":"246840","messageId":"cover.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"53A258D2.7080806@gmail.com","subject":"[PATCH v1 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:00Z","receivedAt":"2014-07-28T23:18:00Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nthis is a reroll of the patch series that enables rudimentary support\nof line options for git-rebase's to-do list commands and reimplements\nthe well-known commands `reword` and `squash` in terms of a\nparameterised `do_pick`.\n\nI tried to address all the issues raised by Junio in this reroll.\nHere is a short summary.\n\n - Test that `reword` behaves like `pick` regarding the `pre-commit`\n   hook and executes `commit-msg` for the new log message.\n\n - Instead of disallowing empty log messages for root commits allow\n   empty log messages for all unchanged commits.\n\n - The patch \"root commits are replayed with an unnecessary option\"\n   does not change the behaviour of git-rebase but it makes the\n   subsequent patch easier to read.\n\n   The hidden agenda is to have one git-commit command line in\n   `do_pick` that takes care of rewriting commits as they are being\n   replayed, be they parentless or not. The advantage of having one\n   rewrite command instead of one for root commits and one for\n   non-root commits is that changes to the rewrite mechanism entail\n   less code changes. As more rewriting mechanisms are being added to\n   `do_pick`, it becomes important that they compose well with each\n   other to avoid having a series of amending commits. The `-C`\n   option conflicts with other ways of substituting the log message,\n   like files and strings, which is why it seems not to compose so\n   well.\n\n - The patch \"explicitly distinguish replay commands and exec tasks\"\n   does not change behaviour either but is again a separated\n   refactoring patch.\n\n   The distinction of the `exec` command and the replay commands,\n   which all share the same line format `command args sha1 rest`,\n   allows us to employ the positional parameters feature of the shell\n   without introducing another indentation level in `do_pick`.\n\nThanks for your time,\n   Fabian\n\nFabian Ruch (19):\n  rebase -i: failed reword prints redundant error message\n  rebase -i: allow rewording an empty commit without complaints\n  rebase -i: reword executes pre-commit hook on interim commit\n  rebase -i: teach do_pick the option --edit\n  rebase -i: implement reword in terms of do_pick\n  rebase -i: allow replaying commits with empty log messages\n  rebase -i: log the replay of root commits\n  rebase -i: root commits are replayed with an unnecessary option\n  rebase -i: commit only once when rewriting picks\n  rebase -i: do not die in do_pick\n  rebase -i: teach do_pick the option --amend\n  rebase -i: teach do_pick the option --file\n  rebase -i: prepare for squash in terms of do_pick --amend\n  rebase -i: implement squash in terms of do_pick\n  rebase -i: explicitly distinguish replay commands and exec tasks\n  rebase -i: parse to-do list command line options\n  rebase -i: teach do_pick the option --reset-author\n  rebase -i: teach do_pick the option --signoff\n  rebase -i: enable options --signoff, --reset-author for pick, reword\n\n git-rebase--interactive.sh    | 284 ++++++++++++++++++++++++++++++++++--------\n t/t3404-rebase-interactive.sh |  70 +++++++++++\n t/t3412-rebase-root.sh        |  19 +++\n t/test-lib-functions.sh       |   6 +-\n 4 files changed, 325 insertions(+), 54 deletions(-)\n\n-- \n2.0.1\n"},{"id":"246841","messageId":"b2b05cb1f5ea70743e90502d05a4d8d13ddff73f.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 01/19] rebase -i: failed reword prints redundant error message","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:01Z","receivedAt":"2014-07-28T23:18:01Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If the edited log\nmessage is empty or is found ill-formatted by one of the commit\nhooks, git-rebase--interactive prints three error messages to the\nconsole.\n\n    1. The git-commit output, which contains all the output from hook\n       scripts.\n    2. A rebase diagnosis saying at which task on the to-do list it\n       got stuck.\n    3. Generic presumptions about what could have triggered the\n       error.\n\nThe third message contains redundant information and does not add any\nenlightenment either, which makes the output unnecessarily longish\nand different from the other command's output. For instance, this is\nwhat the output looks like if the log message is empty (contains\nduplicate Signed-off-by lines).\n\n    (1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by lines.)\n    (2.) Could not amend commit after successfully picking fa1afe1... Some change\n    (3.) This is most likely due to an empty commit message, or the pre-commit hook\n         failed. If the pre-commit hook failed, you may need to resolve the issue before\n         you are able to reword the commit.\n\nDiscard the third message.\n\nIt is true that a failed hook script might not output any diagnosis\nbut then the generic message is not of much help either. Since this\nlack of information affects the built-in git commands for commit,\nmerge and cherry-pick first, the solution would be to keep track of\nthe failed hooks in their output so that the user knows which of her\nhooks require improvement.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 7e1eda0..e733d7f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -506,9 +506,6 @@ do_next () {\n \t\tdo_pick $sha1 \"$rest\"\n \t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n-\t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n-\t\t\twarn \"you are able to reword the commit.\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\n \t\trecord_in_rewritten $sha1\n-- \n2.0.1\n"},{"id":"246844","messageId":"080f67cf9334f0e66ec8ca2e7828295fbdbb096c.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 02/19] rebase -i: allow rewording an empty commit without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:02Z","receivedAt":"2014-07-28T23:18:02Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If `--keep-empty` is\npassed as option to git-rebase--interactive, empty commits ought to\nbe replayed without complaints. However, if the users chooses to\nreword an empty commit by changing the respective to-do list entry\nfrom\n\n    pick fa1afe1 Empty commit\n\nto\n\n    reword fa1afe1 Empty commit\n\n, then git-rebase--interactive suddenly fails to replay the empty\ncommit. This is especially counterintuitive because `reword` is\nthought of as a `pick` that alters the log message in some way but\nnothing more and the unchanged to-do list entry would not fail.\n\nHandle `reword` by cherry-picking the named commit and editing the\nlog message using\n\n    git commit --allow-empty --amend\n\ninstead of\n\n    git commit --amend.\n\nAdd test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 2 +-\n t/t3404-rebase-interactive.sh | 8 ++++++++\n 2 files changed, 9 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e733d7f..689400e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8197ed2..9931143 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,14 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+test_expect_success 'rebase --keep-empty' '\n+\tgit checkout emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 reword 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 6 actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.0.1\n"},{"id":"246842","messageId":"1bb7c0b9aed60f7c65bf812ac42b2f1ad8fd3f82.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:03Z","receivedAt":"2014-07-28T23:18:03Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. This happens in two\nsteps. Firstly, the named commit is cherry-picked. Secondly, the\ncommit created in the first step is amended using an unchanged index\nto edit the log message. The pre-commit hook is meant to verify the\nchanges introduced by a commit (for instance, catching inserted\ntrailing white space). Since the committed tree is not changed\nbetween the two steps and we do not verify rebased patches, do not\nexecute the pre-commit hook in the second step.\n\nSpecify the git-commit option `--no-verify` to disable the pre-commit\nhook when editing the log message. Because `--no-verify` also skips\nthe commit-msg hook, execute the hook from within\ngit-rebase--interactive after the commit is created. Fortunately, the\ncommit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\ngit-commit terminates. Caveat: In case the commit-msg hook finds the\nnew log message ill-formatted, the user is only notified of the\nfailed commit-msg hook but the log message is used for the commit\nanyway. git-commit ought to offer more fine-grained control over\nwhich hooks are executed.\n\nTeach `test_commit` the `--no-verify` option and add test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 17 +++++++++++++----\n t/t3404-rebase-interactive.sh | 38 ++++++++++++++++++++++++++++++++++++++\n t/test-lib-functions.sh       |  6 +++++-\n 3 files changed, 56 insertions(+), 5 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 689400e..b50770d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,10 +504,19 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\texit_with_patch $sha1 1\n-\t\t}\n+\t\t# TODO: Work around the fact that git-commit lets us\n+\t\t# disable either both the pre-commit and the commit-msg\n+\t\t# hook or none. Disable the pre-commit hook because the\n+\t\t# tree is left unchanged but run the commit-msg hook\n+\t\t# from here because the log message is altered.\n+\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n+\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\t\tthen\n+\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\t\tfi || {\n+\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n+\t\t\t\texit_with_patch $sha1 1\n+\t\t\t}\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9931143..2da4b9c 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -577,6 +577,44 @@ test_expect_success 'rebase a commit violating pre-commit' '\n \n '\n \n+test_expect_success 'reword a commit violating pre-commit' '\n+\ttest_when_finished rm -r .git/hooks &&\n+\tmkdir -p .git/hooks &&\n+\tPRE_COMMIT=.git/hooks/pre-commit &&\n+\tcat >\"$PRE_COMMIT\" <<EOF\n+#!/bin/sh\n+echo running pre-commit: exit 1\n+exit 1\n+EOF\n+\tchmod +x \"$PRE_COMMIT\" &&\n+\ttest_must_fail test_commit pre-commit-violated &&\n+\ttest_commit --no-verify pre-commit-violated &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"pick 1\" git rebase -i HEAD^ &&\n+\tFAKE_LINES=\"pick 1\" git rebase -i --no-ff HEAD^ &&\n+\tFAKE_LINES=\"reword 1\" git rebase -i HEAD^\n+'\n+\n+test_expect_success 'reword a commit violating commit-msg' '\n+\ttest_when_finished rm -r .git/hooks &&\n+\tmkdir -p .git/hooks &&\n+\tCOMMIT_MSG=.git/hooks/commit-msg &&\n+\tcat >\"$COMMIT_MSG\" <<EOF\n+#!/bin/sh\n+echo running commit-msg: exit 1\n+exit 1\n+EOF\n+\tchmod +x \"$COMMIT_MSG\" &&\n+\ttest_must_fail test_commit commit-msg-violated &&\n+\ttest_commit --no-verify commit-msg-violated &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"pick 1\" git rebase -i HEAD^ &&\n+\tFAKE_LINES=\"pick 1\" git rebase -i --no-ff HEAD^ &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i HEAD^\n+'\n+\n test_expect_success 'rebase with a file named HEAD in worktree' '\n \n \trm -fr .git/hooks &&\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 0377d3e..db65653 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -155,6 +155,7 @@ test_pause () {\n test_commit () {\n \tnotick= &&\n \tsignoff= &&\n+\tnoverify= &&\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n@@ -164,6 +165,9 @@ test_commit () {\n \t\t--signoff)\n \t\t\tsignoff=\"$1\"\n \t\t\t;;\n+\t\t--no-verify)\n+\t\t\tnoverify=\"$1\"\n+\t\t\t;;\n \t\t*)\n \t\t\tbreak\n \t\t\t;;\n@@ -177,7 +181,7 @@ test_commit () {\n \tthen\n \t\ttest_tick\n \tfi &&\n-\tgit commit $signoff -m \"$1\" &&\n+\tgit commit $signoff $noverify -m \"$1\" &&\n \tgit tag \"${4:-$1}\"\n }\n \n-- \n2.0.1\n"},{"id":"246845","messageId":"a5d2fe395226f3ef9e9bcbafd2ccc5d32dc87074.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 04/19] rebase -i: teach do_pick the option --edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:04Z","receivedAt":"2014-07-28T23:18:04Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`. To cater for\nthe different pick behaviours (like `reword`), `do_pick` accepts\nseveral options not only from the git-cherry-pick but also the\ngit-commit interface. Add the common option `--edit` to let the user\nedit the log message of the named commit.\n\nLoop over `$@` to parse the `do_pick` arguments. Assign the local\nvariable `edit` if one of the options is `--edit` so that the\nremainder of `do_pick` can easily check whether the client code asked\nto edit the commit message. If one of the options is unknown, mention\nit on the console and `die`. Break the loop on the first non-option\nand do some sanity checking to ensure that there exactly two\nnon-options, which are interpreted by the remainder as `<commit>` and\n`<title>` like before.\n\n`do_pick` ought to act as a wrapper around `cherry-pick`.\nUnfortunately, it cannot just forward `--edit` to the `cherry-pick`\ncommand line. The assembled command line is executed within a command\nsubstitution for controlling the verbosity of `rebase--interactive`.\nPassing `--edit` would either hang the terminal or clutter the\nsubstituted command output with control sequences. Execute the\n`reword` code from `do_next` instead if the option `--edit` is\nspecified.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 52 insertions(+)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b50770d..e06d9b6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -461,7 +461,42 @@ record_in_rewritten() {\n \tesac\n }\n \n+# Apply the changes introduced by the given commit to the current head.\n+#\n+# do_pick [--edit] <commit> <title>\n+#\n+# Wrapper around git-cherry-pick.\n+#\n+# -e, --edit\n+#     After picking <commit>, open an editor and let the user edit the\n+#     commit message. The editor contents becomes the commit message of\n+#     the new head. This creates a fresh commit.\n+#\n+# <commit>\n+#     The commit to cherry-pick.\n+#\n+# <title>\n+#     The commit message title of <commit>. Used for information\n+#     purposes only.\n do_pick () {\n+\tedit=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-e|--edit)\n+\t\t\tedit=y\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n \t\t# Set the correct commit message and author info on the\n@@ -483,6 +518,23 @@ do_pick () {\n \t\tpick_one $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n+\n+\tif test -n \"$edit\"\n+\tthen\n+\t\t# TODO: Work around the fact that git-commit lets us\n+\t\t# disable either both the pre-commit and the commit-msg\n+\t\t# hook or none. Disable the pre-commit hook because the\n+\t\t# tree is left unchanged but run the commit-msg hook\n+\t\t# from here because the log message is altered.\n+\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n+\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\t\tthen\n+\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\t\tfi || {\n+\t\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n+\t\t\t\texit_with_patch $1 1\n+\t\t\t}\n+\tfi\n }\n \n do_next () {\n-- \n2.0.1\n"},{"id":"246846","messageId":"7b9d35275dc8c466d3387da920e3ccd6789b34ab.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 05/19] rebase -i: implement reword in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:05Z","receivedAt":"2014-07-28T23:18:05Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If one thinks of `pick`\nentries as scheduled `cherry-pick` command lines, then `reword`\nbecomes an alias for the command line `cherry-pick --edit`. The\nporcelain `rebase--interactive` defines a function `do_pick` for\nprocessing the `pick` entries on to-do lists. Reimplement `reword` in\nterms of `do_pick --edit`.\n\nIf the user picks a commit using the to-do list line\n\n    reword fa1afe1 Some change\n\nexecute the command `do_pick --edit fa1afe1 \"Some change\"` which\ncarries out exactly the same steps as the case arm for `reword` in\n`do_next` so far.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 15 +--------------\n 1 file changed, 1 insertion(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e06d9b6..4c875d5 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -555,20 +555,7 @@ do_next () {\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n-\t\t# TODO: Work around the fact that git-commit lets us\n-\t\t# disable either both the pre-commit and the commit-msg\n-\t\t# hook or none. Disable the pre-commit hook because the\n-\t\t# tree is left unchanged but run the commit-msg hook\n-\t\t# from here because the log message is altered.\n-\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n-\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n-\t\t\tthen\n-\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\t\tfi || {\n-\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\t\texit_with_patch $sha1 1\n-\t\t\t}\n+\t\tdo_pick --edit $sha1 \"$rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n-- \n2.0.1\n"},{"id":"246843","messageId":"95e1a2aa6855b38ce9aaacdc8564b2c4668b4ec7.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 06/19] rebase -i: allow replaying commits with empty log messages","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:06Z","receivedAt":"2014-07-28T23:18:06Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"git-rebase--interactive handles empty log messages inconsistently\nbetween enabled and disabled fast-forwards. By default, commits with\nempty log messages are rebased successfully like in non-interactive\nmode. In contrast, the `--no-ff` option aborts the replay of such\ncommits.\n\nIn line with not verifying rebased commits and behaving like\ngit-rebase for `pick` lines, use the `--allow-empty-message` option\nto replay commits. Root commits are replayed by recreating them in\n`do_pick` using git-commit and commits with parents are replayed\nusing git-cherry-pick in `pick_one`. Apply the option, understood by\nboth git-commit and git-cherry-pick, at the respective sites.\n\nIn case of `reword` and `squash`/`fixup` continue to abort the rebase\nif the resulting commit would have no commit message. The rationale\nbehind this default is that patches and their log messages should be\nverified at least once. For unchanged commits this is assumed to have\nhappened according to the author's standards when she created the\ncommits the first time. While the empty log message can always be\nkept in place by editing and resuming the aborted rebase, a debatable\nalternative could be to teach git-rebase--interactive the option\n`--allow-empty-message` for disabling complaints about empty log\nmessages in changed commits. The to-do list command `edit` is handled\njust like `pick` for this matter, because git-rebase--interactive\nreplays the named commit without changes before the rebase is\ninterrupted and the user can make her changes to the replayed commit.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  4 ++--\n t/t3404-rebase-interactive.sh | 24 ++++++++++++++++++++++++\n t/t3412-rebase-root.sh        | 19 +++++++++++++++++++\n 3 files changed, 45 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 4c875d5..6e2c429 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -249,7 +249,7 @@ pick_one () {\n \n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput eval git cherry-pick \\\n+\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\"$strategy_args\" $empty_args $ff \"$@\"\n }\n@@ -363,7 +363,7 @@ pick_one_preserving_merges () {\n \t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$rewritten_list\"\n \t\t\t;;\n \t\t*)\n-\t\t\toutput eval git cherry-pick \\\n+\t\t\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\t\"$strategy_args\" \"$@\" ||\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 2da4b9c..2e8fa27 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -1085,4 +1085,28 @@ test_expect_success 'short SHA-1 collide' '\n \t)\n '\n \n+test_expect_success 'rebase commits with empty commit log messages' '\n+\tgit checkout -b no-msg-commit &&\n+\ttest_commit no-msg-commit-1 &&\n+\tgit commit --amend --allow-empty-message -m \" \" &&\n+\ttest_commit no-msg-commit-2 &&\n+\tgit commit --amend --allow-empty-message -m \" \" &&\n+\tEDITOR=true git rebase -i HEAD^ &&\n+\tEDITOR=true git rebase -i --no-ff HEAD^\n+'\n+\n+test_expect_success 'reword commit with empty commit log message' '\n+\tgit checkout no-msg-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i HEAD^\n+'\n+\n+test_expect_success 'squash commits with empty commit log messages' '\n+\tgit checkout no-msg-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2\" git rebase -i HEAD^^\n+'\n+\n test_done\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 0b52105..798c9f1 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -278,4 +278,23 @@ test_expect_success 'rebase -i -p --root with conflict (second part)' '\n \ttest_cmp expect-conflict-p out\n '\n \n+test_expect_success 'rebase --root with empty root log message' '\n+\tgit checkout --orphan no-msg-root-commit &&\n+\ttest_commit no-msg-root-commit &&\n+\tgit commit --amend -m \" \" --allow-empty-message &&\n+\tgit rebase --root &&\n+\ttest_path_is_file no-msg-root-commit.t &&\n+\tgit rebase --root --no-ff &&\n+\ttest_path_is_file no-msg-root-commit.t\n+'\n+\n+test_expect_success 'rebase --root with empty child log message' '\n+\ttest_commit no-msg-child-commit &&\n+\tgit commit --amend -m \" \" --allow-empty-message &&\n+\tgit rebase --root &&\n+\ttest_path_is_file no-msg-child-commit.t &&\n+\tgit rebase --root --no-ff &&\n+\ttest_path_is_file no-msg-child-commit.t\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"246859","messageId":"7389745946359e0d9d8c6f1e8f2ebc78033132e6.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 07/19] rebase -i: log the replay of root commits","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:07Z","receivedAt":"2014-07-28T23:18:07Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the option\n`-q` which suppresses the commit summary message. However,\ngit-rebase--interactive tends to tell the user about the commits it\ncreates in the final history, if she wishes (cf. command line option\n`--verbose`). The code parts handling non-root commits and squash\ncommits all output commit summary messages. Do not make the replay of\nroot commits an exception. Remove the option to make the report of\nthe rebased history complete.\n\nIt is OK that the commit summary is still suppressed when git-commit\nis used to initialize the authorship of the sentinel commit because\nthis additional commit is an implementation detail hidden from the\nfinal history. The removed `-q` option was probably introduced as a\ncopy-and-paste error stemming from that part of the root commit\nhandling code.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6e2c429..576e0b1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\tgit commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"246847","messageId":"7ed1b44ae05860a556d86c8b90ac6fff0906128d.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 08/19] rebase -i: root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:08Z","receivedAt":"2014-07-28T23:18:08Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the\neffectless option `-C`. It makes git-commit reuse commit message and\nauthorship of the named commit. However, the commit being amended\nhere, which is the sentinel commit, already carries the authorship\nand log message of the commit being replayed. Remove the option.\n\nSince `-C` (in contrast to `-c`) does not invoke the editor and the\n`--amend` option invokes it by default, disable editor invocation\nagain by specifying `--no-edit`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 576e0b1..46f436f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\tgit commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"246850","messageId":"235b55a0ec3db4a111fbb32e58e578ced6307d72.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 09/19] rebase -i: commit only once when rewriting picks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:09Z","receivedAt":"2014-07-28T23:18:09Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The options passed to `do_pick` determine whether the picked commit\nwill be rewritten or not. If the commit gets rewritten, because the\nuser requested to edit the commit message for instance, let\n`pick_one` merely apply the changes introduced by the commit and do\nnot commit the resulting tree yet. If the commit is replayed as is,\nleave it to `pick_one` to recreate the commit (possibly by\nfast-forwarding the head). This makes it easier to combine git-commit\noptions like `--edit` and `--amend` in `do_pick` because\ngit-cherry-pick does not support `--amend`.\n\nIn the case of `--edit`, do not `exit_with_patch` but assign\n`rewrite` to pick the changes with `-n`. If the pick conflicts, no\ncommit is created which we would have to amend when continuing the\nrebase. To complete the pick after the conflicts are resolved the\nuser just resumes with `git rebase --continue`.\n\ngit-commit lets the user edit the commit log message by default. We\ndo not want that for the rewriting git-commit command line because\nthe default behaviour of git-rebase is exactly the opposite. Pass\n`--no-edit` when rewriting a picked commit. An explicit `--edit`\npassed to `do_pick` (for instance, when reword is executed) enables\nthe editor launch again. Similarly, pass `--allow-empty-message`\nunless the log message is edited.\n\nIf `rebase--interactive` is used to rebase a complete branch onto\nsome head, `rebase` creates a sentinel commit that requires special\ntreatment by `do_pick`. Do not finalize the pick here either because\nits commit message can be altered as for any other pick. Since the\norphaned root commit gets a temporary parent, it is always rewritten.\nSafely use the rewrite infrastructure of `do_pick` to create the\nfinal commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 58 ++++++++++++++++++++++++++++------------------\n 1 file changed, 36 insertions(+), 22 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 46f436f..96c24e8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -63,7 +63,8 @@ msgnum=\"$state_dir\"/msgnum\n author_script=\"$state_dir\"/author-script\n \n # When an \"edit\" rebase command is being processed, the SHA1 of the\n-# commit to be edited is recorded in this file.  When \"git rebase\n+# commit to be edited is recorded in this file.  The same happens when\n+# rewriting a commit fails, for instance \"reword\".  When \"git rebase\n # --continue\" is executed, if there are any staged changes then they\n # will be amended to the HEAD commit, but only provided the HEAD\n # commit is still the commit to be edited.  When any other rebase\n@@ -479,12 +480,17 @@ record_in_rewritten() {\n #     The commit message title of <commit>. Used for information\n #     purposes only.\n do_pick () {\n-\tedit=\n+\tallow_empty_message=y\n+\trewrite=\n+\trewrite_amend=\n+\trewrite_edit=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n \t\t-e|--edit)\n-\t\t\tedit=y\n+\t\t\trewrite=y\n+\t\t\trewrite_edit=y\n+\t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n \t\t\tdie \"do_pick: unrecognized option -- $1\"\n@@ -499,6 +505,10 @@ do_pick () {\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n+\t\trewrite=y\n+\t\trewrite_amend=y\n+\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\n \t\t# Set the correct commit message and author info on the\n \t\t# sentinel root before cherry-picking the original changes\n \t\t# without committing (-n).  Finally, update the sentinel again\n@@ -509,31 +519,35 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 &&\n-\t\t\tgit commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n-\t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tpick_one -n $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-\t\tpick_one $1 ||\n+\t\tpick_one ${rewrite:+-n} $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n \n-\tif test -n \"$edit\"\n+\tif test -n \"$rewrite\"\n \tthen\n-\t\t# TODO: Work around the fact that git-commit lets us\n-\t\t# disable either both the pre-commit and the commit-msg\n-\t\t# hook or none. Disable the pre-commit hook because the\n-\t\t# tree is left unchanged but run the commit-msg hook\n-\t\t# from here because the log message is altered.\n-\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n-\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n-\t\t\tthen\n-\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\t\tfi || {\n-\t\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n-\t\t\t\texit_with_patch $1 1\n-\t\t\t}\n+\t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n+\t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_amend:+--amend} \\\n+\t\t\t   ${rewrite_edit:+--edit} \\\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\tfi\n+\n+\t# TODO: Work around the fact that git-commit lets us\n+\t# disable either both the pre-commit and the commit-msg\n+\t# hook or none. Disable the pre-commit hook because the\n+\t# tree is left unchanged but run the commit-msg hook\n+\t# from here because the log message is altered.\n+\tif test -n \"$rewrite_edit\"\n+\tthen\n+\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n+\t\tthen\n+\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n+\t\tfi ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n \tfi\n }\n \n-- \n2.0.1\n"},{"id":"246848","messageId":"f653cde6193722194f2777b985ec08aa72d8a86b.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 10/19] rebase -i: do not die in do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:10Z","receivedAt":"2014-07-28T23:18:10Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Since `do_pick` might be executed in a sub-shell (a modified author\nenvironment for instance), calling `die` in `do_pick` has no effect\nbut exiting the sub-shell with a failure exit status. The\ngit-rebase--interactive script is not terminated. Moreover, if\n`do_pick` is called while a squash or fixup is in effect,\n`die_with_patch` will discard `$squash_msg` as commit message.\nLastly, after a `die` in `do_pick` `do_next` has no chance to\nreschedule tasks that failed before changes could be applied.\n\nIndicate an error in `do_pick` using return statements and properly\nkill the script at the call sites. Although possible in principle,\nthe issued error messages are no more indicating whether `do_pick`\nfailed while applying or while committing the changes. This reduces\ncode complexity at the call site and does not matter from a user's\npoint of view because a glance at the index reveals whether there are\nconflicts or not and in-depth troubleshooting is still possible using\nthe `--verbose` option.\n\nRemove the commit message title argument from `do_pick`'s interface,\nwhich has become unused.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 37 ++++++++++++++++++++-----------------\n 1 file changed, 20 insertions(+), 17 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 96c24e8..9f08f1b 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit> <title>\n+# do_pick [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -476,9 +476,11 @@ record_in_rewritten() {\n # <commit>\n #     The commit to cherry-pick.\n #\n-# <title>\n-#     The commit message title of <commit>. Used for information\n-#     purposes only.\n+# The return value is 1 if applying the changes resulted in a conflict\n+# and 2 if the specified arguments were incorrect. If the changes could\n+# be applied successfully but creating the commit failed, a value\n+# greater than 2 is returned. No commit is created in either case and\n+# the index is left with the (conflicting) changes in place.\n do_pick () {\n \tallow_empty_message=y\n \trewrite=\n@@ -493,7 +495,8 @@ do_pick () {\n \t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n-\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\twarn \"do_pick: unrecognized option -- $1\"\n+\t\t\treturn 2\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n@@ -501,7 +504,11 @@ do_pick () {\n \t\tesac\n \t\tshift\n \tdone\n-\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\tif test $# -ne 1\n+\tthen\n+\t\twarn \"do_pick: wrong number of arguments\"\n+\t\treturn 2\n+\tfi\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n@@ -519,11 +526,9 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\t\tpick_one -n $1 || return 1\n \telse\n-\t\tpick_one ${rewrite:+-n} $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n \tif test -n \"$rewrite\"\n@@ -532,8 +537,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n-\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n \t# TODO: Work around the fact that git-commit lets us\n@@ -546,8 +550,7 @@ do_pick () {\n \t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n \t\tthen\n \t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n-\t\tfi ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\tfi || return 3\n \tfi\n }\n \n@@ -562,21 +565,21 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 \"$rest\"\n+\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.1\n"},{"id":"246851","messageId":"c9bd9a9361db275c12310c970811384c1a9935e7.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 11/19] rebase -i: teach do_pick the option --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:11Z","receivedAt":"2014-07-28T23:18:11Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list commands `pick`, `reword`\nand `edit`. To cater for the different pick behaviours (like\n`squash`), `do_pick` accepts several options not only from the\ngit-cherry-pick but also the git-commit interface.\n\nAdd the option `--amend` from the git-commit interface to the options\npool of `do_pick`. It creates a new commit for the changes introduced\nby the picked commit and the previous one. The previous commit is\nthen replaced with the new commit. If no other options are specified,\nthe log message of the previous commit is used.\n\nBe careful when `--amend` is used to pick a root commit because HEAD\nmight point to the sentinel commit but there is still nothing to\namend. Be sure to initialize `amend` so that commits are squashed\neven when git-rebase--interactive is interrupted for resolving\nconflicts. It is not a mistake to do the initialization regardless of\nany conflicts because `amend` is always cleared before the next to-do\nitem is processed.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 18 +++++++++++++++++-\n 1 file changed, 17 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 9f08f1b..22a8f7b 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,16 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit>\n+# do_pick [--amend] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --amend\n+#     After picking <commit>, replace the current head commit with a new\n+#     commit that also introduces the changes of <commit>.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -489,6 +495,16 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--amend)\n+\t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse --verify HEAD\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: nothing to amend\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_amend=y\n+\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n-- \n2.0.1\n"},{"id":"246849","messageId":"584f7f377f7fff75dae6fc91089383188820ed82.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 12/19] rebase -i: teach do_pick the option --file","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:12Z","receivedAt":"2014-07-28T23:18:12Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`, `reword` and\n`edit`. To cater for the different pick behaviours (like `squash`),\n`do_pick` accepts several options not only from the git-cherry-pick\nbut also the git-commit interface.\n\nAdd the option `--file` from the git-commit interface to the options\npool of `do_pick`. It expects an argument itself which is interpreted\nas a file path and takes the commit message from the given file. If\n`--file` is passed to `do_pick`, assign the given file path to the\nlocal variable `rewrite_message` and relay the option\n\n    --file \"$rewrite_message\"\n\nto the git-commit command line which creates the commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 20 +++++++++++++++++++-\n 1 file changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 22a8f7b..5df1086 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--edit] <commit>\n+# do_pick [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -474,6 +474,12 @@ record_in_rewritten() {\n #\n #     _This is not a git-cherry-pick option._\n #\n+# -F <file>, --file <file>\n+#     Take the commit message from the given file. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -492,6 +498,7 @@ do_pick () {\n \trewrite=\n \trewrite_amend=\n \trewrite_edit=\n+\trewrite_message=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n@@ -505,6 +512,16 @@ do_pick () {\n \t\t\trewrite_amend=y\n \t\t\tgit rev-parse --verify HEAD >\"$amend\"\n \t\t\t;;\n+\t\t-F|--file)\n+\t\t\tif test $# -eq 0\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: option --file specified but no <file> given\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_message=$2\n+\t\t\tshift\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n@@ -553,6 +570,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n+\t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n-- \n2.0.1\n"},{"id":"246852","messageId":"727fd7808a93b6d03f68e66dac64ee5e11830e55.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 13/19] rebase -i: prepare for squash in terms of do_pick --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:13Z","receivedAt":"2014-07-28T23:18:13Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Rewrite `squash` and `fixup` handling in `do_next` using the sequence\n\n    pick_one\n    commit\n\nin order to test the correctness of a single `do_squash` or\nparameterised `do_pick` and make the subsequent patch reimplementing\n`squash` in terms of such a single function more readable.\n\nDo not call `rm -f \"$GIT_DIR\"/MERGE_MSG` since it has no effect on\nthe state after git-rebase--interactive terminates. The option `-F`\nmakes git-commit ignore `MERGE_MSG` for the log message. If\ngit-commit succeeds, `MERGE_MSG` is removed, and if it fails,\n`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.\nIn summary, removing `MERGE_MSG` neither influences the squash commit\nmessage nor the file state after git-commit returns.\n\nMoreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch\n`$squash_msg` so that it is correct to execute `pick_one` immediately\nbefore git-commit.\n\nMight be squashed into the subsequent commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 21 +++++++++++++++------\n 1 file changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5df1086..d85e55d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -636,15 +636,15 @@ do_next () {\n \t\tauthor_script_content=$(get_author_ident_from_commit HEAD)\n \t\techo \"$author_script_content\" > \"$author_script\"\n \t\teval \"$author_script_content\"\n-\t\tif ! pick_one -n $sha1\n-\t\tthen\n-\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\tdie_failed_squash $sha1 \"$rest\"\n-\t\tfi\n \t\tcase \"$(peek_next_command)\" in\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n+\t\t\tif ! pick_one -n $sha1\n+\t\t\tthen\n+\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\tfi\n \t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n@@ -653,12 +653,21 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n-- \n2.0.1\n"},{"id":"246855","messageId":"ab7f8e0cd02a02144ed6dbe50efacbad2d017838.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 14/19] rebase -i: implement squash in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:14Z","receivedAt":"2014-07-28T23:18:14Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `squash` and its close relative `fixup` replay\nthe changes of a commit like `pick` but do not recreate the commit.\nInstead they replace the previous commit with a new commit that also\nintroduces the changes of the squashed commit. This is roughly like\ncherry-picking without committing and using git-commit to amend the\nprevious commit.\n\nThe to-do list\n\n    pick   a Some changes\n    squash b Some more changes\n\ngets translated into the sequence of git commands\n\n    git cherry-pick a\n    git cherry-pick -n b\n    git commit --amend\n\nand if git-cherry-pick supported `--amend` this would look even more\nlike the to-do list it is based on\n\n    git cherry-pick a\n    git cherry-pick --amend b.\n\nSince `do_pick` takes care of `pick` entries and the above suggests\n`squash` as an alias for `pick --amend`, reimplement `squash` in\nterms of `do_pick --amend`. Introduce `$squash_msg` as the commit\nmessage via the `--file` option. When the last commit of a squash\nseries is processed, the user is asked to review the log message.\nPass `--edit` as additional option in this case. The only difference\nin the options passed to git-commit and `do_pick` is the omitted\n`--no-verify`. However, `do_pick` does not execute the verification\nhooks anyway because it solely replays commits and assumes that they\nhave been verified before.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 30 ++++++------------------------\n 1 file changed, 6 insertions(+), 24 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d85e55d..9307fa4 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -640,37 +640,19 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tif ! pick_one -n $sha1\n-\t\t\tthen\n-\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\tfi\n-\t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n-\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\tdo_with_author do_pick --amend -F \"$squash_msg\" $sha1 \\\n+\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\t;;\n \t\t*)\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$fixup_msg\" $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n \t\t\t;;\n-- \n2.0.1\n"},{"id":"246858","messageId":"b844f549d7b2e6f864dc6e5b13d2390030f5f31c.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 15/19] rebase -i: explicitly distinguish replay commands and exec tasks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:15Z","receivedAt":"2014-07-28T23:18:15Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"There are two kinds of to-do list commands available. One kind\nreplays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that\nis) and the other executes a shell command (`exec`). We will call the\nfirst kind replay commands.\n\nThe two kinds of tasks are scheduled using different line formats.\nReplay commands expect a commit hash argument following the command\nname and exec concatenates all arguments to assemble a command line.\n\nAdhere to the distinction of formats by not trying to parse the\n`sha1` field unless we are dealing with a replay command. Move the\nreplay command handling code to a new function `do_replay` which\nassumes the first argument to be a commit hash and make no more such\nassumptions in `do_next`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 9307fa4..8dde8e6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -588,13 +588,12 @@ do_pick () {\n \tfi\n }\n \n-do_next () {\n-\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest < \"$todo\"\n+do_replay () {\n+\tcommand=$1\n+\tsha1=$2\n+\trest=$3\n+\n \tcase \"$command\" in\n-\t\"$comment_char\"*|''|noop)\n-\t\tmark_action_done\n-\t\t;;\n \tpick|p)\n \t\tcomment_for_reflog pick\n \n@@ -659,6 +658,28 @@ do_next () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\twarn \"Unknown command: $command\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+}\n+\n+do_next () {\n+\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\tread -r command sha1 rest <\"$todo\"\n+\n+\tcase \"$command\" in\n+\t\"$comment_char\"*|''|noop)\n+\t\tmark_action_done\n+\t\t;;\n \tx|\"exec\")\n \t\tread -r command rest < \"$todo\"\n \t\tmark_action_done\n@@ -698,14 +719,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\twarn \"Unknown command: $command $sha1 $rest\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n+\t\tdo_replay $command $sha1 \"$rest\"\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n-- \n2.0.1\n"},{"id":"246856","messageId":"28c12d31fe8aa13d6aa8f76318637f3b644a5b74.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 16/19] rebase -i: parse to-do list command line options","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:16Z","receivedAt":"2014-07-28T23:18:16Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Read in to-do list lines as\n\n    command args\n\ninstead of\n\n    command sha1 rest\n\nso that to-do list command lines can specify additional arguments\napart from the commit hash and the log message title, which become\nthe non-options in `args`. Loop over `args`, put all options (an\nargument beginning with a dash) in `opts`, stop the loop on the first\nnon-option and assign it to `sha1`. The loop does not know the\noptions it parses so that options that take an argument themselves\nare not supported at the moment. Neither are options that contain\nspaces because the shell expansion of `args` in `do_next` interprets\nwhite space characters as argument separator, that is a command line\nlike\n\n    pick --author \"A U Thor\" fa1afe1 Some change\n\nis parsed as the pick command\n\n    pick --author\n\nand the commit hash\n\n    \"A\n\nwhich obviously results in an unknown revision error. For the sake of\ncompleteness, in the example above the message title variable `rest`\nis assigned the string 'U Thor\" fa1afe1 Some change' (without the\nsingle quotes).\n\nPrint an error message for unknown or unsupported command line\noptions, which means an error for all specified options at the\nmoment. Cleanly break the `do_next` loop by assigning the special\nvalue 'unknown' to the local variable `command`, which triggers the\nunknown command case in `do_cmd`.\n\nThe to-do list is also parsed when the commit hashes are translated\nbetween long and short format before and after the to-do list is\nedited. Apply the same procedure as in `do_cmd` with the exception\nthat we only care about where the options stop and the commit hash\nbegins. Do not reject any options when transforming the commit\nhashes.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 49 ++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 41 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8dde8e6..ff4ba7f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -590,8 +590,26 @@ do_pick () {\n \n do_replay () {\n \tcommand=$1\n-\tsha1=$2\n-\trest=$3\n+\tshift\n+\n+\topts=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-*)\n+\t\t\twarn \"Unknown option: $1\"\n+\t\t\tcommand=unknown\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\topts=\"$opts $(git rev-parse --sq-quote \"$1\")\"\n+\t\tshift\n+\tdone\n+\tsha1=$1\n+\tshift\n+\trest=$*\n \n \tcase \"$command\" in\n \tpick|p)\n@@ -674,7 +692,7 @@ do_replay () {\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest <\"$todo\"\n+\tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n \t\"$comment_char\"*|''|noop)\n@@ -719,7 +737,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\tdo_replay $command $sha1 \"$rest\"\n+\t\tdo_replay $command $args\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n@@ -799,19 +817,34 @@ skip_unnecessary_picks () {\n }\n \n transform_todo_ids () {\n-\twhile read -r command rest\n+\twhile read -r command args\n \tdo\n \t\tcase \"$command\" in\n \t\t\"$comment_char\"* | exec)\n \t\t\t# Be careful for oddball commands like 'exec'\n \t\t\t# that do not have a SHA-1 at the beginning of $rest.\n+\t\t\tnewargs=\\ $args\n \t\t\t;;\n \t\t*)\n-\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" ${rest%% *}) &&\n-\t\t\trest=\"$sha1 ${rest#* }\"\n+\t\t\tnewargs=\n+\t\t\tsha1=\n+\t\t\tfor arg in $args\n+\t\t\tdo\n+\t\t\t\tcase \"$arg\" in\n+\t\t\t\t-*)\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\ttest -z \"$sha1\" &&\n+\t\t\t\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" $arg) &&\n+\t\t\t\t\t\targ=$sha1\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone\n \t\t\t;;\n \t\tesac\n-\t\tprintf '%s\\n' \"$command${rest:+ }$rest\"\n+\t\tprintf '%s\\n' \"$command$newargs\"\n \tdone <\"$todo\" >\"$todo.new\" &&\n \tmv -f \"$todo.new\" \"$todo\"\n }\n-- \n2.0.1\n"},{"id":"246857","messageId":"8bca331f9a5caa7d9667eaedb67f1e1d0eb4ea1e.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 17/19] rebase -i: teach do_pick the option --reset-author","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:17Z","receivedAt":"2014-07-28T23:18:17Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement many of the to-do list commands.\nEventually, the complete `do_pick` interface will be exposed to the\nuser in some form or another and those commands will become simple\naliases for the `do_pick` options now used to implement them.\n\nAdd the git-commit option `--reset-author` to the options pool of\n`do_pick`. It rewrites the author date and name of the picked commit\nto match the committer date and name.\n\nIf `--reset-author` is passed to `do_pick`, set the `rewrite` flag\nand relay the option to the git-commit command line which creates the\nfinal commit. If `--amend` is not passed as well, the fresh\nauthorship effect is achieved by the mere fact that we are creating a\nnew commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 23 ++++++++++++++++++++++-\n 1 file changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ff4ba7f..3886a80 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,18 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --reset-author\n+#     Pretend the changes were made for the first time. Declare that the\n+#     authorship of the resulting commit now belongs to the committer.\n+#     This also renews the author timestamp. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # --amend\n #     After picking <commit>, replace the current head commit with a new\n #     commit that also introduces the changes of <commit>.\n@@ -502,6 +510,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--reset-author)\n+\t\t\trewrite=y\n+\t\t\trewrite_author=y\n+\t\t\t;;\n \t\t--amend)\n \t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse --verify HEAD\n \t\t\tthen\n@@ -564,6 +576,14 @@ do_pick () {\n \t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n+\tif test -n \"$rewrite_author\" && test -z \"$rewrite_amend\"\n+\tthen\n+\t\t# keep rewrite flag to create a new commit, rewrite\n+\t\t# without --reset-author though because it can only be\n+\t\t# used with -C, -c or --amend\n+\t\trewrite_author=\n+\tfi\n+\n \tif test -n \"$rewrite\"\n \tthen\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n@@ -571,6 +591,7 @@ do_pick () {\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n+\t\t\t   ${rewrite_author:+--reset-author} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n \n-- \n2.0.1\n"},{"id":"246853","messageId":"c0443c7c2b1367868593baf52a49fc5f8d15b476.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 18/19] rebase -i: teach do_pick the option --signoff","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:18Z","receivedAt":"2014-07-28T23:18:18Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is currently used to implement most of the to-do list commands\nand offers additional options that will eventually find their way\nonto to-do lists.\n\nTo extend the repertoire of available options, add the git-commit and\ngit-cherry-pick option `--signoff` to the `do_pick` interface. It\nappends a Signed-off-by: line using the committer identity to the log\nmessage of the picked commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 12 +++++++++++-\n 1 file changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 3886a80..9324ed3 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,15 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--signoff] [--reset-author] [--amend] [--file <file>]\n+#         [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# -s, --signoff\n+#     Insert a Signed-off-by: line using the committer identity at the\n+#     end of the commit log message. This creates a fresh commit.\n+#\n # --reset-author\n #     Pretend the changes were made for the first time. Declare that the\n #     authorship of the resulting commit now belongs to the committer.\n@@ -510,6 +515,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t-s|--signoff)\n+\t\t\trewrite=y\n+\t\t\trewrite_signoff=y\n+\t\t\t;;\n \t\t--reset-author)\n \t\t\trewrite=y\n \t\t\trewrite_author=y\n@@ -588,6 +597,7 @@ do_pick () {\n \tthen\n \t\tgit commit --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_signoff:+--signoff} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n-- \n2.0.1\n"},{"id":"246854","messageId":"de80b265966e8287317029de1dabd7f117af9971.1406589435.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"[PATCH v1 19/19] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-07-28T23:18:19Z","receivedAt":"2014-07-28T23:18:19Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"pick and reword are atomic to-do list commands in the sense that they\nopen a new task which is closed after the respective command is\ncompleted. squash and fixup are not atomic. They create a new task\nwhich is not completed until the last squash or fixup is processed.\n\nLift the general unknown option blockade for the pick and reword\ncommands. If `do_cmd` comes across one of the options `--signoff` and\n`--reset-author` while parsing a to-do entry and the scheduled\ncommand is either `pick` or `reword`, relay the option to `do_pick`.\n\nThe `do_pick` options `--gpg-sign` and `--file` are not yet supported\nbecause `do_cmd` cannot handle option arguments and options with\nspaces at the moment. It is true that edit is one of the atomic\ncommands but it displays hash information when the rebase is stopped\nand some options rewrite the picked commit which alters that\ninformation. squash and fixup still do not accept user options as the\ninterplay of `--reset-author` and the author script are yet to be\ndetermined.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 9324ed3..32fd047 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -627,6 +627,16 @@ do_replay () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--signoff|--reset-author)\n+\t\t\tcase \"$command\" in\n+\t\t\tpick|reword)\n+\t\t\t\t;;\n+\t\t\t*)\n+\t\t\t\twarn \"Unsupported option: $1\"\n+\t\t\t\tcommand=unknown\n+\t\t\t\t;;\n+\t\t\tesac\n+\t\t\t;;\n \t\t-*)\n \t\t\twarn \"Unknown option: $1\"\n \t\t\tcommand=unknown\n@@ -647,21 +657,24 @@ do_replay () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick --edit $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.1\n"},{"id":"247158","messageId":"20140801234708.GA20040@peff.net","threadId":"36962","inReplyTo":"1bb7c0b9aed60f7c65bf812ac42b2f1ad8fd3f82.1406589435.git.bafain@gmail.com","subject":"Re: [PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-01T23:47:09Z","receivedAt":"2014-08-01T23:47:09Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 29, 2014 at 01:18:03AM +0200, Fabian Ruch wrote:\n\n> Specify the git-commit option `--no-verify` to disable the pre-commit\n> hook when editing the log message. Because `--no-verify` also skips\n> the commit-msg hook, execute the hook from within\n> git-rebase--interactive after the commit is created. Fortunately, the\n> commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\n> git-commit terminates. Caveat: In case the commit-msg hook finds the\n> new log message ill-formatted, the user is only notified of the\n> failed commit-msg hook but the log message is used for the commit\n> anyway. git-commit ought to offer more fine-grained control over\n> which hooks are executed.\n\nThanks for a nice explanation of the tradeoff. Have you looked at adding\nan option to git-commit? We already have --no-post-rewrite. I think you\nwould just need:\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 5ed6036..f7af220 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -102,6 +102,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n static int no_post_rewrite, allow_empty_message;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n static char *sign_commit;\n+static int no_pre_commit;\n \n /*\n  * The default commit message cleanup mode will remove the lines\n@@ -661,7 +662,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t/* This checks and barfs if author is badly specified */\n \tdetermine_author_info(author_ident);\n \n-\tif (!no_verify && run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n+\tif (!no_verify && !no_pre_commit &&\n+\t    run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n \t\treturn 0;\n \n \tif (squash_message) {\n@@ -1604,6 +1606,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\t\t N_(\"terminate entries with NUL\")),\n \t\tOPT_BOOL(0, \"amend\", &amend, N_(\"amend previous commit\")),\n \t\tOPT_BOOL(0, \"no-post-rewrite\", &no_post_rewrite, N_(\"bypass post-rewrite hook\")),\n+\t\tOPT_BOOL(0, \"no-pre-commit\", &no_pre_commit, N_(\"bypass pre-commit hook\")),\n \t\t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, N_(\"mode\"), N_(\"show untracked files, optional modes: all, normal, no. (Default: all)\"), PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n \t\t/* end commit contents options */\n \n\nthough I would also not be opposed to some more uniform hook selection\nmechanism (e.g., \"--no-verify=pre-commit\" or something).\n\n-Peff\n"},{"id":"247160","messageId":"20140802000405.GB20040@peff.net","threadId":"36962","inReplyTo":"7389745946359e0d9d8c6f1e8f2ebc78033132e6.1406589435.git.bafain@gmail.com","subject":"Re: [PATCH v1 07/19] rebase -i: log the replay of root commits","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-02T00:04:05Z","receivedAt":"2014-08-02T00:04:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 29, 2014 at 01:18:07AM +0200, Fabian Ruch wrote:\n\n> The command line used to recreate root commits specifies the option\n> `-q` which suppresses the commit summary message. However,\n> git-rebase--interactive tends to tell the user about the commits it\n> creates in the final history, if she wishes (cf. command line option\n> `--verbose`). The code parts handling non-root commits and squash\n> commits all output commit summary messages. Do not make the replay of\n> root commits an exception. Remove the option to make the report of\n> the rebased history complete.\n> \n> It is OK that the commit summary is still suppressed when git-commit\n> is used to initialize the authorship of the sentinel commit because\n> this additional commit is an implementation detail hidden from the\n> final history. The removed `-q` option was probably introduced as a\n> copy-and-paste error stemming from that part of the root commit\n> handling code.\n\nI'm confused. This implies that we should be seeing summaries for other\ncommits, but not root commits, and this patch is bring them into\nharmony.  But if I have a repo like this:\n\n  git init -q repo &&\n  cd repo &&\n  for i in one two; do\n    echo $i >file &&\n    git add file &&\n    git commit -q -m $i\n  done\n\nthen using stock git gives me this:\n\n  $ GIT_EDITOR=true git rebase -i --root 2>&1 | perl -pe 's/\\r/\\\\r\\n/g'\n  Rebasing (1/2)\\r\n  Rebasing (2/2)\\r\n  Successfully rebased and updated refs/heads/master.\n\nbut with your patch, I get:\n\n  $ GIT_EDITOR=true git.compile rebase -i --root 2>&1 | perl -pe 's/\\r/\\\\r\\n/g'\n  Rebasing (1/2)\\r\n  [detached HEAD 60834b3] one\n   Date: Fri Aug 1 20:00:05 2014 -0400\n   1 file changed, 1 insertion(+)\n   create mode 100644 file\n  Rebasing (2/2)\\r\n  Successfully rebased and updated refs/heads/master.\n\nAm I misunderstanding the purpose of the patch?\n\n-Peff\n"},{"id":"247161","messageId":"20140802001322.GC20040@peff.net","threadId":"36962","inReplyTo":"7ed1b44ae05860a556d86c8b90ac6fff0906128d.1406589435.git.bafain@gmail.com","subject":"Re: [PATCH v1 08/19] rebase -i: root commits are replayed with an unnecessary option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-02T00:13:22Z","receivedAt":"2014-08-02T00:13:22Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 29, 2014 at 01:18:08AM +0200, Fabian Ruch wrote:\n\n> The command line used to recreate root commits specifies the\n> effectless option `-C`. It makes git-commit reuse commit message and\n> authorship of the named commit. However, the commit being amended\n> here, which is the sentinel commit, already carries the authorship\n> and log message of the commit being replayed. Remove the option.\n> \n> Since `-C` (in contrast to `-c`) does not invoke the editor and the\n> `--amend` option invokes it by default, disable editor invocation\n> again by specifying `--no-edit`.\n\nI found this description a little backwards. The \"-C\" does have an\neffect, as you noticed in the second paragraph.\n\nI think the reasoning is more like:\n\n  The command line used to recreate root commits uses \"-C\" to\n  suppress the commit editor. This is unnecessarily confusing,\n  though, because that suppression is a secondary effect of the\n  option. The main purpose of \"-C\" is to pull the metadata from\n  another commit, but here we know that this is a noop, since we\n  are amending a commit just created from the same data.\n\n  At the time, commit did not yet know \"--no-edit\", and this was a\n  reasonable way to get the desired behavior. We can switch it to\n  use \"--no-edit\" to make the intended effect more obvious.\n\n-Peff\n"},{"id":"247162","messageId":"20140802002231.GD20040@peff.net","threadId":"36962","inReplyTo":"235b55a0ec3db4a111fbb32e58e578ced6307d72.1406589435.git.bafain@gmail.com","subject":"Re: [PATCH v1 09/19] rebase -i: commit only once when rewriting picks","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-02T00:22:31Z","receivedAt":"2014-08-02T00:22:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 29, 2014 at 01:18:09AM +0200, Fabian Ruch wrote:\n\n> The options passed to `do_pick` determine whether the picked commit\n> will be rewritten or not. If the commit gets rewritten, because the\n> user requested to edit the commit message for instance, let\n> `pick_one` merely apply the changes introduced by the commit and do\n> not commit the resulting tree yet. If the commit is replayed as is,\n> leave it to `pick_one` to recreate the commit (possibly by\n> fast-forwarding the head). This makes it easier to combine git-commit\n> options like `--edit` and `--amend` in `do_pick` because\n> git-cherry-pick does not support `--amend`.\n> \n> In the case of `--edit`, do not `exit_with_patch` but assign\n> `rewrite` to pick the changes with `-n`. If the pick conflicts, no\n> commit is created which we would have to amend when continuing the\n> rebase. To complete the pick after the conflicts are resolved the\n> user just resumes with `git rebase --continue`.\n\nHmm. So does this mean the user will actually see a different state\nduring such a conflict?\n\nE.g., if I have instructions like:\n\n  pick A\n  squash B\n  squash C\n\nand there is a conflict picking C, then what state do I see? Right now I\nsee a commit with the A+B squash prepared. But your description sounds\nto me like we would avoid the squash for \"B\", and the user would see a\ndifferent state.\n\nHowever, I couldn't trigger that behavior in a few experiments. Am I\nmisunderstanding, or is there some case where the user-visible state\nwill be different?\n\n-Peff\n"},{"id":"247171","messageId":"20140802135255.GA4185@peff.net","threadId":"36962","inReplyTo":"cover.1406589435.git.bafain@gmail.com","subject":"Re: [PATCH v1 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-02T13:52:55Z","receivedAt":"2014-08-02T13:52:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Jul 29, 2014 at 01:18:00AM +0200, Fabian Ruch wrote:\n\n> this is a reroll of the patch series that enables rudimentary support\n> of line options for git-rebase's to-do list commands and reimplements\n> the well-known commands `reword` and `squash` in terms of a\n> parameterised `do_pick`.\n\nI just finished reading over the whole series (which is my first real\nexposure to it). With the exception of the comments I already sent, it\nlooks pretty reasonable to me.\n\nThanks for splitting it and writing good commit messages; that made it\nrelatively easy to follow what was going on.\n\n-Peff\n"},{"id":"247203","messageId":"53DF464D.5020403@gmail.com","threadId":"36962","inReplyTo":"20140802135255.GA4185@peff.net","subject":"Re: [PATCH v1 00/19] Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-04T08:37:33Z","receivedAt":"2014-08-04T08:37:33Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Peff,\n\nJeff King writes:\n> On Tue, Jul 29, 2014 at 01:18:00AM +0200, Fabian Ruch wrote:\n>> this is a reroll of the patch series that enables rudimentary support\n>> of line options for git-rebase's to-do list commands and reimplements\n>> the well-known commands `reword` and `squash` in terms of a\n>> parameterised `do_pick`.\n> \n> I just finished reading over the whole series (which is my first real\n> exposure to it). With the exception of the comments I already sent, it\n> looks pretty reasonable to me.\n> \n> Thanks for splitting it and writing good commit messages; that made it\n> relatively easy to follow what was going on.\n\nThanks a lot for taking the time.\n\nYour review revealed more shortcomings of the patch series. Now that the\nreplay of root commits is logged, the log is dumped on the console even\nin non-verbose mode. And, I must admit that the fact that `--no-edit`\nhasn't been a (documented) feature of git-commit for all time didn't\nstruck me at all as a possible reason for using `-C`, which is a little\nembarrassing.\n\nI will include more details in separate replies to your comments later.\n\n   Fabian\n"},{"id":"247210","messageId":"vpqzjfki8t8.fsf@anie.imag.fr","threadId":"36962","inReplyTo":"a82fd64f943d4b59a01509ae52fc2d7a05d51f4a.1404323078.git.bafain@gmail.com","subject":"Re: [PATCH RFC v2 05/19] rebase -i: Implement reword in terms of do_pick","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2014-08-04T15:16:51Z","receivedAt":"2014-08-04T15:16:51Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -555,20 +555,7 @@ do_next () {\n>  \t\tcomment_for_reflog reword\n>  \n>  \t\tmark_action_done\n> -\t\tdo_pick $sha1 \"$rest\"\n> -\t\t# TODO: Work around the fact that git-commit lets us\n> -\t\t# disable either both the pre-commit and the commit-msg\n> -\t\t# hook or none. Disable the pre-commit hook because the\n> -\t\t# tree is left unchanged but run the commit-msg hook\n> -\t\t# from here because the log message is altered.\n> -\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n> -\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n> -\t\t\tthen\n> -\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n> -\t\t\tfi || {\n> -\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n> -\t\t\t\texit_with_patch $sha1 1\n> -\t\t\t}\n> +\t\tdo_pick --edit $sha1 \"$rest\"\n\nI would have found this easier to review if squashed into the previous\npatch. My reaction reading the previous patch was \"Uh, why duplicate\ncode?\", and reading this one \"Ah, that's OK\". A single patch doing both\nwould have avoided the confusion.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"247211","messageId":"53DFAAAF.20705@gmail.com","threadId":"36962","inReplyTo":"vpqzjfki8t8.fsf@anie.imag.fr","subject":"Re: [PATCH RFC v2 05/19] rebase -i: Implement reword in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-04T15:45:51Z","receivedAt":"2014-08-04T15:45:51Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Matthieu,\n\nthanks for taking a look at this patch series. I might have caused some\nconfusion by starting with version v1 again after removing the RFC tag.\nThe current reroll[1] is tagged with PATCH v1, not PATCH RFC v2.\n\nI'm sorry if this is the reason why your reply appears on this sub-thread.\n\nYour concerns below are of course noted.\n\n   Fabian\n\n[1] http://article.gmane.org/gmane.comp.version-control.git/254361\n\nMatthieu Moy writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -555,20 +555,7 @@ do_next () {\n>>  \t\tcomment_for_reflog reword\n>>  \n>>  \t\tmark_action_done\n>> -\t\tdo_pick $sha1 \"$rest\"\n>> -\t\t# TODO: Work around the fact that git-commit lets us\n>> -\t\t# disable either both the pre-commit and the commit-msg\n>> -\t\t# hook or none. Disable the pre-commit hook because the\n>> -\t\t# tree is left unchanged but run the commit-msg hook\n>> -\t\t# from here because the log message is altered.\n>> -\t\tgit commit --allow-empty --amend --no-post-rewrite -n ${gpg_sign_opt:+\"$gpg_sign_opt\"} &&\n>> -\t\t\tif test -x \"$GIT_DIR\"/hooks/commit-msg\n>> -\t\t\tthen\n>> -\t\t\t\t\"$GIT_DIR\"/hooks/commit-msg \"$GIT_DIR\"/COMMIT_EDITMSG\n>> -\t\t\tfi || {\n>> -\t\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n>> -\t\t\t\texit_with_patch $sha1 1\n>> -\t\t\t}\n>> +\t\tdo_pick --edit $sha1 \"$rest\"\n> \n> I would have found this easier to review if squashed into the previous\n> patch. My reaction reading the previous patch was \"Uh, why duplicate\n> code?\", and reading this one \"Ah, that's OK\". A single patch doing both\n> would have avoided the confusion.\n"},{"id":"247234","messageId":"53DFD63E.8040806@gmail.com","threadId":"36962","inReplyTo":"20140801234708.GA20040@peff.net","subject":"Re: [PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-04T18:51:42Z","receivedAt":"2014-08-04T18:51:42Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nJeff King writes:\n> On Tue, Jul 29, 2014 at 01:18:03AM +0200, Fabian Ruch wrote:\n> \n>> Specify the git-commit option `--no-verify` to disable the pre-commit\n>> hook when editing the log message. Because `--no-verify` also skips\n>> the commit-msg hook, execute the hook from within\n>> git-rebase--interactive after the commit is created. Fortunately, the\n>> commit message is still available in `$GIT_DIR/COMMIT_EDITMSG` after\n>> git-commit terminates. Caveat: In case the commit-msg hook finds the\n>> new log message ill-formatted, the user is only notified of the\n>> failed commit-msg hook but the log message is used for the commit\n>> anyway. git-commit ought to offer more fine-grained control over\n>> which hooks are executed.\n> \n> Thanks for a nice explanation of the tradeoff. Have you looked at adding\n> an option to git-commit? We already have --no-post-rewrite. I think you\n> would just need:\n> \n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 5ed6036..f7af220 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -102,6 +102,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n>  static int no_post_rewrite, allow_empty_message;\n>  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n>  static char *sign_commit;\n> +static int no_pre_commit;\n>  \n>  /*\n>   * The default commit message cleanup mode will remove the lines\n> @@ -661,7 +662,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \t/* This checks and barfs if author is badly specified */\n>  \tdetermine_author_info(author_ident);\n>  \n> -\tif (!no_verify && run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n> +\tif (!no_verify && !no_pre_commit &&\n> +\t    run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n>  \t\treturn 0;\n>  \n>  \tif (squash_message) {\n> @@ -1604,6 +1606,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n>  \t\t\t N_(\"terminate entries with NUL\")),\n>  \t\tOPT_BOOL(0, \"amend\", &amend, N_(\"amend previous commit\")),\n>  \t\tOPT_BOOL(0, \"no-post-rewrite\", &no_post_rewrite, N_(\"bypass post-rewrite hook\")),\n> +\t\tOPT_BOOL(0, \"no-pre-commit\", &no_pre_commit, N_(\"bypass pre-commit hook\")),\n>  \t\t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, N_(\"mode\"), N_(\"show untracked files, optional modes: all, normal, no. (Default: all)\"), PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n>  \t\t/* end commit contents options */\n>  \n> \n> though I would also not be opposed to some more uniform hook selection\n> mechanism (e.g., \"--no-verify=pre-commit\" or something).\n\nWhile the --no-verify= mechanism doesn't add a new option to the\ngit-commit interface but lets one refine the --no-verify option, users\nmight find it weird to have an argument to name disabled hooks but then\nnot be able to disable all hooks that way.\n\nTo have that uniform hook selection without duplicating code, we might\nwant to have something like --bypass-hook= right away. This would cover\n--no-post-rewrite as well and add support for disabling\nprepare-commit-msg and post-commit, whose execution cannot be controlled\nvia the git-commit interface at the moment.\n\nSince the hook selection wouldn't have to change, the options parsing\ncode seems to be simpler (--bypass-hook= would have to support several\noccurrences with different arguments which could be implemented as an\nOPT_CALLBACK?) and git-commit decided to have --no- options for hook\nselection so far, I would lean towards your patch from above.\n\nI know you didn't say anything otherwise, I just wanted to expand a\nlittle. You find an amended version of your patch below that documents\n--no-verify as a synonym for --no-pre-commit and --no-commit-msg, and\nadds tests.\n\n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 5e2221c..813aa78 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -98,12 +98,27 @@ static char *edit_message, *use_message;\n>  static char *fixup_message, *squash_message;\n>  static int all, also, interactive, patch_interactive, only, amend, signoff;\n>  static int edit_flag = -1; /* unspecified */\n> -static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n> +static int quiet, verbose, allow_empty, dry_run, renew_authorship;\n>  static int no_post_rewrite, allow_empty_message;\n>  static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n>  static char *sign_commit;\n>  \n>  /*\n> + * The verify variable is interpreted as a bitmap of enabled commit\n> + * verification hooks according to the legend below.\n> + *\n> + * By default, the pre-commit and commit-msg hooks are enabled. This\n> + * is represented by both the PRE_COMMIT and COMMIT_MSG bits being\n> + * set.\n> + *\n> + * The bitmap is changed through the command line options\n> + * --no-verify, --no-pre-commit and --no-commit-msg.\n> + */\n> +#define PRE_COMMIT (1<<0)\n> +#define COMMIT_MSG (1<<1)\n> +static int verify = PRE_COMMIT | COMMIT_MSG;\n> +\n> +/*\n>   * The default commit message cleanup mode will remove the lines\n>   * beginning with # (shell comments) and leading and trailing\n>   * whitespaces (empty lines or containing only whitespaces)\n> @@ -667,7 +682,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \t/* This checks and barfs if author is badly specified */\n>  \tdetermine_author_info(author_ident);\n>  \n> -\tif (!no_verify && run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n> +\tif (verify & PRE_COMMIT &&\n> +\t    run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n>  \t\treturn 0;\n>  \n>  \tif (squash_message) {\n> @@ -968,7 +984,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>  \t\t}\n>  \t}\n>  \n> -\tif (!no_verify &&\n> +\tif (verify & COMMIT_MSG &&\n>  \t    run_commit_hook(use_editor, index_file, \"commit-msg\", git_path(commit_editmsg), NULL)) {\n>  \t\treturn 0;\n>  \t}\n> @@ -1597,7 +1613,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_BOOL(0, \"interactive\", &interactive, N_(\"interactively add files\")),\n>  \t\tOPT_BOOL('p', \"patch\", &patch_interactive, N_(\"interactively add changes\")),\n>  \t\tOPT_BOOL('o', \"only\", &only, N_(\"commit only specified files\")),\n> -\t\tOPT_BOOL('n', \"no-verify\", &no_verify, N_(\"bypass pre-commit hook\")),\n> +\t\tOPT_NEGBIT('n', \"no-verify\", &verify,\n> +\t\t\t   N_(\"synonym for --no-pre-commit --no-commit-msg\"),\n> +\t\t\t   PRE_COMMIT | COMMIT_MSG),\n>  \t\tOPT_BOOL(0, \"dry-run\", &dry_run, N_(\"show what would be committed\")),\n>  \t\tOPT_SET_INT(0, \"short\", &status_format, N_(\"show status concisely\"),\n>  \t\t\t    STATUS_FORMAT_SHORT),\n> @@ -1610,6 +1628,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n>  \t\tOPT_BOOL('z', \"null\", &s.null_termination,\n>  \t\t\t N_(\"terminate entries with NUL\")),\n>  \t\tOPT_BOOL(0, \"amend\", &amend, N_(\"amend previous commit\")),\n> +\t\tOPT_NEGBIT(0, \"no-pre-commit\", &verify,\n> +\t\t\t   N_(\"bypass pre-commit hook\"),\n> +\t\t\t   PRE_COMMIT),\n> +\t\tOPT_NEGBIT(0, \"no-commit-msg\", &verify,\n> +\t\t\t   N_(\"bypass commit-msg hook\"),\n> +\t\t\t   COMMIT_MSG),\n>  \t\tOPT_BOOL(0, \"no-post-rewrite\", &no_post_rewrite, N_(\"bypass post-rewrite hook\")),\n>  \t\t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, N_(\"mode\"), N_(\"show untracked files, optional modes: all, normal, no. (Default: all)\"), PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n>  \t\t/* end commit contents options */\n\nSince all of the hook options are motivated by internal usage from\ngit-rebase, perhaps they should be configured as PARSE_OPT_HIDDEN. Any\nthoughts on this?\n\n    Fabian\n"},{"id":"247255","messageId":"53DFF965.8020808@gmail.com","threadId":"36962","inReplyTo":"20140802000405.GB20040@peff.net","subject":"Re: [PATCH v1 07/19] rebase -i: log the replay of root commits","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-04T21:21:41Z","receivedAt":"2014-08-04T21:21:41Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nJeff King writes:\n> On Tue, Jul 29, 2014 at 01:18:07AM +0200, Fabian Ruch wrote:\n>> The command line used to recreate root commits specifies the option\n>> `-q` which suppresses the commit summary message. However,\n>> git-rebase--interactive tends to tell the user about the commits it\n>> creates in the final history, if she wishes (cf. command line option\n>> `--verbose`). The code parts handling non-root commits and squash\n>> commits all output commit summary messages. Do not make the replay of\n>> root commits an exception. Remove the option to make the report of\n>> the rebased history complete.\n>>\n>> It is OK that the commit summary is still suppressed when git-commit\n>> is used to initialize the authorship of the sentinel commit because\n>> this additional commit is an implementation detail hidden from the\n>> final history. The removed `-q` option was probably introduced as a\n>> copy-and-paste error stemming from that part of the root commit\n>> handling code.\n> \n> I'm confused. This implies that we should be seeing summaries for other\n> commits, but not root commits, and this patch is bring them into\n> harmony.  But if I have a repo like this:\n> \n>   git init -q repo &&\n>   cd repo &&\n>   for i in one two; do\n>     echo $i >file &&\n>     git add file &&\n>     git commit -q -m $i\n>   done\n> \n> then using stock git gives me this:\n> \n>   $ GIT_EDITOR=true git rebase -i --root 2>&1 | perl -pe 's/\\r/\\\\r\\n/g'\n>   Rebasing (1/2)\\r\n>   Rebasing (2/2)\\r\n>   Successfully rebased and updated refs/heads/master.\n> \n> but with your patch, I get:\n> \n>   $ GIT_EDITOR=true git.compile rebase -i --root 2>&1 | perl -pe 's/\\r/\\\\r\\n/g'\n>   Rebasing (1/2)\\r\n>   [detached HEAD 60834b3] one\n>    Date: Fri Aug 1 20:00:05 2014 -0400\n>    1 file changed, 1 insertion(+)\n>    create mode 100644 file\n>   Rebasing (2/2)\\r\n>   Successfully rebased and updated refs/heads/master.\n> \n> Am I misunderstanding the purpose of the patch?\n\nThanks for laying out the differences in the user visible output. With\nstock git we are seeing summaries for other commits, but not root\ncommits, _with the --verbose option_. It's the fault of my patch to show\nthe summary even in non-verbose mode. This is now fixed by wrapping the\nrelevant command in 'output', a shell function defined in git-rebase.sh\nas follows:\n\n> output=$(\"$@\" 2>&1 )\n> status=$?\n> test $status != 0 && printf \"%s\\n\" \"$output\"\n> return $status\n\nThe problem that git-rebase--interactive has is that the redirection of\nstdin to a variable (or a file) does not work reliably with commands\nthat invoke the log message editor, that is 'reword' and 'squash'\nproduce their output both in verbose and non-verbose mode. I wouldn't\nknow how to fix this but\n\n1) invoking $GIT_EDITOR from git-rebase--interactive.sh, but to make\nthis right there should be a built-in command for shell scripts and an\ninterface for git-commit that prepare the editor contents like\ngit-commit does now, or\n\n2) forcing $GIT_EDITOR and git-commit to print on distinct file\ndescriptors, which would involve temporarily wrapping the $GIT_EDITOR\ncall in a shell script that redirects stdin to some other file\ndescriptor similar to what t/test-lib.sh does, or\n\n>         cat >\"$state_dir\"/editor.sh <<EOF\n> #!/bin/sh\n> $(git var GIT_EDITOR) \\$* >&3\n> EOF\n>         chmod +x \"$state_dir\"/editor.sh\n>         (\n>                 export GIT_EDITOR=\"$state_dir\"/editor.sh\n>                 \"$@\" 3>&1 >\"$state_dir\"/output 2>&1\n>         )\n\n3) passing the --quiet option in non-verbose mode and omitting it in\nverbose mode, which would cover the '$status != 0' above for if a\ncommand fails, it should indicate its error status despite being asked\nto be silent.\n\nOptions 2) and 3) seem attainable within this patch series and 3) sounds\nlike the cleanest option but I'm uncertain if I'm missing something\nhere. The only command line that is wrapped in 'output' and that doesn't\nsupport a --quiet option seems to be a 'warn' line which could simply be\nskipped in non-verbose mode. (Johannes Schindelin is cc'd as the\noriginal author of git-rebase--interactive.sh and 'output' in particular).\n\n   Fabian\n"},{"id":"247256","messageId":"53DFFBC7.2070902@gmail.com","threadId":"36962","inReplyTo":"20140802001322.GC20040@peff.net","subject":"Re: [PATCH v1 08/19] rebase -i: root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-04T21:31:51Z","receivedAt":"2014-08-04T21:31:51Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Jeff,\n\nJeff King writes:\n> On Tue, Jul 29, 2014 at 01:18:08AM +0200, Fabian Ruch wrote:\n>> The command line used to recreate root commits specifies the\n>> effectless option `-C`. It makes git-commit reuse commit message and\n>> authorship of the named commit. However, the commit being amended\n>> here, which is the sentinel commit, already carries the authorship\n>> and log message of the commit being replayed. Remove the option.\n>>\n>> Since `-C` (in contrast to `-c`) does not invoke the editor and the\n>> `--amend` option invokes it by default, disable editor invocation\n>> again by specifying `--no-edit`.\n> \n> I found this description a little backwards. The \"-C\" does have an\n> effect, as you noticed in the second paragraph.\n> \n> I think the reasoning is more like:\n> \n>   The command line used to recreate root commits uses \"-C\" to\n>   suppress the commit editor. This is unnecessarily confusing,\n>   though, because that suppression is a secondary effect of the\n>   option. The main purpose of \"-C\" is to pull the metadata from\n>   another commit, but here we know that this is a noop, since we\n>   are amending a commit just created from the same data.\n> \n>   At the time, commit did not yet know \"--no-edit\", and this was a\n>   reasonable way to get the desired behavior. We can switch it to\n>   use \"--no-edit\" to make the intended effect more obvious.\n\nThanks again, I shamelessly copied your formulation but squeezed in an\n\"undocumented\" because --no-edit had just been implemented (commit\nca1ba2010), though was then still missing from the git-commit manpage.\n\n    Fabian\n"},{"id":"247369","messageId":"20140806214624.GA23878@peff.net","threadId":"36962","inReplyTo":"53DFD63E.8040806@gmail.com","subject":"Re: [PATCH v1 03/19] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-06T21:46:24Z","receivedAt":"2014-08-06T21:46:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 04, 2014 at 08:51:42PM +0200, Fabian Ruch wrote:\n\n> > though I would also not be opposed to some more uniform hook selection\n> > mechanism (e.g., \"--no-verify=pre-commit\" or something).\n> \n> While the --no-verify= mechanism doesn't add a new option to the\n> git-commit interface but lets one refine the --no-verify option, users\n> might find it weird to have an argument to name disabled hooks but then\n> not be able to disable all hooks that way.\n\nRight, I think that is only worth doing if we add it uniformly for all\nhooks. I wonder if it should be a \"git\" option, not one to specific\ncommands. Like:\n\n  git --disable-hook=pre-commit commit ...\n\nand then the run_hook code can just respect the disabled list.\n\nI think a name like \"--disable-hook\" or your \"--bypass-hook\" is\nbetter than \"--no-verify\" here, too. Not all hooks are about verifying\n(I also think \"disable\" is better than \"bypass\" for that reason, too).\n\n> Since the hook selection wouldn't have to change, the options parsing\n> code seems to be simpler (--bypass-hook= would have to support several\n> occurrences with different arguments which could be implemented as an\n> OPT_CALLBACK?) and git-commit decided to have --no- options for hook\n> selection so far, I would lean towards your patch from above.\n\nYou'd probably implement --disable-hook with OPT_STRING_LIST (or just do\nit by hand if it's the git.c option parser). And then the\n--no-post-rewrite arguments remain for historical compatibility, and can\nbe implemented as synonyms for \"--disable-hook=post-rewrite\", etc.\n\nI think people have also asked for the ability to override hooks, too,\nthough I do not remember the exact details.  Instead of --disable-hook,\nwe could have an option for setting specific hooks (and setting them to\nnothing to disable would just be one possibility).\n\nThis is getting bigger in scope, though. I was trying not to derail you\ntoo much from your GSoC project, but see if we could just fix this one\nhacky corner easily.\n\n> Since all of the hook options are motivated by internal usage from\n> git-rebase, perhaps they should be configured as PARSE_OPT_HIDDEN. Any\n> thoughts on this?\n\nI could go either way. Just because they are motivated by git-rebase\ndoes not mean other callers might not find them useful (after all, git\ncommands are often meant to be scripted). As long as we promise to\nsupport them in future versions as we do with normal options, I do not\nthink there is any problem in advertising them.\n\nThat being said, \"git commit -h\" is already getting pretty long. It\nmight be worth cutting some seldom-used options from that list just to\nmake it more palatable to normal users.\n\n-Peff\n"},{"id":"247370","messageId":"20140806220125.GB23878@peff.net","threadId":"36962","inReplyTo":"53DFF965.8020808@gmail.com","subject":"Re: [PATCH v1 07/19] rebase -i: log the replay of root commits","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2014-08-06T22:01:25Z","receivedAt":"2014-08-06T22:01:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Aug 04, 2014 at 11:21:41PM +0200, Fabian Ruch wrote:\n\n> Thanks for laying out the differences in the user visible output. With\n> stock git we are seeing summaries for other commits, but not root\n> commits, _with the --verbose option_. It's the fault of my patch to show\n> the summary even in non-verbose mode. This is now fixed by wrapping the\n> relevant command in 'output', a shell function defined in git-rebase.sh\n> as follows:\n\nAh, OK. That makes a lot more sense, then.\n\n> > output=$(\"$@\" 2>&1 )\n> > status=$?\n> > test $status != 0 && printf \"%s\\n\" \"$output\"\n> > return $status\n> \n> The problem that git-rebase--interactive has is that the redirection of\n> stdin to a variable (or a file) does not work reliably with commands\n> that invoke the log message editor, that is 'reword' and 'squash'\n> produce their output both in verbose and non-verbose mode. I wouldn't\n> know how to fix this but\n> \n> 1) invoking $GIT_EDITOR from git-rebase--interactive.sh, but to make\n> this right there should be a built-in command for shell scripts and an\n> interface for git-commit that prepare the editor contents like\n> git-commit does now, or\n> \n> 2) forcing $GIT_EDITOR and git-commit to print on distinct file\n> descriptors, which would involve temporarily wrapping the $GIT_EDITOR\n> call in a shell script that redirects stdin to some other file\n> descriptor similar to what t/test-lib.sh does, or\n\nHmm. In the test scripts, we send stdout and stderr for sub-commands to\nfds 3 and 4 respectively. And then we either point those at /dev/null or\nto >&1 and >&2, depending on whether $verbose mode was specified.\n\nI don't think that will work here, though. You literally have one \"git\ncommit\" command to run, and you want its stderr/stdout to go somewhere\ndifferent than the $GIT_EDITOR it will invoke. Your (2) makes some sense\nto me. Something like:\n\n  GIT_EDITOR=\"$(shellquote \"$(git var GIT_EDITOR)\") >&3 2>&4\" \\\n    git commit ... 3>&1 4>&2 >wherever 2>&1\n\nOr we could just point it at /dev/tty, though I guess that may open\nanother can of worms (systems without /dev/tty, what happens when you do\nnot have a terminal, etc).\n\n> 3) passing the --quiet option in non-verbose mode and omitting it in\n> verbose mode, which would cover the '$status != 0' above for if a\n> command fails, it should indicate its error status despite being asked\n> to be silent.\n\nYeah, that is probably the cleanest option if it works. I would just\nworry that it is not as complete. It works for \"git commit\", but are\nthere are other commands wrapped in the verbose output that would want\nthe same treatment (that might not know about --quiet)? Your paragraph\nbelow says it would not be that big a deal, so as long as we don't plan\nto add anything in the future that could not handle the requirement,\nthat may be enough.\n\n-Peff\n"},{"id":"247380","messageId":"cover.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"53A258D2.7080806@gmail.com","subject":"[PATCH v2 00/23] Enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:07Z","receivedAt":"2014-08-06T23:59:07Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi List,\n\nthis is the second reroll of the patch series fixing corner-case bugs\nregarding empty commits, commits with no log message and root\ncommits, providing a uniform implementation of the to-do list\ncommands using the `do_pick` interface.\n\nThis reroll includes the following list of changes to PATCH v1 from\nlast week, mostly induced by Jeff's comments. However, I didn't get\naround the most recent discussion from tonight yet.\n\n - new tests: allow replaying commits with empty log messages\n     - coverage of all to-do list commands\n - new patch: allow squashing empty commits without complaints\n     - do not complain about an empty squash commit unless it is the\n       final one and --keep-empty is not specified on the command line\n - new tests: allow rewording empty commits without complaints\n     - coverage of all to-do list commands\n - new patch: hide interactive command messages in verbose mode\n     - make it possible to launch an editor inside 'output'\n - new patch: allow disabling pre-commit and commit-msg separately\n     - add options --no-pre-commit and --no-commit-msg to git-commit\n     - redefine --no-verify as synonym for the above two\n - new patch: squash skips commit-msg hook\n     - run commit-msg hook for reworded _and_ squashed commits\n - a change to 'test_commit' options and 'fake_editor' debug output\n\nThanks for your time and reviews,\n   Fabian\n\nFabian Ruch (23):\n  rebase -i: allow replaying commits with empty log messages\n  rebase -i: allow squashing empty commits without complaints\n  rebase -i: allow rewording empty commits without complaints\n  rebase -i: hide interactive command messages in verbose mode\n  rebase -i: failed reword prints redundant error message\n  commit: allow disabling pre-commit and commit-msg separately\n  rebase -i: squash skips commit-msg hook\n  rebase -i: reword executes pre-commit hook on interim commit\n  rebase -i: teach do_pick the option --edit\n  rebase -i: implement reword in terms of do_pick\n  rebase -i: log the replay of root commits\n  rebase -i: root commits are replayed with an unnecessary option\n  rebase -i: commit only once when rewriting picks\n  rebase -i: do not die in do_pick\n  rebase -i: teach do_pick the option --amend\n  rebase -i: teach do_pick the option --file\n  rebase -i: prepare for squash in terms of do_pick --amend\n  rebase -i: implement squash in terms of do_pick\n  rebase -i: explicitly distinguish replay commands and exec tasks\n  rebase -i: parse to-do list command line options\n  rebase -i: teach do_pick the option --reset-author\n  rebase -i: teach do_pick the option --signoff\n  rebase -i: enable options --signoff, --reset-author for pick, reword\n\n Documentation/git-commit.txt  |   8 +-\n builtin/commit.c              |  32 ++++-\n git-rebase--interactive.sh    | 288 ++++++++++++++++++++++++++++++++++--------\n git-rebase.sh                 |  12 +-\n t/lib-rebase.sh               |   8 +-\n t/t3404-rebase-interactive.sh | 234 ++++++++++++++++++++++++++++++++--\n t/t3406-rebase-message.sh     |  18 +++\n t/t3412-rebase-root.sh        |  16 +++\n t/t7503-pre-commit-hook.sh    |  65 ++++++++--\n t/t7504-commit-msg-hook.sh    |  85 ++++++++++---\n t/test-lib-functions.sh       |  23 +++-\n 11 files changed, 680 insertions(+), 109 deletions(-)\n\n-- \n2.0.1\n"},{"id":"247381","messageId":"ee69dc1067436877aec9df5ffb69a90bfb3f7066.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 01/23] rebase -i: allow replaying commits with empty log messages","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:08Z","receivedAt":"2014-08-06T23:59:08Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"git-rebase--interactive handles empty log messages inconsistently\nbetween enabled and disabled fast-forwards. By default, commits with\nempty log messages are rebased successfully like in non-interactive\nmode. In contrast, the `--no-ff` option aborts the replay of such\ncommits.\n\nIn line with not verifying rebased commits and behaving like\ngit-rebase for `pick` lines, use the `--allow-empty-message` option\nto replay commits. Root commits are replayed by recreating them in\n`do_pick` using git-commit and all other commits are replayed using\ngit-cherry-pick in `pick_one`. Apply the option, understood by both\ngit-commit and git-cherry-pick, at the respective sites.\n\nIn case of `reword` and `squash`, continue to abort the rebase if the\n_resulting_ commit would have no commit message. The rationale behind\nthis default is that patches and their log messages should be\nverified at least once. For unchanged commits this is assumed to have\nhappened according to the author's standards when she created the\ncommits for the first time. While the empty log message can always be\nkept in place by editing and resuming the aborted rebase, a debatable\nalternative could be to teach git-rebase--interactive the option\n`--allow-empty-message` for disabling complaints about empty log\nmessages even in changed commits.\n\nThe `fixup` case is different again because it throws away the second\ncommit's log message and uses the first log message for the changed\ncommit. Do not abort the rebase if that message is empty either since\nit is assumed to have been verified already.\n\nThe remaining to-do list command `edit` is handled just like `pick`\nfor this matter, because git-rebase--interactive replays the named\ncommit without changes before the rebase is interrupted and the user\ncan make her changes to the replayed commit.\n\nAdd tests. In particular, design the `squash`-specific test case such\nthat it involves interim commits and `fixup` steps. Interim commits\nshould not trigger failures themselves and `fixup` steps should not\nlet git-rebase--interactive forget that it is still dealing with a\n`squash` result.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 10 ++++++----\n t/t3404-rebase-interactive.sh | 38 ++++++++++++++++++++++++++++++++++++++\n t/t3412-rebase-root.sh        | 16 ++++++++++++++++\n 3 files changed, 60 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b64dd28..3222bf6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -249,7 +249,7 @@ pick_one () {\n \n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput eval git cherry-pick \\\n+\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\"$strategy_args\" $empty_args $ff \"$@\"\n }\n@@ -363,7 +363,7 @@ pick_one_preserving_merges () {\n \t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$rewritten_list\"\n \t\t\t;;\n \t\t*)\n-\t\t\toutput eval git cherry-pick \\\n+\t\t\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\t\"$strategy_args\" \"$@\" ||\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\n@@ -549,7 +549,8 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n+\t\t\tdo_with_author output git commit --allow-empty-message \\\n+\t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\t;;\n@@ -557,7 +558,8 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n+\t\t\t\tdo_with_author git commit --allow-empty-message \\\n+\t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8197ed2..9c71835 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -1039,4 +1039,42 @@ test_expect_success 'short SHA-1 collide' '\n \t)\n '\n \n+test_expect_success 'setup commits with empty commit log messages' '\n+\tgit checkout -b empty-log-messages master &&\n+\ttest_commit no-msg-commit-1 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_commit no-msg-commit-2 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_commit no-msg-commit-3 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null\n+'\n+\n+test_expect_success 'rebase commits with empty commit log messages' '\n+\tgit checkout -b rebase-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\ttest_expect_code 0 env FAKE_LINES=\"1\" git rebase -i master &&\n+\ttest_expect_code 0 env FAKE_LINES=\"1\" git rebase -i --no-ff master\n+'\n+\n+test_expect_success 'reword commits with empty commit log messages' '\n+\tgit checkout -b reword-empty-log-messages empty-log-messages &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n+test_expect_success 'squash commits with empty commit log messages' '\n+\tgit checkout -b squash-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2 fixup 3\" git rebase -i master &&\n+\tgit commit --allow-empty-message --amend &&\n+\tgit rebase --continue\n+'\n+\n+test_expect_success 'fixup commits with empty commit log messages' '\n+\tgit checkout -b fixup-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2\" git rebase -i master\n+'\n+\n test_done\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 0b52105..7add7a1 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -278,4 +278,20 @@ test_expect_success 'rebase -i -p --root with conflict (second part)' '\n \ttest_cmp expect-conflict-p out\n '\n \n+test_expect_success 'rebase --root root with empty log message' '\n+\tgit checkout --orphan empty-log-messages-root master &&\n+\ttest_commit no-msg-root-commit &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_expect_code 0 git rebase --root &&\n+\ttest_expect_code 0 git rebase --root --no-ff\n+'\n+\n+test_expect_success 'rebase --root commits with empty log messages' '\n+\tgit checkout -b empty-log-messages master &&\n+\ttest_commit no-msg-commit &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_expect_code 0 git rebase --root &&\n+\ttest_expect_code 0 git rebase --root --no-ff\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"247382","messageId":"16751a4402233b6c2925bf00d7ecebdccedd0eef.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:09Z","receivedAt":"2014-08-06T23:59:09Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list commands `squash` and `fixup` apply the changes\nintroduced by the named commit to the tree but instead of creating\na new commit on top of the current head it replaces the previous\ncommit with a new commit that records the updated tree. If the\nresult is an empty commit git-rebase stops with the error message\n\n   You asked to amend the most recent commit, but doing so would make\n   it empty. You can repeat your command with --allow-empty, or you can\n   remove the commit entirely with \"git reset HEAD^\".\n\nThis message is not very helpful because neither does git-rebase\nsupport an option `--allow-empty` nor does the messages say how to\nresume the rebase. Firstly, change the error message to\n\n   The squash result is empty and --keep-empty was not specified.\n\n   You can remove the squash commit now with\n\n     git reset HEAD^\n\n   Once you are down, run\n\n     git rebase --continue\n\nIf the user wishes to squash a sequence of commits into one\ncommit, f. i.\n\n   pick A\n   squash Revert \"A\"\n   squash A'\n\n, it does not matter for the end result that the first squash\nresult, or any sub-sequence in general, is going to be empty. The\nsquash message is not affected at all by which commits are created\nand only the commit created by the last line in the sequence will\nend up in the final history. Secondly, print the error message\nonly if the whole squash sequence produced an empty commit.\n\nLastly, since an empty squash commit is not a failure to rewrite\nthe history as planned, issue the message above as a mere warning\nand interrupt the rebase with the return value zero. The\ninterruption should be considered as a notification with the\nchance to undo it on the spot. Specifying the `--keep-empty`\noption tells git-rebase to keep empty squash commits in the\nrebased history without notification.\n\nAdd tests.\n\nReported-by: Peter Krefting <peter@softwolves.pp.se>\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\nHi,\n\nPeter Krefting is cc'd as the author of the bug report \"Confusing\nerror message in rebase when commit becomes empty\" discussed on the\nmailing list in June. Phil Hord and Jeff King both participated in\nthe problem discussion which ended with two proposals by Jeff.\n\nJeff King writes:\n>   1. Always keep such empty commits. A user who is surprised by them\n>      being empty can then revisit them. Or drop them by doing another\n>      rebase without --keep-empty.\n> \n>   2. Notice ourselves that the end-result of the whole squash is an\n>      empty commit, and stop to let the user deal with it.\n\nThis patch chooses the second alternative. Either way seems OK. The\ncrucial consensus of the discussion was to silently throw away empty\ninterim commits.\n\n   Fabian\n\n git-rebase--interactive.sh    | 20 +++++++++++---\n t/t3404-rebase-interactive.sh | 62 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 79 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 3222bf6..8820eac 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -549,7 +549,7 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_with_author output git commit --allow-empty-message \\\n+\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n@@ -558,18 +558,32 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --allow-empty-message \\\n+\t\t\t\tdo_with_author git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n+\t\t\tif test -z \"$keep_empty\" && is_empty_commit HEAD\n+\t\t\tthen\n+\t\t\t\techo \"$sha1\" >\"$state_dir\"/stopped-sha\n+\t\t\t\twarn \"The squash result is empty and --keep-empty was not specified.\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"You can remove the squash commit now with\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"  git reset HEAD^\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"Once you are down, run\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"  git rebase --continue\"\n+\t\t\t\texit 0\n+\t\t\tfi\n \t\t\t;;\n \t\tesac\n \t\trecord_in_rewritten $sha1\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9c71835..a95cb2a 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -237,6 +237,68 @@ test_expect_success 'retain authorship' '\n \tgit show HEAD | grep \"^Author: Twerp Snog\"\n '\n \n+test_expect_success 'setup squash/fixup reverted and fixed feature' '\n+\tgit checkout -b reverted-feature master &&\n+\ttest_commit feature &&\n+\tgit revert feature &&\n+\tgit checkout -b fixed-feature reverted-feature &&\n+\ttest_commit featurev2\n+'\n+\n+test_expect_success 'fixup fixed feature (empty interim commit)' '\n+\tgit checkout -b fixup-fixed-feature fixed-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code featurev2\n+'\n+\n+test_expect_success 'squash fixed feature (empty interim commit)' '\n+\tgit checkout -b squash-fixed-feature fixed-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code featurev2\n+'\n+\n+test_expect_success 'fixup reverted feature (empty final commit)' '\n+\tgit checkout -b fixup-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase -i master &&\n+\tgit reset HEAD^ &&\n+\tgit rebase --continue &&\n+\ttest_cmp_rev master HEAD\n+'\n+\n+test_expect_success 'squash reverted feature (empty final commit)' '\n+\tgit checkout -b squash-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase -i master &&\n+\tgit reset HEAD^ &&\n+\tgit rebase --continue &&\n+\ttest_cmp_rev master HEAD\n+'\n+\n+test_expect_success 'fixup reverted feature (empty final commit with --keep-empty)' '\n+\tgit checkout -b fixup-keep-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase -i --keep-empty master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code master\n+'\n+\n+test_expect_success 'squash reverted feature (empty final commit with --keep-empty)' '\n+\tgit checkout -b squash-keep-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase -i --keep-empty master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code master\n+'\n+\n test_expect_success 'squash' '\n \tgit reset --hard twerp &&\n \techo B > file7 &&\n-- \n2.0.1\n"},{"id":"247383","messageId":"1ca51649186b3c51d9d1d69fef7bfd43799349ef.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 03/23] rebase -i: allow rewording empty commits without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:10Z","receivedAt":"2014-08-06T23:59:10Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If `--keep-empty` is\npassed as option to git-rebase--interactive, empty commits ought to\nbe replayed without complaints. However, if the users chooses to\nreword an empty commit by changing the respective to-do list entry\nfrom\n\n    pick fa1afe1 Empty commit\n\nto\n\n    reword fa1afe1 Empty commit\n\n, then git-rebase--interactive suddenly fails to replay the empty\ncommit. This is especially counterintuitive because `reword` is\nthought of as a `pick` that alters the log message in some way but\nnothing more and the unchanged to-do list entry would not fail.\n\nHandle `reword` by cherry-picking the named commit and editing the\nlog message using\n\n    git commit --allow-empty --amend\n\ninstead of\n\n    git commit --amend.\n\nAdd test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 24 ++++++++++++++++++++++++\n 2 files changed, 25 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8820eac..89ef5e2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n \t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a95cb2a..3e64280 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,30 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+test_expect_success 'rebase --keep-empty (reword)' '\n+\tgit checkout -b reword-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 reword 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 6 actual\n+'\n+\n+test_expect_success 'rebase --keep-empty (fixup)' '\n+\tgit checkout -b fixup-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 5 actual\n+'\n+\n+test_expect_success 'rebase --keep-empty (squash)' '\n+\tgit checkout -b squash-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 5 actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.0.1\n"},{"id":"247384","messageId":"6d4f66b21315661e4f267f59341ebb798232a381.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:11Z","receivedAt":"2014-08-06T23:59:11Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"git-rebase--interactive prints summary messages of the commits it\ncreates in the final history only if the `--verbose` option is\nspecified by the user and suppresses them otherwise. This behaviour\nis implemented by wrapping git-commit calls in a shell function named\n`output` which redirects stderr to stdout, captures stdout in a shell\nvariable and ignores its contents unless the command exits with an\nerror status.\n\nThe command lines used to implement the to-do list commands `reword`\nand `squash` print diagnostic messages even in non-verbose mode. The\nreason for this inconsistency is that both commands launch the log\nmessage editor which usually requires a working terminal attached to\nstdin. Temporarily redirect the editor output to a third file\ndescriptor in order to ship it around the capture stream. Wrap the\nrespective git-commit command lines in `output`.\n\nfake_editor prints the to-do list before and after applying the\n`FAKE_LINES` rewrite rules to it. Redirect this debug output to\nstderr so that it does not interfere with the git-rebase status\noutput. Add test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  9 +++++----\n git-rebase.sh                 | 12 ++++++++++--\n t/lib-rebase.sh               |  8 ++++----\n t/t3404-rebase-interactive.sh | 18 ++++++------------\n t/t3406-rebase-message.sh     | 18 ++++++++++++++++++\n 5 files changed, 43 insertions(+), 22 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 89ef5e2..5dfdf13 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n \t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n@@ -558,14 +558,14 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --allow-empty-message --allow-empty \\\n+\t\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n@@ -923,6 +923,8 @@ EOF\n \t;;\n esac\n \n+mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n+\n git var GIT_COMMITTER_IDENT >/dev/null ||\n \tdie \"You need to set your committer info first\"\n \n@@ -938,7 +940,6 @@ then\n fi\n \n orig_head=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n-mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n \n : > \"$state_dir\"/interactive || die \"Could not mark as interactive\"\n write_basic_state\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 55da9db..f90541e 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -131,9 +131,17 @@ write_basic_state () {\n output () {\n \tcase \"$verbose\" in\n \t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n+\t\tcat >\"$state_dir\"/editor.sh <<EOF\n+#!/bin/sh\n+$(git var GIT_EDITOR) \"\\$@\" >&3\n+EOF\n+\t\tchmod +x \"$state_dir\"/editor.sh\n+\t\t(\n+\t\t\texport GIT_EDITOR=\\\"\"$state_dir\"/editor.sh\\\"\n+\t\t\t\"$@\" 3>&1 >\"$state_dir\"/output 2>&1\n+\t\t)\n \t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\ttest $status != 0 && cat \"$state_dir\"/output\n \t\treturn $status\n \t\t;;\n \t*)\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex 6bd2522..0cd1193 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -41,8 +41,8 @@ set_fake_editor () {\n \ttest -z \"$FAKE_LINES\" && exit\n \tgrep -v '^#' < \"$1\" > \"$1\".tmp\n \trm -f \"$1\"\n-\techo 'rebase -i script before editing:'\n-\tcat \"$1\".tmp\n+\techo 'rebase -i script before editing:' >&2\n+\tcat \"$1\".tmp >&2\n \taction=pick\n \tfor line in $FAKE_LINES; do\n \t\tcase $line in\n@@ -59,8 +59,8 @@ set_fake_editor () {\n \t\t\taction=pick;;\n \t\tesac\n \tdone\n-\techo 'rebase -i script after editing:'\n-\tcat \"$1\"\n+\techo 'rebase -i script after editing:' >&2\n+\tcat \"$1\" >&2\n \tEOF\n \n \ttest_set_editor \"$(pwd)/fake-editor.sh\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 3e64280..c6578c3 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -873,9 +873,8 @@ test_expect_success 'running \"git rebase -i --exec git show HEAD\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -887,9 +886,8 @@ test_expect_success 'running \"git rebase --exec git show HEAD -i\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -901,9 +899,8 @@ test_expect_success 'running \"git rebase -ix git show HEAD\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -915,9 +912,8 @@ test_expect_success 'rebase -ix with several <CMD>' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -930,9 +926,8 @@ test_expect_success 'rebase -ix with several instances of --exec' '\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD exec_pwd 2\n \t\t\t\texec_git_show_HEAD exec_pwd\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,11d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -956,9 +951,8 @@ test_expect_success 'rebase -ix with --autosquash' '\n \t\tgit checkout -b autosquash_expected &&\n \t\tFAKE_LINES=\"1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~4 >expect\n+\t\tgit rebase -i HEAD~4 >expected\n \t) &&\n-\tsed -e \"1,13d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \ndiff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\nindex 0392e36..d7003a9 100755\n--- a/t/t3406-rebase-message.sh\n+++ b/t/t3406-rebase-message.sh\n@@ -4,6 +4,8 @@ test_description='messages from rebase operation'\n \n . ./test-lib.sh\n \n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n test_expect_success 'setup' '\n \ttest_commit O fileO &&\n \ttest_commit X fileX &&\n@@ -84,4 +86,20 @@ test_expect_success 'rebase --onto outputs the invalid ref' '\n \ttest_i18ngrep \"invalid-ref\" err\n '\n \n+test_expect_success 'commit summary is suppressed in non-verbose mode' '\n+\tgit checkout --detach Y &&\n+\tcat >expected.out <<-EOF &&\n+\tRebasing (1/5)\\r\n+\tRebasing (2/5)\\r\n+\tRebasing (3/5)\\r\n+\tRebasing (4/5)\\r\n+\tRebasing (5/5)\\r\n+\tEOF\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"reword 1 fixup 2 fixup 3 4 squash 5\" \\\n+\tgit rebase -i --root >actual.out.tmp &&\n+\tsed -e \"s/\\r/\\\\\\\\r\\n/g\" <actual.out.tmp >actual.out &&\n+\ttest_cmp expected.out actual.out\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"247387","messageId":"452efde97c066275d6ed05b18a1fd79b475d3d6e.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 05/23] rebase -i: failed reword prints redundant error message","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:12Z","receivedAt":"2014-08-06T23:59:12Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If the edited log\nmessage is empty or is found ill-formatted by one of the commit\nhooks, git-rebase--interactive prints three error messages to the\nconsole.\n\n    1. The git-commit output, which contains all the output from hook\n       scripts.\n    2. A rebase diagnosis saying at which task on the to-do list it\n       got stuck.\n    3. Generic presumptions about what could have triggered the\n       error.\n\nThe third message contains redundant information and does not add any\nenlightenment either, which makes the output unnecessarily longish\nand different from the other command's output. For instance, this is\nwhat the output looks like if the log message is empty (contains\nduplicate Signed-off-by lines).\n\n    (1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by lines.)\n    (2.) Could not amend commit after successfully picking fa1afe1... Some change\n    (3.) This is most likely due to an empty commit message, or the pre-commit hook\n         failed. If the pre-commit hook failed, you may need to resolve the issue before\n         you are able to reword the commit.\n\nDiscard the third message.\n\nIt is true that a failed hook script might not output any diagnosis\nbut then the generic message is not of much help either. Since this\nlack of information affects the built-in git commands for commit,\nmerge and cherry-pick first, the solution would be to keep track of\nthe failed hooks in their output so that the user knows which of her\nhooks require improvement.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5dfdf13..3ee13c2 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -506,9 +506,6 @@ do_next () {\n \t\tdo_pick $sha1 \"$rest\"\n \t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n-\t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n-\t\t\twarn \"you are able to reword the commit.\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\n \t\trecord_in_rewritten $sha1\n-- \n2.0.1\n"},{"id":"247385","messageId":"7b3f91d5d079de10aebedcf6d6e7f43c0e7f1fce.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 06/23] commit: allow disabling pre-commit and commit-msg separately","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:13Z","receivedAt":"2014-08-06T23:59:13Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Introduce the git-commit command line options `--no-pre-commit` and\n`--no-commit-msg` to disable the pre-commit and commit-msg hooks,\nrespectively. Make `--no-verify` a synonym for specifying both at the\nsame time.\n\nThis change is motivated by an internal usage of git-commit in\ngit-rebase--interactive to disable pre-commit while keeping\ncommit-msg enabled when rewording a commit.\n\nMake `test_commit` forward unknown options to git-commit instead of\nteaching it all possible options. In order to support leading double\ndashes in `<message>`, stop interpreting `test_commit` arguments\nfollowing a `--` argument as options. This wasn't a problem before\nbecause the first unknown option would be used as `<message>`.\n\nAllow disabling tag creation to avoid name clashes when using\n`test_commit` with the same arguments several times from the same\ntest suite. By default, `test_commit` tags successful commits using\ngit-tag for easy reference. The `--notag` option skips this step.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n Documentation/git-commit.txt |  8 ++++-\n builtin/commit.c             | 32 ++++++++++++++---\n t/t7503-pre-commit-hook.sh   | 65 ++++++++++++++++++++++++++++-----\n t/t7504-commit-msg-hook.sh   | 85 ++++++++++++++++++++++++++++++++++----------\n t/test-lib-functions.sh      | 23 ++++++++----\n 5 files changed, 176 insertions(+), 37 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex 0bbc8f5..28a2c5c 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -158,7 +158,7 @@ OPTIONS\n \n -n::\n --no-verify::\n-\tThis option bypasses the pre-commit and commit-msg hooks.\n+\tA synonym for `--no-pre-commit --no-commit-msg`.\n \tSee also linkgit:githooks[5].\n \n --allow-empty::\n@@ -238,6 +238,12 @@ You should understand the implications of rewriting history if you\n amend a commit that has already been published.  (See the \"RECOVERING\n FROM UPSTREAM REBASE\" section in linkgit:git-rebase[1].)\n \n+--no-pre-commit::\n+\tThis option bypasses the pre-commit hook.\n+\n+--no-commit-msg::\n+\tThis option bypasses the commit-msg hook.\n+\n --no-post-rewrite::\n \tBypass the post-rewrite hook.\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 5ed6036..dfd354e 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -98,12 +98,27 @@ static char *edit_message, *use_message;\n static char *fixup_message, *squash_message;\n static int all, also, interactive, patch_interactive, only, amend, signoff;\n static int edit_flag = -1; /* unspecified */\n-static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n+static int quiet, verbose, allow_empty, dry_run, renew_authorship;\n static int no_post_rewrite, allow_empty_message;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n static char *sign_commit;\n \n /*\n+ * The verify variable is interpreted as a bitmap of enabled commit\n+ * verification hooks according to the legend below.\n+ *\n+ * By default, the pre-commit and commit-msg hooks are enabled. This\n+ * is represented by both the PRE_COMMIT and COMMIT_MSG bits being\n+ * set.\n+ *\n+ * The bitmap is changed through the command line options\n+ * --no-verify, --no-pre-commit and --no-commit-msg.\n+ */\n+#define PRE_COMMIT (1<<0)\n+#define COMMIT_MSG (1<<1)\n+static int verify = PRE_COMMIT | COMMIT_MSG;\n+\n+/*\n  * The default commit message cleanup mode will remove the lines\n  * beginning with # (shell comments) and leading and trailing\n  * whitespaces (empty lines or containing only whitespaces)\n@@ -661,7 +676,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t/* This checks and barfs if author is badly specified */\n \tdetermine_author_info(author_ident);\n \n-\tif (!no_verify && run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n+\tif (verify & PRE_COMMIT &&\n+\t    run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n \t\treturn 0;\n \n \tif (squash_message) {\n@@ -962,7 +978,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\t}\n \t}\n \n-\tif (!no_verify &&\n+\tif (verify & COMMIT_MSG &&\n \t    run_commit_hook(use_editor, index_file, \"commit-msg\", git_path(commit_editmsg), NULL)) {\n \t\treturn 0;\n \t}\n@@ -1590,7 +1606,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"interactive\", &interactive, N_(\"interactively add files\")),\n \t\tOPT_BOOL('p', \"patch\", &patch_interactive, N_(\"interactively add changes\")),\n \t\tOPT_BOOL('o', \"only\", &only, N_(\"commit only specified files\")),\n-\t\tOPT_BOOL('n', \"no-verify\", &no_verify, N_(\"bypass pre-commit hook\")),\n+\t\tOPT_NEGBIT('n', \"no-verify\", &verify,\n+\t\t\t   N_(\"synonym for --no-pre-commit --no-commit-msg\"),\n+\t\t\t   PRE_COMMIT | COMMIT_MSG),\n \t\tOPT_BOOL(0, \"dry-run\", &dry_run, N_(\"show what would be committed\")),\n \t\tOPT_SET_INT(0, \"short\", &status_format, N_(\"show status concisely\"),\n \t\t\t    STATUS_FORMAT_SHORT),\n@@ -1603,6 +1621,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL('z', \"null\", &s.null_termination,\n \t\t\t N_(\"terminate entries with NUL\")),\n \t\tOPT_BOOL(0, \"amend\", &amend, N_(\"amend previous commit\")),\n+\t\tOPT_NEGBIT(0, \"no-pre-commit\", &verify,\n+\t\t\t   N_(\"bypass pre-commit hook\"),\n+\t\t\t   PRE_COMMIT),\n+\t\tOPT_NEGBIT(0, \"no-commit-msg\", &verify,\n+\t\t\t   N_(\"bypass commit-msg hook\"),\n+\t\t\t   COMMIT_MSG),\n \t\tOPT_BOOL(0, \"no-post-rewrite\", &no_post_rewrite, N_(\"bypass post-rewrite hook\")),\n \t\t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, N_(\"mode\"), N_(\"show untracked files, optional modes: all, normal, no. (Default: all)\"), PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n \t\t/* end commit contents options */\ndiff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh\nindex 984889b..db5de1c 100755\n--- a/t/t7503-pre-commit-hook.sh\n+++ b/t/t7503-pre-commit-hook.sh\n@@ -12,11 +12,11 @@ test_expect_success 'with no hook' '\n \n '\n \n-test_expect_success '--no-verify with no hook' '\n+test_expect_success '--no-pre-commit with no hook' '\n \n \techo \"bar\" > file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"bar\"\n+\tgit commit --no-pre-commit -m \"bar\"\n \n '\n \n@@ -38,11 +38,11 @@ test_expect_success 'with succeeding hook' '\n \n '\n \n-test_expect_success '--no-verify with succeeding hook' '\n+test_expect_success '--no-pre-commit with succeeding hook' '\n \n \techo \"even more\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"even more\"\n+\tgit commit --no-pre-commit -m \"even more\"\n \n '\n \n@@ -60,11 +60,11 @@ test_expect_success 'with failing hook' '\n \n '\n \n-test_expect_success '--no-verify with failing hook' '\n+test_expect_success '--no-pre-commit with failing hook' '\n \n \techo \"stuff\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"stuff\"\n+\tgit commit --no-pre-commit -m \"stuff\"\n \n '\n \n@@ -77,15 +77,64 @@ test_expect_success POSIXPERM 'with non-executable hook' '\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n+test_expect_success POSIXPERM '--no-pre-commit with non-executable hook' '\n \n \techo \"more content\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"more content\"\n+\tgit commit --no-pre-commit -m \"more content\"\n \n '\n chmod +x \"$HOOK\"\n \n+test_hook_enabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing pre-commit hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\techo \"$output\" >expected.output &&\n+\ttest_must_fail test_commit $* file &&\n+\ttest_cmp expected.output actual.output\n+}\n+\n+test_hook_disabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing pre-commit hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\ttest_commit --notag $* file &&\n+\ttest_must_be_empty actual.output\n+}\n+\n+test_expect_success 'command line options combinations' '\n+\ttest_hook_enabled &&\n+\ttest_hook_enabled --pre-commit &&\n+\ttest_hook_enabled --no-pre-commit --pre-commit &&\n+\ttest_hook_enabled --no-verify --pre-commit &&\n+\ttest_hook_enabled --verify &&\n+\ttest_hook_enabled --no-pre-commit --verify &&\n+\ttest_hook_enabled --no-verify --verify &&\n+\ttest_hook_enabled --verify --no-commit-msg &&\n+\ttest_hook_enabled --verify --commit-msg &&\n+\ttest_hook_disabled --no-pre-commit &&\n+\ttest_hook_disabled --pre-commit --no-pre-commit &&\n+\ttest_hook_disabled --pre-commit --no-verify &&\n+\ttest_hook_disabled --no-verify &&\n+\ttest_hook_disabled --verify --no-pre-commit &&\n+\ttest_hook_disabled --verify --no-verify &&\n+\ttest_hook_disabled --no-verify --no-commit-msg &&\n+\ttest_hook_disabled --no-verify --commit-msg\n+'\n+\n # a hook that checks $GIT_PREFIX and succeeds inside the\n # success/ subdirectory only\n cat > \"$HOOK\" <<EOF\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex 1f53ea8..59642a3 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -34,20 +34,20 @@ test_expect_success 'with no hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with no hook' '\n+test_expect_success '--no-commit-msg with no hook' '\n \n \techo \"bar\" > file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"bar\"\n+\tgit commit --no-commit-msg -m \"bar\"\n \n '\n \n-test_expect_success '--no-verify with no hook (editor)' '\n+test_expect_success '--no-commit-msg with no hook (editor)' '\n \n \techo \"more bar\" > file &&\n \tgit add file &&\n \techo \"more bar\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -78,20 +78,20 @@ test_expect_success 'with succeeding hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with succeeding hook' '\n+test_expect_success '--no-commit-msg with succeeding hook' '\n \n \techo \"even more\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"even more\"\n+\tgit commit --no-commit-msg -m \"even more\"\n \n '\n \n-test_expect_success '--no-verify with succeeding hook (editor)' '\n+test_expect_success '--no-commit-msg with succeeding hook (editor)' '\n \n \techo \"even more more\" >> file &&\n \tgit add file &&\n \techo \"even more more\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -118,20 +118,20 @@ test_expect_success 'with failing hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with failing hook' '\n+test_expect_success '--no-commit-msg with failing hook' '\n \n \techo \"stuff\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"stuff\"\n+\tgit commit --no-commit-msg -m \"stuff\"\n \n '\n \n-test_expect_success '--no-verify with failing hook (editor)' '\n+test_expect_success '--no-commit-msg with failing hook (editor)' '\n \n \techo \"more stuff\" >> file &&\n \tgit add file &&\n \techo \"more stuff\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -153,23 +153,72 @@ test_expect_success POSIXPERM 'with non-executable hook (editor)' '\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n+test_expect_success POSIXPERM '--no-commit-msg with non-executable hook' '\n \n \techo \"more content\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"more content\"\n+\tgit commit --no-commit-msg -m \"more content\"\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook (editor)' '\n+test_expect_success POSIXPERM '--no-commit-msg with non-executable hook (editor)' '\n \n \techo \"even more content\" >> file &&\n \tgit add file &&\n \techo \"even more content\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n+test_hook_enabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing commit-msg hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\techo \"$output\" >expected.output &&\n+\ttest_must_fail test_commit $* file &&\n+\ttest_cmp expected.output actual.output\n+}\n+\n+test_hook_disabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing commit-msg hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\ttest_commit --notag $* file &&\n+\ttest_must_be_empty actual.output\n+}\n+\n+test_expect_success 'command line options combinations' '\n+\ttest_hook_enabled &&\n+\ttest_hook_enabled --commit-msg &&\n+\ttest_hook_enabled --no-commit-msg --commit-msg &&\n+\ttest_hook_enabled --no-verify --commit-msg &&\n+\ttest_hook_enabled --verify &&\n+\ttest_hook_enabled --no-commit-msg --verify &&\n+\ttest_hook_enabled --no-verify --verify &&\n+\ttest_hook_enabled --verify --no-pre-commit &&\n+\ttest_hook_enabled --verify --pre-commit &&\n+\ttest_hook_disabled --no-commit-msg &&\n+\ttest_hook_disabled --commit-msg --no-commit-msg &&\n+\ttest_hook_disabled --commit-msg --no-verify &&\n+\ttest_hook_disabled --no-verify &&\n+\ttest_hook_disabled --verify --no-commit-msg &&\n+\ttest_hook_disabled --verify --no-verify &&\n+\ttest_hook_disabled --no-verify --no-pre-commit &&\n+\ttest_hook_disabled --no-verify --pre-commit\n+'\n+\n # now a hook that edits the commit message\n cat > \"$HOOK\" <<'EOF'\n #!/bin/sh\n@@ -205,7 +254,7 @@ test_expect_success \"hook doesn't edit commit message\" '\n \n \techo \"plus\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"plus\" &&\n+\tgit commit --no-commit-msg -m \"plus\" &&\n \tcommit_msg_is \"plus\"\n \n '\n@@ -215,7 +264,7 @@ test_expect_success \"hook doesn't edit commit message (editor)\" '\n \techo \"more plus\" >> file &&\n \tgit add file &&\n \techo \"more plus\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify &&\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg &&\n \tcommit_msg_is \"more plus\"\n \n '\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex dafd6ad..a107073 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -154,20 +154,28 @@ test_pause () {\n \n test_commit () {\n \tnotick= &&\n-\tsignoff= &&\n+\tnotag= &&\n+\tcommit_opts= &&\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n \t\t--notick)\n \t\t\tnotick=yes\n \t\t\t;;\n-\t\t--signoff)\n-\t\t\tsignoff=\"$1\"\n+\t\t--notag)\n+\t\t\tnotag=yes\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift &&\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tcommit_opts=\"$commit_opts $1\"\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n \t\t\t;;\n-\t\tesac\n+\t\tesac &&\n \t\tshift\n \tdone &&\n \tfile=${2:-\"$1.t\"} &&\n@@ -177,8 +185,11 @@ test_commit () {\n \tthen\n \t\ttest_tick\n \tfi &&\n-\tgit commit $signoff -m \"$1\" &&\n-\tgit tag \"${4:-$1}\"\n+\tgit commit $commit_opts -m \"$1\" &&\n+\tif test -z \"$notag\"\n+\tthen\n+\t\tgit tag \"${4:-$1}\"\n+\tfi\n }\n \n # Call test_merge with the arguments \"<message> <commit>\", where <commit>\n-- \n2.0.1\n"},{"id":"247389","messageId":"116e93f11356f41d1c4726216d486eebca0f1e02.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 07/23] rebase -i: squash skips commit-msg hook","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:14Z","receivedAt":"2014-08-06T23:59:14Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Using the to-do list command `squash` the user can specify two or\nmore commits and git-rebase creates one commit that introduces all\ntheir changes combined. The authorship for the created commit is\ntaken from the first commit specified and the user can edit the log\nmessage. There is a variant of `squash` available named `fixup` which\nalso takes the first log message without asking for user input.\n\nWhile it is reasonable to not verify replayed changes twice or\nrejecting some other author's changes in her name, it is insufficient\nto not verify the user input used as log message in the case of\n`squash`. Specify the git-commit option `--commit-msg` when\ncommitting the squash result to execute the commit-msg hook and\nverify the new log message. For the same reasons the pre-commit hook\nis disabled in all replay modes, the commit-msg hook gets disabled in\n`fixup` mode.\n\nAdd tests. In addition to the existing test checking that the\npre-commit hook is disabled when simply picking a commit, provide a\ntest checking that the commit-msg hook is disabled as well.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 78 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 79 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 3ee13c2..97386aa 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -562,7 +562,7 @@ do_next () {\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex c6578c3..bc2dda1 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -655,6 +655,84 @@ test_expect_success 'rebase a commit violating pre-commit' '\n \n '\n \n+test_expect_success 'setup failing pre-commit' '\n+\tHOOKDIR=\"$(git rev-parse --git-dir)\"/hooks &&\n+\tmkdir -p \"$HOOKDIR\" &&\n+\tPRE_COMMIT=\"$HOOKDIR\"/pre-commit &&\n+\tcat >\"$PRE_COMMIT\" <<-EOF &&\n+\t#!/bin/sh\n+\techo running failing pre-commit...\n+\texit 1\n+\tEOF\n+\tchmod +x \"$PRE_COMMIT\" &&\n+\tgit checkout -b violating-pre-commit master &&\n+\ttest_must_fail test_commit pre-commit-violated-1 &&\n+\ttest_commit --no-verify pre-commit-violated-1 &&\n+\ttest_must_fail test_commit pre-commit-violated-2 &&\n+\ttest_commit --no-verify pre-commit-violated-2\n+'\n+\n+test_expect_success 'squash a commit violating pre-commit' '\n+\tgit checkout -b squash-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 squash 2\" git rebase -i master\n+'\n+\n+test_expect_success 'fixup a commit violating pre-commit' '\n+\tgit checkout -b fixup-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2\" git rebase -i master\n+'\n+\n+test_expect_success 'clean up failing pre-commit' '\n+\trm \"$PRE_COMMIT\"\n+'\n+\n+test_expect_success 'setup failing commit-msg' '\n+\tHOOKDIR=\"$(git rev-parse --git-dir)\"/hooks &&\n+\tmkdir -p \"$HOOKDIR\" &&\n+\tCOMMIT_MSG=\"$HOOKDIR\"/commit-msg &&\n+\tcat >\"$COMMIT_MSG\" <<-EOF &&\n+\t#!/bin/sh\n+\techo running failing commit-msg...\n+\texit 1\n+\tEOF\n+\tchmod +x \"$COMMIT_MSG\" &&\n+\tgit checkout -b violating-commit-msg master &&\n+\ttest_must_fail test_commit commit-msg-violated-1 &&\n+\ttest_commit --no-verify commit-msg-violated-1 &&\n+\ttest_must_fail test_commit commit-msg-violated-2 &&\n+\ttest_commit --no-verify commit-msg-violated-2 &&\n+\ttest_must_fail test_commit commit-msg-violated-3 &&\n+\ttest_commit --no-verify commit-msg-violated-3\n+'\n+\n+test_expect_success 'rebase a commit violating commit-msg' '\n+\tgit checkout -b rebase-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1\" git rebase -i master\n+'\n+\n+test_expect_success 'squash a commit violating commit-msg' '\n+\tgit checkout -b squash-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2 fixup 3\" git rebase -i master &&\n+\tgit commit --no-verify --amend &&\n+\tgit rebase --continue\n+'\n+\n+test_expect_success 'fixup a commit violating commit-msg' '\n+\tgit checkout -b fixup-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2\" git rebase -i master\n+'\n+\n+test_expect_success 'clean up failing commit-msg' '\n+\trm \"$COMMIT_MSG\"\n+'\n+\n test_expect_success 'rebase with a file named HEAD in worktree' '\n \n \trm -fr .git/hooks &&\n-- \n2.0.1\n"},{"id":"247386","messageId":"03febc7259c741a0891183bf578c93600ab0d68d.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:15Z","receivedAt":"2014-08-06T23:59:15Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. This happens in two\nsteps. Firstly, the named commit is cherry-picked. Secondly, the\ncommit created in the first step is amended using an unchanged index\nto edit the log message. The pre-commit hook is meant to verify the\nchanges introduced by a commit (for instance, catching inserted\ntrailing white space). Since the committed tree is not changed\nbetween the two steps and we do not verify rebased patches, do not\nexecute the pre-commit hook in the second step.\n\nSpecify the git-commit option `--no-pre-commit` to disable the\npre-commit hook when editing the log message. The commit-msg hook\nwill still be executed to verify the edited commit log message. As\nbefore, if the hook finds the new log message ill-formatted, the\nrebase will be interrupted with the unchanged commit replayed and the\nnew log message in `$GIT_DIR/COMMIT_EDITMSG`.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 14 ++++++++++++++\n 2 files changed, 15 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 97386aa..edc323d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex bc2dda1..3dac022 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -672,6 +672,13 @@ test_expect_success 'setup failing pre-commit' '\n \ttest_commit --no-verify pre-commit-violated-2\n '\n \n+test_expect_success 'reword a commit violating pre-commit' '\n+\tgit checkout -b reword-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n test_expect_success 'squash a commit violating pre-commit' '\n \tgit checkout -b squash-violating-pre-commit violating-pre-commit &&\n \ttest_when_finished reset_rebase &&\n@@ -715,6 +722,13 @@ test_expect_success 'rebase a commit violating commit-msg' '\n \tFAKE_LINES=\"1\" git rebase -i master\n '\n \n+test_expect_success 'reword a commit violating commit-msg' '\n+\tgit checkout -b reword-violating-commit-msg violating-commit-msg &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n test_expect_success 'squash a commit violating commit-msg' '\n \tgit checkout -b squash-violating-commit-msg violating-commit-msg &&\n \tset_fake_editor &&\n-- \n2.0.1\n"},{"id":"247388","messageId":"7b2e3963355a01519892205116570cbd96f20f5b.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 09/23] rebase -i: teach do_pick the option --edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:16Z","receivedAt":"2014-08-06T23:59:16Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`. To cater for\nthe different pick behaviours (like `reword`), `do_pick` accepts\nseveral options not only from the git-cherry-pick but also the\ngit-commit interface. Add the common option `--edit` to let the user\nedit the log message of the named commit.\n\nLoop over `$@` to parse the `do_pick` arguments. Assign the local\nvariable `edit` if one of the options is `--edit` so that the\nremainder of `do_pick` can easily check whether the client code asked\nto edit the commit message. If one of the options is unknown, mention\nit on the console and `die`. Break the loop on the first non-option\nand do some sanity checking to ensure that there exactly two\nnon-options, which are interpreted by the remainder as `<commit>` and\n`<title>` like before.\n\n`do_pick` ought to act as a wrapper around `cherry-pick`.\nUnfortunately, it cannot just forward `--edit` to the `cherry-pick`\ncommand line. The assembled command line is executed within a command\nsubstitution for controlling the verbosity of `rebase--interactive`.\nPassing `--edit` would either hang the terminal or clutter the\nsubstituted command output with control sequences. Execute the\n`reword` code from `do_next` instead if the option `--edit` is\nspecified.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 43 +++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex edc323d..aed2f93 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -461,7 +461,42 @@ record_in_rewritten() {\n \tesac\n }\n \n+# Apply the changes introduced by the given commit to the current head.\n+#\n+# do_pick [--edit] <commit> <title>\n+#\n+# Wrapper around git-cherry-pick.\n+#\n+# -e, --edit\n+#     After picking <commit>, open an editor and let the user edit the\n+#     commit message. The editor contents becomes the commit message of\n+#     the new head. This creates a fresh commit.\n+#\n+# <commit>\n+#     The commit to cherry-pick.\n+#\n+# <title>\n+#     The commit message title of <commit>. Used for information\n+#     purposes only.\n do_pick () {\n+\tedit=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-e|--edit)\n+\t\t\tedit=y\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n \t\t# Set the correct commit message and author info on the\n@@ -483,6 +518,14 @@ do_pick () {\n \t\tpick_one $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n+\n+\tif test -n \"$edit\"\n+\tthen\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n+\t\t\texit_with_patch $1 1\n+\t\t}\n+\tfi\n }\n \n do_next () {\n-- \n2.0.1\n"},{"id":"247403","messageId":"2cf01362ddacead66352229a232d8174e33bb82f.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 10/23] rebase -i: implement reword in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:17Z","receivedAt":"2014-08-06T23:59:17Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If one thinks of `pick`\nentries as scheduled `cherry-pick` command lines, then `reword`\nbecomes an alias for the command line `cherry-pick --edit`. The\nporcelain `rebase--interactive` defines a function `do_pick` for\nprocessing the `pick` entries on to-do lists. Reimplement `reword` in\nterms of `do_pick --edit`.\n\nIf the user picks a commit using the to-do list line\n\n    reword fa1afe1 Some change\n\nexecute the command `do_pick --edit fa1afe1 \"Some change\"` which\ncarries out exactly the same steps as the case arm for `reword` in\n`do_next` so far.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 6 +-----\n 1 file changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex aed2f93..8e1730c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -546,11 +546,7 @@ do_next () {\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\texit_with_patch $sha1 1\n-\t\t}\n+\t\tdo_pick --edit $sha1 \"$rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n-- \n2.0.1\n"},{"id":"247390","messageId":"2666e31872a679c1cc00c00fce542ce8be40fe09.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 11/23] rebase -i: log the replay of root commits","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:18Z","receivedAt":"2014-08-06T23:59:18Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the option\n`-q` which suppresses the commit summary message. However,\ngit-rebase--interactive tends to tell the user about the commits it\ncreates in the final history, if she wishes (cf. command line option\n`--verbose`). The code parts handling non-root commits and squash\ncommits all output commit summary messages. Do not make the replay of\nroot commits an exception. Remove the option to make the report of\nthe rebased history complete. Do not forget to wrap the git-commit\ncommand line in `output` so that the summary is shown if git-rebase\nis called with the `--verbose` option but suppressed otherwise.\n\nIt is OK that the commit summary is still suppressed when git-commit\nis used to initialize the authorship of the sentinel commit because\nthis additional commit is an implementation detail hidden from the\nfinal history. The removed `-q` option was probably introduced as a\ncopy-and-paste error stemming from that part of the root commit\nhandling code.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8e1730c..91ef0f7 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -510,8 +510,8 @@ do_pick () {\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n-\t\t\tgit commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n+\t\t\toutput git commit --allow-empty --allow-empty-message \\\n+\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"247402","messageId":"310132fa864bc7ec6d0268bb37dc1afbee7c8be8.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 12/23] rebase -i: root commits are replayed with an unnecessary option","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:19Z","receivedAt":"2014-08-06T23:59:19Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits uses `-C` to suppress\nthe log message editor. This is unnecessarily confusing, though,\nbecause that suppression is a secondary effect of the option. The\nmain purpose of `-C` is to pull the metadata from another commit, but\nhere we know that this is a noop, since we are amending a commit just\ncreated from the same data.\n\nAt the time `-C` was introduced, git-commit did not yet have a\ndocumented `--no-edit`, and this was a reasonable way to get the\ndesired behavior. Switch it to use `--no-edit` to make the intended\neffect more obvious.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 91ef0f7..71571c8 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\toutput git commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"247391","messageId":"eb8d96ee984a7e55a43ca0bcbdce74bea7f5e088.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 13/23] rebase -i: commit only once when rewriting picks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:20Z","receivedAt":"2014-08-06T23:59:20Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The options passed to `do_pick` determine whether the picked commit\nwill be rewritten or not. If the commit gets rewritten, because the\nuser requested to edit the commit message for instance, let\n`pick_one` merely apply the changes introduced by the commit and do\nnot commit the resulting tree yet. If the commit is replayed as is,\nleave it to `pick_one` to recreate the commit (possibly by\nfast-forwarding the head). This makes it easier to combine git-commit\noptions like `--edit` and `--amend` in `do_pick` because\ngit-cherry-pick does not support `--amend`.\n\nIn the case of `--edit`, do not `exit_with_patch` but assign\n`rewrite` to pick the changes with `-n`. If the pick conflicts, no\ncommit is created which we would have to amend when continuing the\nrebase. To complete the pick after the conflicts are resolved the\nuser just resumes with `git rebase --continue`.\n\ngit-commit lets the user edit the commit log message by default. We\ndo not want that for the rewriting git-commit command line because\nthe default behaviour of git-rebase is exactly the opposite. Pass\n`--no-edit` when rewriting a picked commit. An explicit `--edit`\npassed to `do_pick` (for instance, when reword is executed) enables\nthe editor launch again. Similarly, pass `--allow-empty-message`\nunless the log message is edited.\n\nIf `rebase--interactive` is used to rebase a complete branch onto\nsome head, `rebase` creates a sentinel commit that requires special\ntreatment by `do_pick`. Do not finalize the pick here either because\nits commit message can be altered as for any other pick. Since the\norphaned root commit gets a temporary parent, it is always rewritten.\nSafely use the rewrite infrastructure of `do_pick` to create the\nfinal commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 35 ++++++++++++++++++++++-------------\n 1 file changed, 22 insertions(+), 13 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 71571c8..b8c734e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -63,7 +63,8 @@ msgnum=\"$state_dir\"/msgnum\n author_script=\"$state_dir\"/author-script\n \n # When an \"edit\" rebase command is being processed, the SHA1 of the\n-# commit to be edited is recorded in this file.  When \"git rebase\n+# commit to be edited is recorded in this file.  The same happens when\n+# rewriting a commit fails, for instance \"reword\".  When \"git rebase\n # --continue\" is executed, if there are any staged changes then they\n # will be amended to the HEAD commit, but only provided the HEAD\n # commit is still the commit to be edited.  When any other rebase\n@@ -479,12 +480,17 @@ record_in_rewritten() {\n #     The commit message title of <commit>. Used for information\n #     purposes only.\n do_pick () {\n-\tedit=\n+\tallow_empty_message=y\n+\trewrite=\n+\trewrite_amend=\n+\trewrite_edit=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n \t\t-e|--edit)\n-\t\t\tedit=y\n+\t\t\trewrite=y\n+\t\t\trewrite_edit=y\n+\t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n \t\t\tdie \"do_pick: unrecognized option -- $1\"\n@@ -499,6 +505,10 @@ do_pick () {\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n+\t\trewrite=y\n+\t\trewrite_amend=y\n+\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\n \t\t# Set the correct commit message and author info on the\n \t\t# sentinel root before cherry-picking the original changes\n \t\t# without committing (-n).  Finally, update the sentinel again\n@@ -509,22 +519,21 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 &&\n-\t\t\toutput git commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n-\t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tpick_one -n $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-\t\tpick_one $1 ||\n+\t\tpick_one ${rewrite:+-n} $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n \n-\tif test -n \"$edit\"\n+\tif test -n \"$rewrite\"\n \tthen\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n-\t\t\texit_with_patch $1 1\n-\t\t}\n+\t\toutput git commit --allow-empty --no-post-rewrite -n --no-edit \\\n+\t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_amend:+--amend} \\\n+\t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n \tfi\n }\n \n-- \n2.0.1\n"},{"id":"247401","messageId":"2bd4cfaa20c582c9dd78d2ff917294e8250bf3b6.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 14/23] rebase -i: do not die in do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:21Z","receivedAt":"2014-08-06T23:59:21Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Since `do_pick` might be executed in a sub-shell (a modified author\nenvironment for instance), calling `die` in `do_pick` has no effect\nbut exiting the sub-shell with a failure exit status. The\ngit-rebase--interactive script is not terminated. Moreover, if\n`do_pick` is called while a squash or fixup is in effect,\n`die_with_patch` will discard `$squash_msg` as commit message.\nLastly, after a `die` in `do_pick` `do_next` has no chance to\nreschedule tasks that failed before changes could be applied.\n\nIndicate an error in `do_pick` using return statements and properly\nkill the script at the call sites. Although possible in principle,\nthe issued error messages are no more indicating whether `do_pick`\nfailed while applying or while committing the changes. This reduces\ncode complexity at the call site and does not matter from a user's\npoint of view because a glance at the index reveals whether there are\nconflicts or not and in-depth troubleshooting is still possible using\nthe `--verbose` option.\n\nRemove the commit message title argument from `do_pick`'s interface,\nwhich has become unused.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 34 +++++++++++++++++++---------------\n 1 file changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b8c734e..d812bad 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit> <title>\n+# do_pick [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -476,9 +476,11 @@ record_in_rewritten() {\n # <commit>\n #     The commit to cherry-pick.\n #\n-# <title>\n-#     The commit message title of <commit>. Used for information\n-#     purposes only.\n+# The return value is 1 if applying the changes resulted in a conflict\n+# and 2 if the specified arguments were incorrect. If the changes could\n+# be applied successfully but creating the commit failed, a value\n+# greater than 2 is returned. No commit is created in either case and\n+# the index is left with the (conflicting) changes in place.\n do_pick () {\n \tallow_empty_message=y\n \trewrite=\n@@ -493,7 +495,8 @@ do_pick () {\n \t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n-\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\twarn \"do_pick: unrecognized option -- $1\"\n+\t\t\treturn 2\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n@@ -501,7 +504,11 @@ do_pick () {\n \t\tesac\n \t\tshift\n \tdone\n-\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\tif test $# -ne 1\n+\tthen\n+\t\twarn \"do_pick: wrong number of arguments\"\n+\t\treturn 2\n+\tfi\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n@@ -519,11 +526,9 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\t\tpick_one -n $1 || return 1\n \telse\n-\t\tpick_one ${rewrite:+-n} $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n \tif test -n \"$rewrite\"\n@@ -532,8 +537,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n-\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n }\n \n@@ -548,21 +552,21 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 \"$rest\"\n+\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.1\n"},{"id":"247393","messageId":"6621ca6a43bda212653ba63e7ca0cbc1d5d3a3c5.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 15/23] rebase -i: teach do_pick the option --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:22Z","receivedAt":"2014-08-06T23:59:22Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list commands `pick`, `reword`\nand `edit`. To cater for the different pick behaviours (like\n`squash`), `do_pick` accepts several options not only from the\ngit-cherry-pick but also the git-commit interface.\n\nAdd the option `--amend` from the git-commit interface to the options\npool of `do_pick`. It creates a new commit for the changes introduced\nby the picked commit and the previous one. The previous commit is\nthen replaced with the new commit. If no other options are specified,\nthe log message of the previous commit is used.\n\nBe careful when `--amend` is used to pick a root commit because HEAD\nmight point to the sentinel commit but there is still nothing to\namend. Be sure to initialize `amend` so that commits are squashed\neven when git-rebase--interactive is interrupted for resolving\nconflicts. It is not a mistake to do the initialization regardless of\nany conflicts because `amend` is always cleared before the next to-do\nitem is processed.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 18 +++++++++++++++++-\n 1 file changed, 17 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d812bad..0871302 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,16 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit>\n+# do_pick [--amend] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --amend\n+#     After picking <commit>, replace the current head commit with a new\n+#     commit that also introduces the changes of <commit>.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -489,6 +495,16 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--amend)\n+\t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse -q --verify HEAD >/dev/null\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: nothing to amend\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_amend=y\n+\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n-- \n2.0.1\n"},{"id":"247394","messageId":"c5314115f5b9e32b38821dfff9c8549ee8d77e87.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 16/23] rebase -i: teach do_pick the option --file","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:23Z","receivedAt":"2014-08-06T23:59:23Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`, `reword` and\n`edit`. To cater for the different pick behaviours (like `squash`),\n`do_pick` accepts several options not only from the git-cherry-pick\nbut also the git-commit interface.\n\nAdd the option `--file` from the git-commit interface to the options\npool of `do_pick`. It expects an argument itself which is interpreted\nas a file path and takes the commit message from the given file. If\n`--file` is passed to `do_pick`, assign the given file path to the\nlocal variable `rewrite_message` and relay the option\n\n    --file \"$rewrite_message\"\n\nto the git-commit command line which creates the commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 20 +++++++++++++++++++-\n 1 file changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0871302..0fbf773 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--edit] <commit>\n+# do_pick [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -474,6 +474,12 @@ record_in_rewritten() {\n #\n #     _This is not a git-cherry-pick option._\n #\n+# -F <file>, --file <file>\n+#     Take the commit message from the given file. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -492,6 +498,7 @@ do_pick () {\n \trewrite=\n \trewrite_amend=\n \trewrite_edit=\n+\trewrite_message=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n@@ -505,6 +512,16 @@ do_pick () {\n \t\t\trewrite_amend=y\n \t\t\tgit rev-parse --verify HEAD >\"$amend\"\n \t\t\t;;\n+\t\t-F|--file)\n+\t\t\tif test $# -eq 0\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: option --file specified but no <file> given\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_message=$2\n+\t\t\tshift\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n@@ -553,6 +570,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n+\t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n }\n-- \n2.0.1\n"},{"id":"247396","messageId":"bddbbac363a5491168d48d184e5b584e33b063fa.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 17/23] rebase -i: prepare for squash in terms of do_pick --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:24Z","receivedAt":"2014-08-06T23:59:24Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Rewrite `squash` and `fixup` handling in `do_next` using the sequence\n\n    pick_one\n    commit\n\nin order to test the correctness of a single `do_squash` or\nparameterised `do_pick` and make the subsequent patch reimplementing\n`squash` in terms of such a single function more readable.\n\nDo not call `rm -f \"$GIT_DIR\"/MERGE_MSG` since it has no effect on\nthe state after git-rebase--interactive terminates. The option `-F`\nmakes git-commit ignore `MERGE_MSG` for the log message. If\ngit-commit succeeds, `MERGE_MSG` is removed, and if it fails,\n`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.\nIn summary, removing `MERGE_MSG` neither influences the squash commit\nmessage nor the file state after git-commit returns.\n\nMoreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch\n`$squash_msg` so that it is correct to execute `pick_one` immediately\nbefore git-commit.\n\nMight be squashed into the subsequent commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 21 +++++++++++++++------\n 1 file changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0fbf773..601a2ff 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -623,15 +623,15 @@ do_next () {\n \t\tauthor_script_content=$(get_author_ident_from_commit HEAD)\n \t\techo \"$author_script_content\" > \"$author_script\"\n \t\teval \"$author_script_content\"\n-\t\tif ! pick_one -n $sha1\n-\t\tthen\n-\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\tdie_failed_squash $sha1 \"$rest\"\n-\t\tfi\n \t\tcase \"$(peek_next_command)\" in\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n+\t\t\tif ! pick_one -n $sha1\n+\t\t\tthen\n+\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\tfi\n \t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n@@ -641,13 +641,22 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\tdo_with_author output git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n-- \n2.0.1\n"},{"id":"247392","messageId":"3d6a547c972c3ff057f6494e9e3f02cee5d7af4a.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 18/23] rebase -i: implement squash in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:25Z","receivedAt":"2014-08-06T23:59:25Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `squash` and its close relative `fixup` replay\nthe changes of a commit like `pick` but do not recreate the commit.\nInstead they replace the previous commit with a new commit that also\nintroduces the changes of the squashed commit. This is roughly like\ncherry-picking without committing and using git-commit to amend the\nprevious commit.\n\nThe to-do list\n\n    pick   a Some changes\n    squash b Some more changes\n\ngets translated into the sequence of git commands\n\n    git cherry-pick a\n    git cherry-pick -n b\n    git commit --amend\n\nand if git-cherry-pick supported `--amend` this would look even more\nlike the to-do list it is based on\n\n    git cherry-pick a\n    git cherry-pick --amend b.\n\nSince `do_pick` takes care of `pick` entries and the above suggests\n`squash` as an alias for `pick --amend`, reimplement `squash` in\nterms of `do_pick --amend`. Introduce `$squash_msg` as the commit\nmessage via the `--file` option. When the last commit of a squash\nseries is processed, the user is asked to review the log message.\nPass `--edit` as additional option in this case. The only difference\nin the options passed to git-commit and `do_pick` is the omitted\n`--no-verify`. However, `do_pick` does not execute the verification\nhooks anyway because it solely replays commits and assumes that they\nhave been verified before.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 32 ++++++--------------------------\n 1 file changed, 6 insertions(+), 26 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 601a2ff..29eca7e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -627,39 +627,19 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tif ! pick_one -n $sha1\n-\t\t\tthen\n-\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\tfi\n-\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n-\t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n-\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\tdo_with_author do_pick --amend -F \"$squash_msg\" $sha1 \\\n+\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\t;;\n \t\t*)\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n-\t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$fixup_msg\" $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_with_author do_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n \t\t\tif test -z \"$keep_empty\" && is_empty_commit HEAD\n-- \n2.0.1\n"},{"id":"247395","messageId":"d1ee1d61eb09a582a557acbed64d76287c168dda.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 19/23] rebase -i: explicitly distinguish replay commands and exec tasks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:26Z","receivedAt":"2014-08-06T23:59:26Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"There are two kinds of to-do list commands available. One kind\nreplays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that\nis) and the other executes a shell command (`exec`). We will call the\nfirst kind replay commands.\n\nThe two kinds of tasks are scheduled using different line formats.\nReplay commands expect a commit hash argument following the command\nname and exec concatenates all arguments to assemble a command line.\n\nAdhere to the distinction of formats by not trying to parse the\n`sha1` field unless we are dealing with a replay command. Move the\nreplay command handling code to a new function `do_replay` which\nassumes the first argument to be a commit hash and make no more such\nassumptions in `do_next`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 29eca7e..6ecd4d7 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -575,13 +575,12 @@ do_pick () {\n \tfi\n }\n \n-do_next () {\n-\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest < \"$todo\"\n+do_replay () {\n+\tcommand=$1\n+\tsha1=$2\n+\trest=$3\n+\n \tcase \"$command\" in\n-\t\"$comment_char\"*|''|noop)\n-\t\tmark_action_done\n-\t\t;;\n \tpick|p)\n \t\tcomment_for_reflog pick\n \n@@ -660,6 +659,28 @@ do_next () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\twarn \"Unknown command: $command\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+}\n+\n+do_next () {\n+\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\tread -r command sha1 rest <\"$todo\"\n+\n+\tcase \"$command\" in\n+\t\"$comment_char\"*|''|noop)\n+\t\tmark_action_done\n+\t\t;;\n \tx|\"exec\")\n \t\tread -r command rest < \"$todo\"\n \t\tmark_action_done\n@@ -699,14 +720,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\twarn \"Unknown command: $command $sha1 $rest\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n+\t\tdo_replay $command $sha1 \"$rest\"\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n-- \n2.0.1\n"},{"id":"247399","messageId":"8d01ff53a49647906c9008620435a62f08a1f76f.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 20/23] rebase -i: parse to-do list command line options","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:27Z","receivedAt":"2014-08-06T23:59:27Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Read in to-do list lines as\n\n    command args\n\ninstead of\n\n    command sha1 rest\n\nso that to-do list command lines can specify additional arguments\napart from the commit hash and the log message title, which become\nthe non-options in `args`. Loop over `args`, put all options (an\nargument beginning with a dash) in `opts`, stop the loop on the first\nnon-option and assign it to `sha1`. The loop does not know the\noptions it parses so that options that take an argument themselves\nare not supported at the moment. Neither are options that contain\nspaces because the shell expansion of `args` in `do_next` interprets\nwhite space characters as argument separator, that is a command line\nlike\n\n    pick --author \"A U Thor\" fa1afe1 Some change\n\nis parsed as the pick command\n\n    pick --author\n\nand the commit hash\n\n    \"A\n\nwhich obviously results in an unknown revision error. For the sake of\ncompleteness, in the example above the message title variable `rest`\nis assigned the string 'U Thor\" fa1afe1 Some change' (without the\nsingle quotes).\n\nPrint an error message for unknown or unsupported command line\noptions, which means an error for all specified options at the\nmoment. Cleanly break the `do_next` loop by assigning the special\nvalue 'unknown' to the local variable `command`, which triggers the\nunknown command case in `do_cmd`.\n\nThe to-do list is also parsed when the commit hashes are translated\nbetween long and short format before and after the to-do list is\nedited. Apply the same procedure as in `do_cmd` with the exception\nthat we only care about where the options stop and the commit hash\nbegins. Do not reject any options when transforming the commit\nhashes.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 49 ++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 41 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6ecd4d7..da435cb 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -577,8 +577,26 @@ do_pick () {\n \n do_replay () {\n \tcommand=$1\n-\tsha1=$2\n-\trest=$3\n+\tshift\n+\n+\topts=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-*)\n+\t\t\twarn \"Unknown option: $1\"\n+\t\t\tcommand=unknown\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\topts=\"$opts $(git rev-parse --sq-quote \"$1\")\"\n+\t\tshift\n+\tdone\n+\tsha1=$1\n+\tshift\n+\trest=$*\n \n \tcase \"$command\" in\n \tpick|p)\n@@ -675,7 +693,7 @@ do_replay () {\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest <\"$todo\"\n+\tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n \t\"$comment_char\"*|''|noop)\n@@ -720,7 +738,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\tdo_replay $command $sha1 \"$rest\"\n+\t\tdo_replay $command $args\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n@@ -800,19 +818,34 @@ skip_unnecessary_picks () {\n }\n \n transform_todo_ids () {\n-\twhile read -r command rest\n+\twhile read -r command args\n \tdo\n \t\tcase \"$command\" in\n \t\t\"$comment_char\"* | exec)\n \t\t\t# Be careful for oddball commands like 'exec'\n \t\t\t# that do not have a SHA-1 at the beginning of $rest.\n+\t\t\tnewargs=\\ $args\n \t\t\t;;\n \t\t*)\n-\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" ${rest%% *}) &&\n-\t\t\trest=\"$sha1 ${rest#* }\"\n+\t\t\tnewargs=\n+\t\t\tsha1=\n+\t\t\tfor arg in $args\n+\t\t\tdo\n+\t\t\t\tcase \"$arg\" in\n+\t\t\t\t-*)\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\ttest -z \"$sha1\" &&\n+\t\t\t\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" $arg) &&\n+\t\t\t\t\t\targ=$sha1\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone\n \t\t\t;;\n \t\tesac\n-\t\tprintf '%s\\n' \"$command${rest:+ }$rest\"\n+\t\tprintf '%s\\n' \"$command$newargs\"\n \tdone <\"$todo\" >\"$todo.new\" &&\n \tmv -f \"$todo.new\" \"$todo\"\n }\n-- \n2.0.1\n"},{"id":"247398","messageId":"cebc51133186e31f3d46edbbd42d60d61b5b6c7b.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 21/23] rebase -i: teach do_pick the option --reset-author","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:28Z","receivedAt":"2014-08-06T23:59:28Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement many of the to-do list commands.\nEventually, the complete `do_pick` interface will be exposed to the\nuser in some form or another and those commands will become simple\naliases for the `do_pick` options now used to implement them.\n\nAdd the git-commit option `--reset-author` to the options pool of\n`do_pick`. It rewrites the author date and name of the picked commit\nto match the committer date and name.\n\nIf `--reset-author` is passed to `do_pick`, set the `rewrite` flag\nand relay the option to the git-commit command line which creates the\nfinal commit. If `--amend` is not passed as well, the fresh\nauthorship effect is achieved by the mere fact that we are creating a\nnew commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 23 ++++++++++++++++++++++-\n 1 file changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex da435cb..d6c99ea 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,18 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --reset-author\n+#     Pretend the changes were made for the first time. Declare that the\n+#     authorship of the resulting commit now belongs to the committer.\n+#     This also renews the author timestamp. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # --amend\n #     After picking <commit>, replace the current head commit with a new\n #     commit that also introduces the changes of <commit>.\n@@ -502,6 +510,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--reset-author)\n+\t\t\trewrite=y\n+\t\t\trewrite_author=y\n+\t\t\t;;\n \t\t--amend)\n \t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse -q --verify HEAD >/dev/null\n \t\t\tthen\n@@ -564,6 +576,14 @@ do_pick () {\n \t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n+\tif test -n \"$rewrite_author\" && test -z \"$rewrite_amend\"\n+\tthen\n+\t\t# keep rewrite flag to create a new commit, rewrite\n+\t\t# without --reset-author though because it can only be\n+\t\t# used with -C, -c or --amend\n+\t\trewrite_author=\n+\tfi\n+\n \tif test -n \"$rewrite\"\n \tthen\n \t\toutput git commit --allow-empty --no-post-rewrite -n --no-edit \\\n@@ -571,6 +591,7 @@ do_pick () {\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n+\t\t\t   ${rewrite_author:+--reset-author} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n }\n-- \n2.0.1\n"},{"id":"247397","messageId":"334ed52a4b3a27944c9d616c087b15e31fa439d3.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 22/23] rebase -i: teach do_pick the option --signoff","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:29Z","receivedAt":"2014-08-06T23:59:29Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is currently used to implement most of the to-do list commands\nand offers additional options that will eventually find their way\nonto to-do lists.\n\nTo extend the repertoire of available options, add the git-commit and\ngit-cherry-pick option `--signoff` to the `do_pick` interface. It\nappends a Signed-off-by: line using the committer identity to the log\nmessage of the picked commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 12 +++++++++++-\n 1 file changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d6c99ea..a22459f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,15 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--signoff] [--reset-author] [--amend] [--file <file>]\n+#         [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# -s, --signoff\n+#     Insert a Signed-off-by: line using the committer identity at the\n+#     end of the commit log message. This creates a fresh commit.\n+#\n # --reset-author\n #     Pretend the changes were made for the first time. Declare that the\n #     authorship of the resulting commit now belongs to the committer.\n@@ -510,6 +515,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t-s|--signoff)\n+\t\t\trewrite=y\n+\t\t\trewrite_signoff=y\n+\t\t\t;;\n \t\t--reset-author)\n \t\t\trewrite=y\n \t\t\trewrite_author=y\n@@ -588,6 +597,7 @@ do_pick () {\n \tthen\n \t\toutput git commit --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_signoff:+--signoff} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n-- \n2.0.1\n"},{"id":"247400","messageId":"ed19a079924e11edac0163837500c2e8caa2a555.1407368621.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1407368621.git.bafain@gmail.com","subject":"[PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-06T23:59:30Z","receivedAt":"2014-08-06T23:59:30Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"pick and reword are atomic to-do list commands in the sense that they\nopen a new task which is closed after the respective command is\ncompleted. squash and fixup are not atomic. They create a new task\nwhich is not completed until the last squash or fixup is processed.\n\nLift the general unknown option blockade for the pick and reword\ncommands. If `do_cmd` comes across one of the options `--signoff` and\n`--reset-author` while parsing a to-do entry and the scheduled\ncommand is either `pick` or `reword`, relay the option to `do_pick`.\n\nThe `do_pick` options `--gpg-sign` and `--file` are not yet supported\nbecause `do_cmd` cannot handle option arguments and options with\nspaces at the moment. It is true that edit is one of the atomic\ncommands but it displays hash information when the rebase is stopped\nand some options rewrite the picked commit which alters that\ninformation. squash and fixup still do not accept user options as the\ninterplay of `--reset-author` and the author script are yet to be\ndetermined.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 19 ++++++++++++++++---\n 1 file changed, 16 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a22459f..4c05734 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -614,6 +614,16 @@ do_replay () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--signoff|--reset-author)\n+\t\t\tcase \"$command\" in\n+\t\t\tpick|reword)\n+\t\t\t\t;;\n+\t\t\t*)\n+\t\t\t\twarn \"Unsupported option: $1\"\n+\t\t\t\tcommand=unknown\n+\t\t\t\t;;\n+\t\t\tesac\n+\t\t\t;;\n \t\t-*)\n \t\t\twarn \"Unknown option: $1\"\n \t\t\tcommand=unknown\n@@ -634,21 +644,24 @@ do_replay () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick --edit $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\teval do_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.1\n"},{"id":"247404","messageId":"53E2C744.4040106@gmail.com","threadId":"36962","inReplyTo":"20140802002231.GD20040@peff.net","subject":"Re: [PATCH v1 09/19] rebase -i: commit only once when rewriting picks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-07T00:24:36Z","receivedAt":"2014-08-07T00:24:36Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Jeff,\n\nJeff King writes:\n> On Tue, Jul 29, 2014 at 01:18:09AM +0200, Fabian Ruch wrote:\n>> The options passed to `do_pick` determine whether the picked commit\n>> will be rewritten or not. If the commit gets rewritten, because the\n>> user requested to edit the commit message for instance, let\n>> `pick_one` merely apply the changes introduced by the commit and do\n>> not commit the resulting tree yet. If the commit is replayed as is,\n>> leave it to `pick_one` to recreate the commit (possibly by\n>> fast-forwarding the head). This makes it easier to combine git-commit\n>> options like `--edit` and `--amend` in `do_pick` because\n>> git-cherry-pick does not support `--amend`.\n>>\n>> In the case of `--edit`, do not `exit_with_patch` but assign\n>> `rewrite` to pick the changes with `-n`. If the pick conflicts, no\n>> commit is created which we would have to amend when continuing the\n>> rebase. To complete the pick after the conflicts are resolved the\n>> user just resumes with `git rebase --continue`.\n> \n> Hmm. So does this mean the user will actually see a different state\n> during such a conflict?\n> \n> E.g., if I have instructions like:\n> \n>   pick A\n>   squash B\n>   squash C\n> \n> and there is a conflict picking C, then what state do I see? Right now I\n> see a commit with the A+B squash prepared. But your description sounds\n> to me like we would avoid the squash for \"B\", and the user would see a\n> different state.\n\nThe squash state will not be different. squash sequences are still taken\ncare of one line after the other: committing A, committing A+B,\ncommitting A+B+C. If there is a conflict picking C, HEAD will point to\nA+B and the index will record the conflicting changes.\n\n> However, I couldn't trigger that behavior in a few experiments. Am I\n> misunderstanding, or is there some case where the user-visible state\n> will be different?\n\nThe user-visible state will be different for rewords. For instance,\nlet's consider\n\n    pick A\n    reword B.\n\nThe verbose log used to show two commits for B (with ff disabled), one\nafter picking and one after editing. Now the log will show a single\ncommit in connection with 'reword B' which might be less confusing.\n\nThanks for raising your eyebrows. I noticed now that the last paragraph\nis plainly wrong. The described amend situation did not arise \"if the\npick conflicted\" but \"if the edited commit did not verify\". There will\nbe no \"after the conflicts are resolved\" but the user can either commit\nmanually and circumvent log message verification if she knows what she's\ndoing, or provide a corrected log message in the editor launched by 'git\nrebase --continue'. The _incomplete_ 'git commit --amend' tip which used\nto be displayed after a failed verification hook could become\nunnecessary and this would possibly spare us including correct GPG sign\noptions for instance.\n\nHowever, this patch is mostly motivated by the unification of how\ncommits are rewritten. Before, rewords and squashes went about this\ndifferently, now both fail with an uncommitted index if there are\nconflicts or the log message is ill-formatted.\n\nThe log message must be corrected and the following bug, which was\nnoticed after PATCH v2, must be fixed.\n\n    cat >.git/hooks/commit-msg <<-EOF\n    #!/bin/sh\n    exit 1\n    EOF\n    chmod +x .git/hooks/commit-msg\n    test_must_fail env FAKE_LINES=\"reword 1\" git rebase -i\n    test_must_fail git rebase --continue\n    # the last command succeeds because --continue does not verify\n\n   Fabian\n"},{"id":"247409","messageId":"alpine.DEB.2.00.1408070814230.18704@ds9.cixit.se","threadId":"36962","inReplyTo":"16751a4402233b6c2925bf00d7ecebdccedd0eef.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints","fromName":"Peter Krefting","fromEmail":"peter@softwolves.pp.se","sentAt":"2014-08-07T07:16:23Z","receivedAt":"2014-08-07T07:16:23Z","isPatch":true,"sender":{"key":"peter@softwolves.pp.se","avatar":"https://avatars.githubusercontent.com/u/990764?v=4"},"body":"Fabian Ruch:\n\n>>   2. Notice ourselves that the end-result of the whole squash is an\n>>      empty commit, and stop to let the user deal with it.\n>\n> This patch chooses the second alternative. Either way seems OK. The \n> crucial consensus of the discussion was to silently throw away empty \n> interim commits.\n\nYes, the important part is that giving good advice is better than \ngiving bad advice. Thank you for taking your time to fix this.\n\nI haven't reviewed the changes themselves, but I am happy with the \nunderlying idea.\n\n-- \n\\\\// Peter - http://www.softwolves.pp.se/\n"},{"id":"247461","messageId":"CAPig+cSvLwcwZ_8R0nRYst9V9mfRqc-HMDhyrCoU6cxE254Agg@mail.gmail.com","threadId":"36962","inReplyTo":"16751a4402233b6c2925bf00d7ecebdccedd0eef.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2014-08-07T22:03:21Z","receivedAt":"2014-08-07T22:03:21Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Aug 6, 2014 at 7:59 PM, Fabian Ruch <bafain@gmail.com> wrote:\n> The to-do list commands `squash` and `fixup` apply the changes\n> introduced by the named commit to the tree but instead of creating\n> a new commit on top of the current head it replaces the previous\n> commit with a new commit that records the updated tree. If the\n> result is an empty commit git-rebase stops with the error message\n>\n>    You asked to amend the most recent commit, but doing so would make\n>    it empty. You can repeat your command with --allow-empty, or you can\n>    remove the commit entirely with \"git reset HEAD^\".\n>\n> This message is not very helpful because neither does git-rebase\n> support an option `--allow-empty` nor does the messages say how to\n> resume the rebase. Firstly, change the error message to\n>\n>    The squash result is empty and --keep-empty was not specified.\n>\n>    You can remove the squash commit now with\n>\n>      git reset HEAD^\n>\n>    Once you are down, run\n\nI guess you meant: s/down/done\n\nSame issue with the actually message in the code (below).\n\n>      git rebase --continue\n>\n> If the user wishes to squash a sequence of commits into one\n> commit, f. i.\n>\n>    pick A\n>    squash Revert \"A\"\n>    squash A'\n>\n> , it does not matter for the end result that the first squash\n> result, or any sub-sequence in general, is going to be empty. The\n> squash message is not affected at all by which commits are created\n> and only the commit created by the last line in the sequence will\n> end up in the final history. Secondly, print the error message\n> only if the whole squash sequence produced an empty commit.\n>\n> Lastly, since an empty squash commit is not a failure to rewrite\n> the history as planned, issue the message above as a mere warning\n> and interrupt the rebase with the return value zero. The\n> interruption should be considered as a notification with the\n> chance to undo it on the spot. Specifying the `--keep-empty`\n> option tells git-rebase to keep empty squash commits in the\n> rebased history without notification.\n>\n> Add tests.\n>\n> Reported-by: Peter Krefting <peter@softwolves.pp.se>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n> Hi,\n>\n> Peter Krefting is cc'd as the author of the bug report \"Confusing\n> error message in rebase when commit becomes empty\" discussed on the\n> mailing list in June. Phil Hord and Jeff King both participated in\n> the problem discussion which ended with two proposals by Jeff.\n>\n> Jeff King writes:\n>>   1. Always keep such empty commits. A user who is surprised by them\n>>      being empty can then revisit them. Or drop them by doing another\n>>      rebase without --keep-empty.\n>>\n>>   2. Notice ourselves that the end-result of the whole squash is an\n>>      empty commit, and stop to let the user deal with it.\n>\n> This patch chooses the second alternative. Either way seems OK. The\n> crucial consensus of the discussion was to silently throw away empty\n> interim commits.\n>\n>    Fabian\n>\n>  git-rebase--interactive.sh    | 20 +++++++++++---\n>  t/t3404-rebase-interactive.sh | 62 +++++++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 79 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 3222bf6..8820eac 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -549,7 +549,7 @@ do_next () {\n>                 squash|s|fixup|f)\n>                         # This is an intermediate commit; its message will only be\n>                         # used in case of trouble.  So use the long version:\n> -                       do_with_author output git commit --allow-empty-message \\\n> +                       do_with_author output git commit --allow-empty-message --allow-empty \\\n>                                 --amend --no-verify -F \"$squash_msg\" \\\n>                                 ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                 die_failed_squash $sha1 \"$rest\"\n> @@ -558,18 +558,32 @@ do_next () {\n>                         # This is the final command of this squash/fixup group\n>                         if test -f \"$fixup_msg\"\n>                         then\n> -                               do_with_author git commit --allow-empty-message \\\n> +                               do_with_author git commit --allow-empty-message --allow-empty \\\n>                                         --amend --no-verify -F \"$fixup_msg\" \\\n>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                         die_failed_squash $sha1 \"$rest\"\n>                         else\n>                                 cp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n>                                 rm -f \"$GIT_DIR\"/MERGE_MSG\n> -                               do_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n> +                               do_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                         die_failed_squash $sha1 \"$rest\"\n>                         fi\n>                         rm -f \"$squash_msg\" \"$fixup_msg\"\n> +                       if test -z \"$keep_empty\" && is_empty_commit HEAD\n> +                       then\n> +                               echo \"$sha1\" >\"$state_dir\"/stopped-sha\n> +                               warn \"The squash result is empty and --keep-empty was not specified.\"\n> +                               warn\n> +                               warn \"You can remove the squash commit now with\"\n> +                               warn\n> +                               warn \"  git reset HEAD^\"\n> +                               warn\n> +                               warn \"Once you are down, run\"\n\ns/down/done/\n\n> +                               warn\n> +                               warn \"  git rebase --continue\"\n> +                               exit 0\n> +                       fi\n>                         ;;\n>                 esac\n>                 record_in_rewritten $sha1\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index 9c71835..a95cb2a 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -237,6 +237,68 @@ test_expect_success 'retain authorship' '\n>         git show HEAD | grep \"^Author: Twerp Snog\"\n>  '\n>\n> +test_expect_success 'setup squash/fixup reverted and fixed feature' '\n> +       git checkout -b reverted-feature master &&\n> +       test_commit feature &&\n> +       git revert feature &&\n> +       git checkout -b fixed-feature reverted-feature &&\n> +       test_commit featurev2\n> +'\n> +\n> +test_expect_success 'fixup fixed feature (empty interim commit)' '\n> +       git checkout -b fixup-fixed-feature fixed-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code featurev2\n> +'\n> +\n> +test_expect_success 'squash fixed feature (empty interim commit)' '\n> +       git checkout -b squash-fixed-feature fixed-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code featurev2\n> +'\n> +\n> +test_expect_success 'fixup reverted feature (empty final commit)' '\n> +       git checkout -b fixup-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2\" git rebase -i master &&\n> +       git reset HEAD^ &&\n> +       git rebase --continue &&\n> +       test_cmp_rev master HEAD\n> +'\n> +\n> +test_expect_success 'squash reverted feature (empty final commit)' '\n> +       git checkout -b squash-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2\" git rebase -i master &&\n> +       git reset HEAD^ &&\n> +       git rebase --continue &&\n> +       test_cmp_rev master HEAD\n> +'\n> +\n> +test_expect_success 'fixup reverted feature (empty final commit with --keep-empty)' '\n> +       git checkout -b fixup-keep-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2\" git rebase -i --keep-empty master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code master\n> +'\n> +\n> +test_expect_success 'squash reverted feature (empty final commit with --keep-empty)' '\n> +       git checkout -b squash-keep-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2\" git rebase -i --keep-empty master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code master\n> +'\n> +\n>  test_expect_success 'squash' '\n>         git reset --hard twerp &&\n>         echo B > file7 &&\n> --\n> 2.0.1\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"},{"id":"247523","messageId":"87y4uyajd3.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"6d4f66b21315661e4f267f59341ebb798232a381.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-08T19:09:44Z","receivedAt":"2014-08-08T19:09:44Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> @@ -923,6 +923,8 @@ EOF\n>  \t;;\n>  esac\n>  \n> +mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n> +\n>  git var GIT_COMMITTER_IDENT >/dev/null ||\n>  \tdie \"You need to set your committer info first\"\n>  \n> @@ -938,7 +940,6 @@ then\n>  fi\n>  \n>  orig_head=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n> -mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n>  \n>  : > \"$state_dir\"/interactive || die \"Could not mark as interactive\"\n>  write_basic_state\n\nWhy this change?  I can't figure out how it relates to the output\nchange.\n\n> @@ -873,9 +873,8 @@ test_expect_success 'running \"git rebase -i --exec git show HEAD\"' '\n>  \t(\n>  \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n>  \t\texport FAKE_LINES &&\n> -\t\tgit rebase -i HEAD~2 >expect\n> +\t\tgit rebase -i HEAD~2 >expected\n>  \t) &&\n> -\tsed -e \"1,9d\" expect >expected &&\n>  \ttest_cmp expected actual\n>  '\n\nGetting rid of these magic removals is a very nice change, thank you.\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247524","messageId":"87wqaiajcs.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"03febc7259c741a0891183bf578c93600ab0d68d.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-08T19:09:55Z","receivedAt":"2014-08-08T19:09:55Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Subject: Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit\n\nI think the change makes sense, but can you reword the subjects that it\ndescribes the state after the commit (i.e. what you are doing), instead\nof before the commit?\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247525","messageId":"87vbq2ajcc.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"8d01ff53a49647906c9008620435a62f08a1f76f.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 20/23] rebase -i: parse to-do list command line options","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-08T19:10:11Z","receivedAt":"2014-08-08T19:10:11Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n[...]\n> are not supported at the moment. Neither are options that contain\n> spaces because the shell expansion of `args` in `do_next` interprets\n> white space characters as argument separator, that is a command line\n> like\n>\n>     pick --author \"A U Thor\" fa1afe1 Some change\n>\n> is parsed as the pick command\n>\n>     pick --author\n>\n> and the commit hash\n>\n>     \"A\n>\n> which obviously results in an unknown revision error. For the sake of\n> completeness, in the example above the message title variable `rest`\n> is assigned the string 'U Thor\" fa1afe1 Some change' (without the\n> single quotes).\n\nYou could probably trim down the non-example a bit and instead give an\nexample :-)\n\n> Print an error message for unknown or unsupported command line\n> options, which means an error for all specified options at the\n> moment.\n\nCan you add a test that verifies we catch an obvious unknown option\n(such as --unknown-option)?\n\n> Cleanly break the `do_next` loop by assigning the special\n> value 'unknown' to the local variable `command`, which triggers the\n> unknown command case in `do_cmd`.\n[...]\n>  do_replay () {\n>  \tcommand=$1\n> -\tsha1=$2\n> -\trest=$3\n> +\tshift\n> +\n> +\topts=\n> +\twhile test $# -gt 0\n> +\tdo\n> +\t\tcase \"$1\" in\n> +\t\t-*)\n> +\t\t\twarn \"Unknown option: $1\"\n> +\t\t\tcommand=unknown\n> +\t\t\t;;\n> +\t\t*)\n> +\t\t\tbreak\n> +\t\t\t;;\n\nThis seems a rather hacky solution to me.  Doesn't this now print\n\n  warning: Unknown option: --unknown-option\n  warning: Unknown command: pick --unknown-option\n\n?\n\nIt shouldn't claim the command is unknown if the command itself was\nvalid.\n\nAlso, you speak of do_cmd above, but the unknown command handling seems\nto be part of do_replay?\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247526","messageId":"87sil6ajbx.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"ed19a079924e11edac0163837500c2e8caa2a555.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-08T19:10:26Z","receivedAt":"2014-08-08T19:10:26Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> @@ -634,21 +644,24 @@ do_replay () {\n>  \t\tcomment_for_reflog pick\n>  \n>  \t\tmark_action_done\n> -\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n> +\t\teval do_pick $opts $sha1 \\\n> +\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n\nYou had me a little puzzled at the switch to 'eval' here.  That is\nnecessary to match the quoting added in 20/23, not for any change in\nthis commit.  This commit is simply the first one to trigger this.\nAlso, are you sure $sha1 does not require quoting through an eval?\n\n\nPlease add tests to this patch.\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247575","messageId":"53E86A5C.2050202@gmail.com","threadId":"36962","inReplyTo":"CAPig+cSvLwcwZ_8R0nRYst9V9mfRqc-HMDhyrCoU6cxE254Agg@mail.gmail.com","subject":"Re: [PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-11T07:01:48Z","receivedAt":"2014-08-11T07:01:48Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Eric,\n\nEric Sunshine writes:\n> On Wed, Aug 6, 2014 at 7:59 PM, Fabian Ruch <bafain@gmail.com> wrote:\n>> The to-do list commands `squash` and `fixup` apply the changes\n>> introduced by the named commit to the tree but instead of creating\n>> a new commit on top of the current head it replaces the previous\n>> commit with a new commit that records the updated tree. If the\n>> result is an empty commit git-rebase stops with the error message\n>>\n>>    You asked to amend the most recent commit, but doing so would make\n>>    it empty. You can repeat your command with --allow-empty, or you can\n>>    remove the commit entirely with \"git reset HEAD^\".\n>>\n>> This message is not very helpful because neither does git-rebase\n>> support an option `--allow-empty` nor does the messages say how to\n>> resume the rebase. Firstly, change the error message to\n>>\n>>    The squash result is empty and --keep-empty was not specified.\n>>\n>>    You can remove the squash commit now with\n>>\n>>      git reset HEAD^\n>>\n>>    Once you are down, run\n> \n> I guess you meant: s/down/done\n> \n> Same issue with the actually message in the code (below).\n\nFixed.\n\n>>      git rebase --continue\n>>\n>> If the user wishes to squash a sequence of commits into one\n>> commit, f. i.\n>>\n>>    pick A\n>>    squash Revert \"A\"\n>>    squash A'\n>>\n>> , it does not matter for the end result that the first squash\n>> result, or any sub-sequence in general, is going to be empty. The\n>> squash message is not affected at all by which commits are created\n>> and only the commit created by the last line in the sequence will\n>> end up in the final history. Secondly, print the error message\n>> only if the whole squash sequence produced an empty commit.\n>>\n>> Lastly, since an empty squash commit is not a failure to rewrite\n>> the history as planned, issue the message above as a mere warning\n>> and interrupt the rebase with the return value zero. The\n>> interruption should be considered as a notification with the\n>> chance to undo it on the spot. Specifying the `--keep-empty`\n>> option tells git-rebase to keep empty squash commits in the\n>> rebased history without notification.\n>>\n>> Add tests.\n>>\n>> Reported-by: Peter Krefting <peter@softwolves.pp.se>\n>> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n>> ---\n>> Hi,\n>>\n>> Peter Krefting is cc'd as the author of the bug report \"Confusing\n>> error message in rebase when commit becomes empty\" discussed on the\n>> mailing list in June. Phil Hord and Jeff King both participated in\n>> the problem discussion which ended with two proposals by Jeff.\n>>\n>> Jeff King writes:\n>>>   1. Always keep such empty commits. A user who is surprised by them\n>>>      being empty can then revisit them. Or drop them by doing another\n>>>      rebase without --keep-empty.\n>>>\n>>>   2. Notice ourselves that the end-result of the whole squash is an\n>>>      empty commit, and stop to let the user deal with it.\n>>\n>> This patch chooses the second alternative. Either way seems OK. The\n>> crucial consensus of the discussion was to silently throw away empty\n>> interim commits.\n>>\n>>    Fabian\n>>\n>>  git-rebase--interactive.sh    | 20 +++++++++++---\n>>  t/t3404-rebase-interactive.sh | 62 +++++++++++++++++++++++++++++++++++++++++++\n>>  2 files changed, 79 insertions(+), 3 deletions(-)\n>>\n>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>> index 3222bf6..8820eac 100644\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -549,7 +549,7 @@ do_next () {\n>>                 squash|s|fixup|f)\n>>                         # This is an intermediate commit; its message will only be\n>>                         # used in case of trouble.  So use the long version:\n>> -                       do_with_author output git commit --allow-empty-message \\\n>> +                       do_with_author output git commit --allow-empty-message --allow-empty \\\n>>                                 --amend --no-verify -F \"$squash_msg\" \\\n>>                                 ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>>                                 die_failed_squash $sha1 \"$rest\"\n>> @@ -558,18 +558,32 @@ do_next () {\n>>                         # This is the final command of this squash/fixup group\n>>                         if test -f \"$fixup_msg\"\n>>                         then\n>> -                               do_with_author git commit --allow-empty-message \\\n>> +                               do_with_author git commit --allow-empty-message --allow-empty \\\n>>                                         --amend --no-verify -F \"$fixup_msg\" \\\n>>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>>                                         die_failed_squash $sha1 \"$rest\"\n>>                         else\n>>                                 cp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n>>                                 rm -f \"$GIT_DIR\"/MERGE_MSG\n>> -                               do_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n>> +                               do_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n>>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>>                                         die_failed_squash $sha1 \"$rest\"\n>>                         fi\n>>                         rm -f \"$squash_msg\" \"$fixup_msg\"\n>> +                       if test -z \"$keep_empty\" && is_empty_commit HEAD\n>> +                       then\n>> +                               echo \"$sha1\" >\"$state_dir\"/stopped-sha\n>> +                               warn \"The squash result is empty and --keep-empty was not specified.\"\n>> +                               warn\n>> +                               warn \"You can remove the squash commit now with\"\n>> +                               warn\n>> +                               warn \"  git reset HEAD^\"\n>> +                               warn\n>> +                               warn \"Once you are down, run\"\n> \n> s/down/done/\n\nThanks for the thorough reading.\n\n   Fabian\n"},{"id":"247576","messageId":"53E87E47.9060007@gmail.com","threadId":"36962","inReplyTo":"87y4uyajd3.fsf@thomasrast.ch","subject":"Re: [PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-11T08:26:47Z","receivedAt":"2014-08-11T08:26:47Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Thomas,\n\nThomas Rast writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> @@ -923,6 +923,8 @@ EOF\n>>  \t;;\n>>  esac\n>>  \n>> +mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n>> +\n>>  git var GIT_COMMITTER_IDENT >/dev/null ||\n>>  \tdie \"You need to set your committer info first\"\n>>  \n>> @@ -938,7 +940,6 @@ then\n>>  fi\n>>  \n>>  orig_head=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n>> -mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n>>  \n>>  : > \"$state_dir\"/interactive || die \"Could not mark as interactive\"\n>>  write_basic_state\n> \n> Why this change?  I can't figure out how it relates to the output\n> change.\n\nCreating the state directory a few steps earlier into\n'git_rebase__interactive' is necessary because the changed definition of\n'output' needs it for 'editor.sh'. This change was triggered by a\nfailing test case that used the <branch> argument with git-rebase. The\n'git checkout <branch>', which is executed if 'switch_to' is set to\n<branch>, is wrapped into an 'output' line and 'output' failed because\nit wasn't able to create 'editor.sh'.\n\nThe state directory (of git-rebase--interactive!) is now created\ndirectly after the case expression that handles --continue, --skip and\n--edit-todo. They all assume the existence of the state directory and\neither jump into 'do_rest' or 'exit' immediately, that is creating the\ndirectory earlier would make the options handling code somewhat\nincorrect and would not change anything for the start sequence of\ngit-rebase--interactive.\n\nThe patch message now reads as follows (with the reference to 7725cb5 in\nthe second paragraph and the complete third paragraph added):\n\n> rebase -i: hide interactive command messages in verbose mode\n> \n> git-rebase--interactive prints summary messages of the commits it\n> creates in the final history only if the `--verbose` option is\n> specified by the user and suppresses them otherwise. This behaviour\n> is implemented by wrapping git-commit calls in a shell function named\n> `output` which redirects stderr to stdout, captures stdout in a shell\n> variable and ignores its contents unless the command exits with an\n> error status.\n> \n> The command lines used to implement the to-do list commands `reword`\n> and `squash` print diagnostic messages even in non-verbose mode. The\n> reason for this inconsistency is that both commands launch the log\n> message editor which usually requires a working terminal attached to\n> stdin. Wrapping the `reword` and `squash` command lines in `output`\n> would seemingly freeze the terminal (see commit 7725cb5, \"rebase -i:\n> fix reword when using a terminal editor\"). Temporarily redirect the\n> editor output to a third file descriptor in order to ship it around\n> the capture stream. Wrap the remaining git-commit command lines in\n> the new `output`.\n> \n> In order to temporarily redirect the editor output, the new\n> definition of `output` creates a script in the state directory to be\n> used as `GIT_EDITOR`. Make sure the state directory exists before\n> `output` is called for the first time.\n> \n> fake_editor prints the to-do list before and after applying the\n> `FAKE_LINES` rewrite rules to it. Redirect this debug output to\n> stderr so that it does not interfere with the git-rebase status\n> output. Add test.\n\n   Fabian\n"},{"id":"247577","messageId":"53E882B8.4070209@gmail.com","threadId":"36962","inReplyTo":"87wqaiajcs.fsf@thomasrast.ch","subject":"Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-11T08:45:44Z","receivedAt":"2014-08-11T08:45:44Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Thomas,\n\nThomas Rast writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> Subject: Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit\n> \n> I think the change makes sense, but can you reword the subjects that it\n> describes the state after the commit (i.e. what you are doing), instead\n> of before the commit?\n\nThe log message subject now reads as follows:\n\n> rebase -i: do not verify reworded patches using pre-commit\n\n   Fabian\n"},{"id":"247585","messageId":"87bnrqanu8.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"53E87E47.9060007@gmail.com","subject":"Re: [PATCH v2 04/23] rebase -i: hide interactive command messages in verbose mode","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-11T18:22:07Z","receivedAt":"2014-08-11T18:22:07Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Hi Thomas,\n>\n> Thomas Rast writes:\n>> Fabian Ruch <bafain@gmail.com> writes:\n>>> @@ -923,6 +923,8 @@ EOF\n>>>  \t;;\n>>>  esac\n>>>  \n>>> +mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n>>> +\n>>>  git var GIT_COMMITTER_IDENT >/dev/null ||\n>>>  \tdie \"You need to set your committer info first\"\n>>>  \n>>> @@ -938,7 +940,6 @@ then\n>>>  fi\n>>>  \n>>>  orig_head=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n>>> -mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n>>>  \n>>>  : > \"$state_dir\"/interactive || die \"Could not mark as interactive\"\n>>>  write_basic_state\n>> \n>> Why this change?  I can't figure out how it relates to the output\n>> change.\n>\n> Creating the state directory a few steps earlier into\n> 'git_rebase__interactive' is necessary because the changed definition of\n> 'output' needs it for 'editor.sh'. This change was triggered by a\n> failing test case that used the <branch> argument with git-rebase. The\n> 'git checkout <branch>', which is executed if 'switch_to' is set to\n> <branch>, is wrapped into an 'output' line and 'output' failed because\n> it wasn't able to create 'editor.sh'.\n[...]\n>> In order to temporarily redirect the editor output, the new\n>> definition of `output` creates a script in the state directory to be\n>> used as `GIT_EDITOR`. Make sure the state directory exists before\n>> `output` is called for the first time.\n\nAh, makes sense.  Thanks for the explanations!\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247586","messageId":"874mxiant0.fsf@thomasrast.ch","threadId":"36962","inReplyTo":"53E882B8.4070209@gmail.com","subject":"Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit hook on interim commit","fromName":"Thomas Rast","fromEmail":"tr@thomasrast.ch","sentAt":"2014-08-11T18:22:51Z","receivedAt":"2014-08-11T18:22:51Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Fabian Ruch <bafain@gmail.com> writes:\n\n> Hi Thomas,\n>\n> Thomas Rast writes:\n>> Fabian Ruch <bafain@gmail.com> writes:\n>>> Subject: Re: [PATCH v2 08/23] rebase -i: reword executes pre-commit\n>>> hook on interim commit\n>> \n>> I think the change makes sense, but can you reword the subjects that it\n>> describes the state after the commit (i.e. what you are doing), instead\n>> of before the commit?\n>\n> The log message subject now reads as follows:\n>\n>> rebase -i: do not verify reworded patches using pre-commit\n\nExcellent wording, thanks!\n\n-- \nThomas Rast\ntr@thomasrast.ch\n"},{"id":"247597","messageId":"53E92DFD.2050601@gmail.com","threadId":"36962","inReplyTo":"87vbq2ajcc.fsf@thomasrast.ch","subject":"Re: [PATCH v2 20/23] rebase -i: parse to-do list command line options","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-11T20:56:29Z","receivedAt":"2014-08-11T20:56:29Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Thomas,\n\nan updated patch is attached below.\n\nThomas Rast writes:> Fabian Ruch <bafain@gmail.com> writes:\n> [...]\n>> are not supported at the moment. Neither are options that contain\n>> spaces because the shell expansion of `args` in `do_next` interprets\n>> white space characters as argument separator, that is a command line\n>> like\n>>\n>>     pick --author \"A U Thor\" fa1afe1 Some change\n>>\n>> is parsed as the pick command\n>>\n>>     pick --author\n>>\n>> and the commit hash\n>>\n>>     \"A\n>>\n>> which obviously results in an unknown revision error. For the sake of\n>> completeness, in the example above the message title variable `rest`\n>> is assigned the string 'U Thor\" fa1afe1 Some change' (without the\n>> single quotes).\n> \n> You could probably trim down the non-example a bit and instead give an\n> example :-)\n\nDone. The example \"reword --signoff\" is substituted for the\nnon-example and used for an error message example as well. I hope\nthat is not confusing.\n\n>> Print an error message for unknown or unsupported command line\n>> options, which means an error for all specified options at the\n>> moment.\n> \n> Can you add a test that verifies we catch an obvious unknown option\n> (such as --unknown-option)?\n\nDone. The test checks that git-rebase--interactive fails to execute\n'pick --unknown-option' and that the rebase can be resumed after\nremoving the --unknown-option part.\n\n>> Cleanly break the `do_next` loop by assigning the special\n>> value 'unknown' to the local variable `command`, which triggers the\n>> unknown command case in `do_cmd`.\n> [...]\n>>  do_replay () {\n>>  \tcommand=$1\n>> -\tsha1=$2\n>> -\trest=$3\n>> +\tshift\n>> +\n>> +\topts=\n>> +\twhile test $# -gt 0\n>> +\tdo\n>> +\t\tcase \"$1\" in\n>> +\t\t-*)\n>> +\t\t\twarn \"Unknown option: $1\"\n>> +\t\t\tcommand=unknown\n>> +\t\t\t;;\n>> +\t\t*)\n>> +\t\t\tbreak\n>> +\t\t\t;;\n> \n> This seems a rather hacky solution to me.  Doesn't this now print\n> \n>   warning: Unknown option: --unknown-option\n>   warning: Unknown command: pick --unknown-option\n> \n> ?\n> \n> It shouldn't claim the command is unknown if the command itself was\n> valid.\n\nOK. \"do_replay\" now first checks for unknown commands and exits\nimmediately if that is the case, ignoring any options specified.\n\n> Also, you speak of do_cmd above, but the unknown command handling seems\n> to be part of do_replay?\n\nFixed.\n\n   Fabian\n\n-- >8 --\nSubject: rebase -i: parse to-do list command line options\n\nRead in to-do list lines as\n\n    command args\n\ninstead of\n\n    command sha1 rest\n\nso that to-do list command lines can specify additional arguments\napart from the commit hash and the log message title, which become\nthe non-options in `args`. Loop over `args`, put all options (an\nargument beginning with a dash) in `opts`, stop the loop on the first\nnon-option and assign it to `sha1`. For instance, the to-do list\n\n    reword --signoff fa1afe1 Some change\n\nis parsed as `command=reword`, `opts= '--signoff'` (including the\nsingle quotes and the space for evaluation and concatenation of\noptions), `sha1=fa1afel` and `rest=Some change`. The loop does not\nknow the options it parses so that options that take an argument\nthemselves are not supported at the moment. Neither are options that\ncontain spaces because the shell expansion of `args` in `do_next`\ninterprets white space characters as argument separator.\n\nPrint an error message for unknown or unsupported command line\noptions, which means an error for all specified options at the\nmoment. Cleanly break the `do_next` loop by assigning a reason to the\nlocal variable `malformed`, which triggers the unknown command code\nin `do_replay`. Move the error code to the beginning of `do_replay`\nso that unknown commands are reported before bad options are as only\nthe first error we come across is reported. For instance, the to-do\nlist from above produces the error\n\n    Unknown 'reword' option: --signoff\n    Please fix this using 'git rebase --edit-todo'.\n\nThe to-do list is also parsed when the commit hashes are translated\nbetween long and short format before and after the to-do list is\nedited. Apply the same procedure as in `do_replay` with the exception\nthat we only care about where the options stop and the commit hash\nbegins. Do not reject any options when transforming the commit\nhashes.\n\nEnable the specification of to-do list command line options in\n`FAKE_LINES` the same way this is accomplished for command lines\npassed to `exec`. Define a new `fake_editor.sh` that edits a static\nto-do list instead of the one passed as argument when invoked by\ngit-rebase. Add a test case that checks that unknown options are\nrefused and can be corrected using `--edit-todo`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh     | 80 ++++++++++++++++++++++++++++++++----------\n t/lib-rebase.sh                | 20 +++++++++--\n t/t3427-rebase-line-options.sh | 26 ++++++++++++++\n 3 files changed, 105 insertions(+), 21 deletions(-)\n create mode 100755 t/t3427-rebase-line-options.sh\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 344d2cc..20636da 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -576,9 +576,47 @@ do_pick () {\n }\n \n do_replay () {\n+\tmalformed=\n \tcommand=$1\n-\tsha1=$2\n-\trest=$3\n+\tshift\n+\tcase \"$command\" in\n+\tpick|reword|edit|squash|fixup)\n+\t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\tmalformed=\"Unknown command: $command\"\n+\t\t;;\n+\tesac\n+\n+\topts=\n+\twhile test $# -gt 0 && test -z \"$malformed\"\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-*)\n+\t\t\tmalformed=\"Unknown '$command' option: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\topts=\"$opts $(git rev-parse --sq-quote \"$1\")\"\n+\t\tshift\n+\tdone\n+\tsha1=$1\n+\tshift\n+\trest=$*\n+\n+\tif test -n \"$malformed\"\n+\tthen\n+\t\twarn \"$malformed\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\tfi\n \n \tcase \"$command\" in\n \tpick|p)\n@@ -659,23 +697,12 @@ do_replay () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n-\t*)\n-\t\tread -r command <\"$todo\"\n-\t\twarn \"Unknown command: $command\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n-\t\t;;\n \tesac\n }\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest <\"$todo\"\n+\tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n \t\"$comment_char\"*|''|noop)\n@@ -720,7 +747,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\tdo_replay $command $sha1 \"$rest\"\n+\t\tdo_replay $command $args\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n@@ -800,19 +827,34 @@ skip_unnecessary_picks () {\n }\n \n transform_todo_ids () {\n-\twhile read -r command rest\n+\twhile read -r command args\n \tdo\n \t\tcase \"$command\" in\n \t\t\"$comment_char\"* | exec)\n \t\t\t# Be careful for oddball commands like 'exec'\n \t\t\t# that do not have a SHA-1 at the beginning of $rest.\n+\t\t\tnewargs=\\ $args\n \t\t\t;;\n \t\t*)\n-\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" ${rest%% *}) &&\n-\t\t\trest=\"$sha1 ${rest#* }\"\n+\t\t\tnewargs=\n+\t\t\tsha1=\n+\t\t\tfor arg in $args\n+\t\t\tdo\n+\t\t\t\tcase \"$arg\" in\n+\t\t\t\t-*)\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\ttest -z \"$sha1\" &&\n+\t\t\t\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" $arg) &&\n+\t\t\t\t\t\targ=$sha1\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone\n \t\t\t;;\n \t\tesac\n-\t\tprintf '%s\\n' \"$command${rest:+ }$rest\"\n+\t\tprintf '%s\\n' \"$command$newargs\"\n \tdone <\"$todo\" >\"$todo.new\" &&\n \tmv -f \"$todo.new\" \"$todo\"\n }\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex 0cd1193..104f5bd 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -46,8 +46,8 @@ set_fake_editor () {\n \taction=pick\n \tfor line in $FAKE_LINES; do\n \t\tcase $line in\n-\t\tsquash|fixup|edit|reword)\n-\t\t\taction=\"$line\";;\n+\t\tpick*|squash*|fixup*|edit*|reword*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\texec*)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n \t\t\"#\")\n@@ -80,6 +80,22 @@ set_cat_todo_editor () {\n \ttest_set_editor \"$(pwd)/fake-editor.sh\"\n }\n \n+# set_fixed_todo_editor takes a file path as argument and installs an\n+# editor script that, firstly, overwrites the file path argument with\n+# the one specified during installation and, secondly, calls\n+# fake-editor.sh for changing the contents as usual. This comes in\n+# handy if it is easier to change some fixed file instead of the one\n+# that will be passed when the editor is being invoked.\n+\n+set_fixed_todo_editor () {\n+\tset_fake_editor\n+\twrite_script fake-editor-wrapper.sh <<-EOF\n+\tcp \"$1\" \"\\$1\"\n+\t\"$(pwd)\"/fake-editor.sh \"\\$1\"\n+\tEOF\n+\ttest_set_editor \"$(pwd)/fake-editor-wrapper.sh\"\n+}\n+\n # checks that the revisions in \"$2\" represent a linear range with the\n # subjects in \"$1\"\n test_linear_range () {\ndiff --git a/t/t3427-rebase-line-options.sh b/t/t3427-rebase-line-options.sh\nnew file mode 100755\nindex 0000000..5881162\n--- /dev/null\n+++ b/t/t3427-rebase-line-options.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+test_description='git rebase -i with line options'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'Set up repository' '\n+\ttest_commit Initial &&\n+\ttest_commit Commit1 &&\n+\ttest_commit Commit2\n+'\n+\n+test_expect_success 'Unknown option' '\n+\tgit checkout -b unknown-option master &&\n+\tset_cat_todo_editor &&\n+\ttest_must_fail git rebase -i HEAD^ >todo &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 pick_--unknown-option 2\" git rebase -i HEAD~2 &&\n+\tset_fixed_todo_editor \"$(pwd)\"/todo &&\n+\tgit rebase --edit-todo &&\n+\tgit rebase --continue\n+'\n+\n+test_done\n-- \n2.0.1\n"},{"id":"247622","messageId":"53EA814C.2050802@gmail.com","threadId":"36962","inReplyTo":"87sil6ajbx.fsf@thomasrast.ch","subject":"Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-12T21:04:12Z","receivedAt":"2014-08-12T21:04:12Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Thomas,\n\nThomas Rast writes:\n> Fabian Ruch <bafain@gmail.com> writes:\n>> @@ -634,21 +644,24 @@ do_replay () {\n>>  \t\tcomment_for_reflog pick\n>>  \n>>  \t\tmark_action_done\n>> -\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n>> +\t\teval do_pick $opts $sha1 \\\n>> +\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n> \n> You had me a little puzzled at the switch to 'eval' here.  That is\n> necessary to match the quoting added in 20/23, not for any change in\n> this commit.  This commit is simply the first one to trigger this.\n\nThis patch switches to 'eval' here because it is the first time\n'opts' occurs. However, I agree that it might be confusing that\n'opts' wasn't already added to the 'do_pick' lines by 20/23. By\n\"trigger\" you mean that this commit is the first to actually fill\n'opts' with contents? I will move these changes to 20/23 then.\n\n> Also, are you sure $sha1 does not require quoting through an eval?\n\nAt least if we can assume that it is really a SHA-1 object name. As\nsuch it does not contain characters interpreted by the shell, like\nbackslashes, quotes or whitespace.\n\n> Please add tests to this patch.\n\nThe ones I had in mind are attached below the scissors line. The\ncurrent reroll fails the authorship checks and the 'git rebase\n--continue' test cases. As the necessary changes would obfuscate this\nsub-thread, they will be included in the next reroll.\n\n   Fabian\n\n-- >8 --\ndiff --git a/t/t3427-rebase-line-options.sh b/t/t3427-rebase-line-options.sh\nindex 5881162..a5a9e66 100755\n--- a/t/t3427-rebase-line-options.sh\n+++ b/t/t3427-rebase-line-options.sh\n@@ -6,10 +6,32 @@ test_description='git rebase -i with line options'\n \n . \"$TEST_DIRECTORY\"/lib-rebase.sh\n \n+commit_message () {\n+\tgit cat-file commit \"$1\" | sed '1,/^$/d'\n+}\n+\n+commit_authorship () {\n+\tgit cat-file commit \"$1\" | sed -n '/^$/q;/^author /p'\n+}\n+\n+authorship () {\n+\techo \"author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE\"\n+}\n+\n+test_diff_file () {\n+\tif cmp \"$1\" \"$2\" >/dev/null\n+\tthen\n+\t\techo \"'$1' and '$2' are the same\"\n+\t\treturn 1\n+\tfi\n+}\n+\n test_expect_success 'Set up repository' '\n \ttest_commit Initial &&\n \ttest_commit Commit1 &&\n-\ttest_commit Commit2\n+\ttest_commit Commit2 &&\n+\tgit checkout -b branch Commit1 &&\n+\ttest_commit Commit2_ Commit2.t\n '\n \n test_expect_success 'Unknown option' '\n@@ -23,4 +45,137 @@ test_expect_success 'Unknown option' '\n \tgit rebase --continue\n '\n \n+test_msg_author () {\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 $1 2\" git rebase -i HEAD~2 &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_msg_author_misspelled () {\n+\tset_cat_todo_editor &&\n+\ttest_must_fail git rebase -i HEAD^ >todo &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 $1-misspelled 2\" git rebase -i HEAD~2 &&\n+\tset_fixed_todo_editor \"$(pwd)\"/todo &&\n+\tFAKE_LINES=\"$1 1\" git rebase --edit-todo &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_msg_author_conflicted () {\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"$1 1\" git rebase -i master &&\n+\tgit checkout --theirs Commit2.t &&\n+\tgit add Commit2.t &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_expect_success 'Misspelled pick --signoff' '\n+\tgit checkout -b misspelled-pick--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author_misspelled pick_--signoff\n+'\n+\n+test_expect_success 'Conflicted pick --signoff' '\n+\tgit checkout -b conflicted-pick--signoff branch &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author_conflicted pick_--signoff\n+'\n+\n+test_expect_success 'pick --signoff' '\n+\tgit checkout -b pick--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author pick_--signoff\n+'\n+\n+test_expect_success 'reword --signoff' '\n+\tgit checkout -b reword--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author reword_--signoff\n+'\n+\n+test_expect_success 'Misspelled pick --reset-author' '\n+\tgit checkout -b misspelled-pick--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author_misspelled pick_--reset-author\n+'\n+\n+test_expect_success 'Conflicted pick --reset-author' '\n+\tgit checkout -b conflicted-pick--reset-author branch &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author_conflicted pick_--reset-author\n+'\n+\n+test_expect_success 'pick --reset-author' '\n+\tgit checkout -b pick--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author pick_--reset-author\n+'\n+\n+test_expect_success 'pick --reset-author --signoff' '\n+\tgit checkout -b pick--reset-author--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author pick_--reset-author_--signoff\n+'\n+\n+test_expect_success 'reword --reset-author' '\n+\tgit checkout -b reword--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author reword_--reset-author\n+'\n+\n test_done\n"},{"id":"247663","messageId":"53EB5E77.8010005@alum.mit.edu","threadId":"36962","inReplyTo":"ed19a079924e11edac0163837500c2e8caa2a555.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2014-08-13T12:47:51Z","receivedAt":"2014-08-13T12:47:51Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 08/07/2014 01:59 AM, Fabian Ruch wrote:\n> pick and reword are atomic to-do list commands in the sense that they\n> open a new task which is closed after the respective command is\n> completed. squash and fixup are not atomic. They create a new task\n> which is not completed until the last squash or fixup is processed.\n\nI don't understand the distinction that you are attempting to draw\nbetween \"atomic\" and \"non-atomic\" commands.  For example, in the\nfollowing command list:\n\n    pick 1111111\n    squash 2222222\n    fixup 3333333\n\nthe \"pick\" command doesn't seem very atomic, because the *end* result of\nthe three commands is a single commit that is affected by all three\ncommands.  Furthermore, if we change the example to\n\n    pick 1111111\n    squash --reset-author 2222222\n    fixup --signoff 3333333\n\nthen isn't it clear that the user's intention was to apply both options,\n\"--reset-author\" and \"--signoff\", to the resulting commit?  In other\nwords, it seems to me that any options on such a chain of lines should\nbe collected and applied to the final commit as a whole.\n\n> Lift the general unknown option blockade for the pick and reword\n> commands. If `do_cmd` comes across one of the options `--signoff` and\n> `--reset-author` while parsing a to-do entry and the scheduled\n> command is either `pick` or `reword`, relay the option to `do_pick`.\n\nThe new user-exposed options should be documented in the git-rebase(1)\nmanpage and probably also in the help text that is appended to every\n\"rebase -i\" todo list.\n\n> The `do_pick` options `--gpg-sign` and `--file` are not yet supported\n> because `do_cmd` cannot handle option arguments and options with\n> spaces at the moment. It is true that edit is one of the atomic\n> commands but it displays hash information when the rebase is stopped\n> and some options rewrite the picked commit which alters that\n> information. squash and fixup still do not accept user options as the\n> interplay of `--reset-author` and the author script are yet to be\n> determined.\n> [...]\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\n"},{"id":"247680","messageId":"CABURp0qyMT2L7GHCdPP_hpFh9WDfoLTgJA3wru+iAgb__ig2fA@mail.gmail.com","threadId":"36962","inReplyTo":"16751a4402233b6c2925bf00d7ecebdccedd0eef.1407368621.git.bafain@gmail.com","subject":"Re: [PATCH v2 02/23] rebase -i: allow squashing empty commits without complaints","fromName":"Phil Hord","fromEmail":"phil.hord@gmail.com","sentAt":"2014-08-13T19:24:06Z","receivedAt":"2014-08-13T19:24:06Z","isPatch":true,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"Thanks for working on this.\n\nOn Wed, Aug 6, 2014 at 7:59 PM, Fabian Ruch <bafain@gmail.com> wrote:\n> The to-do list commands `squash` and `fixup` apply the changes\n> introduced by the named commit to the tree but instead of creating\n> a new commit on top of the current head it replaces the previous\n> commit with a new commit that records the updated tree. If the\n> result is an empty commit git-rebase stops with the error message\n>\n>    You asked to amend the most recent commit, but doing so would make\n>    it empty. You can repeat your command with --allow-empty, or you can\n>    remove the commit entirely with \"git reset HEAD^\".\n>\n> This message is not very helpful because neither does git-rebase\n> support an option `--allow-empty` nor does the messages say how to\n> resume the rebase. Firstly, change the error message to\n>\n>    The squash result is empty and --keep-empty was not specified.\n>\n>    You can remove the squash commit now with\n>\n>      git reset HEAD^\n>\n>    Once you are down, run\n\ns/down/done\n\n>\n>      git rebase --continue\n>\n\nI like the direction of this rewording, but it seems to hide the\ninstructions for the user who wants to keep the empty commit.\n\nI'm not sure how to improve it.  Maybe this:\n\n    The squash result is empty and --keep-empty was not specified.\n\n    You may remove the squash commit now with\n\n      git reset HEAD^\n\n    or keep it by doing nothing extra.\n\n    Continue the rebase with\n\n      git rebase --continue\n\n> If the user wishes to squash a sequence of commits into one\n> commit, f. i.\n>\n>    pick A\n>    squash Revert \"A\"\n>    squash A'\n>\n> , it does not matter for the end result that the first squash\n> result, or any sub-sequence in general, is going to be empty. The\n> squash message is not affected at all by which commits are created\n> and only the commit created by the last line in the sequence will\n> end up in the final history. Secondly, print the error message\n> only if the whole squash sequence produced an empty commit.\n>\n> Lastly, since an empty squash commit is not a failure to rewrite\n> the history as planned, issue the message above as a mere warning\n> and interrupt the rebase with the return value zero. The\n> interruption should be considered as a notification with the\n> chance to undo it on the spot. Specifying the `--keep-empty`\n> option tells git-rebase to keep empty squash commits in the\n> rebased history without notification.\n>\n> Add tests.\n>\n> Reported-by: Peter Krefting <peter@softwolves.pp.se>\n> Signed-off-by: Fabian Ruch <bafain@gmail.com>\n> ---\n> Hi,\n>\n> Peter Krefting is cc'd as the author of the bug report \"Confusing\n> error message in rebase when commit becomes empty\" discussed on the\n> mailing list in June. Phil Hord and Jeff King both participated in\n> the problem discussion which ended with two proposals by Jeff.\n>\n> Jeff King writes:\n>>   1. Always keep such empty commits. A user who is surprised by them\n>>      being empty can then revisit them. Or drop them by doing another\n>>      rebase without --keep-empty.\n>>\n>>   2. Notice ourselves that the end-result of the whole squash is an\n>>      empty commit, and stop to let the user deal with it.\n>\n> This patch chooses the second alternative. Either way seems OK. The\n> crucial consensus of the discussion was to silently throw away empty\n> interim commits.\n\nThis patch does _not_ silently throw away empty commits. I wonder if\nsuch behavior could be triggered with something like --no-keep-empty.\nMaybe that belongs in another patch.\n\n>\n>    Fabian\n>\n>  git-rebase--interactive.sh    | 20 +++++++++++---\n>  t/t3404-rebase-interactive.sh | 62 +++++++++++++++++++++++++++++++++++++++++++\n>  2 files changed, 79 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 3222bf6..8820eac 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -549,7 +549,7 @@ do_next () {\n>                 squash|s|fixup|f)\n>                         # This is an intermediate commit; its message will only be\n>                         # used in case of trouble.  So use the long version:\n> -                       do_with_author output git commit --allow-empty-message \\\n> +                       do_with_author output git commit --allow-empty-message --allow-empty \\\n>                                 --amend --no-verify -F \"$squash_msg\" \\\n>                                 ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                 die_failed_squash $sha1 \"$rest\"\n> @@ -558,18 +558,32 @@ do_next () {\n>                         # This is the final command of this squash/fixup group\n>                         if test -f \"$fixup_msg\"\n>                         then\n> -                               do_with_author git commit --allow-empty-message \\\n> +                               do_with_author git commit --allow-empty-message --allow-empty \\\n>                                         --amend --no-verify -F \"$fixup_msg\" \\\n>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                         die_failed_squash $sha1 \"$rest\"\n>                         else\n>                                 cp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n>                                 rm -f \"$GIT_DIR\"/MERGE_MSG\n> -                               do_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n> +                               do_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n>                                         ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n>                                         die_failed_squash $sha1 \"$rest\"\n>                         fi\n>                         rm -f \"$squash_msg\" \"$fixup_msg\"\n> +                       if test -z \"$keep_empty\" && is_empty_commit HEAD\n> +                       then\n> +                               echo \"$sha1\" >\"$state_dir\"/stopped-sha\n> +                               warn \"The squash result is empty and --keep-empty was not specified.\"\n> +                               warn\n> +                               warn \"You can remove the squash commit now with\"\n> +                               warn\n> +                               warn \"  git reset HEAD^\"\n> +                               warn\n> +                               warn \"Once you are down, run\"\n\ns/down/done\n\n> +                               warn\n> +                               warn \"  git rebase --continue\"\n> +                               exit 0\n> +                       fi\n>                         ;;\n>                 esac\n>                 record_in_rewritten $sha1\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index 9c71835..a95cb2a 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -237,6 +237,68 @@ test_expect_success 'retain authorship' '\n>         git show HEAD | grep \"^Author: Twerp Snog\"\n>  '\n>\n> +test_expect_success 'setup squash/fixup reverted and fixed feature' '\n> +       git checkout -b reverted-feature master &&\n> +       test_commit feature &&\n> +       git revert feature &&\n> +       git checkout -b fixed-feature reverted-feature &&\n> +       test_commit featurev2\n> +'\n> +\n> +test_expect_success 'fixup fixed feature (empty interim commit)' '\n> +       git checkout -b fixup-fixed-feature fixed-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code featurev2\n> +'\n> +\n> +test_expect_success 'squash fixed feature (empty interim commit)' '\n> +       git checkout -b squash-fixed-feature fixed-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code featurev2\n> +'\n> +\n> +test_expect_success 'fixup reverted feature (empty final commit)' '\n> +       git checkout -b fixup-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2\" git rebase -i master &&\n> +       git reset HEAD^ &&\n> +       git rebase --continue &&\n> +       test_cmp_rev master HEAD\n> +'\n> +\n> +test_expect_success 'squash reverted feature (empty final commit)' '\n> +       git checkout -b squash-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2\" git rebase -i master &&\n> +       git reset HEAD^ &&\n> +       git rebase --continue &&\n> +       test_cmp_rev master HEAD\n> +'\n> +\n> +test_expect_success 'fixup reverted feature (empty final commit with --keep-empty)' '\n> +       git checkout -b fixup-keep-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 fixup 2\" git rebase -i --keep-empty master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code master\n> +'\n> +\n> +test_expect_success 'squash reverted feature (empty final commit with --keep-empty)' '\n> +       git checkout -b squash-keep-reverted-feature reverted-feature &&\n> +       set_fake_editor &&\n> +       FAKE_LINES=\"1 squash 2\" git rebase -i --keep-empty master &&\n> +       git log --oneline master.. >actual &&\n> +       test_line_count = 1 actual &&\n> +       git diff --exit-code master\n> +'\n> +\n>  test_expect_success 'squash' '\n>         git reset --hard twerp &&\n>         echo B > file7 &&\n> --\n> 2.0.1\n>\n"},{"id":"247724","messageId":"53ECF0BF.5070200@gmail.com","threadId":"36962","inReplyTo":"53EB5E77.8010005@alum.mit.edu","subject":"Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-14T17:24:15Z","receivedAt":"2014-08-14T17:24:15Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nMichael Haggerty writes:\n> On 08/07/2014 01:59 AM, Fabian Ruch wrote:\n>> Lift the general unknown option blockade for the pick and reword\n>> commands. If `do_cmd` comes across one of the options `--signoff` and\n>> `--reset-author` while parsing a to-do entry and the scheduled\n>> command is either `pick` or `reword`, relay the option to `do_pick`.\n> \n> The new user-exposed options should be documented in the git-rebase(1)\n> manpage and probably also in the help text that is appended to every\n> \"rebase -i\" todo list.\n\nThe next reroll will add the following paragraph to the git-rebase man\npage right after the introduction of the 'reword' command in the section\n\"INTERACTIVE MODE\":\n\n> The commands \"pick\" and \"reword\" understand some well-known options.\n> To add a Signed-off-by line at the end of the commit message, pass\n> the `--signoff` option. The authorship can be renewed by specifying\n> the `--reset-author` option. For instance, before you decide to\n> publish a heavily edited commit you might want to reset the\n> authorship and add your signature. You can do so on a per line basis:\n> \n> -------------------------------------------\n> pick deadbee The oneline of this commit\n> pick --reset-author --signoff fa1afe1 The oneline of the next commit\n> ...\n> -------------------------------------------\n\nBy saying \"heavily edited commit\" I tried to describe a commit that has\nbeen amended, reworded and reordered in such a way that the actual\nauthor information has become meaningless.\n\nThe help text at the end of every to-do list would look like this:\n\n> Commands:\n>  p, pick = use commit\n>  r, reword = use commit, but edit the commit message\n>  e, edit = use commit, but stop for amending\n>  s, squash = use commit, but meld into previous commit\n>  f, fixup = like \"squash\", but discard this commit's log message\n>  x, exec = run command (the rest of the line) using shell\n> \n> Options:\n>  [pick | reword] --signoff = add a Signed-off-by line\n>  [pick | reword] --reset-author = renew authorship\n> \n> These lines can be re-ordered; they are executed from top to bottom.\n> \n> If you remove a line here THAT COMMIT WILL BE LOST.\n\nNew about this is the \"Options\" headline.\n\n   Fabian\n"},{"id":"247859","messageId":"cover.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"53A258D2.7080806@gmail.com","subject":"[PATCH v3 00/27] Enable options --signoff, --reset-author for pick, reword, edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:43Z","receivedAt":"2014-08-18T21:22:43Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi,\n\nthis is the third reroll of the patch series that makes the\nwell-known commit options `--signoff` and `--reset-author` available\nto be used with the to-do list commands `pick`, `reword` and `edit`.\n\nWhat follows is a short changelog since the second reroll from almost\ntwo weeks ago. The changes were mostly made in response to Thomas'\nreview.\n\n- Merely a commit message comment: The `editor.sh` wrapper script is\n  still necessary to use `output` with interactive to-do list\n  commands because the `--quiet` option does not force all commands\n  to be totally silent.\n\n- `git-rebase--interactive.sh` now uses the quoting functionality of\n  git-rev-parse when assigning the `editor.sh` path to the\n  `GIT_EDITOR` environment variable, in case the path includes double\n  quotes itself.\n\n- The tests dealing with squash commits that violate either\n  commit-msg or pre-commit now test `squash` and `fixup` sequences\n  with more than two commits. This is important since the final\n  commit is created on a different code path than the others.\n\n- The `fake_editor.sh` change that prints the debug output on stderr\n  instead of stdout is now a separate patch so that it can be\n  referred to directly. The change might be considered a hack and\n  needs revision.\n\n- Since whitespace and shell quoting are not supported by line\n  options, the `opts` variable does not need to be evaluated using\n  `eval` anymore.\n\n- Malformed to-do command lines either trigger an \"unknown command\"\n  or an \"unknown option\" error message but not both.\n\n- A test case that specifies that `git rebase --continue` only\n  commits staged changes if the user has not committed on top of the\n  last successfully replayed commit in the meantime. The rationale\n  behind this is that `git rebase --continue` commits using the\n  author information of the commit it tried to replay last. While it\n  perfectly makes sense to assume that this information is correct\n  when HEAD has not changed, it is probable that it is incorrect when\n  the user has created commits herself because the rebase process was\n  interrupted for conflict resolution only and one must know\n  internals to intentionally make `git rebase --continue` commit\n  changes on top of user-created commits using original author\n  information.\n\n- `do_pick` did not preserve the authorship of the original commit\n  when it was asked to rewrite the commit, for instance using\n  `reword`. This was fixed by applying the authorship of the named\n  commit using `do_with_author`. That doesn't interfere with squash\n  commits because `do_with_author` is a no-op when used with `git\n  commit --amend`.\n\n- `git rebase --continue` did not apply the line options after\n  conflict resolution. This was added by remembering line options the\n  way `git-rebase--interactive.sh` reminds itself of amending\n  commits.\n\n- The test suite `t3427-rebase-line-options.sh` is responsible for\n  the specification of to-do lists that use line options.\n\n- The two line options available are now documented both in the\n  git-rebase man page and the to-do list help text.\n\nThanks for your time,\n   Fabian\n\nFabian Ruch (27):\n  rebase -i: allow replaying commits with empty log messages\n  rebase -i: allow squashing empty commits without complaints\n  rebase -i: allow rewording empty commits without complaints\n  fake_editor: leave standard output unchanged\n  rebase -i: hide interactive command messages in verbose mode\n  rebase -i: discard redundant message when rewording fails\n  commit: allow disabling pre-commit and commit-msg separately\n  rebase -i: verify squash messages using commit-msg\n  rebase -i: do not verify reworded patches using pre-commit\n  rebase -i: teach do_pick the option --edit\n  rebase -i: implement reword in terms of do_pick\n  rebase -i: log the replay of root commits\n  rebase -i: do not use -C when --no-edit is sufficient\n  rebase -i: commit only once when rewriting picks\n  rebase -i: do not die in do_pick\n  rebase -i: teach do_pick the option --amend\n  rebase -i: teach do_pick the option --file\n  rebase -i: remove no-op do_with_author git commit --amend\n  rebase -i: prepare for squash in terms of do_pick --amend\n  rebase -i: implement squash in terms of do_pick\n  rebase -i: explicitly distinguish replay commands and exec tasks\n  rebase -i: parse to-do list command line options\n  rebase -i: teach do_pick the option --reset-author\n  rebase -i: teach do_pick the option --signoff\n  rebase -i: do not overwrite user author information\n  rebase -i: refuse to commit when resuming with updated head\n  rebase -i: enable --signoff, --reset-author for pick, reword, edit\n\n Documentation/git-commit.txt   |   8 +-\n Documentation/git-rebase.txt   |  13 ++\n builtin/commit.c               |  32 +++-\n git-rebase--interactive.sh     | 370 ++++++++++++++++++++++++++++++++---------\n git-rebase.sh                  |  13 +-\n t/lib-rebase.sh                |  28 +++-\n t/t3404-rebase-interactive.sh  | 290 ++++++++++++++++++++++++++++++--\n t/t3406-rebase-message.sh      |  18 ++\n t/t3412-rebase-root.sh         |  16 ++\n t/t3427-rebase-line-options.sh | 216 ++++++++++++++++++++++++\n t/t7503-pre-commit-hook.sh     |  65 +++++++-\n t/t7504-commit-msg-hook.sh     |  85 ++++++++--\n t/test-lib-functions.sh        |  23 ++-\n 13 files changed, 1044 insertions(+), 133 deletions(-)\n create mode 100755 t/t3427-rebase-line-options.sh\n\n-- \n2.0.1\n"},{"id":"247860","messageId":"ea58c1b83349b8bc4c2a0abf31de53a54f651299.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 01/27] rebase -i: allow replaying commits with empty log messages","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:44Z","receivedAt":"2014-08-18T21:22:44Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"git-rebase--interactive handles empty log messages inconsistently\nbetween enabled and disabled fast-forwards. By default, commits with\nempty log messages are rebased successfully like in non-interactive\nmode. In contrast, the `--no-ff` option aborts the replay of such\ncommits.\n\nIn line with not verifying rebased commits and behaving like\ngit-rebase for `pick` lines, use the `--allow-empty-message` option\nto replay commits. Root commits are replayed by recreating them in\n`do_pick` using git-commit and all other commits are replayed using\ngit-cherry-pick in `pick_one`. Apply the option, understood by both\ngit-commit and git-cherry-pick, at the respective sites.\n\nIn case of `reword` and `squash`, continue to abort the rebase if the\n_resulting_ commit would have no commit message. The rationale behind\nthis default is that patches and their log messages should be\nverified at least once. For unchanged commits this is assumed to have\nhappened according to the author's standards when she created the\ncommits for the first time. While the empty log message can always be\nkept in place by editing and resuming the aborted rebase, a debatable\nalternative could be to teach git-rebase--interactive the option\n`--allow-empty-message` for disabling complaints about empty log\nmessages even in changed commits.\n\nThe `fixup` case is different again because it throws away the second\ncommit's log message and uses the first log message for the changed\ncommit. Do not abort the rebase if that message is empty either since\nit is assumed to have been verified already.\n\nThe remaining to-do list command `edit` is handled just like `pick`\nfor this matter, because git-rebase--interactive replays the named\ncommit without changes before the rebase is interrupted and the user\ncan make her changes to the replayed commit.\n\nAdd tests. In particular, design the `squash`-specific test case such\nthat it involves interim commits and `fixup` steps. Interim commits\nshould not trigger failures themselves and `fixup` steps should not\nlet git-rebase--interactive forget that it is still dealing with a\n`squash` result.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 10 ++++++----\n t/t3404-rebase-interactive.sh | 38 ++++++++++++++++++++++++++++++++++++++\n t/t3412-rebase-root.sh        | 16 ++++++++++++++++\n 3 files changed, 60 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b64dd28..3222bf6 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -249,7 +249,7 @@ pick_one () {\n \n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput eval git cherry-pick \\\n+\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\"$strategy_args\" $empty_args $ff \"$@\"\n }\n@@ -363,7 +363,7 @@ pick_one_preserving_merges () {\n \t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$rewritten_list\"\n \t\t\t;;\n \t\t*)\n-\t\t\toutput eval git cherry-pick \\\n+\t\t\toutput eval git cherry-pick --allow-empty-message \\\n \t\t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\t\"$strategy_args\" \"$@\" ||\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\n@@ -549,7 +549,8 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_with_author output git commit --amend --no-verify -F \"$squash_msg\" \\\n+\t\t\tdo_with_author output git commit --allow-empty-message \\\n+\t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\t;;\n@@ -557,7 +558,8 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$fixup_msg\" \\\n+\t\t\t\tdo_with_author git commit --allow-empty-message \\\n+\t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8197ed2..9c71835 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -1039,4 +1039,42 @@ test_expect_success 'short SHA-1 collide' '\n \t)\n '\n \n+test_expect_success 'setup commits with empty commit log messages' '\n+\tgit checkout -b empty-log-messages master &&\n+\ttest_commit no-msg-commit-1 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_commit no-msg-commit-2 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_commit no-msg-commit-3 &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null\n+'\n+\n+test_expect_success 'rebase commits with empty commit log messages' '\n+\tgit checkout -b rebase-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\ttest_expect_code 0 env FAKE_LINES=\"1\" git rebase -i master &&\n+\ttest_expect_code 0 env FAKE_LINES=\"1\" git rebase -i --no-ff master\n+'\n+\n+test_expect_success 'reword commits with empty commit log messages' '\n+\tgit checkout -b reword-empty-log-messages empty-log-messages &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n+test_expect_success 'squash commits with empty commit log messages' '\n+\tgit checkout -b squash-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2 fixup 3\" git rebase -i master &&\n+\tgit commit --allow-empty-message --amend &&\n+\tgit rebase --continue\n+'\n+\n+test_expect_success 'fixup commits with empty commit log messages' '\n+\tgit checkout -b fixup-empty-log-messages empty-log-messages &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2\" git rebase -i master\n+'\n+\n test_done\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 0b52105..7add7a1 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -278,4 +278,20 @@ test_expect_success 'rebase -i -p --root with conflict (second part)' '\n \ttest_cmp expect-conflict-p out\n '\n \n+test_expect_success 'rebase --root root with empty log message' '\n+\tgit checkout --orphan empty-log-messages-root master &&\n+\ttest_commit no-msg-root-commit &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_expect_code 0 git rebase --root &&\n+\ttest_expect_code 0 git rebase --root --no-ff\n+'\n+\n+test_expect_success 'rebase --root commits with empty log messages' '\n+\tgit checkout -b empty-log-messages master &&\n+\ttest_commit no-msg-commit &&\n+\tgit commit --amend --allow-empty-message -F - </dev/null &&\n+\ttest_expect_code 0 git rebase --root &&\n+\ttest_expect_code 0 git rebase --root --no-ff\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"247861","messageId":"c6c1060f8f646b9e2dd0966370dde9ed70361194.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 02/27] rebase -i: allow squashing empty commits without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:45Z","receivedAt":"2014-08-18T21:22:45Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list commands `squash` and `fixup` apply the changes\nintroduced by the named commit to the tree but instead of creating\na new commit on top of the current head it replaces the previous\ncommit with a new commit that records the updated tree. If the\nresult is an empty commit git-rebase stops with the error message\n\n   You asked to amend the most recent commit, but doing so would make\n   it empty. You can repeat your command with --allow-empty, or you can\n   remove the commit entirely with \"git reset HEAD^\".\n\nThis message is not very helpful because neither does git-rebase\nsupport an option `--allow-empty` nor does the messages say how to\nresume the rebase. Firstly, change the error message to\n\n   The squash result is empty and --keep-empty was not specified.\n\n   You can remove the squash commit now with\n\n     git reset HEAD^\n\n   Once you are done, run\n\n     git rebase --continue\n\nIf the user wishes to squash a sequence of commits into one\ncommit, f. i.\n\n   pick A\n   squash Revert \"A\"\n   squash A'\n\n, it does not matter for the end result that the first squash\nresult, or any sub-sequence in general, is going to be empty. The\nsquash message is not affected at all by which commits are created\nand only the commit created by the last line in the sequence will\nend up in the final history. Secondly, print the error message\nonly if the whole squash sequence produced an empty commit.\n\nLastly, since an empty squash commit is not a failure to rewrite\nthe history as planned, issue the message above as a mere warning\nand interrupt the rebase with the return value zero. The\ninterruption should be considered as a notification with the\nchance to undo it on the spot. Specifying the `--keep-empty`\noption tells git-rebase to keep empty squash commits in the\nrebased history without notification.\n\nAdd tests.\n\nReported-by: Peter Krefting <peter@softwolves.pp.se>\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 20 +++++++++++---\n t/t3404-rebase-interactive.sh | 62 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 79 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 3222bf6..ada340c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -549,7 +549,7 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_with_author output git commit --allow-empty-message \\\n+\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n@@ -558,18 +558,32 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --allow-empty-message \\\n+\t\t\t\tdo_with_author git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author git commit --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n+\t\t\tif test -z \"$keep_empty\" && is_empty_commit HEAD\n+\t\t\tthen\n+\t\t\t\techo \"$sha1\" >\"$state_dir\"/stopped-sha\n+\t\t\t\twarn \"The squash result is empty and --keep-empty was not specified.\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"You can remove the squash commit now with\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"  git reset HEAD^\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"Once you are done, run\"\n+\t\t\t\twarn\n+\t\t\t\twarn \"  git rebase --continue\"\n+\t\t\t\texit 0\n+\t\t\tfi\n \t\t\t;;\n \t\tesac\n \t\trecord_in_rewritten $sha1\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 9c71835..a95cb2a 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -237,6 +237,68 @@ test_expect_success 'retain authorship' '\n \tgit show HEAD | grep \"^Author: Twerp Snog\"\n '\n \n+test_expect_success 'setup squash/fixup reverted and fixed feature' '\n+\tgit checkout -b reverted-feature master &&\n+\ttest_commit feature &&\n+\tgit revert feature &&\n+\tgit checkout -b fixed-feature reverted-feature &&\n+\ttest_commit featurev2\n+'\n+\n+test_expect_success 'fixup fixed feature (empty interim commit)' '\n+\tgit checkout -b fixup-fixed-feature fixed-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code featurev2\n+'\n+\n+test_expect_success 'squash fixed feature (empty interim commit)' '\n+\tgit checkout -b squash-fixed-feature fixed-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code featurev2\n+'\n+\n+test_expect_success 'fixup reverted feature (empty final commit)' '\n+\tgit checkout -b fixup-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase -i master &&\n+\tgit reset HEAD^ &&\n+\tgit rebase --continue &&\n+\ttest_cmp_rev master HEAD\n+'\n+\n+test_expect_success 'squash reverted feature (empty final commit)' '\n+\tgit checkout -b squash-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase -i master &&\n+\tgit reset HEAD^ &&\n+\tgit rebase --continue &&\n+\ttest_cmp_rev master HEAD\n+'\n+\n+test_expect_success 'fixup reverted feature (empty final commit with --keep-empty)' '\n+\tgit checkout -b fixup-keep-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase -i --keep-empty master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code master\n+'\n+\n+test_expect_success 'squash reverted feature (empty final commit with --keep-empty)' '\n+\tgit checkout -b squash-keep-reverted-feature reverted-feature &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase -i --keep-empty master &&\n+\tgit log --oneline master.. >actual &&\n+\ttest_line_count = 1 actual &&\n+\tgit diff --exit-code master\n+'\n+\n test_expect_success 'squash' '\n \tgit reset --hard twerp &&\n \techo B > file7 &&\n-- \n2.0.1\n"},{"id":"247864","messageId":"a98cda7aa0c98e6335dd1c6932e30909e49bdb0f.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 03/27] rebase -i: allow rewording empty commits without complaints","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:46Z","receivedAt":"2014-08-18T21:22:46Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If `--keep-empty` is\npassed as option to git-rebase--interactive, empty commits ought to\nbe replayed without complaints. However, if the users chooses to\nreword an empty commit by changing the respective to-do list entry\nfrom\n\n    pick fa1afe1 Empty commit\n\nto\n\n    reword fa1afe1 Empty commit\n\n, then git-rebase--interactive suddenly fails to replay the empty\ncommit. This is especially counterintuitive because `reword` is\nthought of as a `pick` that alters the log message in some way but\nnothing more and the unchanged to-do list entry would not fail.\n\nHandle `reword` by cherry-picking the named commit and editing the\nlog message using\n\n    git commit --allow-empty --amend\n\ninstead of\n\n    git commit --amend.\n\nAdd test.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 33 +++++++++++++++++++++++++++++++++\n 2 files changed, 34 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ada340c..eb1dcda 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n \t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex a95cb2a..f4e886f 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -75,6 +75,39 @@ test_expect_success 'rebase --keep-empty' '\n \ttest_line_count = 6 actual\n '\n \n+test_expect_success 'rebase --keep-empty (reword)' '\n+\tgit checkout -b reword-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 reword 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 6 actual\n+'\n+\n+test_expect_success 'rebase --keep-empty (edit)' '\n+\tgit checkout -b edit-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 edit 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit rebase --continue &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 6 actual\n+'\n+\n+test_expect_success 'rebase --keep-empty (fixup)' '\n+\tgit checkout -b fixup-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 fixup 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 5 actual\n+'\n+\n+test_expect_success 'rebase --keep-empty (squash)' '\n+\tgit checkout -b squash-emptybranch emptybranch &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2\" git rebase --keep-empty -i HEAD~2 &&\n+\tgit log --oneline >actual &&\n+\ttest_line_count = 5 actual\n+'\n+\n test_expect_success 'rebase -i with the exec command' '\n \tgit checkout master &&\n \t(\n-- \n2.0.1\n"},{"id":"247865","messageId":"b0667f0b0de6f9881dd8c81903b266e39663abb0.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 04/27] fake_editor: leave standard output unchanged","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:47Z","receivedAt":"2014-08-18T21:22:47Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The helper function `set_fake_editor` installs a script as\n`GIT_EDITOR` that applies pre-defined editing rules to the files it\nis called with, which is a quite powerful tool when writing test\ncases for git-rebase--interactive. To aid in debugging the changes it\nmakes, the installed script dumps the file contents to stdout before\nand after editing. That interferes with the output from\ngit-rebase--interactive, however, and the debug information has to be\nremoved from stdout in a error-prone way. Print the editor contents\non stderr instead.\n\nWhen a test case wants to analyse stderr, we need to come up with a\ndifferent solution. The less convenient possibility that always\nremains is to store the debug output in a file in the \"trash\"\ndirectory or even keeping copies of the edited files before and after\nediting.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n t/lib-rebase.sh               |  8 ++++----\n t/t3404-rebase-interactive.sh | 18 ++++++------------\n 2 files changed, 10 insertions(+), 16 deletions(-)\n\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex 6bd2522..0cd1193 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -41,8 +41,8 @@ set_fake_editor () {\n \ttest -z \"$FAKE_LINES\" && exit\n \tgrep -v '^#' < \"$1\" > \"$1\".tmp\n \trm -f \"$1\"\n-\techo 'rebase -i script before editing:'\n-\tcat \"$1\".tmp\n+\techo 'rebase -i script before editing:' >&2\n+\tcat \"$1\".tmp >&2\n \taction=pick\n \tfor line in $FAKE_LINES; do\n \t\tcase $line in\n@@ -59,8 +59,8 @@ set_fake_editor () {\n \t\t\taction=pick;;\n \t\tesac\n \tdone\n-\techo 'rebase -i script after editing:'\n-\tcat \"$1\"\n+\techo 'rebase -i script after editing:' >&2\n+\tcat \"$1\" >&2\n \tEOF\n \n \ttest_set_editor \"$(pwd)/fake-editor.sh\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex f4e886f..7cc6ebf 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -882,9 +882,8 @@ test_expect_success 'running \"git rebase -i --exec git show HEAD\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -896,9 +895,8 @@ test_expect_success 'running \"git rebase --exec git show HEAD -i\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -910,9 +908,8 @@ test_expect_success 'running \"git rebase -ix git show HEAD\"' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -924,9 +921,8 @@ test_expect_success 'rebase -ix with several <CMD>' '\n \t(\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,9d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -939,9 +935,8 @@ test_expect_success 'rebase -ix with several instances of --exec' '\n \t\tFAKE_LINES=\"1 exec_git_show_HEAD exec_pwd 2\n \t\t\t\texec_git_show_HEAD exec_pwd\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~2 >expect\n+\t\tgit rebase -i HEAD~2 >expected\n \t) &&\n-\tsed -e \"1,11d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n@@ -965,9 +960,8 @@ test_expect_success 'rebase -ix with --autosquash' '\n \t\tgit checkout -b autosquash_expected &&\n \t\tFAKE_LINES=\"1 fixup 3 fixup 4 exec_git_show_HEAD 2 exec_git_show_HEAD\" &&\n \t\texport FAKE_LINES &&\n-\t\tgit rebase -i HEAD~4 >expect\n+\t\tgit rebase -i HEAD~4 >expected\n \t) &&\n-\tsed -e \"1,13d\" expect >expected &&\n \ttest_cmp expected actual\n '\n \n-- \n2.0.1\n"},{"id":"247863","messageId":"8a3fe174ce0bdc3d083187d2258c16352e450652.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 05/27] rebase -i: hide interactive command messages in verbose mode","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:48Z","receivedAt":"2014-08-18T21:22:48Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"git-rebase--interactive prints summary messages of the commits it\ncreates in the final history only if the `--verbose` option is\nspecified by the user and suppresses them otherwise. This behaviour\nis implemented by wrapping git-commit calls in a shell function named\n`output` which redirects stderr to stdout, captures stdout in a shell\nvariable and ignores its contents unless the command exits with an\nerror status.\n\nThe command lines used to implement the to-do list commands `reword`\nand `squash` print diagnostic messages even in non-verbose mode. The\nreason for this inconsistency is that both commands launch the log\nmessage editor `GIT_EDITOR` which usually requires a working terminal\nattached to stdin. Wrapping the `reword` and `squash` command lines\nin `output` would seemingly freeze the terminal (see commit 7725cb5,\n\"rebase -i: fix reword when using a terminal editor\"). Temporarily\nredirect the `GIT_EDITOR` output to a third file descriptor in order\nto ship it around the capture stream. Wrap the remaining git-commit\ncommand lines in the new `output`. At the moment, it is still no\nalternative to pass the `--quiet` option in non-verbose mode because\ngit-merge-recursive for instance prints some messages regardless of\nthe verbosity level.\n\nIn order to temporarily redirect the editor output, the new\ndefinition of `output` creates a wrapper script in the state\ndirectory to be used as `GIT_EDITOR`. Make sure the state directory\nexists before `output` is called for the first time.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh |  9 +++++----\n git-rebase.sh              | 13 +++++++++++--\n t/t3406-rebase-message.sh  | 18 ++++++++++++++++++\n 3 files changed, 34 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex eb1dcda..cebe742 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\tgit commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n \t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n@@ -558,14 +558,14 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author git commit --allow-empty-message --allow-empty \\\n+\t\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n@@ -923,6 +923,8 @@ EOF\n \t;;\n esac\n \n+mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n+\n git var GIT_COMMITTER_IDENT >/dev/null ||\n \tdie \"You need to set your committer info first\"\n \n@@ -938,7 +940,6 @@ then\n fi\n \n orig_head=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n-mkdir -p \"$state_dir\" || die \"Could not create temporary $state_dir\"\n \n : > \"$state_dir\"/interactive || die \"Could not mark as interactive\"\n write_basic_state\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 55da9db..46141b8 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -131,9 +131,18 @@ write_basic_state () {\n output () {\n \tcase \"$verbose\" in\n \t'')\n-\t\toutput=$(\"$@\" 2>&1 )\n+\t\tcat >\"$state_dir\"/editor.sh <<-EOF\n+\t\t#!/bin/sh\n+\t\t$(git var GIT_EDITOR) \"\\$@\" >&3\n+\t\tEOF\n+\t\tchmod +x \"$state_dir\"/editor.sh\n+\t\t(\n+\t\t\tGIT_EDITOR=$(git rev-parse --sq-quote \"$state_dir\"/editor.sh)\n+\t\t\texport GIT_EDITOR\n+\t\t\t\"$@\" 3>&1 1>\"$state_dir\"/output 2>&1\n+\t\t)\n \t\tstatus=$?\n-\t\ttest $status != 0 && printf \"%s\\n\" \"$output\"\n+\t\ttest $status != 0 && cat \"$state_dir\"/output\n \t\treturn $status\n \t\t;;\n \t*)\ndiff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\nindex 0392e36..d7003a9 100755\n--- a/t/t3406-rebase-message.sh\n+++ b/t/t3406-rebase-message.sh\n@@ -4,6 +4,8 @@ test_description='messages from rebase operation'\n \n . ./test-lib.sh\n \n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n test_expect_success 'setup' '\n \ttest_commit O fileO &&\n \ttest_commit X fileX &&\n@@ -84,4 +86,20 @@ test_expect_success 'rebase --onto outputs the invalid ref' '\n \ttest_i18ngrep \"invalid-ref\" err\n '\n \n+test_expect_success 'commit summary is suppressed in non-verbose mode' '\n+\tgit checkout --detach Y &&\n+\tcat >expected.out <<-EOF &&\n+\tRebasing (1/5)\\r\n+\tRebasing (2/5)\\r\n+\tRebasing (3/5)\\r\n+\tRebasing (4/5)\\r\n+\tRebasing (5/5)\\r\n+\tEOF\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"reword 1 fixup 2 fixup 3 4 squash 5\" \\\n+\tgit rebase -i --root >actual.out.tmp &&\n+\tsed -e \"s/\\r/\\\\\\\\r\\n/g\" <actual.out.tmp >actual.out &&\n+\ttest_cmp expected.out actual.out\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"247862","messageId":"c53714eaa34804c55b6cd4b72db8405b700a381d.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 06/27] rebase -i: discard redundant message when rewording fails","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:49Z","receivedAt":"2014-08-18T21:22:49Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If the edited log\nmessage is empty or is found ill-formatted by one of the commit\nhooks, git-rebase--interactive prints three error messages to the\nconsole.\n\n    1. The git-commit output, which contains all the output from hook\n       scripts.\n    2. A rebase diagnosis saying at which task on the to-do list it\n       got stuck.\n    3. Generic presumptions about what could have triggered the\n       error.\n\nThe third message contains redundant information and does not add any\nenlightenment either, which makes the output unnecessarily longish\nand different from the other commands' output. For instance, this is\nwhat the output looks like if the log message is empty (contains\nduplicate Signed-off-by lines).\n\n    (1.) Aborting commit due to empty commit message. (Duplicate Signed-off-by lines.)\n    (2.) Could not amend commit after successfully picking fa1afe1... Some change\n    (3.) This is most likely due to an empty commit message, or the pre-commit hook\n         failed. If the pre-commit hook failed, you may need to resolve the issue before\n         you are able to reword the commit.\n\nDiscard the third message.\n\nIt is true that a failed hook script might not output any diagnosis\nbut then the generic message is not of much help either. Since this\nlack of information affects the built-in git commands for commit,\nmerge and cherry-pick first, the solution would be to keep track of\nthe failed hooks in their output so that the user knows which of her\nhooks require improvement.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 3 ---\n 1 file changed, 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex cebe742..cf62daa 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -506,9 +506,6 @@ do_next () {\n \t\tdo_pick $sha1 \"$rest\"\n \t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n-\t\t\twarn \"failed. If the pre-commit hook failed, you may need to resolve the issue before\"\n-\t\t\twarn \"you are able to reword the commit.\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\n \t\trecord_in_rewritten $sha1\n-- \n2.0.1\n"},{"id":"247870","messageId":"0f321cb359c454217da5ac5a9bfe06907342bdb5.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 07/27] commit: allow disabling pre-commit and commit-msg separately","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:50Z","receivedAt":"2014-08-18T21:22:50Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Introduce the git-commit command line options `--no-pre-commit` and\n`--no-commit-msg` to disable the pre-commit and commit-msg hooks,\nrespectively. Make `--no-verify` a synonym for specifying both at the\nsame time.\n\nThis change is motivated by an internal usage of git-commit in\ngit-rebase--interactive to disable pre-commit while keeping\ncommit-msg enabled when rewording a commit.\n\nMake `test_commit` forward unknown options to git-commit instead of\nteaching it all possible options. In order to support leading double\ndashes in `<message>`, stop interpreting `test_commit` arguments\nfollowing a `--` argument as options. This wasn't a problem before\nbecause the first unknown option would be used as `<message>`.\n\nAllow disabling tag creation to avoid name clashes when using\n`test_commit` with the same arguments several times from the same\ntest suite. By default, `test_commit` tags successful commits using\ngit-tag for easy reference. The `--notag` option skips this step.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n Documentation/git-commit.txt |  8 ++++-\n builtin/commit.c             | 32 ++++++++++++++---\n t/t7503-pre-commit-hook.sh   | 65 ++++++++++++++++++++++++++++-----\n t/t7504-commit-msg-hook.sh   | 85 ++++++++++++++++++++++++++++++++++----------\n t/test-lib-functions.sh      | 23 ++++++++----\n 5 files changed, 176 insertions(+), 37 deletions(-)\n\ndiff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt\nindex 0bbc8f5..28a2c5c 100644\n--- a/Documentation/git-commit.txt\n+++ b/Documentation/git-commit.txt\n@@ -158,7 +158,7 @@ OPTIONS\n \n -n::\n --no-verify::\n-\tThis option bypasses the pre-commit and commit-msg hooks.\n+\tA synonym for `--no-pre-commit --no-commit-msg`.\n \tSee also linkgit:githooks[5].\n \n --allow-empty::\n@@ -238,6 +238,12 @@ You should understand the implications of rewriting history if you\n amend a commit that has already been published.  (See the \"RECOVERING\n FROM UPSTREAM REBASE\" section in linkgit:git-rebase[1].)\n \n+--no-pre-commit::\n+\tThis option bypasses the pre-commit hook.\n+\n+--no-commit-msg::\n+\tThis option bypasses the commit-msg hook.\n+\n --no-post-rewrite::\n \tBypass the post-rewrite hook.\n \ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 5ed6036..dfd354e 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -98,12 +98,27 @@ static char *edit_message, *use_message;\n static char *fixup_message, *squash_message;\n static int all, also, interactive, patch_interactive, only, amend, signoff;\n static int edit_flag = -1; /* unspecified */\n-static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;\n+static int quiet, verbose, allow_empty, dry_run, renew_authorship;\n static int no_post_rewrite, allow_empty_message;\n static char *untracked_files_arg, *force_date, *ignore_submodule_arg;\n static char *sign_commit;\n \n /*\n+ * The verify variable is interpreted as a bitmap of enabled commit\n+ * verification hooks according to the legend below.\n+ *\n+ * By default, the pre-commit and commit-msg hooks are enabled. This\n+ * is represented by both the PRE_COMMIT and COMMIT_MSG bits being\n+ * set.\n+ *\n+ * The bitmap is changed through the command line options\n+ * --no-verify, --no-pre-commit and --no-commit-msg.\n+ */\n+#define PRE_COMMIT (1<<0)\n+#define COMMIT_MSG (1<<1)\n+static int verify = PRE_COMMIT | COMMIT_MSG;\n+\n+/*\n  * The default commit message cleanup mode will remove the lines\n  * beginning with # (shell comments) and leading and trailing\n  * whitespaces (empty lines or containing only whitespaces)\n@@ -661,7 +676,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t/* This checks and barfs if author is badly specified */\n \tdetermine_author_info(author_ident);\n \n-\tif (!no_verify && run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n+\tif (verify & PRE_COMMIT &&\n+\t    run_commit_hook(use_editor, index_file, \"pre-commit\", NULL))\n \t\treturn 0;\n \n \tif (squash_message) {\n@@ -962,7 +978,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \t\t}\n \t}\n \n-\tif (!no_verify &&\n+\tif (verify & COMMIT_MSG &&\n \t    run_commit_hook(use_editor, index_file, \"commit-msg\", git_path(commit_editmsg), NULL)) {\n \t\treturn 0;\n \t}\n@@ -1590,7 +1606,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL(0, \"interactive\", &interactive, N_(\"interactively add files\")),\n \t\tOPT_BOOL('p', \"patch\", &patch_interactive, N_(\"interactively add changes\")),\n \t\tOPT_BOOL('o', \"only\", &only, N_(\"commit only specified files\")),\n-\t\tOPT_BOOL('n', \"no-verify\", &no_verify, N_(\"bypass pre-commit hook\")),\n+\t\tOPT_NEGBIT('n', \"no-verify\", &verify,\n+\t\t\t   N_(\"synonym for --no-pre-commit --no-commit-msg\"),\n+\t\t\t   PRE_COMMIT | COMMIT_MSG),\n \t\tOPT_BOOL(0, \"dry-run\", &dry_run, N_(\"show what would be committed\")),\n \t\tOPT_SET_INT(0, \"short\", &status_format, N_(\"show status concisely\"),\n \t\t\t    STATUS_FORMAT_SHORT),\n@@ -1603,6 +1621,12 @@ int cmd_commit(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOL('z', \"null\", &s.null_termination,\n \t\t\t N_(\"terminate entries with NUL\")),\n \t\tOPT_BOOL(0, \"amend\", &amend, N_(\"amend previous commit\")),\n+\t\tOPT_NEGBIT(0, \"no-pre-commit\", &verify,\n+\t\t\t   N_(\"bypass pre-commit hook\"),\n+\t\t\t   PRE_COMMIT),\n+\t\tOPT_NEGBIT(0, \"no-commit-msg\", &verify,\n+\t\t\t   N_(\"bypass commit-msg hook\"),\n+\t\t\t   COMMIT_MSG),\n \t\tOPT_BOOL(0, \"no-post-rewrite\", &no_post_rewrite, N_(\"bypass post-rewrite hook\")),\n \t\t{ OPTION_STRING, 'u', \"untracked-files\", &untracked_files_arg, N_(\"mode\"), N_(\"show untracked files, optional modes: all, normal, no. (Default: all)\"), PARSE_OPT_OPTARG, NULL, (intptr_t)\"all\" },\n \t\t/* end commit contents options */\ndiff --git a/t/t7503-pre-commit-hook.sh b/t/t7503-pre-commit-hook.sh\nindex 984889b..db5de1c 100755\n--- a/t/t7503-pre-commit-hook.sh\n+++ b/t/t7503-pre-commit-hook.sh\n@@ -12,11 +12,11 @@ test_expect_success 'with no hook' '\n \n '\n \n-test_expect_success '--no-verify with no hook' '\n+test_expect_success '--no-pre-commit with no hook' '\n \n \techo \"bar\" > file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"bar\"\n+\tgit commit --no-pre-commit -m \"bar\"\n \n '\n \n@@ -38,11 +38,11 @@ test_expect_success 'with succeeding hook' '\n \n '\n \n-test_expect_success '--no-verify with succeeding hook' '\n+test_expect_success '--no-pre-commit with succeeding hook' '\n \n \techo \"even more\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"even more\"\n+\tgit commit --no-pre-commit -m \"even more\"\n \n '\n \n@@ -60,11 +60,11 @@ test_expect_success 'with failing hook' '\n \n '\n \n-test_expect_success '--no-verify with failing hook' '\n+test_expect_success '--no-pre-commit with failing hook' '\n \n \techo \"stuff\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"stuff\"\n+\tgit commit --no-pre-commit -m \"stuff\"\n \n '\n \n@@ -77,15 +77,64 @@ test_expect_success POSIXPERM 'with non-executable hook' '\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n+test_expect_success POSIXPERM '--no-pre-commit with non-executable hook' '\n \n \techo \"more content\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"more content\"\n+\tgit commit --no-pre-commit -m \"more content\"\n \n '\n chmod +x \"$HOOK\"\n \n+test_hook_enabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing pre-commit hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\techo \"$output\" >expected.output &&\n+\ttest_must_fail test_commit $* file &&\n+\ttest_cmp expected.output actual.output\n+}\n+\n+test_hook_disabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing pre-commit hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\ttest_commit --notag $* file &&\n+\ttest_must_be_empty actual.output\n+}\n+\n+test_expect_success 'command line options combinations' '\n+\ttest_hook_enabled &&\n+\ttest_hook_enabled --pre-commit &&\n+\ttest_hook_enabled --no-pre-commit --pre-commit &&\n+\ttest_hook_enabled --no-verify --pre-commit &&\n+\ttest_hook_enabled --verify &&\n+\ttest_hook_enabled --no-pre-commit --verify &&\n+\ttest_hook_enabled --no-verify --verify &&\n+\ttest_hook_enabled --verify --no-commit-msg &&\n+\ttest_hook_enabled --verify --commit-msg &&\n+\ttest_hook_disabled --no-pre-commit &&\n+\ttest_hook_disabled --pre-commit --no-pre-commit &&\n+\ttest_hook_disabled --pre-commit --no-verify &&\n+\ttest_hook_disabled --no-verify &&\n+\ttest_hook_disabled --verify --no-pre-commit &&\n+\ttest_hook_disabled --verify --no-verify &&\n+\ttest_hook_disabled --no-verify --no-commit-msg &&\n+\ttest_hook_disabled --no-verify --commit-msg\n+'\n+\n # a hook that checks $GIT_PREFIX and succeeds inside the\n # success/ subdirectory only\n cat > \"$HOOK\" <<EOF\ndiff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh\nindex 1f53ea8..59642a3 100755\n--- a/t/t7504-commit-msg-hook.sh\n+++ b/t/t7504-commit-msg-hook.sh\n@@ -34,20 +34,20 @@ test_expect_success 'with no hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with no hook' '\n+test_expect_success '--no-commit-msg with no hook' '\n \n \techo \"bar\" > file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"bar\"\n+\tgit commit --no-commit-msg -m \"bar\"\n \n '\n \n-test_expect_success '--no-verify with no hook (editor)' '\n+test_expect_success '--no-commit-msg with no hook (editor)' '\n \n \techo \"more bar\" > file &&\n \tgit add file &&\n \techo \"more bar\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -78,20 +78,20 @@ test_expect_success 'with succeeding hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with succeeding hook' '\n+test_expect_success '--no-commit-msg with succeeding hook' '\n \n \techo \"even more\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"even more\"\n+\tgit commit --no-commit-msg -m \"even more\"\n \n '\n \n-test_expect_success '--no-verify with succeeding hook (editor)' '\n+test_expect_success '--no-commit-msg with succeeding hook (editor)' '\n \n \techo \"even more more\" >> file &&\n \tgit add file &&\n \techo \"even more more\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -118,20 +118,20 @@ test_expect_success 'with failing hook (editor)' '\n \n '\n \n-test_expect_success '--no-verify with failing hook' '\n+test_expect_success '--no-commit-msg with failing hook' '\n \n \techo \"stuff\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"stuff\"\n+\tgit commit --no-commit-msg -m \"stuff\"\n \n '\n \n-test_expect_success '--no-verify with failing hook (editor)' '\n+test_expect_success '--no-commit-msg with failing hook (editor)' '\n \n \techo \"more stuff\" >> file &&\n \tgit add file &&\n \techo \"more stuff\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n@@ -153,23 +153,72 @@ test_expect_success POSIXPERM 'with non-executable hook (editor)' '\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook' '\n+test_expect_success POSIXPERM '--no-commit-msg with non-executable hook' '\n \n \techo \"more content\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"more content\"\n+\tgit commit --no-commit-msg -m \"more content\"\n \n '\n \n-test_expect_success POSIXPERM '--no-verify with non-executable hook (editor)' '\n+test_expect_success POSIXPERM '--no-commit-msg with non-executable hook (editor)' '\n \n \techo \"even more content\" >> file &&\n \tgit add file &&\n \techo \"even more content\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg\n \n '\n \n+test_hook_enabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing commit-msg hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\techo \"$output\" >expected.output &&\n+\ttest_must_fail test_commit $* file &&\n+\ttest_cmp expected.output actual.output\n+}\n+\n+test_hook_disabled () {\n+\tgit checkout --detach master &&\n+\toutput=\"running failing commit-msg hook with ${*:-(none)}...\" &&\n+\t>actual.output &&\n+\tcat >\"$HOOK\" <<-EOF &&\n+\t#!/bin/sh\n+\techo \"$output\" >>actual.output\n+\texit 1\n+\tEOF\n+\tchmod +x \"$HOOK\" &&\n+\ttest_commit --notag $* file &&\n+\ttest_must_be_empty actual.output\n+}\n+\n+test_expect_success 'command line options combinations' '\n+\ttest_hook_enabled &&\n+\ttest_hook_enabled --commit-msg &&\n+\ttest_hook_enabled --no-commit-msg --commit-msg &&\n+\ttest_hook_enabled --no-verify --commit-msg &&\n+\ttest_hook_enabled --verify &&\n+\ttest_hook_enabled --no-commit-msg --verify &&\n+\ttest_hook_enabled --no-verify --verify &&\n+\ttest_hook_enabled --verify --no-pre-commit &&\n+\ttest_hook_enabled --verify --pre-commit &&\n+\ttest_hook_disabled --no-commit-msg &&\n+\ttest_hook_disabled --commit-msg --no-commit-msg &&\n+\ttest_hook_disabled --commit-msg --no-verify &&\n+\ttest_hook_disabled --no-verify &&\n+\ttest_hook_disabled --verify --no-commit-msg &&\n+\ttest_hook_disabled --verify --no-verify &&\n+\ttest_hook_disabled --no-verify --no-pre-commit &&\n+\ttest_hook_disabled --no-verify --pre-commit\n+'\n+\n # now a hook that edits the commit message\n cat > \"$HOOK\" <<'EOF'\n #!/bin/sh\n@@ -205,7 +254,7 @@ test_expect_success \"hook doesn't edit commit message\" '\n \n \techo \"plus\" >> file &&\n \tgit add file &&\n-\tgit commit --no-verify -m \"plus\" &&\n+\tgit commit --no-commit-msg -m \"plus\" &&\n \tcommit_msg_is \"plus\"\n \n '\n@@ -215,7 +264,7 @@ test_expect_success \"hook doesn't edit commit message (editor)\" '\n \techo \"more plus\" >> file &&\n \tgit add file &&\n \techo \"more plus\" > FAKE_MSG &&\n-\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-verify &&\n+\tGIT_EDITOR=\"\\\"\\$FAKE_EDITOR\\\"\" git commit --no-commit-msg &&\n \tcommit_msg_is \"more plus\"\n \n '\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex dafd6ad..a107073 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -154,20 +154,28 @@ test_pause () {\n \n test_commit () {\n \tnotick= &&\n-\tsignoff= &&\n+\tnotag= &&\n+\tcommit_opts= &&\n \twhile test $# != 0\n \tdo\n \t\tcase \"$1\" in\n \t\t--notick)\n \t\t\tnotick=yes\n \t\t\t;;\n-\t\t--signoff)\n-\t\t\tsignoff=\"$1\"\n+\t\t--notag)\n+\t\t\tnotag=yes\n+\t\t\t;;\n+\t\t--)\n+\t\t\tshift &&\n+\t\t\tbreak\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tcommit_opts=\"$commit_opts $1\"\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n \t\t\t;;\n-\t\tesac\n+\t\tesac &&\n \t\tshift\n \tdone &&\n \tfile=${2:-\"$1.t\"} &&\n@@ -177,8 +185,11 @@ test_commit () {\n \tthen\n \t\ttest_tick\n \tfi &&\n-\tgit commit $signoff -m \"$1\" &&\n-\tgit tag \"${4:-$1}\"\n+\tgit commit $commit_opts -m \"$1\" &&\n+\tif test -z \"$notag\"\n+\tthen\n+\t\tgit tag \"${4:-$1}\"\n+\tfi\n }\n \n # Call test_merge with the arguments \"<message> <commit>\", where <commit>\n-- \n2.0.1\n"},{"id":"247866","messageId":"2882c5b3f2c385492f6aa8d9f6ed1ec2308ebce3.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 08/27] rebase -i: verify squash messages using commit-msg","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:51Z","receivedAt":"2014-08-18T21:22:51Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Using the to-do list command `squash` the user can specify two or\nmore commits and git-rebase creates one commit that introduces all\ntheir changes combined. The authorship for the created commit is\ntaken from the first commit specified and the user can edit the log\nmessage. There is a variant of `squash` available named `fixup` which\nalso takes the first log message without asking for user input.\n\nWhile it is reasonable to not verify replayed changes twice or\nrejecting some other author's changes in her name, it is insufficient\nto not verify the user input used as log message in the case of\n`squash`. Specify the git-commit option `--no-pre-commit` instead of\n`--no-verify` when committing the squash result, but not before, to\nlet the commit-msg hook verify the final squash message. For the same\nreasons the pre-commit hook is disabled in all replay modes, the\ncommit-msg hook is disabled in `fixup` mode.\n\nAdd tests. In addition to the existing test checking that the\npre-commit hook is disabled when simply picking a commit, provide a\ntest checking that the commit-msg hook is disabled as well.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 80 +++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 81 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex cf62daa..54c4614 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -562,7 +562,7 @@ do_next () {\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-verify -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 7cc6ebf..abb829e 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -664,6 +664,86 @@ test_expect_success 'rebase a commit violating pre-commit' '\n \n '\n \n+test_expect_success 'setup failing pre-commit' '\n+\tHOOKDIR=\"$(git rev-parse --git-dir)\"/hooks &&\n+\tmkdir -p \"$HOOKDIR\" &&\n+\tPRE_COMMIT=\"$HOOKDIR\"/pre-commit &&\n+\tcat >\"$PRE_COMMIT\" <<-EOF &&\n+\t#!/bin/sh\n+\techo running failing pre-commit...\n+\texit 1\n+\tEOF\n+\tchmod +x \"$PRE_COMMIT\" &&\n+\tgit checkout -b violating-pre-commit master &&\n+\ttest_must_fail test_commit pre-commit-violated-1 &&\n+\ttest_commit --no-verify pre-commit-violated-1 &&\n+\ttest_must_fail test_commit pre-commit-violated-2 &&\n+\ttest_commit --no-verify pre-commit-violated-2 &&\n+\ttest_must_fail test_commit pre-commit-violated-3 &&\n+\ttest_commit --no-verify pre-commit-violated-3\n+'\n+\n+test_expect_success 'squash commits violating pre-commit' '\n+\tgit checkout -b squash-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master\n+'\n+\n+test_expect_success 'fixup commits violating pre-commit' '\n+\tgit checkout -b fixup-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master\n+'\n+\n+test_expect_success 'clean up failing pre-commit' '\n+\trm \"$PRE_COMMIT\"\n+'\n+\n+test_expect_success 'setup failing commit-msg' '\n+\tHOOKDIR=\"$(git rev-parse --git-dir)\"/hooks &&\n+\tmkdir -p \"$HOOKDIR\" &&\n+\tCOMMIT_MSG=\"$HOOKDIR\"/commit-msg &&\n+\tcat >\"$COMMIT_MSG\" <<-EOF &&\n+\t#!/bin/sh\n+\techo running failing commit-msg...\n+\texit 1\n+\tEOF\n+\tchmod +x \"$COMMIT_MSG\" &&\n+\tgit checkout -b violating-commit-msg master &&\n+\ttest_must_fail test_commit commit-msg-violated-1 &&\n+\ttest_commit --no-verify commit-msg-violated-1 &&\n+\ttest_must_fail test_commit commit-msg-violated-2 &&\n+\ttest_commit --no-verify commit-msg-violated-2 &&\n+\ttest_must_fail test_commit commit-msg-violated-3 &&\n+\ttest_commit --no-verify commit-msg-violated-3\n+'\n+\n+test_expect_success 'rebase a commit violating commit-msg' '\n+\tgit checkout -b rebase-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1\" git rebase -i master\n+'\n+\n+test_expect_success 'squash commits violating commit-msg' '\n+\tgit checkout -b squash-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2 squash 3\" git rebase -i master &&\n+\tgit commit --no-verify --amend &&\n+\tgit rebase --continue\n+'\n+\n+test_expect_success 'fixup commits violating commit-msg' '\n+\tgit checkout -b fixup-violating-commit-msg violating-commit-msg &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"1 fixup 2 fixup 3\" git rebase -i master\n+'\n+\n+test_expect_success 'clean up failing commit-msg' '\n+\trm \"$COMMIT_MSG\"\n+'\n+\n test_expect_success 'rebase with a file named HEAD in worktree' '\n \n \trm -fr .git/hooks &&\n-- \n2.0.1\n"},{"id":"247867","messageId":"a15c35c8d5eb9424bca8ae8ad50143f32c867b28.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 09/27] rebase -i: do not verify reworded patches using pre-commit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:52Z","receivedAt":"2014-08-18T21:22:52Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. This happens in two\nsteps. Firstly, the named commit is cherry-picked. Secondly, the\ncommit created in the first step is amended using an unchanged index\nto edit the log message. The pre-commit hook is meant to verify the\nchanges introduced by a commit (for instance, catching inserted\ntrailing white space). Since the committed tree is not changed\nbetween the two steps and we do not verify rebased patches, do not\nexecute the pre-commit hook in the second step.\n\nSpecify the git-commit option `--no-pre-commit` to disable the\npre-commit hook when editing the log message. The commit-msg hook\nwill still be executed to verify the edited commit log message. As\nbefore, if the hook finds the new log message ill-formatted, the\nrebase will be interrupted with the unchanged commit replayed and the\nnew log message in `$GIT_DIR/COMMIT_EDITMSG`.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    |  2 +-\n t/t3404-rebase-interactive.sh | 14 ++++++++++++++\n 2 files changed, 15 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 54c4614..570c4e9 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -504,7 +504,7 @@ do_next () {\n \n \t\tmark_action_done\n \t\tdo_pick $sha1 \"$rest\"\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\texit_with_patch $sha1 1\n \t\t}\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex abb829e..ecdab11 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -683,6 +683,13 @@ test_expect_success 'setup failing pre-commit' '\n \ttest_commit --no-verify pre-commit-violated-3\n '\n \n+test_expect_success 'reword a commit violating pre-commit' '\n+\tgit checkout -b reword-violating-pre-commit violating-pre-commit &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\tenv FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n test_expect_success 'squash commits violating pre-commit' '\n \tgit checkout -b squash-violating-pre-commit violating-pre-commit &&\n \ttest_when_finished reset_rebase &&\n@@ -726,6 +733,13 @@ test_expect_success 'rebase a commit violating commit-msg' '\n \tFAKE_LINES=\"1\" git rebase -i master\n '\n \n+test_expect_success 'reword a commit violating commit-msg' '\n+\tgit checkout -b reword-violating-commit-msg violating-commit-msg &&\n+\ttest_when_finished reset_rebase &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"reword 1\" git rebase -i master\n+'\n+\n test_expect_success 'squash commits violating commit-msg' '\n \tgit checkout -b squash-violating-commit-msg violating-commit-msg &&\n \tset_fake_editor &&\n-- \n2.0.1\n"},{"id":"247882","messageId":"ec6319e4ee8c594360a0678d05cc9c6e178af7fa.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 10/27] rebase -i: teach do_pick the option --edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:53Z","receivedAt":"2014-08-18T21:22:53Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`. To cater for\nthe different pick behaviours (like `reword`), `do_pick` accepts\nseveral options not only from the git-cherry-pick but also the\ngit-commit interface. Add the common option `--edit` to let the user\nedit the log message of the named commit.\n\nLoop over `$@` to parse the `do_pick` arguments. Assign the local\nvariable `edit` if one of the options is `--edit` so that the\nremainder of `do_pick` can easily check whether the client code asked\nto edit the commit message. If one of the options is unknown, mention\nit on the console and `die`. Break the loop on the first non-option\nand do some sanity checking to ensure that there exactly two\nnon-options, which are interpreted by the remainder as `<commit>` and\n`<title>` like before.\n\n`do_pick` ought to act as a wrapper around `cherry-pick`.\nUnfortunately, it cannot just forward `--edit` to the `cherry-pick`\ncommand line. The assembled command line is executed within a command\nsubstitution for controlling the verbosity of `rebase--interactive`.\nPassing `--edit` would either hang the terminal or clutter the\nsubstituted command output with control sequences. Execute the\n`reword` code from `do_next` instead if the option `--edit` is\nspecified.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 43 +++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 43 insertions(+)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 570c4e9..8a89ced 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -461,7 +461,42 @@ record_in_rewritten() {\n \tesac\n }\n \n+# Apply the changes introduced by the given commit to the current head.\n+#\n+# do_pick [--edit] <commit> <title>\n+#\n+# Wrapper around git-cherry-pick.\n+#\n+# -e, --edit\n+#     After picking <commit>, open an editor and let the user edit the\n+#     commit message. The editor contents becomes the commit message of\n+#     the new head. This creates a fresh commit.\n+#\n+# <commit>\n+#     The commit to cherry-pick.\n+#\n+# <title>\n+#     The commit message title of <commit>. Used for information\n+#     purposes only.\n do_pick () {\n+\tedit=\n+\twhile test $# -gt 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-e|--edit)\n+\t\t\tedit=y\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\tshift\n+\tdone\n+\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n \t\t# Set the correct commit message and author info on the\n@@ -483,6 +518,14 @@ do_pick () {\n \t\tpick_one $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n+\n+\tif test -n \"$edit\"\n+\tthen\n+\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n+\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n+\t\t\texit_with_patch $1 1\n+\t\t}\n+\tfi\n }\n \n do_next () {\n-- \n2.0.1\n"},{"id":"247883","messageId":"3f8d98069b5920883d55b666dd344cc02c174c1e.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 11/27] rebase -i: implement reword in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:54Z","receivedAt":"2014-08-18T21:22:54Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `reword` replays a commit like `pick` but lets\nthe user also edit the commit's log message. If one thinks of `pick`\nentries as scheduled `cherry-pick` command lines, then `reword`\nbecomes an alias for the command line `cherry-pick --edit`. The\nporcelain `rebase--interactive` defines a function `do_pick` for\nprocessing the `pick` entries on to-do lists. Reimplement `reword` in\nterms of `do_pick --edit`.\n\nIf the user picks a commit using the to-do list line\n\n    reword fa1afe1 Some change\n\nexecute the command `do_pick --edit fa1afe1 \"Some change\"` which\ncarries out exactly the same steps as the case arm for `reword` in\n`do_next` so far.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 6 +-----\n 1 file changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8a89ced..2d768b3 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -546,11 +546,7 @@ do_next () {\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n-\t\t\texit_with_patch $sha1 1\n-\t\t}\n+\t\tdo_pick --edit $sha1 \"$rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n-- \n2.0.1\n"},{"id":"247886","messageId":"93551acf7a6d2bd861c071c6d344247b9b4094dd.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 12/27] rebase -i: log the replay of root commits","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:55Z","receivedAt":"2014-08-18T21:22:55Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits specifies the option\n`-q` which suppresses the commit summary message. However,\ngit-rebase--interactive tends to tell the user about the commits it\ncreates in the final history, if she wishes (cf. command line option\n`--verbose`). The code parts handling non-root commits and squash\ncommits all output commit summary messages. Do not make the replay of\nroot commits an exception. Remove the option to make the report of\nthe rebased history complete. Do not forget to wrap the git-commit\ncommand line in `output` so that the summary is shown if git-rebase\nis called with the `--verbose` option but suppressed otherwise.\n\nIt is OK that the commit summary is still suppressed when git-commit\nis used to initialize the authorship of the sentinel commit because\nthis additional commit is an implementation detail hidden from the\nfinal history. The removed `-q` option was probably introduced as a\ncopy-and-paste error stemming from that part of the root commit\nhandling code.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2d768b3..f4bb822 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -510,8 +510,8 @@ do_pick () {\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n-\t\t\tgit commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 \\\n+\t\t\toutput git commit --allow-empty --allow-empty-message \\\n+\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"247884","messageId":"eea24286b323e225fac4239a25d4c495e753eea0.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 13/27] rebase -i: do not use -C when --no-edit is sufficient","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:56Z","receivedAt":"2014-08-18T21:22:56Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The command line used to recreate root commits uses `-C` to suppress\nthe log message editor. This is unnecessarily confusing, though,\nbecause that suppression is a secondary effect of the option. The\nmain purpose of `-C` is to pull the metadata from another commit, but\nhere we know that this is a no-op, since we are amending a commit\njust created from the same data.\n\nAt the time `-C` was introduced, git-commit did not yet have a\ndocumented `--no-edit`, and this was a reasonable way to get the\ndesired behavior. Switch it to use `--no-edit` to make the intended\neffect more obvious.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex f4bb822..6561831 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -511,7 +511,7 @@ do_pick () {\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n \t\t\tpick_one -n $1 &&\n \t\t\toutput git commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n -C $1 \\\n+\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n \t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-- \n2.0.1\n"},{"id":"247885","messageId":"1ac131d6fbcb3ba7e086e31db9a8d87cae66b8b5.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 14/27] rebase -i: commit only once when rewriting picks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:57Z","receivedAt":"2014-08-18T21:22:57Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The options passed to `do_pick` determine whether the picked commit\nwill be rewritten or not. If the commit gets rewritten, because the\nuser requested to edit the commit message for instance, let\n`pick_one` merely apply the changes introduced by the commit and do\nnot commit the resulting tree yet. If the commit is replayed as is,\nleave it to `pick_one` to recreate the commit (possibly by\nfast-forwarding the head). This makes it easier to combine git-commit\noptions like `--edit` and `--amend` in `do_pick` because\ngit-cherry-pick does not support `--amend`.\n\nIn the case of `--edit`, do not `exit_with_patch` but assign\n`rewrite` to pick the changes with `-n`. If the pick conflicts, no\ncommit is created which we would have to amend when continuing the\nrebase. To complete the pick after the conflicts are resolved the\nuser just resumes with `git rebase --continue`.\n\ngit-commit lets the user edit the commit log message by default. We\ndo not want that for the rewriting git-commit command line because\nthe default behaviour of git-rebase is exactly the opposite. Pass\n`--no-edit` when rewriting a picked commit. An explicit `--edit`\npassed to `do_pick` (for instance, when reword is executed) enables\nthe editor launch again. Similarly, pass `--allow-empty-message`\nunless the log message is edited.\n\nIf `rebase--interactive` is used to rebase a complete branch onto\nsome head, `rebase` creates a sentinel commit that requires special\ntreatment by `do_pick`. Do not finalize the pick here either because\nits commit message can be altered as for any other pick. Since the\norphaned root commit gets a temporary parent, it is always rewritten.\nSafely use the rewrite infrastructure of `do_pick` to create the\nfinal commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 41 ++++++++++++++++++++++++++---------------\n t/t3404-rebase-interactive.sh | 10 ++++++++++\n 2 files changed, 36 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6561831..181e06a 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -63,9 +63,10 @@ msgnum=\"$state_dir\"/msgnum\n author_script=\"$state_dir\"/author-script\n \n # When an \"edit\" rebase command is being processed, the SHA1 of the\n-# commit to be edited is recorded in this file.  When \"git rebase\n-# --continue\" is executed, if there are any staged changes then they\n-# will be amended to the HEAD commit, but only provided the HEAD\n+# commit to be edited is recorded in this file.  The same happens when\n+# rewriting a root commit fails, for instance \"reword\".  When \"git\n+# rebase --continue\" is executed, if there are any staged changes then\n+# they will be amended to the HEAD commit, but only provided the HEAD\n # commit is still the commit to be edited.  When any other rebase\n # command is processed, this file is deleted.\n amend=\"$state_dir\"/amend\n@@ -479,12 +480,17 @@ record_in_rewritten() {\n #     The commit message title of <commit>. Used for information\n #     purposes only.\n do_pick () {\n-\tedit=\n+\tallow_empty_message=y\n+\trewrite=\n+\trewrite_amend=\n+\trewrite_edit=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n \t\t-e|--edit)\n-\t\t\tedit=y\n+\t\t\trewrite=y\n+\t\t\trewrite_edit=y\n+\t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n \t\t\tdie \"do_pick: unrecognized option -- $1\"\n@@ -499,6 +505,10 @@ do_pick () {\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n+\t\trewrite=y\n+\t\trewrite_amend=y\n+\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\n \t\t# Set the correct commit message and author info on the\n \t\t# sentinel root before cherry-picking the original changes\n \t\t# without committing (-n).  Finally, update the sentinel again\n@@ -509,22 +519,23 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 &&\n-\t\t\toutput git commit --allow-empty --allow-empty-message \\\n-\t\t\t\t   --amend --no-post-rewrite -n --no-edit \\\n-\t\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tpick_one -n $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \telse\n-\t\tpick_one $1 ||\n+\t\tpick_one ${rewrite:+-n} $1 ||\n \t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n \tfi\n \n-\tif test -n \"$edit\"\n+\tif test -n \"$rewrite\"\n \tthen\n-\t\toutput git commit --allow-empty --amend --no-post-rewrite --no-pre-commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} || {\n-\t\t\twarn \"Could not amend commit after successfully picking $1... $2\"\n-\t\t\texit_with_patch $1 1\n-\t\t}\n+\t\teval $(get_author_ident_from_commit $1)\n+\t\tdo_with_author output git commit \\\n+\t\t\t   --allow-empty --no-post-rewrite -n --no-edit \\\n+\t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_amend:+--amend} \\\n+\t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n \tfi\n }\n \ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex ecdab11..8de7a39 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -270,6 +270,16 @@ test_expect_success 'retain authorship' '\n \tgit show HEAD | grep \"^Author: Twerp Snog\"\n '\n \n+test_expect_success 'retain authorship (reword)' '\n+\techo A > file8 &&\n+\tgit add file8 &&\n+\ttest_tick &&\n+\tGIT_AUTHOR_NAME=\"Twerp Snog\" git commit -m \"different author\" &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"reword 1\" git rebase -i --onto master HEAD^ &&\n+\tgit show HEAD | grep \"^Author: Twerp Snog\"\n+'\n+\n test_expect_success 'setup squash/fixup reverted and fixed feature' '\n \tgit checkout -b reverted-feature master &&\n \ttest_commit feature &&\n-- \n2.0.1\n"},{"id":"247869","messageId":"9d68cb8df89937fa71a93416d573213fcadec6ba.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 15/27] rebase -i: do not die in do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:58Z","receivedAt":"2014-08-18T21:22:58Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Since `do_pick` might be executed in a sub-shell (a modified author\nenvironment for instance), calling `die` in `do_pick` has no effect\nbut exiting the sub-shell with a failure exit status. The\ngit-rebase--interactive script is not terminated. Moreover, if\n`do_pick` is called while a squash or fixup is in effect,\n`die_with_patch` will discard `$squash_msg` as commit message.\nLastly, after a `die` in `do_pick` `do_next` has no chance to\nreschedule tasks that failed before changes could be applied.\n\nIndicate an error in `do_pick` using return statements and properly\nkill the script at the call sites. Although possible in principle,\nthe issued error messages are no more indicating whether `do_pick`\nfailed while applying or while committing the changes. This reduces\ncode complexity at the call site and does not matter from a user's\npoint of view because a glance at the index reveals whether there are\nconflicts or not and in-depth troubleshooting is still possible using\nthe `--verbose` option.\n\nRemove the commit message title argument from `do_pick`'s interface,\nwhich has become unused.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 34 +++++++++++++++++++---------------\n 1 file changed, 19 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 181e06a..a5a8aa3 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit> <title>\n+# do_pick [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -476,9 +476,11 @@ record_in_rewritten() {\n # <commit>\n #     The commit to cherry-pick.\n #\n-# <title>\n-#     The commit message title of <commit>. Used for information\n-#     purposes only.\n+# The return value is 1 if applying the changes resulted in a conflict\n+# and 2 if the specified arguments were incorrect. If the changes could\n+# be applied successfully but creating the commit failed, a value\n+# greater than 2 is returned. No commit is created in either case and\n+# the index is left with the (conflicting) changes in place.\n do_pick () {\n \tallow_empty_message=y\n \trewrite=\n@@ -493,7 +495,8 @@ do_pick () {\n \t\t\tallow_empty_message=\n \t\t\t;;\n \t\t-*)\n-\t\t\tdie \"do_pick: unrecognized option -- $1\"\n+\t\t\twarn \"do_pick: unrecognized option -- $1\"\n+\t\t\treturn 2\n \t\t\t;;\n \t\t*)\n \t\t\tbreak\n@@ -501,7 +504,11 @@ do_pick () {\n \t\tesac\n \t\tshift\n \tdone\n-\ttest $# -ne 2 && die \"do_pick: wrong number of arguments\"\n+\tif test $# -ne 1\n+\tthen\n+\t\twarn \"do_pick: wrong number of arguments\"\n+\t\treturn 2\n+\tfi\n \n \tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n \tthen\n@@ -519,11 +526,9 @@ do_pick () {\n \t\t# rebase --continue.\n \t\tgit commit --allow-empty --allow-empty-message --amend \\\n \t\t\t   --no-post-rewrite -n -q -C $1 &&\n-\t\t\tpick_one -n $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\t\tpick_one -n $1 || return 1\n \telse\n-\t\tpick_one ${rewrite:+-n} $1 ||\n-\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\t\tpick_one ${rewrite:+-n} $1 || return 1\n \tfi\n \n \tif test -n \"$rewrite\"\n@@ -534,8 +539,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n-\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\tdie_with_patch $1 \"Could not rewrite commit after successfully picking $1... $2\"\n+\t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n }\n \n@@ -550,21 +554,21 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 \"$rest\"\n+\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 \"$rest\"\n+\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n-- \n2.0.1\n"},{"id":"247868","messageId":"cebade19be37aeea66f823ac4a4289c916f04d6c.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 16/27] rebase -i: teach do_pick the option --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:22:59Z","receivedAt":"2014-08-18T21:22:59Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list commands `pick`, `reword`\nand `edit`. To cater for the different pick behaviours (like\n`squash`), `do_pick` accepts several options not only from the\ngit-cherry-pick but also the git-commit interface.\n\nAdd the option `--amend` from the git-commit interface to the options\npool of `do_pick`. It creates a new commit for the changes introduced\nby the picked commit and the previous one. The previous commit is\nthen replaced with the new commit. If no other options are specified,\nthe log message of the previous commit is used.\n\nBe careful when `--amend` is used to pick a root commit because HEAD\nmight point to the sentinel commit but there is still nothing to\namend. Be sure to initialize `amend` so that commits are squashed\neven when git-rebase--interactive is interrupted for resolving\nconflicts. It is not a mistake to do the initialization regardless of\nany conflicts because `amend` is always cleared before the next to-do\nitem is processed.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 18 +++++++++++++++++-\n 1 file changed, 17 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex a5a8aa3..20a637a 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,16 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--edit] <commit>\n+# do_pick [--amend] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --amend\n+#     After picking <commit>, replace the current head commit with a new\n+#     commit that also introduces the changes of <commit>.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -489,6 +495,16 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--amend)\n+\t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse -q --verify HEAD >/dev/null\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: nothing to amend\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_amend=y\n+\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n-- \n2.0.1\n"},{"id":"247871","messageId":"7fde59a391dea9474eb9b2ad07667fe528086922.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 17/27] rebase -i: teach do_pick the option --file","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:00Z","receivedAt":"2014-08-18T21:23:00Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement the to-do list command `pick`, `reword` and\n`edit`. To cater for the different pick behaviours (like `squash`),\n`do_pick` accepts several options not only from the git-cherry-pick\nbut also the git-commit interface.\n\nAdd the option `--file` from the git-commit interface to the options\npool of `do_pick`. It expects an argument itself which is interpreted\nas a file path and takes the commit message from the given file. If\n`--file` is passed to `do_pick`, assign the given file path to the\nlocal variable `rewrite_message` and relay the option\n\n    --file \"$rewrite_message\"\n\nto the git-commit command line which creates the commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 20 +++++++++++++++++++-\n 1 file changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 20a637a..f8be238 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,7 +464,7 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--edit] <commit>\n+# do_pick [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n@@ -474,6 +474,12 @@ record_in_rewritten() {\n #\n #     _This is not a git-cherry-pick option._\n #\n+# -F <file>, --file <file>\n+#     Take the commit message from the given file. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # -e, --edit\n #     After picking <commit>, open an editor and let the user edit the\n #     commit message. The editor contents becomes the commit message of\n@@ -492,6 +498,7 @@ do_pick () {\n \trewrite=\n \trewrite_amend=\n \trewrite_edit=\n+\trewrite_message=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n@@ -505,6 +512,16 @@ do_pick () {\n \t\t\trewrite_amend=y\n \t\t\tgit rev-parse --verify HEAD >\"$amend\"\n \t\t\t;;\n+\t\t-F|--file)\n+\t\t\tif test $# -eq 0\n+\t\t\tthen\n+\t\t\t\twarn \"do_pick: option --file specified but no <file> given\"\n+\t\t\t\treturn 2\n+\t\t\tfi\n+\t\t\trewrite=y\n+\t\t\trewrite_message=$2\n+\t\t\tshift\n+\t\t\t;;\n \t\t-e|--edit)\n \t\t\trewrite=y\n \t\t\trewrite_edit=y\n@@ -555,6 +572,7 @@ do_pick () {\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n \t\t\t   ${rewrite_amend:+--amend} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n+\t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n \tfi\n }\n-- \n2.0.1\n"},{"id":"247873","messageId":"7b099a9806ac31d5b686c6fb790301c0c14aae67.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 18/27] rebase -i: remove no-op do_with_author git commit --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:01Z","receivedAt":"2014-08-18T21:23:01Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The author script is a file in the state directory that contains\nassignments of the environment variables\n\n    GIT_AUTHOR_NAME\n    GIT_AUTHOR_EMAIL\n    GIT_AUTHOR_DATE\n\nto be evaluated by the shell. It is used to store author information\nand has two applications in `git-rebase--interactive.sh`. Firstly,\nthe authorship of squash commits is read from it while the squash\ncommit is being amended step by step. Secondly, after conflict\nresolution `git rebase --continue` restores the author information of\nthe original commit by sourcing the author script. For the\nassignments of the git environment variables to take effect,\ngit-rebase--interactive executes the respective git-commit commands\nwrapped in `do_with_author`. That shell function executes the named\ncommand in a subshell that exports the git environment variables.\n\nSince\n\n    git commit --amend\n\nhas been used instead of\n\n    git reset --soft HEAD^\n    git commit\n\nto amend squash commits, wrapping git-commit in `do_with_author` has\nbecome a no-op because, unless the `--reset-author` option is\nspecified, `git commit --amend` ignores the user environment and\nreuses the authorship of the commit it amends. To make the code\nclearer and until we decide to use other authorships for squash\ncommits than the one of the first commit, unwrap `git commit\n--amend`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 17 +++++++----------\n t/t3404-rebase-interactive.sh | 23 +++++++++++++++++++++++\n 2 files changed, 30 insertions(+), 10 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex f8be238..ab807e5 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -622,9 +622,6 @@ do_next () {\n \n \t\tmark_action_done\n \t\tupdate_squash_messages $squash_style $sha1\n-\t\tauthor_script_content=$(get_author_ident_from_commit HEAD)\n-\t\techo \"$author_script_content\" > \"$author_script\"\n-\t\teval \"$author_script_content\"\n \t\tif ! pick_one -n $sha1\n \t\tthen\n \t\t\tgit rev-parse --verify HEAD >\"$amend\"\n@@ -634,7 +631,7 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n+\t\t\toutput git commit --allow-empty-message --allow-empty \\\n \t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie_failed_squash $sha1 \"$rest\"\n@@ -643,14 +640,14 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_with_author output git commit --allow-empty-message --allow-empty \\\n+\t\t\t\toutput git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n \t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n-\t\t\t\tdo_with_author output git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n+\t\t\t\toutput git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n@@ -939,7 +936,7 @@ continue)\n \tthen\n \t\t: Nothing to commit -- skip this\n \telse\n-\t\tif ! test -f \"$author_script\"\n+\t\tif ! test -f \"$author_script\" && ! test -f \"$amend\"\n \t\tthen\n \t\t\tgpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")}\n \t\t\tdie \"You have staged changes in your working tree. If these changes are meant to be\n@@ -956,8 +953,6 @@ In both case, once you're done, continue with:\n   git rebase --continue\n \"\n \t\tfi\n-\t\t. \"$author_script\" ||\n-\t\t\tdie \"Error trying to find the author identity to amend commit\"\n \t\tif test -f \"$amend\"\n \t\tthen\n \t\t\tcurrent_head=$(git rev-parse --verify HEAD)\n@@ -965,10 +960,12 @@ In both case, once you're done, continue with:\n \t\t\tdie \"\\\n You have uncommitted changes in your working tree. Please, commit them\n first and then run 'git rebase --continue' again.\"\n-\t\t\tdo_with_author git commit --amend --no-verify -F \"$msg\" -e \\\n+\t\t\tgit commit --amend --no-verify -F \"$msg\" -e \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\telse\n+\t\t\t. \"$author_script\" ||\n+\t\t\t\tdie \"Error trying to find the author identity to amend commit\"\n \t\t\tdo_with_author git commit --no-verify -F \"$msg\" -e \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 8de7a39..c037a07 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -1270,4 +1270,27 @@ test_expect_success 'fixup commits with empty commit log messages' '\n \tenv FAKE_LINES=\"1 fixup 2\" git rebase -i master\n '\n \n+test_expect_success 'squash commits have authorship of the first commit' '\n+\tgit checkout -b squash-authorship master &&\n+\tgit cat-file commit HEAD~3 | sed -n -e \"/^$/q\" -e \"/^author /p\" >expected.author &&\n+\ttest_tick &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 squash 2 squash 3 fixup 4\" git rebase -i HEAD~4 &&\n+\tgit cat-file commit HEAD | sed -n -e \"/^$/q\" -e \"/^author /p\" >actual.author &&\n+\ttest_cmp expected.author actual.author\n+'\n+\n+test_expect_success 'squash commits have authorship of the first commit after conflict' '\n+\tgit checkout -b squash-authorship-conflict conflict-branch &&\n+\tgit cat-file commit HEAD~3 | sed -n -e \"/^$/q\" -e \"/^author /p\" >expected.author &&\n+\ttest_tick &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 squash 2 squash 4 fixup 3\" git rebase -i HEAD~4 &&\n+\tgit checkout --ours conflict &&\n+\tgit add conflict &&\n+\tgit rebase --continue &&\n+\tgit cat-file commit HEAD | sed -n -e \"/^$/q\" -e \"/^author /p\" >actual.author &&\n+\ttest_cmp expected.author actual.author\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"247880","messageId":"27101bc167217e58a3b694e113d991d1d76d7be8.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 19/27] rebase -i: prepare for squash in terms of do_pick --amend","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:02Z","receivedAt":"2014-08-18T21:23:02Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Rewrite `squash` and `fixup` handling in `do_next` using the sequence\n\n    pick_one\n    commit\n\nin order to test the correctness of a single `do_squash` or\nparameterised `do_pick` and make the subsequent patch reimplementing\n`squash` in terms of such a single function more readable.\n\nDo not call `rm -f \"$GIT_DIR\"/MERGE_MSG` since it has no effect on\nthe state after git-rebase--interactive terminates. The option `-F`\nmakes git-commit ignore `MERGE_MSG` for the log message. If\ngit-commit succeeds, `MERGE_MSG` is removed, and if it fails,\n`MERGE_MSG` is overwritten by the error sequence `die_failed_squash`.\nIn summary, removing `MERGE_MSG` neither influences the squash commit\nmessage nor the file state after git-commit returns.\n\nMoreover, `pick_one` ignores `$GIT_DIR/SQUASH_MSG` and does not touch\n`$squash_msg` so that it is correct to execute `pick_one` immediately\nbefore git-commit.\n\nMight be squashed into the subsequent commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 21 +++++++++++++++------\n 1 file changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex ab807e5..614579c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -622,15 +622,15 @@ do_next () {\n \n \t\tmark_action_done\n \t\tupdate_squash_messages $squash_style $sha1\n-\t\tif ! pick_one -n $sha1\n-\t\tthen\n-\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\tdie_failed_squash $sha1 \"$rest\"\n-\t\tfi\n \t\tcase \"$(peek_next_command)\" in\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n+\t\t\tif ! pick_one -n $sha1\n+\t\t\tthen\n+\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\tfi\n \t\t\toutput git commit --allow-empty-message --allow-empty \\\n \t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n@@ -640,13 +640,22 @@ do_next () {\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\toutput git commit --allow-empty-message --allow-empty \\\n \t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\trm -f \"$GIT_DIR\"/MERGE_MSG\n+\t\t\t\tif ! pick_one -n $sha1\n+\t\t\t\tthen\n+\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n+\t\t\t\tfi\n \t\t\t\toutput git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n \t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n-- \n2.0.1\n"},{"id":"247881","messageId":"4e81ed23e4cb5344fc5e8feb9e8c8bbd2d24b545.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 20/27] rebase -i: implement squash in terms of do_pick","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:03Z","receivedAt":"2014-08-18T21:23:03Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The to-do list command `squash` and its close relative `fixup` replay\nthe changes of a commit like `pick` but do not recreate the commit.\nInstead they replace the previous commit with a new commit that also\nintroduces the changes of the squashed commit. This is roughly like\ncherry-picking without committing and using git-commit to amend the\nprevious commit.\n\nThe to-do list\n\n    pick   a Some changes\n    squash b Some more changes\n\ngets translated into the sequence of git commands\n\n    git cherry-pick a\n    git cherry-pick -n b\n    git commit --amend\n\nand if git-cherry-pick supported `--amend` this would look even more\nlike the to-do list it is based on\n\n    git cherry-pick a\n    git cherry-pick --amend b.\n\nSince `do_pick` takes care of `pick` entries and the above suggests\n`squash` as an alias for `pick --amend`, reimplement `squash` in\nterms of `do_pick --amend`. Introduce `$squash_msg` as the commit\nmessage via the `--file` option. When the last commit of a squash\nseries is processed, the user is asked to review the log message.\nPass `--edit` as additional option in this case. The only difference\nin the options passed to git-commit and `do_pick` is the omitted\n`--no-verify`. However, `do_pick` does not execute the verification\nhooks anyway because it solely replays commits and assumes that they\nhave been verified before.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 32 ++++++--------------------------\n 1 file changed, 6 insertions(+), 26 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 614579c..6a123f0 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -626,39 +626,19 @@ do_next () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tif ! pick_one -n $sha1\n-\t\t\tthen\n-\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\tfi\n-\t\t\toutput git commit --allow-empty-message --allow-empty \\\n-\t\t\t\t--amend --no-verify -F \"$squash_msg\" \\\n-\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\tdo_pick --amend -F \"$squash_msg\" $sha1 \\\n+\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\t;;\n \t\t*)\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\toutput git commit --allow-empty-message --allow-empty \\\n-\t\t\t\t\t--amend --no-verify -F \"$fixup_msg\" \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_pick --amend -F \"$fixup_msg\" $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\tif ! pick_one -n $sha1\n-\t\t\t\tthen\n-\t\t\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n-\t\t\t\t\tdie_failed_squash $sha1 \"Could not apply $sha1... $rest\"\n-\t\t\t\tfi\n-\t\t\t\toutput git commit --allow-empty --amend --no-pre-commit -F \"$GIT_DIR\"/SQUASH_MSG -e \\\n-\t\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n-\t\t\t\t\tdie_failed_squash $sha1 \"$rest\"\n+\t\t\t\tdo_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $sha1 \\\n+\t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n \t\t\tif test -z \"$keep_empty\" && is_empty_commit HEAD\n-- \n2.0.1\n"},{"id":"247872","messageId":"f2bd4b597ddabc0fb79d40b494041a43b0ffbddf.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 21/27] rebase -i: explicitly distinguish replay commands and exec tasks","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:04Z","receivedAt":"2014-08-18T21:23:04Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"There are two kinds of to-do list commands available. One kind\nreplays a commit (`pick`, `reword`, `edit`, `squash` and `fixup` that\nis) and the other executes a shell command (`exec`). We will call the\nfirst kind replay commands.\n\nThe two kinds of tasks are scheduled using different line formats.\nReplay commands expect a commit hash argument following the command\nname and exec concatenates all arguments to assemble a command line.\n\nAdhere to the distinction of formats by not trying to parse the\n`sha1` field unless we are dealing with a replay command. Move the\nreplay command handling code to a new function `do_replay` which\nassumes the first argument to be a commit hash and make no more such\nassumptions in `do_next`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 42 ++++++++++++++++++++++++++++--------------\n 1 file changed, 28 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6a123f0..e140bf0 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -577,13 +577,12 @@ do_pick () {\n \tfi\n }\n \n-do_next () {\n-\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest < \"$todo\"\n+do_replay () {\n+\tcommand=$1\n+\tsha1=$2\n+\trest=$3\n+\n \tcase \"$command\" in\n-\t\"$comment_char\"*|''|noop)\n-\t\tmark_action_done\n-\t\t;;\n \tpick|p)\n \t\tcomment_for_reflog pick\n \n@@ -659,6 +658,28 @@ do_next () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\twarn \"Unknown command: $command\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\t\t;;\n+\tesac\n+}\n+\n+do_next () {\n+\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\tread -r command sha1 rest <\"$todo\"\n+\n+\tcase \"$command\" in\n+\t\"$comment_char\"*|''|noop)\n+\t\tmark_action_done\n+\t\t;;\n \tx|\"exec\")\n \t\tread -r command rest < \"$todo\"\n \t\tmark_action_done\n@@ -698,14 +719,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\twarn \"Unknown command: $command $sha1 $rest\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n+\t\tdo_replay $command $sha1 \"$rest\"\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n-- \n2.0.1\n"},{"id":"247879","messageId":"c054086dab6d301d0a02b4440bc047036f305fd6.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 22/27] rebase -i: parse to-do list command line options","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:05Z","receivedAt":"2014-08-18T21:23:05Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Read in to-do list lines as\n\n    command args\n\ninstead of\n\n    command sha1 rest\n\nso that to-do list command lines can specify additional arguments\napart from the commit hash and the log message title, which become\nthe non-options in `args`. Loop over `args`, put all options (an\nargument beginning with a dash) in `opts`, stop the loop on the first\nnon-option and assign it to `sha1`. For instance, the to-do list\n\n    reword --signoff fa1afe1 Some change\n\nis parsed as `command=reword`, `opts= '--signoff'` (including the\nsingle quotes and the space for evaluation and concatenation of\noptions), `sha1=fa1afel` and `rest=Some change`. The loop does not\nknow the options it parses so that options that take an argument\nthemselves are not supported at the moment. Neither are options that\ncontain spaces because the shell expansion of `args` in `do_next`\ninterprets white space characters as argument separator.\n\nPrint an error message for unknown or unsupported command line\noptions, which means an error for all specified options at the\nmoment. Cleanly break the `do_next` loop by assigning a reason to the\nlocal variable `malformed`, which triggers the unknown command code\nin `do_replay`. Move the error code to the beginning of `do_replay`\nso that unknown commands are reported before bad options are as only\nthe first error we come across is reported. For instance, the to-do\nlist from above produces the error\n\n    Unknown 'reword' option: --signoff\n    Please fix this using 'git rebase --edit-todo'.\n\nThe to-do list is also parsed when the commit hashes are translated\nbetween long and short format before and after the to-do list is\nedited. Apply the same procedure as in `do_replay` with the exception\nthat we only care about where the options stop and the commit hash\nbegins. Do not reject any options when transforming the commit\nhashes.\n\nEnable the specification of to-do list command line options in\n`FAKE_LINES` the same way this is accomplished for command lines\npassed to `exec`. Define a new `fake_editor.sh` that edits a static\nto-do list instead of the one passed as argument when invoked by\ngit-rebase. Add a test case that checks that unknown options are\nrefused and can be corrected using `--edit-todo`.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh     | 95 +++++++++++++++++++++++++++++++-----------\n t/lib-rebase.sh                | 20 ++++++++-\n t/t3427-rebase-line-options.sh | 26 ++++++++++++\n 3 files changed, 114 insertions(+), 27 deletions(-)\n create mode 100755 t/t3427-rebase-line-options.sh\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex e140bf0..8b39f2d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -578,30 +578,71 @@ do_pick () {\n }\n \n do_replay () {\n+\tmalformed=\n \tcommand=$1\n-\tsha1=$2\n-\trest=$3\n+\tshift\n+\tcase \"$command\" in\n+\tpick|reword|edit|squash|fixup)\n+\t\t;;\n+\t*)\n+\t\tread -r command <\"$todo\"\n+\t\tmalformed=\"Unknown command: $command\"\n+\t\t;;\n+\tesac\n+\n+\topts=\n+\twhile test $# -gt 0 && test -z \"$malformed\"\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-*)\n+\t\t\tmalformed=\"Unknown '$command' option: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n+\t\topts=\"$opts $1\"\n+\t\tshift\n+\tdone\n+\tsha1=$1\n+\tshift\n+\trest=$*\n+\n+\tif test -n \"$malformed\"\n+\tthen\n+\t\twarn \"$malformed\"\n+\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n+\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n+\t\tthen\n+\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n+\t\telse\n+\t\t\tdie \"$fixtodo\"\n+\t\tfi\n+\tfi\n \n \tcase \"$command\" in\n \tpick|p)\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tdo_pick --edit $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick --edit $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \tedit|e)\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tdo_pick $sha1 || die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick $opts $sha1 \\\n+\t\t\t|| die_with_patch $sha1 \"Could not apply $sha1... $rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\n@@ -625,18 +666,18 @@ do_replay () {\n \t\tsquash|s|fixup|f)\n \t\t\t# This is an intermediate commit; its message will only be\n \t\t\t# used in case of trouble.  So use the long version:\n-\t\t\tdo_pick --amend -F \"$squash_msg\" $sha1 \\\n+\t\t\tdo_pick --amend -F \"$squash_msg\" $opts $sha1 \\\n \t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\t;;\n \t\t*)\n \t\t\t# This is the final command of this squash/fixup group\n \t\t\tif test -f \"$fixup_msg\"\n \t\t\tthen\n-\t\t\t\tdo_pick --amend -F \"$fixup_msg\" $sha1 \\\n+\t\t\t\tdo_pick --amend -F \"$fixup_msg\" $opts $sha1 \\\n \t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\telse\n \t\t\t\tcp \"$squash_msg\" \"$GIT_DIR\"/SQUASH_MSG || exit\n-\t\t\t\tdo_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $sha1 \\\n+\t\t\t\tdo_pick --amend -F \"$GIT_DIR\"/SQUASH_MSG -e $opts $sha1 \\\n \t\t\t\t\t|| die_failed_squash $sha1 \"$rest\"\n \t\t\tfi\n \t\t\trm -f \"$squash_msg\" \"$fixup_msg\"\n@@ -658,23 +699,12 @@ do_replay () {\n \t\tesac\n \t\trecord_in_rewritten $sha1\n \t\t;;\n-\t*)\n-\t\tread -r command <\"$todo\"\n-\t\twarn \"Unknown command: $command\"\n-\t\tfixtodo=\"Please fix this using 'git rebase --edit-todo'.\"\n-\t\tif git rev-parse --verify -q \"$sha1\" >/dev/null\n-\t\tthen\n-\t\t\tdie_with_patch $sha1 \"$fixtodo\"\n-\t\telse\n-\t\t\tdie \"$fixtodo\"\n-\t\tfi\n-\t\t;;\n \tesac\n }\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n-\tread -r command sha1 rest <\"$todo\"\n+\tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n \t\"$comment_char\"*|''|noop)\n@@ -719,7 +749,7 @@ do_next () {\n \t\tfi\n \t\t;;\n \t*)\n-\t\tdo_replay $command $sha1 \"$rest\"\n+\t\tdo_replay $command $args\n \t\t;;\n \tesac\n \ttest -s \"$todo\" && return\n@@ -799,19 +829,34 @@ skip_unnecessary_picks () {\n }\n \n transform_todo_ids () {\n-\twhile read -r command rest\n+\twhile read -r command args\n \tdo\n \t\tcase \"$command\" in\n \t\t\"$comment_char\"* | exec)\n \t\t\t# Be careful for oddball commands like 'exec'\n \t\t\t# that do not have a SHA-1 at the beginning of $rest.\n+\t\t\tnewargs=\\ $args\n \t\t\t;;\n \t\t*)\n-\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" ${rest%% *}) &&\n-\t\t\trest=\"$sha1 ${rest#* }\"\n+\t\t\tnewargs=\n+\t\t\tsha1=\n+\t\t\tfor arg in $args\n+\t\t\tdo\n+\t\t\t\tcase \"$arg\" in\n+\t\t\t\t-*)\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\t*)\n+\t\t\t\t\ttest -z \"$sha1\" &&\n+\t\t\t\t\t\tsha1=$(git rev-parse --verify --quiet \"$@\" $arg) &&\n+\t\t\t\t\t\targ=$sha1\n+\t\t\t\t\tnewargs=\"$newargs $arg\"\n+\t\t\t\t\t;;\n+\t\t\t\tesac\n+\t\t\tdone\n \t\t\t;;\n \t\tesac\n-\t\tprintf '%s\\n' \"$command${rest:+ }$rest\"\n+\t\tprintf '%s\\n' \"$command$newargs\"\n \tdone <\"$todo\" >\"$todo.new\" &&\n \tmv -f \"$todo.new\" \"$todo\"\n }\ndiff --git a/t/lib-rebase.sh b/t/lib-rebase.sh\nindex 0cd1193..104f5bd 100644\n--- a/t/lib-rebase.sh\n+++ b/t/lib-rebase.sh\n@@ -46,8 +46,8 @@ set_fake_editor () {\n \taction=pick\n \tfor line in $FAKE_LINES; do\n \t\tcase $line in\n-\t\tsquash|fixup|edit|reword)\n-\t\t\taction=\"$line\";;\n+\t\tpick*|squash*|fixup*|edit*|reword*)\n+\t\t\taction=$(echo \"$line\" | sed 's/_/ /g');;\n \t\texec*)\n \t\t\techo \"$line\" | sed 's/_/ /g' >> \"$1\";;\n \t\t\"#\")\n@@ -80,6 +80,22 @@ set_cat_todo_editor () {\n \ttest_set_editor \"$(pwd)/fake-editor.sh\"\n }\n \n+# set_fixed_todo_editor takes a file path as argument and installs an\n+# editor script that, firstly, overwrites the file path argument with\n+# the one specified during installation and, secondly, calls\n+# fake-editor.sh for changing the contents as usual. This comes in\n+# handy if it is easier to change some fixed file instead of the one\n+# that will be passed when the editor is being invoked.\n+\n+set_fixed_todo_editor () {\n+\tset_fake_editor\n+\twrite_script fake-editor-wrapper.sh <<-EOF\n+\tcp \"$1\" \"\\$1\"\n+\t\"$(pwd)\"/fake-editor.sh \"\\$1\"\n+\tEOF\n+\ttest_set_editor \"$(pwd)/fake-editor-wrapper.sh\"\n+}\n+\n # checks that the revisions in \"$2\" represent a linear range with the\n # subjects in \"$1\"\n test_linear_range () {\ndiff --git a/t/t3427-rebase-line-options.sh b/t/t3427-rebase-line-options.sh\nnew file mode 100755\nindex 0000000..5881162\n--- /dev/null\n+++ b/t/t3427-rebase-line-options.sh\n@@ -0,0 +1,26 @@\n+#!/bin/sh\n+\n+test_description='git rebase -i with line options'\n+\n+. ./test-lib.sh\n+\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'Set up repository' '\n+\ttest_commit Initial &&\n+\ttest_commit Commit1 &&\n+\ttest_commit Commit2\n+'\n+\n+test_expect_success 'Unknown option' '\n+\tgit checkout -b unknown-option master &&\n+\tset_cat_todo_editor &&\n+\ttest_must_fail git rebase -i HEAD^ >todo &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 pick_--unknown-option 2\" git rebase -i HEAD~2 &&\n+\tset_fixed_todo_editor \"$(pwd)\"/todo &&\n+\tgit rebase --edit-todo &&\n+\tgit rebase --continue\n+'\n+\n+test_done\n-- \n2.0.1\n"},{"id":"247874","messageId":"fafd51bd06a21956dc349c89726d8b2820b4bb2d.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 23/27] rebase -i: teach do_pick the option --reset-author","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:06Z","receivedAt":"2014-08-18T21:23:06Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is used to implement many of the to-do list commands.\nEventually, the complete `do_pick` interface will be exposed to the\nuser in some form or another and those commands will become simple\naliases for the `do_pick` options now used to implement them.\n\nAdd the git-commit option `--reset-author` to the options pool of\n`do_pick`. It rewrites the author date and name of the picked commit\nto match the committer date and name.\n\nIf `--reset-author` is passed to `do_pick`, set the `rewrite` flag\nand relay the option to the git-commit command line which creates the\nfinal commit. If `--amend` is not passed as well, the fresh\nauthorship effect is achieved by the mere fact that we are creating a\nnew commit. Do not even source the ident information in that case\nbecause the user shell might have already exported the respective\nenvironment variables.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 26 ++++++++++++++++++++++----\n 1 file changed, 22 insertions(+), 4 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8b39f2d..6c75bc5 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,18 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# --reset-author\n+#     Pretend the changes were made for the first time. Declare that the\n+#     authorship of the resulting commit now belongs to the committer.\n+#     This also renews the author timestamp. This creates a fresh\n+#     commit.\n+#\n+#     _This is not a git-cherry-pick option._\n+#\n # --amend\n #     After picking <commit>, replace the current head commit with a new\n #     commit that also introduces the changes of <commit>.\n@@ -496,12 +504,17 @@ record_in_rewritten() {\n do_pick () {\n \tallow_empty_message=y\n \trewrite=\n+\trewrite_reset_author=\n \trewrite_amend=\n \trewrite_edit=\n \trewrite_message=\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t--reset-author)\n+\t\t\trewrite=y\n+\t\t\trewrite_reset_author=y\n+\t\t\t;;\n \t\t--amend)\n \t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse -q --verify HEAD >/dev/null\n \t\t\tthen\n@@ -566,11 +579,16 @@ do_pick () {\n \n \tif test -n \"$rewrite\"\n \tthen\n-\t\teval $(get_author_ident_from_commit $1)\n-\t\tdo_with_author output git commit \\\n+\t\tdo_with_author=\n+\t\tif test -z \"$rewrite_reset_author\" && test -z \"$rewrite_amend\"\n+\t\tthen\n+\t\t\teval $(get_author_ident_from_commit $1)\n+\t\t\tdo_with_author=do_with_author\n+\t\tfi\n+\t\t$do_with_author output git commit \\\n \t\t\t   --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n-\t\t\t   ${rewrite_amend:+--amend} \\\n+\t\t\t   ${rewrite_amend:+--amend ${rewrite_reset_author:+--reset-author}} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n \t\t\t   ${gpg_sign_opt:+\"$gpg_sign_opt\"} || return 3\n-- \n2.0.1\n"},{"id":"247876","messageId":"e6224211727d9a1f3edfb00f417f4ac9e385b9f3.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 24/27] rebase -i: teach do_pick the option --signoff","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:07Z","receivedAt":"2014-08-18T21:23:07Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"`do_pick` is the git-cherry-pick wrapper in git-rebase--interactive\nthat is currently used to implement most of the to-do list commands\nand offers additional options that will eventually find their way\nonto to-do lists.\n\nTo extend the repertoire of available options, add the git-commit and\ngit-cherry-pick option `--signoff` to the `do_pick` interface. It\nappends a Signed-off-by: line using the committer identity to the log\nmessage of the picked commit.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 13 ++++++++++++-\n 1 file changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 6c75bc5..73c97a1 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -464,10 +464,15 @@ record_in_rewritten() {\n \n # Apply the changes introduced by the given commit to the current head.\n #\n-# do_pick [--reset-author] [--amend] [--file <file>] [--edit] <commit>\n+# do_pick [--signoff] [--reset-author] [--amend] [--file <file>]\n+#         [--edit] <commit>\n #\n # Wrapper around git-cherry-pick.\n #\n+# -s, --signoff\n+#     Insert a Signed-off-by: line using the committer identity at the\n+#     end of the commit log message. This creates a fresh commit.\n+#\n # --reset-author\n #     Pretend the changes were made for the first time. Declare that the\n #     authorship of the resulting commit now belongs to the committer.\n@@ -504,6 +509,7 @@ record_in_rewritten() {\n do_pick () {\n \tallow_empty_message=y\n \trewrite=\n+\trewrite_signoff=\n \trewrite_reset_author=\n \trewrite_amend=\n \trewrite_edit=\n@@ -511,6 +517,10 @@ do_pick () {\n \twhile test $# -gt 0\n \tdo\n \t\tcase \"$1\" in\n+\t\t-s|--signoff)\n+\t\t\trewrite=y\n+\t\t\trewrite_signoff=y\n+\t\t\t;;\n \t\t--reset-author)\n \t\t\trewrite=y\n \t\t\trewrite_reset_author=y\n@@ -588,6 +598,7 @@ do_pick () {\n \t\t$do_with_author output git commit \\\n \t\t\t   --allow-empty --no-post-rewrite -n --no-edit \\\n \t\t\t   ${allow_empty_message:+--allow-empty-message} \\\n+\t\t\t   ${rewrite_signoff:+--signoff} \\\n \t\t\t   ${rewrite_amend:+--amend ${rewrite_reset_author:+--reset-author}} \\\n \t\t\t   ${rewrite_edit:+--edit --commit-msg} \\\n \t\t\t   ${rewrite_message:+--file \"$rewrite_message\"} \\\n-- \n2.0.1\n"},{"id":"247877","messageId":"38063822188190750b20942d242f5826fe97df4f.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 25/27] rebase -i: do not overwrite user author information","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:08Z","receivedAt":"2014-08-18T21:23:08Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"The shell function `get_author_ident_from_commit` defined by\ngit-sh-setup retrieves the author information from the named commit\nand returns assignments of the environment variables\n\n    GIT_AUTHOR_NAME\n    GIT_AUTHOR_EMAIL\n    GIT_AUTHOR_DATE\n\nready for evaluation by the shell.\n\nThis interface is used in conjunction with the so-called author\nscript which is a git-rebase--interactive state file that contains\nthe `get_author_ident_from_commit` output. It is sourced when `git\nrebase --continue` is executed after conflict resolution to retain\nthe original commit authorship.\n\nThe variable assignments are only exported by the subshell that\nexecutes the git-commit command line that commits the resolved\nconflicts. That is taken care of by wrapping the git-commit call in\n`do_with_author`. However, this is not enough protection from\nmodifying the git environment variables unintentionally because the\nuser running git-rebase could have already exported those herself.\nAnd therefore, a bare git-commit could result in an authorship that\nis neither intended by the user nor by git-rebase--interactive.\n\nWhile it is not an issue now (either `do_with_author`,\ngit-cherry-pick or `--amend` are used to create commits), the\nunnecessary loss of the author name and e-mail copied from the user\nenvironment, and the unneeded fixing of the author date might become\na problem when we decide to support something similar to\n`--reset-author` or `--ignore-date in interactive git-rebase.\n\nDo not assign the git environment variables until in the\n`do_with_author` subshell.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh | 19 ++++++++++---------\n 1 file changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 73c97a1..8fbfe6d 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -166,7 +166,7 @@ make_patch () {\n \ttest -f \"$msg\" ||\n \t\tcommit_message \"$1\" > \"$msg\"\n \ttest -f \"$author_script\" ||\n-\t\tget_author_ident_from_commit \"$1\" > \"$author_script\"\n+\t\techo \"$1\" > \"$author_script\"\n }\n \n die_with_patch () {\n@@ -215,9 +215,13 @@ is_merge_commit()\n }\n \n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n-# GIT_AUTHOR_DATE exported from the current environment.\n+# GIT_AUTHOR_DATE assigned the author information extracted from the\n+# named commit and exported.\n do_with_author () {\n \t(\n+\t\tsha1=$1\n+\t\tshift\n+\t\teval $(get_author_ident_from_commit $sha1)\n \t\texport GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE\n \t\t\"$@\"\n \t)\n@@ -348,13 +352,11 @@ pick_one_preserving_merges () {\n \t\t\ttest \"a$1\" = a-n && die \"Refusing to squash a merge: $sha1\"\n \n \t\t\t# redo merge\n-\t\t\tauthor_script_content=$(get_author_ident_from_commit $sha1)\n-\t\t\teval \"$author_script_content\"\n \t\t\tmsg_content=\"$(commit_message $sha1)\"\n \t\t\t# No point in merging the first parent, that's HEAD\n \t\t\tnew_parents=${new_parents# $first_parent}\n \t\t\tmerge_args=\"--no-log --no-ff\"\n-\t\t\tif ! do_with_author output eval \\\n+\t\t\tif ! do_with_author $sha1 output eval \\\n \t\t\t'git merge ${gpg_sign_opt:+\"$gpg_sign_opt\"} \\\n \t\t\t\t$merge_args $strategy_args -m \"$msg_content\" $new_parents'\n \t\t\tthen\n@@ -592,8 +594,7 @@ do_pick () {\n \t\tdo_with_author=\n \t\tif test -z \"$rewrite_reset_author\" && test -z \"$rewrite_amend\"\n \t\tthen\n-\t\t\teval $(get_author_ident_from_commit $1)\n-\t\t\tdo_with_author=do_with_author\n+\t\t\tdo_with_author=\"do_with_author $1\"\n \t\tfi\n \t\t$do_with_author output git commit \\\n \t\t\t   --allow-empty --no-post-rewrite -n --no-edit \\\n@@ -1041,9 +1042,9 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\telse\n-\t\t\t. \"$author_script\" ||\n+\t\t\ttest -r \"$author_script\" ||\n \t\t\t\tdie \"Error trying to find the author identity to amend commit\"\n-\t\t\tdo_with_author git commit --no-verify -F \"$msg\" -e \\\n+\t\t\tdo_with_author $(cat \"$author_script\") git commit --no-verify -F \"$msg\" -e \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\tfi\n-- \n2.0.1\n"},{"id":"247875","messageId":"e4a115adb51335f197ba5b35437dce8dfa3e363d.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 26/27] rebase -i: refuse to commit when resuming with updated head","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:09Z","receivedAt":"2014-08-18T21:23:09Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"If git-rebase--interactive fails to apply the changes introduced by a\ncommit due to conflicts, it interrupts the rebase process and gives\nthe user a shell to resolve the conflicts manually. The process is\nresumed when the user executes `git rebase --continue`. If the index\nhas changes, the script assumes that those are to be committed under\nthe authorship and with the log message of the commit it tried to\nreplay last. However, that assumption is most likely incorrect if the\nuser has already committed the resolved changes herself. To prevent\ncommitting unrelated changes under the wrong authorship and with the\nwrong log message, at least check that HEAD is still at the same\ncommit by tracking the hash of the last replayed commit. A similar\ncheck already happens before `git rebase --continue` amends the\nprevious commit after an `edit` or a conflicted `squash` command.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n git-rebase--interactive.sh    | 35 +++++++++++++++++++++--------------\n t/t3404-rebase-interactive.sh | 12 ++++++++++++\n 2 files changed, 33 insertions(+), 14 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 8fbfe6d..51ee80c 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -62,13 +62,18 @@ msgnum=\"$state_dir\"/msgnum\n # being rebased.\n author_script=\"$state_dir\"/author-script\n \n-# When an \"edit\" rebase command is being processed, the SHA1 of the\n-# commit to be edited is recorded in this file.  The same happens when\n-# rewriting a root commit fails, for instance \"reword\".  When \"git\n-# rebase --continue\" is executed, if there are any staged changes then\n-# they will be amended to the HEAD commit, but only provided the HEAD\n-# commit is still the commit to be edited.  When any other rebase\n-# command is processed, this file is deleted.\n+# This file keeps track of the SHA1 of the last replayed commit, the\n+# new parent of the next commit being replayed. It is used to make\n+# sure that \"git rebase --continue\" only commits resolved conflicts\n+# or \"edit\" changes automatically.\n+last_head=\"$state_dir\"/last_head\n+\n+# When an \"edit\" or a \"squash\" rebase command is being processed, the\n+# file 'amend' is created. When \"git rebase --continue\" is executed,\n+# if there are any staged changes then they will be amended to the\n+# HEAD commit, but only provided the HEAD commit is still the commit\n+# to be edited or the squash commit. When any other rebase command is\n+# processed, these files are deleted.\n amend=\"$state_dir\"/amend\n \n # For the post-rewrite hook, we make a list of rewritten commits and\n@@ -179,7 +184,8 @@ die_with_patch () {\n exit_with_patch () {\n \techo \"$1\" > \"$state_dir\"/stopped-sha\n \tmake_patch $1\n-\tgit rev-parse --verify HEAD > \"$amend\"\n+\t>\"$amend\"\n+\tgit rev-parse --verify HEAD >\"$last_head\"\n \tgpg_sign_opt_quoted=${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")}\n \twarn \"You can amend the commit now, with\"\n \twarn\n@@ -535,7 +541,7 @@ do_pick () {\n \t\t\tfi\n \t\t\trewrite=y\n \t\t\trewrite_amend=y\n-\t\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t\t>\"$amend\"\n \t\t\t;;\n \t\t-F|--file)\n \t\t\tif test $# -eq 0\n@@ -572,7 +578,7 @@ do_pick () {\n \tthen\n \t\trewrite=y\n \t\trewrite_amend=y\n-\t\tgit rev-parse --verify HEAD >\"$amend\"\n+\t\t>\"$amend\"\n \n \t\t# Set the correct commit message and author info on the\n \t\t# sentinel root before cherry-picking the original changes\n@@ -734,6 +740,7 @@ do_replay () {\n \n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\tgit rev-parse --verify HEAD >\"$last_head\" || exit\n \tread -r command args <\"$todo\"\n \n \tcase \"$command\" in\n@@ -1031,13 +1038,13 @@ In both case, once you're done, continue with:\n   git rebase --continue\n \"\n \t\tfi\n-\t\tif test -f \"$amend\"\n-\t\tthen\n-\t\t\tcurrent_head=$(git rev-parse --verify HEAD)\n-\t\t\ttest \"$current_head\" = $(cat \"$amend\") ||\n+\t\tcurrent_head=$(git rev-parse --verify HEAD)\n+\t\ttest \"$current_head\" = $(cat \"$last_head\") ||\n \t\t\tdie \"\\\n You have uncommitted changes in your working tree. Please, commit them\n first and then run 'git rebase --continue' again.\"\n+\t\tif test -f \"$amend\"\n+\t\tthen\n \t\t\tgit commit --amend --no-verify -F \"$msg\" -e \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex c037a07..5955bd8 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -444,6 +444,18 @@ test_expect_success '--continue tries to commit' '\n \tgit show HEAD | grep chouette\n '\n \n+test_expect_success '--continue does not commit after head is moved' '\n+\tgit reset --hard to-be-rebased@{1} &&\n+\ttest_must_fail git rebase -i --onto new-branch1 HEAD^ &&\n+\techo resolved >file1 &&\n+\tgit add file1 &&\n+\tgit commit &&\n+\techo dirty >file1 &&\n+\ttest_must_fail git rebase --continue &&\n+\tgit checkout file1 &&\n+\tgit rebase --continue\n+'\n+\n test_expect_success 'verbose flag is heeded, even after --continue' '\n \tgit reset --hard master@{1} &&\n \ttest_tick &&\n-- \n2.0.1\n"},{"id":"247878","messageId":"3e91ba1f6f59b9667c329b224a4f54bf0af9ee3e.1408396036.git.bafain@gmail.com","threadId":"36962","inReplyTo":"cover.1408396036.git.bafain@gmail.com","subject":"[PATCH v3 27/27] rebase -i: enable --signoff, --reset-author for pick, reword, edit","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-08-18T21:23:10Z","receivedAt":"2014-08-18T21:23:10Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Lift the general unknown option blockade for the `pick`, `reword` and\n`edit` commands. If `do_cmd` comes across one of the options\n`--signoff` and `--reset-author` while parsing a to-do entry and the\nscheduled command is either `pick` or `reword`, relay the option to\n`do_pick`.\n\nRemember to add Signed-off-by: and to reset the authorship even when\nthe rebase is interrupted for conflict resolution and `git rebase\n--continue` creates the commit. Employ the same mechanism that is\nused to remember amending an interim squash commit after conflict\nresolution or a commit after editing. If a line option was specified,\ncreate the files `signoff` and `resetauthor` respectively in the\nstate directory. While `signoff` is handled by simply specifying the\n`--signoff` option when creating the commit, the `resetauthor` case\nis somewhat more involved. The author script contains the author\ninformation of the replayed commit. Renewing the authorship means\nusing the user environment for the authorship so that we need to skip\nthe author script if `resetauthor` exists and we are not amending. If\nwe are amending, `--reset-author` must be passed to git-commit\nbecause otherwise the authorship of HEAD would be used.\n\n`do_pick` options like `--gpg-sign` and `--file` are not yet\nsupported because `do_cmd` cannot handle option arguments and options\nwith spaces at the moment. `squash` and `fixup` still do not accept\nuser options as the interplay of `--reset-author` and the author\nscript is yet to be determined.\n\nDocument the new options by listing them in the to-do help and giving\na usage example in the \"INTERACTIVE MODE\" section of the git-rebase\nman page.\n\nAdd tests.\n\nSigned-off-by: Fabian Ruch <bafain@gmail.com>\n---\n Documentation/git-rebase.txt   |  13 +++\n git-rebase--interactive.sh     |  38 +++++++-\n t/t3427-rebase-line-options.sh | 192 ++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 240 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 2a93c64..10c0fd2 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -508,6 +508,19 @@ rebasing.\n If you just want to edit the commit message for a commit, replace the\n command \"pick\" with the command \"reword\".\n \n+The commands \"pick\", \"reword\" and \"edit\" understand some well-known\n+options. To add a Signed-off-by line at the end of the commit\n+message, pass the `--signoff` option. The authorship can be renewed\n+by specifying the `--reset-author` option. For instance, before you\n+decide to publish a heavily edited commit you might want to reset the\n+authorship and add your signature. You can do so on a per line basis:\n+\n+-------------------------------------------\n+pick deadbee The oneline of this commit\n+pick --reset-author --signoff fa1afe1 The oneline of the next commit\n+...\n+-------------------------------------------\n+\n 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\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 51ee80c..0db5001 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -72,9 +72,15 @@ last_head=\"$state_dir\"/last_head\n # file 'amend' is created. When \"git rebase --continue\" is executed,\n # if there are any staged changes then they will be amended to the\n # HEAD commit, but only provided the HEAD commit is still the commit\n-# to be edited or the squash commit. When any other rebase command is\n+# to be edited or the squash commit. Similarly, when a Signed-off-by:\n+# should be added to a log message or the authorship should be\n+# renewed, the files 'signoff' and 'resetauthor' are created\n+# respectively, and \"git rebase --continue\" carries out the changes\n+# after conflict resolution. When any other rebase command is\n # processed, these files are deleted.\n amend=\"$state_dir\"/amend\n+signoff=\"$state_dir\"/signoff\n+resetauthor=\"$state_dir\"/resetauthor\n \n # For the post-rewrite hook, we make a list of rewritten commits and\n # their new sha1s.  The rewritten-pending list keeps the sha1s of\n@@ -149,6 +155,10 @@ Commands:\n  f, fixup = like \"squash\", but discard this commit's log message\n  x, exec = run command (the rest of the line) using shell\n \n+Options:\n+ [pick | reword | edit] --signoff = add a Signed-off-by line\n+ [pick | reword | edit] --reset-author = renew authorship\n+\n These lines can be re-ordered; they are executed from top to bottom.\n \n If you remove a line here THAT COMMIT WILL BE LOST.\n@@ -528,10 +538,12 @@ do_pick () {\n \t\t-s|--signoff)\n \t\t\trewrite=y\n \t\t\trewrite_signoff=y\n+\t\t\t>\"$signoff\"\n \t\t\t;;\n \t\t--reset-author)\n \t\t\trewrite=y\n \t\t\trewrite_reset_author=y\n+\t\t\t>\"$resetauthor\"\n \t\t\t;;\n \t\t--amend)\n \t\t\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\" || ! git rev-parse -q --verify HEAD >/dev/null\n@@ -630,6 +642,15 @@ do_replay () {\n \twhile test $# -gt 0 && test -z \"$malformed\"\n \tdo\n \t\tcase \"$1\" in\n+\t\t--signoff|--reset-author)\n+\t\t\tcase \"$command\" in\n+\t\t\tpick|reword|edit)\n+\t\t\t\t;;\n+\t\t\t*)\n+\t\t\t\tmalformed=\"Unsupported '$command' option: $1\"\n+\t\t\t\t;;\n+\t\t\tesac\n+\t\t\t;;\n \t\t-*)\n \t\t\tmalformed=\"Unknown '$command' option: $1\"\n \t\t\t;;\n@@ -739,7 +760,7 @@ do_replay () {\n }\n \n do_next () {\n-\trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n+\trm -f \"$msg\" \"$author_script\" \"$amend\" \"$signoff\" \"$resetauthor\" || exit\n \tgit rev-parse --verify HEAD >\"$last_head\" || exit\n \tread -r command args <\"$todo\"\n \n@@ -1043,15 +1064,28 @@ In both case, once you're done, continue with:\n \t\t\tdie \"\\\n You have uncommitted changes in your working tree. Please, commit them\n first and then run 'git rebase --continue' again.\"\n+\t\trewrite_reset_author=\n+\t\trewrite_signoff=\n+\t\ttest -f \"$resetauthor\" && rewrite_reset_author=y\n+\t\ttest -f \"$signoff\" && rewrite_signoff=y\n \t\tif test -f \"$amend\"\n \t\tthen\n \t\t\tgit commit --amend --no-verify -F \"$msg\" -e \\\n+\t\t\t\t${rewrite_signoff:+--signoff} \\\n+\t\t\t\t${rewrite_reset_author:+--reset-author} \\\n+\t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n+\t\t\t\tdie \"Could not commit staged changes.\"\n+\t\telif test -n \"$rewrite_reset_author\"\n+\t\tthen\n+\t\t\tgit commit --no-verify -F \"$msg\" -e \\\n+\t\t\t\t${rewrite_signoff:+--signoff} \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\telse\n \t\t\ttest -r \"$author_script\" ||\n \t\t\t\tdie \"Error trying to find the author identity to amend commit\"\n \t\t\tdo_with_author $(cat \"$author_script\") git commit --no-verify -F \"$msg\" -e \\\n+\t\t\t\t${rewrite_signoff:+--signoff} \\\n \t\t\t\t${gpg_sign_opt:+\"$gpg_sign_opt\"} ||\n \t\t\t\tdie \"Could not commit staged changes.\"\n \t\tfi\ndiff --git a/t/t3427-rebase-line-options.sh b/t/t3427-rebase-line-options.sh\nindex 5881162..9c9501a 100755\n--- a/t/t3427-rebase-line-options.sh\n+++ b/t/t3427-rebase-line-options.sh\n@@ -6,10 +6,32 @@ test_description='git rebase -i with line options'\n \n . \"$TEST_DIRECTORY\"/lib-rebase.sh\n \n+commit_message () {\n+\tgit cat-file commit \"$1\" | sed '1,/^$/d'\n+}\n+\n+commit_authorship () {\n+\tgit cat-file commit \"$1\" | sed -n '/^$/q;/^author /p'\n+}\n+\n+authorship () {\n+\techo \"author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE\"\n+}\n+\n+test_diff_file () {\n+\tif cmp \"$1\" \"$2\" >/dev/null\n+\tthen\n+\t\techo \"'$1' and '$2' are the same\"\n+\t\treturn 1\n+\tfi\n+}\n+\n test_expect_success 'Set up repository' '\n \ttest_commit Initial &&\n \ttest_commit Commit1 &&\n-\ttest_commit Commit2\n+\ttest_commit Commit2 &&\n+\tgit checkout -b branch Commit1 &&\n+\ttest_commit Commit2_ Commit2.t\n '\n \n test_expect_success 'Unknown option' '\n@@ -23,4 +45,172 @@ test_expect_success 'Unknown option' '\n \tgit rebase --continue\n '\n \n+test_msg_author () {\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 $1 2\" git rebase -i HEAD~2 &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_msg_author_misspelled () {\n+\tset_cat_todo_editor &&\n+\ttest_must_fail git rebase -i HEAD^ >todo &&\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"1 $1-misspelled 2\" git rebase -i HEAD~2 &&\n+\tset_fixed_todo_editor \"$(pwd)\"/todo &&\n+\tFAKE_LINES=\"$1 1\" git rebase --edit-todo &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_msg_author_conflicted () {\n+\tset_fake_editor &&\n+\ttest_must_fail env FAKE_LINES=\"$1 1\" git rebase -i master &&\n+\tgit checkout --theirs Commit2.t &&\n+\tgit add Commit2.t &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+}\n+\n+test_expect_success 'Misspelled pick --signoff' '\n+\tgit checkout -b misspelled-pick--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author_misspelled pick_--signoff\n+'\n+\n+test_expect_success 'Conflicted pick --signoff' '\n+\tgit checkout -b conflicted-pick--signoff branch &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author_conflicted pick_--signoff\n+'\n+\n+test_expect_success 'pick --signoff' '\n+\tgit checkout -b pick--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author pick_--signoff\n+'\n+\n+test_expect_success 'reword --signoff' '\n+\tgit checkout -b reword--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\ttest_msg_author reword_--signoff\n+'\n+\n+test_expect_success 'edit --signoff' '\n+\tgit checkout -b edit--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\tcommit_authorship HEAD >expected.author &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 edit_--signoff 2\" git rebase -i HEAD~2 &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+'\n+\n+test_expect_success 'Misspelled pick --reset-author' '\n+\tgit checkout -b misspelled-pick--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author_misspelled pick_--reset-author\n+'\n+\n+test_expect_success 'Conflicted pick --reset-author' '\n+\tgit checkout -b conflicted-pick--reset-author branch &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author_conflicted pick_--reset-author\n+'\n+\n+test_expect_success 'pick --reset-author' '\n+\tgit checkout -b pick--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author pick_--reset-author\n+'\n+\n+test_expect_success 'pick --reset-author --signoff' '\n+\tgit checkout -b pick--reset-author--signoff master &&\n+\tcat >expected.msg <<-EOF &&\n+\t$(commit_message HEAD)\n+\n+\tSigned-off-by: C O Mitter <committer@example.com>\n+\tEOF\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author pick_--reset-author_--signoff\n+'\n+\n+test_expect_success 'reword --reset-author' '\n+\tgit checkout -b reword--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\ttest_msg_author reword_--reset-author\n+'\n+\n+test_expect_success 'edit --reset-author' '\n+\tgit checkout -b edit--reset-author master &&\n+\tcommit_message HEAD >expected.msg &&\n+\tcommit_authorship HEAD >original.author &&\n+\ttest_diff_file expected.author original.author &&\n+\tset_fake_editor &&\n+\tFAKE_LINES=\"1 edit_--reset-author 2\" git rebase -i HEAD~2 &&\n+\t>Commit2.t &&\n+\tgit add Commit2.t &&\n+\ttest_tick &&\n+\tauthorship >expected.author &&\n+\tgit rebase --continue &&\n+\tcommit_message HEAD >actual.msg &&\n+\tcommit_authorship HEAD >actual.author &&\n+\ttest_cmp expected.msg actual.msg &&\n+\ttest_cmp expected.author actual.author\n+'\n+\n test_done\n-- \n2.0.1\n"},{"id":"249725","messageId":"541F03FC.8040506@gmail.com","threadId":"36962","inReplyTo":"53EB5E77.8010005@alum.mit.edu","subject":"Re: [PATCH v2 23/23] rebase -i: enable options --signoff, --reset-author for pick, reword","fromName":"Fabian Ruch","fromEmail":"bafain@gmail.com","sentAt":"2014-09-21T16:59:40Z","receivedAt":"2014-09-21T16:59:40Z","isPatch":true,"sender":{"key":"bafain@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1150972?v=4"},"body":"Hi Michael,\n\nOn 08/13/2014 02:47 PM, Michael Haggerty wrote:\n> On 08/07/2014 01:59 AM, Fabian Ruch wrote:\n>> pick and reword are atomic to-do list commands in the sense that they\n>> open a new task which is closed after the respective command is\n>> completed. squash and fixup are not atomic. They create a new task\n>> which is not completed until the last squash or fixup is processed.\n> \n> I don't understand the distinction that you are attempting to draw\n> between \"atomic\" and \"non-atomic\" commands.  For example, in the\n> following command list:\n> \n>     pick 1111111\n>     squash 2222222\n>     fixup 3333333\n> \n> the \"pick\" command doesn't seem very atomic, because the *end* result of\n> the three commands is a single commit that is affected by all three\n> commands.\n\nRight, when I wrote the commit message I was thinking in abstract terms\nso I implicitly thought of your example as a (single) squash/fixup\ncommand. Now it has become obvious that I wasn't very thorough with the\nimplementation part. The git-rebase implementation is oblivious to the\ncontext when it processes 'pick' lines and your example shows how 'pick'\nlines can be part of squash/fixup command context. In conclusion, I\nintended to keep options disabled for squash/fixup commands but failed\nto do so because I neglected that a 'pick' line can initiate a\nsquash/fixup command.\n\n> Furthermore, if we change the example to\n> \n>     pick 1111111\n>     squash --reset-author 2222222\n>     fixup --signoff 3333333\n> \n> then isn't it clear that the user's intention was to apply both options,\n> \"--reset-author\" and \"--signoff\", to the resulting commit?\n\nThis seems to suggest an interpretation of todo lists similar to what I\nwas thinking of when writing the commit message, that is one in which\npick is not oblivious to the neighbouring commands. It might be a\nproblem that it forbids the (admittedly improbable) use case where\n--reset-author is used to rewrite the authorship to something recent and\nfixup to have an even more recent committership.\n\nTo reconcile this kind of vertical interpretation with the horizontal\nspecification of options one could introduce a todo list command taking\nthe list of commits to be squashed as an argument. However, that seems\nto make it difficult to obtain the squash behaviour for some commits and\nthe fixup behaviour for others that are part of the same chain.\n\nThe alternative interpretation of todo lists as simplified batch scripts\nfor git commands would allow the intended behaviour (--reset-author and\n--signoff applied to the resulting commit), not restrict the user\nrelatively to what she can already do on the command line and give\nactually different meanings to the syntactically different todo lists\n\n    pick 1111111\n    squash --reset-author 2222222\n    fixup --signoff 3333333\n\nand\n\n    pick 1111111\n    squash --signoff 2222222\n    fixup --reset-author 3333333\n\n, which would be treated identically by an implementation that collects\nthe options. The current meaning of squash/fixup seems to be valid in\nthe batch interpretation.\n\n> In other\n> words, it seems to me that any options on such a chain of lines should\n> be collected and applied to the final commit as a whole.\n\nTo summarise, I think line options might be confusing if we interpret\n\n    pick 1111111\n    squash --reset-author 2222222\n    fixup --signoff 3333333\n\nas\n\n    combine the changes of 1111111, 2222222, 3333333\n    concatenate the messages of 1111111 and 2222222\n    edit the message\n    reset the authorship to the committership\n    add a Signed-off-by: line\n\nand not as\n\n    pick 1111111\n    pick -n 2222222\n    commit amend --reset-author -m $squash_msg\n    pick -n 3333333\n    commit amend --signoff --edit\n\n.\n\nThanks for pointing me at these issues. \"Atomic\" and \"non-atomic\" are\nreally poorly-chosen terminology and the squash-initiating 'pick' might\nnot be implemented correctly.\n\n   Fabian\n"}]}