{"thread":{"id":"30112","subject":"[PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits","startedAt":"2012-03-30T19:48:38Z","lastAt":"2012-07-18T12:17:58Z","messageCount":121,"participants":["Neil Horman","Junio C Hamano","Jeff King","Jonathan Nieder","Johannes Sixt","Clemens Buchacher","Zbigniew Jędrzejewski-Szmek","Thomas Rast","Martin von Zweigbergk"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"188191","messageId":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":null,"subject":"[PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-30T19:48:38Z","receivedAt":"2012-03-30T19:48:38Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Hey all-\n\tBased on your feedback from my earlier thread on this subject, I've come\nup with this series as a first pass in enhancing git-rebases ability to handle\nempty commits.  I'm not sure if its exactly what everyone wants, but I think its\na good start, and it works for what I need it to do here.\n\nI started with adding a -keep-empty option to git-cherry-pick, which allows\nnon-fast forward commits that are empty to be cherry-pick without failing, and\nrequiring a separate git commit --allow-empty.\n\nBuilding on that, I've added --keep-empty option to git-rebase.  For an\nautomatic rebase adding --keep-empty simply passes the --keep-empty flag along\nto git cherry-pick so that the empty commits are preserved instead of discarded\n\nfor interactive rebases, I changed the default selection editor text somewhat.\nBy default, empty commits are allowed in this list.  With patch 4 here, empty\ncommits are commented out automatically, unless --keep-empty is selected (in\nwhich case all commits are pick-ed).  The user sees additional text indicating\nthat empty commits are commented and if they wish to be kept, then they must be\nuncommented.  The pick_one function then intellegently passes the --keep-empty\noption allong to cherry-pick as needed.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n"},{"id":"188192","messageId":"1333136922-12872-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 1/4] git-cherry-pick: add keep-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-30T19:48:39Z","receivedAt":"2012-03-30T19:48:39Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operaion.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-cherry-pick.txt |    7 +++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 15 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..3e975dc 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,13 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--keep-empty:\n+\tIf a commit is not a fast forward, or if fast forwarding is not allowed,\n+\tcherry-picking an empty commit will fail, indicating that an explicit\n+\tinvokation of git commit --allow-empty is required.  This option\n+\toverrides that behavior, allowing empty commits to be preserved\n+\tautomatically in a cherry-pick\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..47d5522 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"188193","messageId":"1333136922-12872-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 2/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-30T19:48:40Z","receivedAt":"2012-03-30T19:48:40Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-rebase.txt |    6 ++++++\n git-rebase.sh                |    5 +++++\n 2 files changed, 11 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..9717d3e 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tInforms git-rebase that comits which are empty should not be\n+\tautomatically removed.  This is at times useful when empty commits\n+\tare used to hold developer information and notes, but contain no real\n+\tcode changes\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"188194","messageId":"1333136922-12872-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-30T19:48:41Z","receivedAt":"2012-03-30T19:48:41Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Using the keep_empy environment variable, this change allows git-commit-am to\napply empty commits to the new branch we are rebasing to\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n git-rebase--am.sh |   20 +++++++++++++++-----\n 1 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..c1d1b60 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,21 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if [ -n \"$keep_empty\" ]\n+then\n+\t# we have to do this the hard way.  git format-patch completly squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --keep-empty \"$revisions\" && move_to_original_branch\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n+\tmove_to_original_branch\n+fi\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\n-- \n1.7.7.6\n"},{"id":"188195","messageId":"1333136922-12872-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-30T19:48:42Z","receivedAt":"2012-03-30T19:48:42Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"This updates git-commit-interactive to recognize and make use of the keep_empty\nflag.  When not set, git-rebase -i will now comment out commits that are empty,\nand informs the user that commits which they wish to explicitly keep that are\nempty should be uncommented, or --keep-empty should be specified.  if keep_empty\nis specified, all commits, regardless of their empty status are included.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---\n 1 files changed, 35 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..97eeb21 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -191,12 +191,24 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\tis_empty=$(git show --pretty=format:%b \"$@\" | wc -l)\n+\n+\tif [ $is_empty -eq 0 ]\n+\tthen\n+\t\tempty_args=--keep-empty\n+\tfi\n+\n+\tif [ -n \"$keep_empty\" ]\n+\tthen\n+\t\tempty_args=--keep_empty\n+\tfi\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\tlocal comment_out\n+\n+\tif [ -z \"$keep_empty\" ]\n+\tthen\n+\t\tcomment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)\n+\t\tif [ $comment_out -eq 0 ]\n+\t\tthen\n+\t\t\tcomment_out=\"#pick\"\n+\t\telse\n+\t\t\tcomment_out=\"pick\"\n+\t\tfi\n+\telse\n+\t\tcomment_out=\"pick\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +828,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -849,6 +876,11 @@ cat >> \"$todo\" << EOF\n # If you remove a line here THAT COMMIT WILL BE LOST.\n # However, if you remove everything, the rebase will be aborted.\n #\n+# Note that commits which are empty at the time of rebasing are \n+# commented out.  If you wish to keep empty commits, either \n+# specify the --keep-empty option to the rebase command, or \n+# uncomment the commits you wish to keep\n+#\n EOF\n \n has_action \"$todo\" ||\n-- \n1.7.7.6\n"},{"id":"188200","messageId":"7vpqbtltiq.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:32:13Z","receivedAt":"2012-03-30T20:32:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> for interactive rebases, I changed the default selection editor text somewhat.\n> By default, empty commits are allowed in this list.  With patch 4 here, empty\n> commits are commented out automatically, unless --keep-empty is selected (in\n> which case all commits are pick-ed).  The user sees additional text indicating\n> that empty commits are commented and if they wish to be kept, then they must be\n> uncommented.  The pick_one function then intellegently passes the --keep-empty\n> option allong to cherry-pick as needed.\n\nSounds like a sensible UI design.  I am a bit curious what it would do\nwhen you try to \"rebase -i\" a series of commits, all of which are empty,\nthough.\n\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n\nPlease do not do this; Cc: goes to your e-mail header, not here.\n"},{"id":"188201","messageId":"7vlimhltf4.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-2-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 1/4] git-cherry-pick: add keep-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:34:23Z","receivedAt":"2012-03-30T20:34:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"It strikes me very strange why this is not called --allow-empty, but other\nthan that the addition look straightforward enough to me.  You would want\nto add a test for this, though.\n"},{"id":"188204","messageId":"7vhax5lt05.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 2/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:43:22Z","receivedAt":"2012-03-30T20:43:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Add a command line switch to git-rebase to allow a user the ability to specify\n> that they want to keep any commits in a series that are empty.\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n\nThe same comments on Cc: apply to all of your patches.\n\n>  Documentation/git-rebase.txt |    6 ++++++\n>  git-rebase.sh                |    5 +++++\n>  2 files changed, 11 insertions(+), 0 deletions(-)\n>\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 504945c..9717d3e 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n>  \twill be reset to where it was when the rebase operation was\n>  \tstarted.\n>  \n> +--keep-empty::\n> +\tInforms git-rebase that comits which are empty should not be\n> +\tautomatically removed.  This is at times useful when empty commits\n> +\tare used to hold developer information and notes, but contain no real\n> +\tcode changes\n> +\n\nUnlike \"cherry-pick\", I think \"--keep-empty\" is a better name for the\noption than \"--allow-empty\" in this context.  The difference is that from\nthe end-user's point of view, cherry-pick _replays_ commits that exist\nelsewhere, and you are allowing the command to replay empty ones as well,\nwhile rebase _rebuilds_ commits on the same branch, and you are telling\nthe command to keep empty ones.\n\n\"... which are empty should not be removed\" is a bit of double-negation,\nthough.  Perhaps\n\n\t--keep-empty::\n\t\tKeep the commits that do not change anything from its\n\t\tparents in the result.  This is at times useful when empty\n\t\tcommits are used to hold developer information and notes\n\t\twithout having any real changes.\n\nBut as I rephrased the first part, the last line may have become redundant\nand could safely be removed.\n\nThe patch does not seem to do anything other than accepting and silently\nignoring the option, though.\n"},{"id":"188205","messageId":"7vd37tlsve.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-4-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:46:13Z","receivedAt":"2012-03-30T20:46:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Using the keep_empy environment variable, this change allows git-commit-am to\n\nIs it an environment variable?  I thought not.\n\n> apply empty commits to the new branch we are rebasing to\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n> ---\n>  git-rebase--am.sh |   20 +++++++++++++++-----\n>  1 files changed, 15 insertions(+), 5 deletions(-)\n>\n> diff --git a/git-rebase--am.sh b/git-rebase--am.sh\n> index c815a24..c1d1b60 100644\n> --- a/git-rebase--am.sh\n> +++ b/git-rebase--am.sh\n> @@ -20,11 +20,21 @@ esac\n>  \n>  test -n \"$rebase_root\" && root_flag=--root\n>  \n> -git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> -\t--src-prefix=a/ --dst-prefix=b/ \\\n> -\t--no-renames $root_flag \"$revisions\" |\n> -git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> -move_to_original_branch\n> +if [ -n \"$keep_empty\" ]\n> +then\n> +\t# we have to do this the hard way.  git format-patch completly squashes\n> +\t# empty commits and even if it didn't the format doesn't really lend\n> +\t# itself well to recording empty patches.  fortunately, cherry-pick\n> +\t# makes this easy\n> +\tgit cherry-pick --keep-empty \"$revisions\" && move_to_original_branch\n> +else\n> +\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> +\t\t--src-prefix=a/ --dst-prefix=b/ \\\n> +\t\t--no-renames $root_flag \"$revisions\" |\n> +\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> +\tmove_to_original_branch\n> +fi\n\nFactor out the \"&& move_to_original_branch\" at the end of then/else, like\nthis:\n\n\tif ...\n        then\n\t\t...\n        else\n\t\t...\n        fi && move_to_original_branch\n\n>  ret=$?\n>  test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n>  exit $ret\n"},{"id":"188206","messageId":"7v8vihlssj.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-4-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:47:56Z","receivedAt":"2012-03-30T20:47:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Using the keep_empy environment variable, this change allows git-commit-am to\n> apply empty commits to the new branch we are rebasing to\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n> ---\n>  git-rebase--am.sh |   20 +++++++++++++++-----\n>  1 files changed, 15 insertions(+), 5 deletions(-)\n>\n> diff --git a/git-rebase--am.sh b/git-rebase--am.sh\n> index c815a24..c1d1b60 100644\n> --- a/git-rebase--am.sh\n> +++ b/git-rebase--am.sh\n> @@ -20,11 +20,21 @@ esac\n>  \n>  test -n \"$rebase_root\" && root_flag=--root\n>  \n> -git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> -\t--src-prefix=a/ --dst-prefix=b/ \\\n> -\t--no-renames $root_flag \"$revisions\" |\n> -git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> -move_to_original_branch\n> +if [ -n \"$keep_empty\" ]\n> +then\n> +\t# we have to do this the hard way.  git format-patch completly squashes\n> +\t# empty commits and even if it didn't the format doesn't really lend\n> +\t# itself well to recording empty patches.  fortunately, cherry-pick\n> +\t# makes this easy\n> +\tgit cherry-pick --keep-empty \"$revisions\" && move_to_original_branch\n\nDoes cherry-pick know the \"--ignore-if-in-upstream\" trick?  Otherwise I\nsuspect that this will introduce a severe regression to the command, as\nthe commits that are already in the new base you are rebasing to will all\nbe kept as empty commits, no?\n\n> +else\n> +\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> +\t\t--src-prefix=a/ --dst-prefix=b/ \\\n> +\t\t--no-renames $root_flag \"$revisions\" |\n> +\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> +\tmove_to_original_branch\n> +fi\n> +\n>  ret=$?\n>  test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n>  exit $ret\n"},{"id":"188207","messageId":"7v4nt5lsa1.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333136922-12872-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-30T20:59:02Z","receivedAt":"2012-03-30T20:59:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> This updates git-commit-interactive to recognize and make use of the keep_empty\n> flag.  When not set, git-rebase -i will now comment out commits that are empty,\n> and informs the user that commits which they wish to explicitly keep that are\n> empty should be uncommented, or --keep-empty should be specified.  if keep_empty\n> is specified, all commits, regardless of their empty status are included.\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n> ---\n>  git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---\n>  1 files changed, 35 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 5812222..97eeb21 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -191,12 +191,24 @@ git_sequence_editor () {\n>  \n>  pick_one () {\n>  \tff=--ff\n> +\tis_empty=$(git show --pretty=format:%b \"$@\" | wc -l)\n\nThat is a very expensive way to see if the commit is empty, no?\n\nIf and only if commit C is empty, \"git rev-parse\" on C^{tree} and\nC^^{tree}\" will yield the same tree object name.\n\n> +\tif [ $is_empty -eq 0 ]\n\nAlso this test (which by the way is against our coding style guideline)\nshows that the variable is misnamed.\n\n> +\tthen\n> +\t\tempty_args=--keep-empty\n> +\tfi\n> +\n> +\tif [ -n \"$keep_empty\" ]\n> +\tthen\n> +\t\tempty_args=--keep_empty\n> +\tfi\n> +\n>  \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n>  \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n>  \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n>  \ttest -d \"$rewritten\" &&\n>  \t\tpick_one_preserving_merges \"$@\" && return\n> -\toutput git cherry-pick $ff \"$@\"\n> +\toutput git cherry-pick $empty_args $ff \"$@\"\n>  }\n>  \n>  pick_one_preserving_merges () {\n> @@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n>  \tsed -n \"s/^>//p\" |\n>  while read -r shortsha1 rest\n>  do\n> +\tlocal comment_out\n\nbashism.\n\n> +\n> +\tif [ -z \"$keep_empty\" ]\n> +\tthen\n> +\t\tcomment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)\n\nDitto.\n\n> +\t\tif [ $comment_out -eq 0 ]\n> +\t\tthen\n> +\t\t\tcomment_out=\"#pick\"\n\nPerhaps it is easier to read if you say \"# pick\"?\n\n> +\t\telse\n> +\t\t\tcomment_out=\"pick\"\n> +\t\tfi\n> +\telse\n> +\t\tcomment_out=\"pick\"\n> +\tfi\n> +\n>  \tif test t != \"$preserve_merges\"\n>  \tthen\n> -\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n> +\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n\nThe variable comment_out is grossly misnamed.  Why not do it this way?\n\n\tcomment_out=\n\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n        then\n        \tcomment_out=\"# \"\n\tfi\n\n        if ...\n        then\n\t\tprintf \"%s\\n\" \"${leader}pick $shortsha1 $rest\" >>\"$todo\"\n\n> @@ -849,6 +876,11 @@ cat >> \"$todo\" << EOF\n>  # If you remove a line here THAT COMMIT WILL BE LOST.\n>  # However, if you remove everything, the rebase will be aborted.\n>  #\n> +# Note that commits which are empty at the time of rebasing are \n> +# commented out.  If you wish to keep empty commits, either \n> +# specify the --keep-empty option to the rebase command, or \n> +# uncomment the commits you wish to keep\n> +#\n\nGood.\n\nI do not think \" either specify...rebase command, or\" is necessary here,\nthough.  This message is meant to be a quick reminder, not a tutorial.\nKeep it short and sweet.\n\nAlso, you may probably want to add this text _only_ when you have actually\ncommented out something.\n"},{"id":"188214","messageId":"20120330211513.GB20734@sigill.intra.peff.net","threadId":"30112","inReplyTo":"1333136922-12872-2-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 1/4] git-cherry-pick: add keep-empty option","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-03-30T21:15:13Z","receivedAt":"2012-03-30T21:15:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Mar 30, 2012 at 03:48:39PM -0400, Neil Horman wrote:\n\n> +--keep-empty:\n> +\tIf a commit is not a fast forward, or if fast forwarding is not allowed,\n> +\tcherry-picking an empty commit will fail, indicating that an explicit\n> +\tinvokation of git commit --allow-empty is required.  This option\n> +\toverrides that behavior, allowing empty commits to be preserved\n> +\tautomatically in a cherry-pick\n\nThis didn't parse very well for me. A commit cannot be \"a fast forward\"\nby itself. Fast-forwarding is an operation that depends on the\nrelationship between commits.\n\nI think what you are trying to say is that this option is used only if\nthe \"--ff\" logic does not kick in. Maybe it would be clearer to get to\nthe point early, and mention --ff later, like:\n\n  --keep-empty:\n          By default, cherry-picking an empty commit will fail,\n          indicating that an explicit invocation of `git commit\n          --allow-empty` is required. This option overrides that\n          behavior, allowing empty commits to be preserved automatically\n          in a cherry-pick. Note that when \"--ff\" is in effect, empty\n          commits that meet the \"fast-forward\" requirement will be kept\n          even without this option.\n\nLike Junio, I agree this should simply be called --allow-empty.\n\n> diff --git a/sequencer.c b/sequencer.c\n> index a37846a..71929ba 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n>   */\n>  static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n>  {\n> -\t/* 6 is max possible length of our args array including NULL */\n> -\tconst char *args[6];\n> +\t/* 7 is max possible length of our args array including NULL */\n> +\tconst char *args[7];\n>  \tint i = 0;\n\nIt might be nice to refactor this to use argv_array, which handles the\nallocation automatically.\n\n> +\tif (opts->allow_empty)\n> +\t\targs[i++] = \"--allow-empty\";\n> +\n\nWhat happens if I cherry-pick a commit that is not empty, but that\nbecomes empty because its changes have already been applied?\n\n-Peff\n"},{"id":"188248","messageId":"20120331125716.GA2409@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"1333136922-12872-2-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 1/4] git-cherry-pick: add keep-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-31T12:57:16Z","receivedAt":"2012-03-31T12:57:16Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Mar 30, 2012 at 03:48:39PM -0400, Neil Horman wrote:\n> git cherry-pick fails when picking a non-ff commit that is empty.  The advice\n> given with the failure is that a git-commit --allow-empty should be issued to\n> explicitly add the empty commit during the cherry pick.  This option allows a\n> user to specify before hand that they want to keep the empty commit.  This\n> eliminates the need to issue both a cherry pick and a commit operaion.\n> \n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\nAs you and Jeff noted, I can certainly change keep-empty to allow-empty, both\nhere and in the rebase command.  I'll add a test for it as well, early this\ncomming week.  Thanks!\n\nNeil\n"},{"id":"188249","messageId":"20120331125949.GB2409@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7vhax5lt05.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-31T12:59:49Z","receivedAt":"2012-03-31T12:59:49Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Mar 30, 2012 at 01:43:22PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Add a command line switch to git-rebase to allow a user the ability to specify\n> > that they want to keep any commits in a series that are empty.\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > CC: Jeff King <peff@peff.net>\n> > CC: Phil Hord <phil.hord@gmail.com>\n> > CC: Junio C Hamano <gitster@pobox.com>\n> \n> The same comments on Cc: apply to all of your patches.\n> \nRoger that.\n\n> >  Documentation/git-rebase.txt |    6 ++++++\n> >  git-rebase.sh                |    5 +++++\n> >  2 files changed, 11 insertions(+), 0 deletions(-)\n> >\n> > diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> > index 504945c..9717d3e 100644\n> > --- a/Documentation/git-rebase.txt\n> > +++ b/Documentation/git-rebase.txt\n> > @@ -238,6 +238,12 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n> >  \twill be reset to where it was when the rebase operation was\n> >  \tstarted.\n> >  \n> > +--keep-empty::\n> > +\tInforms git-rebase that comits which are empty should not be\n> > +\tautomatically removed.  This is at times useful when empty commits\n> > +\tare used to hold developer information and notes, but contain no real\n> > +\tcode changes\n> > +\n> \n> Unlike \"cherry-pick\", I think \"--keep-empty\" is a better name for the\n> option than \"--allow-empty\" in this context.  The difference is that from\n> the end-user's point of view, cherry-pick _replays_ commits that exist\n> elsewhere, and you are allowing the command to replay empty ones as well,\n> while rebase _rebuilds_ commits on the same branch, and you are telling\n> the command to keep empty ones.\n> \n> \"... which are empty should not be removed\" is a bit of double-negation,\n> though.  Perhaps\n> \n> \t--keep-empty::\n> \t\tKeep the commits that do not change anything from its\n> \t\tparents in the result.  This is at times useful when empty\n> \t\tcommits are used to hold developer information and notes\n> \t\twithout having any real changes.\n> \n> But as I rephrased the first part, the last line may have become redundant\n> and could safely be removed.\n> \nAck, I can make the above changes.\n\n> The patch does not seem to do anything other than accepting and silently\n> ignoring the option, though.\n> \nIt does, as the use of the option is pushed into the type specific rebase\nscripts.  I probably should have rolled this patch in with one of those. I'll\nsquash it in when I repost.\n"},{"id":"188250","messageId":"20120331130116.GC2409@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7vd37tlsve.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-31T13:01:17Z","receivedAt":"2012-03-31T13:01:17Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Mar 30, 2012 at 01:46:13PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Using the keep_empy environment variable, this change allows git-commit-am to\n> \n> Is it an environment variable?  I thought not.\n> \nSorry, I use the term loosely.  keep_empty is the script variable I use to track\nthe keep-empty option.  I can fix up the commit message on my repost.\n\n> > +\t# makes this easy\n> > +\tgit cherry-pick --keep-empty \"$revisions\" && move_to_original_branch\n> > +else\n> > +\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> > +\t\t--src-prefix=a/ --dst-prefix=b/ \\\n> > +\t\t--no-renames $root_flag \"$revisions\" |\n> > +\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> > +\tmove_to_original_branch\n> > +fi\n> \n> Factor out the \"&& move_to_original_branch\" at the end of then/else, like\n> this:\n> \n> \tif ...\n>         then\n> \t\t...\n>         else\n> \t\t...\n>         fi && move_to_original_branch\n> \nWill do, thanks!\nNeil\n"},{"id":"188251","messageId":"20120331130308.GD2409@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7v8vihlssj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/4] git-commit-am: Allow automatic rebasing to preserve empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-31T13:03:08Z","receivedAt":"2012-03-31T13:03:08Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Mar 30, 2012 at 01:47:56PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Using the keep_empy environment variable, this change allows git-commit-am to\n> > apply empty commits to the new branch we are rebasing to\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > CC: Jeff King <peff@peff.net>\n> > CC: Phil Hord <phil.hord@gmail.com>\n> > CC: Junio C Hamano <gitster@pobox.com>\n> > ---\n> >  git-rebase--am.sh |   20 +++++++++++++++-----\n> >  1 files changed, 15 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/git-rebase--am.sh b/git-rebase--am.sh\n> > index c815a24..c1d1b60 100644\n> > --- a/git-rebase--am.sh\n> > +++ b/git-rebase--am.sh\n> > @@ -20,11 +20,21 @@ esac\n> >  \n> >  test -n \"$rebase_root\" && root_flag=--root\n> >  \n> > -git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n> > -\t--src-prefix=a/ --dst-prefix=b/ \\\n> > -\t--no-renames $root_flag \"$revisions\" |\n> > -git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n> > -move_to_original_branch\n> > +if [ -n \"$keep_empty\" ]\n> > +then\n> > +\t# we have to do this the hard way.  git format-patch completly squashes\n> > +\t# empty commits and even if it didn't the format doesn't really lend\n> > +\t# itself well to recording empty patches.  fortunately, cherry-pick\n> > +\t# makes this easy\n> > +\tgit cherry-pick --keep-empty \"$revisions\" && move_to_original_branch\n> \n> Does cherry-pick know the \"--ignore-if-in-upstream\" trick?  Otherwise I\n> suspect that this will introduce a severe regression to the command, as\n> the commits that are already in the new base you are rebasing to will all\n> be kept as empty commits, no?\n> \nHmm, you may be correct.  I'd not really thought of that.  I can borrow the\nformat-patch code for that option and incorporate it into cherry-pick to fix\nthat up.  Would that be sufficient?\n\nNeil\n"},{"id":"188252","messageId":"20120331131116.GE2409@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7v4nt5lsa1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 4/4] git-commit-interactive: Allow rebasing to preserve empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-03-31T13:11:16Z","receivedAt":"2012-03-31T13:11:16Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Mar 30, 2012 at 01:59:02PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > This updates git-commit-interactive to recognize and make use of the keep_empty\n> > flag.  When not set, git-rebase -i will now comment out commits that are empty,\n> > and informs the user that commits which they wish to explicitly keep that are\n> > empty should be uncommented, or --keep-empty should be specified.  if keep_empty\n> > is specified, all commits, regardless of their empty status are included.\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > CC: Jeff King <peff@peff.net>\n> > CC: Phil Hord <phil.hord@gmail.com>\n> > CC: Junio C Hamano <gitster@pobox.com>\n> > ---\n> >  git-rebase--interactive.sh |   38 +++++++++++++++++++++++++++++++++++---\n> >  1 files changed, 35 insertions(+), 3 deletions(-)\n> >\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index 5812222..97eeb21 100644\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n> > @@ -191,12 +191,24 @@ git_sequence_editor () {\n> >  \n> >  pick_one () {\n> >  \tff=--ff\n> > +\tis_empty=$(git show --pretty=format:%b \"$@\" | wc -l)\n> \n> That is a very expensive way to see if the commit is empty, no?\n> \n> If and only if commit C is empty, \"git rev-parse\" on C^{tree} and\n> C^^{tree}\" will yield the same tree object name.\n> \nAh, you see, I'm learning something :).  I can fix that up.\n\n> > +\tif [ $is_empty -eq 0 ]\n> \n> Also this test (which by the way is against our coding style guideline)\n> shows that the variable is misnamed.\n> \nOk, sorry about that.  I'll switch that to use test\n\n> > +\tthen\n> > +\t\tempty_args=--keep-empty\n> > +\tfi\n> > +\n> > +\tif [ -n \"$keep_empty\" ]\n> > +\tthen\n> > +\t\tempty_args=--keep_empty\n> > +\tfi\n> > +\n> >  \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n> >  \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n> >  \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n> >  \ttest -d \"$rewritten\" &&\n> >  \t\tpick_one_preserving_merges \"$@\" && return\n> > -\toutput git cherry-pick $ff \"$@\"\n> > +\toutput git cherry-pick $empty_args $ff \"$@\"\n> >  }\n> >  \n> >  pick_one_preserving_merges () {\n> > @@ -780,9 +792,24 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n> >  \tsed -n \"s/^>//p\" |\n> >  while read -r shortsha1 rest\n> >  do\n> > +\tlocal comment_out\n> \n> bashism.\n> \nRoger.\n\n> > +\n> > +\tif [ -z \"$keep_empty\" ]\n> > +\tthen\n> > +\t\tcomment_out=$(git show --pretty=format:%b $shortsha1 | wc -l)\n> \n> Ditto.\n> \n> > +\t\tif [ $comment_out -eq 0 ]\n> > +\t\tthen\n> > +\t\t\tcomment_out=\"#pick\"\n> \n> Perhaps it is easier to read if you say \"# pick\"?\n> \nSure, easy enough fix\n\n> > +\t\telse\n> > +\t\t\tcomment_out=\"pick\"\n> > +\t\tfi\n> > +\telse\n> > +\t\tcomment_out=\"pick\"\n> > +\tfi\n> > +\n> >  \tif test t != \"$preserve_merges\"\n> >  \tthen\n> > -\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n> > +\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n> \n> The variable comment_out is grossly misnamed.  Why not do it this way?\n> \nI think you meant to assign leader there instead of comment_out, but your point\nis a good one :).\n\n> \tcomment_out=\n> \tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n>         then\n>         \tcomment_out=\"# \"\n> \tfi\n> \n>         if ...\n>         then\n> \t\tprintf \"%s\\n\" \"${leader}pick $shortsha1 $rest\" >>\"$todo\"\n> \n> > @@ -849,6 +876,11 @@ cat >> \"$todo\" << EOF\n> >  # If you remove a line here THAT COMMIT WILL BE LOST.\n> >  # However, if you remove everything, the rebase will be aborted.\n> >  #\n> > +# Note that commits which are empty at the time of rebasing are \n> > +# commented out.  If you wish to keep empty commits, either \n> > +# specify the --keep-empty option to the rebase command, or \n> > +# uncomment the commits you wish to keep\n> > +#\n> \n> Good.\n> \n> I do not think \" either specify...rebase command, or\" is necessary here,\n> though.  This message is meant to be a quick reminder, not a tutorial.\n> Keep it short and sweet.\n> \nCopy that, I'll tone down the verbosity.\n\n> Also, you may probably want to add this text _only_ when you have actually\n> commented out something.\n> \nEasily done.  thanks!\nNeil\n"},{"id":"188582","messageId":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 0/5] Enhance git-rebases flexibiilty handling empty commits [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:00Z","receivedAt":"2012-04-05T19:39:00Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --ignore-if-made-empty, which allows the user to restrict the \napplication of --allow-empty to only those commits which were initially empty \n(not those commits made empty by a prior commit).  It also enhances git-rebase\nto add a --keep-empty option, which implies the use of the above new options to\ncherry-pick.  \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\n"},{"id":"188580","messageId":"1333654745-7898-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:01Z","receivedAt":"2012-04-05T19:39:01Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"As a convienience, it would be nice if we could pop entries off the argv_array\nstructs so that if they had multiple uses in a function, we wouldn't have to\nclear them and repopulate common entries.  This patch adds the argv_array_pop\nfunction to do just that.  Common entries can be added to an argv_array first,\nthen useage specific ones can be added on the end and removed later on.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n argv-array.c |   12 ++++++++++++\n argv-array.h |    1 +\n 2 files changed, 13 insertions(+), 0 deletions(-)\n\ndiff --git a/argv-array.c b/argv-array.c\nindex a4e0420..ce24a48 100644\n--- a/argv-array.c\n+++ b/argv-array.c\n@@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)\n \targv_array_push_nodup(array, strbuf_detach(&v, NULL));\n }\n \n+int argv_array_pop(struct argv_array *array, unsigned int num)\n+{\n+\tif (num > array->argc)\n+\t\treturn -1;\n+\n+\tfor(num--; num>0; num--) {\n+\t\tfree((char **)array->argv[num]);\n+\t\tarray->argv[num] = NULL;\n+\t}\n+\treturn 0;\n+}\n+\n void argv_array_clear(struct argv_array *array)\n {\n \tif (array->argv != empty_argv) {\ndiff --git a/argv-array.h b/argv-array.h\nindex 74dd2b1..8233243 100644\n--- a/argv-array.h\n+++ b/argv-array.h\n@@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);\n void argv_array_push(struct argv_array *, const char *);\n __attribute__((format (printf,2,3)))\n void argv_array_pushf(struct argv_array *, const char *fmt, ...);\n+int argv_array_pop(struct argv_array *, unsigned int num);\n void argv_array_clear(struct argv_array *);\n \n #endif /* ARGV_ARRAY_H */\n-- \n1.7.7.6\n"},{"id":"188581","messageId":"1333654745-7898-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 2/5] git-cherry-pick: add allow-empty option [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:02Z","receivedAt":"2012-04-05T19:39:02Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operaion.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..c283d8c 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty:\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"188584","messageId":"1333654745-7898-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:03Z","receivedAt":"2012-04-05T19:39:03Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve\nempty commits, we open ourselves to the possibility of preserving commits that\nare made empty by a previous merge as well, which is almost certainly not what\nwe want (most of the time).  To handle this, we can add the ignore-if-made-empty\noption.  If enabled, it will look at cherry-picked commits, and if the origional\nsha1 has the same tree as its parent, then the cherry-pick is comitted as an\nempty commit, otherwise the commit is skipped (because it previously made\nchanges to the tree, but no longer does).\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-cherry-pick.txt |   10 +++-\n builtin/revert.c                  |    2 +\n sequencer.c                       |  113 ++++++++++++++++++++++++++++++++-----\n sequencer.h                       |    1 +\n 4 files changed, 111 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex c283d8c..bb7eb4a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,7 +103,7 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n---allow-empty:\n+--allow-empty:::\n \tBy default, cherry-picking an empty commit will fail,\n \tindicating that an explicit invocation of `git commit\n \t--allow-empty` is required. This option overrides that\n@@ -112,6 +112,14 @@ effect to your index in a row.\n \tcommits that meet the \"fast-forward\" requirement will be kept\n \teven without this option.\n \n+--ignore-if-made-empty::\n+\tIf the --allow-empty option is used, all empty commits are kept,\n+\tincluding those which were made empty due to a previous change.\n+\tWhile this may be desireable, likely it is not.  This option\n+\trestricts the scope of --allow-empty to only those commits which\n+\twere created as empty commits (i.e. if for commit C,  C^{tree} and \n+\tC^^{tree} are identical).\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..0fa76ca 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,6 +115,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n@@ -122,6 +123,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n \t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"ignore-if-made-empty\", &opts->ignore_if_made_empty, \"ignore commits already in tree\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..a512598 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -258,26 +259,107 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n-{\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n+{\n+\tstruct argv_array array;\n+\tint rc;\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n+\n+\tif ((!empty) && (opts->ignore_if_made_empty)) {\n+\t\t/* Note: This implies --dry-run */\n+\t\targv_array_push(&array, \"--porcelain\");\n+\t\tif (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {\n+\t\t\t/* The dry run exit code of 1 tells us this is\n+ \t\t\t * an empty commit, just skip it.\n+ \t\t\t */\n+\t\t\targv_array_clear(&array);\n+\t\t\treturn 0;\n+\t\t}\n+\t\targv_array_pop(&array, 1);\n+\t}\n+\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\t\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n+\n+\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n+\n+static int is_origional_commit_empty(struct commit *commit)\n+{\n+\tstruct argv_array argv_array;\n+\tstruct child_process cp;\n+\tchar ptree[41], pptree[41];\n+\tint pipefd[2];\n+\tFILE *output;\n+\tint ret = 0;\n+\n+\tif (pipe2(pipefd, 0) < 0)\n+\t\treturn 0;\n+\n+\toutput = xfdopen(pipefd[0], \"r\");\n+\n+\targv_array_init(&argv_array);\n+\tmemset(&cp, 0, sizeof(struct child_process));\n \n-\targs[i] = NULL;\n+\targv_array_push(&argv_array, \"rev-parse\");\n+\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\tcp.git_cmd = 1;\n+\tcp.no_stdin = 1;\n+\tcp.no_stderr = 1;\n+\tcp.out = pipefd[1];\n+\tcp.argv = argv_array.argv;\n+\n+\tif (start_command(&cp) < 0)\n+\t\tgoto out;\n+\n+\tif (fscanf(output, \"%s\\n\", ptree) < 1)\n+\t\tgoto out;\n+\n+\tfinish_command(&cp);\n+\n+\tfclose(output);\n+\tclose(pipefd[0]);\n+\targv_array_clear(&argv_array);\n+\n+\tif (pipe2(pipefd, 0) < 0)\n+\t\treturn 0;\n+\n+\toutput = xfdopen(pipefd[0], \"r\");\n+\n+\targv_array_push(&argv_array, \"rev-parse\");\n+\targv_array_pushf(&argv_array, \"%s^^{tree}\", sha1_to_hex(commit->object.sha1));\n+\tcp.argv = argv_array.argv;\n+\n+\tif (start_command(&cp) < 0)\n+\t\tgoto out;\n+\n+\tif (fscanf(output, \"%s\\n\", pptree) < 1)\n+\t\tgoto out;\n+\n+\tfinish_command(&cp);\n+\tclose(pipefd[0]);\n+\n+\tif (!strncmp(ptree, pptree, 40))\n+\t\tret = 1;\n+out:\n+\tfclose(output);\n+\targv_array_clear(&argv_array);\t\n+\treturn ret;\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +371,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +497,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_origional_commit_empty(commit);\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -435,7 +520,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n \t\tif (!opts->no_commit)\n-\t\t\tres = run_git_commit(defmsg, opts);\n+\t\t\tres = run_git_commit(defmsg, opts, empty_commit);\n \t}\n \n \tfree_message(&msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..3e1106f 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint ignore_if_made_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"188579","messageId":"1333654745-7898-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 4/5] git-cherry-pick: Add test to validate new options [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:04Z","receivedAt":"2012-04-05T19:39:04Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --ignore-if-made-empty\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n t/t3505-cherry-pick-empty.sh |   31 ++++++++++++++++++++++++++++++-\n 1 files changed, 30 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..049ed28 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,28 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fouth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" && {\n+\t\tgit cherry-pick empty-branch2\n+\t\ttest \"$?\" = 1 \n+\t}\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --allow-empty empty-branch2\n+\t\ttest \"$?\" = 0\n+\t}\n+'\n+\n+test_expect_success 'cherry pick with --ignore-if-made-empty' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --allow-empty --ignore-if-made-empty empty-branch2\n+\t\ttest \"$?\" = 0\n+\t}\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"188583","messageId":"1333654745-7898-6-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333654745-7898-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH 5/5] git-rebase: add keep_empty flag [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T19:39:05Z","receivedAt":"2012-04-05T19:39:05Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\nCC: Jeff King <peff@peff.net>\nCC: Phil Hord <phil.hord@gmail.com>\nCC: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   40 +++++++++++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 60 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..a7194f7 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if [ -n \"$keep_empty\" ]\n+then\n+\t# we have to do this the hard way.  git format-patch completly squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty --ignore-if-made-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..beb06cf 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,12 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\tptree=$(git rev-parse \"$1\"^{tree})\n+\tpptree=$(git rev-parse \"$1\"^^{tree})\n+\treturn test \"$ptree\" = \"$pptree\"\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +197,23 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n+\tif is_emtpy_commit $@ \n+\tthen\n+\t\tempty_args=\"--allow-empty --ignore-if-made-empty\"\n+\tfi\n+\n+\tif test -n \"$keep_empty\" \n+\tthen\n+\t\tempty_args=\"--allow_empty --ignore-if-made-empty\"\n+\tfi\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +797,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $sha1\n+\tthen\n+\t\tcomment_out=\"# pick\"\n+\telse\n+\t\tcomment_out=\"pick\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +826,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +876,15 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\tcat >> \"$todo\" << EOF\n+\t# Note that commits which are empty at the time of rebasing are \n+\t# commented out. \n+\tEOF\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"188588","messageId":"7vd37m5458.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333654745-7898-2-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-05T20:12:51Z","receivedAt":"2012-04-05T20:12:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> As a convienience, it would be nice if we could pop entries off the argv_array\n> structs so that if they had multiple uses in a function, we wouldn't have to\n> clear them and repopulate common entries.  This patch adds the argv_array_pop\n> function to do just that.  Common entries can be added to an argv_array first,\n> then useage specific ones can be added on the end and removed later on.\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n\n> CC: Jeff King <peff@peff.net>\n> CC: Phil Hord <phil.hord@gmail.com>\n> CC: Junio C Hamano <gitster@pobox.com>\n> ---\n\nPlease don't do \"Cc:\" here; they belong to your e-mail header.\n\n> diff --git a/argv-array.c b/argv-array.c\n> index a4e0420..ce24a48 100644\n> --- a/argv-array.c\n> +++ b/argv-array.c\n> @@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)\n>  \targv_array_push_nodup(array, strbuf_detach(&v, NULL));\n>  }\n>  \n> +int argv_array_pop(struct argv_array *array, unsigned int num)\n> +{\n> +\tif (num > array->argc)\n> +\t\treturn -1;\n\nIf your use case is \"After using an argv_array for the first invocation,\ntruncate it while keeping the common ones that appear early, so that ones\nthat are specific to the second invocation can be pushed\", it strikes me\nsomewhat odd why you would want to specify \"how many to pop\".\n\nWouldn't argv_array_truncate() or argv_array_setlen() make more sense?\n\n\n> +\tfor(num--; num>0; num--) {\n\nGaah.\n\n> +\t\tfree((char **)array->argv[num]);\n> +\t\tarray->argv[num] = NULL;\n> +\t}\n> +\treturn 0;\n> +}\n> +\n>  void argv_array_clear(struct argv_array *array)\n>  {\n>  \tif (array->argv != empty_argv) {\n> diff --git a/argv-array.h b/argv-array.h\n> index 74dd2b1..8233243 100644\n> --- a/argv-array.h\n> +++ b/argv-array.h\n> @@ -15,6 +15,7 @@ void argv_array_init(struct argv_array *);\n>  void argv_array_push(struct argv_array *, const char *);\n>  __attribute__((format (printf,2,3)))\n>  void argv_array_pushf(struct argv_array *, const char *fmt, ...);\n> +int argv_array_pop(struct argv_array *, unsigned int num);\n>  void argv_array_clear(struct argv_array *);\n>  \n>  #endif /* ARGV_ARRAY_H */\n"},{"id":"188594","messageId":"7vobr551vs.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1333654745-7898-4-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-05T21:01:43Z","receivedAt":"2012-04-05T21:01:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Subject: Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]\n\nPlease don't do this.  The tools do not strip the garbage at the end.\n\nInstead, do it like either one of these:\n\n\tSubject: [PATCH 3/5 (v2)] mumble mumble...\n\tSubject: [PATCH v2 3/5] mumble mumble...\n\nThe latter is more appropriate when resending everything, including the\nones that did not change from the earlier round.\n\n> Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve\n> empty commits, we open ourselves to the possibility of preserving commits that\n> are made empty by a previous merge as well, which is almost certainly not what\n> we want (most of the time).  To handle this, we can add the ignore-if-made-empty\n> option.  If enabled, it will look at cherry-picked commits, and if the origional\n> sha1 has the same tree as its parent, then the cherry-pick is comitted as an\n> empty commit, otherwise the commit is skipped (because it previously made\n> changes to the tree, but no longer does).\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index c283d8c..bb7eb4a 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -103,7 +103,7 @@ effect to your index in a row.\n>  \tcherry-pick'ed commit, then a fast forward to this commit will\n>  \tbe performed.\n>  \n> ---allow-empty:\n> +--allow-empty:::\n\nA single colon is already buggy, but three colons is equally bad.  Please\nfix that in the original point this bug was introduced.  I guess it was\n2/5 of this series?\n\n> @@ -112,6 +112,14 @@ effect to your index in a row.\n>  \tcommits that meet the \"fast-forward\" requirement will be kept\n>  \teven without this option.\n>  \n> +--ignore-if-made-empty::\n> +\tIf the --allow-empty option is used, all empty commits are kept,\n\nLiteral strings the user may type are typically set in tt font\n(i.e. `--allow-empty`).\n\n> +\tincluding those which were made empty due to a previous change.\n> +\tWhile this may be desireable, likely it is not.\n\nMental note.  Up to this point, the reader is told that \"--allow-empty\"\nalone is likely to do a wrong thing.\n\n> +\tThis option\n> +\trestricts the scope of --allow-empty to only those commits which\n> +\twere created as empty commits ...\n\nAnd the user is asked to give \"--ignore-if-made-empty\" in addition to\n\"--allow-empty\" to get a saner and more likely to be useful behaviour.\nIsn't that backwards?  This \"the other option is insane, and please make\nit saner\" option needs a lot more typing than the more insane option.\n\nI would expect that \"--allow-empty\" would by default filter ones that are\noriginally non-empty but are made unnecessary (we are allowing empty\ncommits in the original history to be cherry-picked, but the general\nprinciple that unnecessary commits must not be picked still is in effect).\nIf you want to give a user the other more insane mode of operation, it is\nOK to let the user give a different option *instead* *of* the saner\n\"--allow-empty\".\n\nPerhaps name that \"--keep-unnecessary-commit\" (it is no longer about\nallowing empty commits in the original history to be picked; it is about\nkeeping unnecessary and irrelevant commits in the resulting history).\n\nAnd error out if both options are given.\n\n> +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n> +{\n> +\tstruct argv_array array;\n> +\tint rc;\n> +\n> +\targv_array_init(&array);\n> +\targv_array_push(&array, \"commit\");\n> +\targv_array_push(&array, \"-n\");\n> +\n> +\tif ((!empty) && (opts->ignore_if_made_empty)) {\n\nStyle: lose the extra and unnecessary parentheses, especially when the\nexpression inside them are so trivial, i.e.\n\n\tif (!empty && opts->ignore_if_made_empty) {\n\nalthough I suspect that redesign of the command line interface might make\nit a moot point to polish this part of the code without major rethinking.\n\n> +\t\t/* Note: This implies --dry-run */\n> +\t\targv_array_push(&array, \"--porcelain\");\n> +\t\tif (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {\n\nThe only thing you want to check at this point is if the contents of the\nindex being committed is the same as the tree of HEAD.  Why do we even\nwant to incur this much overhead?\n\nIsn't running \"diff-index --cached HEAD\" sufficient?\n\n> +\t\t\t/* The dry run exit code of 1 tells us this is\n> + \t\t\t * an empty commit, just skip it.\n> + \t\t\t */\n\n\t/*\n         * Our multi-line comments are\n         * formatted this way.\n         */\n\n> +\t\t\targv_array_clear(&array);\n> +\t\t\treturn 0;\n> +\t\t}\n> +\t\targv_array_pop(&array, 1);\n> +\t}\n> +\n>  \n>  \tif (opts->signoff)\n> +\t\targv_array_push(&array, \"-s\");\n>  \tif (!opts->edit) {\n> +\t\targv_array_push(&array, \"-F\");\n> +\t\targv_array_push(&array, defmsg);\n>  \t}\n> +\t\n>  \tif (opts->allow_empty)\n> +\t\targv_array_push(&array, \"--allow-empty\");\n> +\n> +\n> +\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n> +\targv_array_clear(&array);\n> +\treturn rc;\n> +}\n> +\n> +static int is_origional_commit_empty(struct commit *commit)\n\nWhat is origional?\n\nIs there a reason why this series is not marked as WIP or RFC?\n\nI am starting to wonder if it is worth spending time on careful reviewing,\nor it would be sufficient to give a cursory review quickly to give you\nmore time to polish your re-roll.\n\n> +{\n> +\tstruct argv_array argv_array;\n> +\tstruct child_process cp;\n> +\tchar ptree[41], pptree[41];\n> +\tint pipefd[2];\n> +\tFILE *output;\n> +\tint ret = 0;\n> +\n> +\tif (pipe2(pipefd, 0) < 0)\n> +\t\treturn 0;\n> +\n> +\toutput = xfdopen(pipefd[0], \"r\");\n> +\n> +\targv_array_init(&argv_array);\n> +\tmemset(&cp, 0, sizeof(struct child_process));\n>  \n> -\targs[i] = NULL;\n> +\targv_array_push(&argv_array, \"rev-parse\");\n> +\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n>  \n> -\treturn run_command_v_opt(args, RUN_GIT_CMD);\n> +\tcp.git_cmd = 1;\n> +\tcp.no_stdin = 1;\n> +\tcp.no_stderr = 1;\n> +\tcp.out = pipefd[1];\n> +\tcp.argv = argv_array.argv;\n> +\n> +\tif (start_command(&cp) < 0)\n> +\t\tgoto out;\n> +\n> +\tif (fscanf(output, \"%s\\n\", ptree) < 1)\n> +\t\tgoto out;\n> +\n> +\tfinish_command(&cp);\n> +\n> +\tfclose(output);\n> +\tclose(pipefd[0]);\n> +\targv_array_clear(&argv_array);\n> +\n> +\tif (pipe2(pipefd, 0) < 0)\n\nHuh?  \"man pipe2\" and see if it is portable.\n"},{"id":"188604","messageId":"20120405232429.GA8654@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vd37m5458.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T23:24:29Z","receivedAt":"2012-04-05T23:24:29Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > As a convienience, it would be nice if we could pop entries off the argv_array\n> > structs so that if they had multiple uses in a function, we wouldn't have to\n> > clear them and repopulate common entries.  This patch adds the argv_array_pop\n> > function to do just that.  Common entries can be added to an argv_array first,\n> > then useage specific ones can be added on the end and removed later on.\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> \n> \n> > CC: Jeff King <peff@peff.net>\n> > CC: Phil Hord <phil.hord@gmail.com>\n> > CC: Junio C Hamano <gitster@pobox.com>\n> > ---\n> \n> Please don't do \"Cc:\" here; they belong to your e-mail header.\n> \nYou mean place them below the snip line?  I can do that.\n\n> > diff --git a/argv-array.c b/argv-array.c\n> > index a4e0420..ce24a48 100644\n> > --- a/argv-array.c\n> > +++ b/argv-array.c\n> > @@ -39,6 +39,18 @@ void argv_array_pushf(struct argv_array *array, const char *fmt, ...)\n> >  \targv_array_push_nodup(array, strbuf_detach(&v, NULL));\n> >  }\n> >  \n> > +int argv_array_pop(struct argv_array *array, unsigned int num)\n> > +{\n> > +\tif (num > array->argc)\n> > +\t\treturn -1;\n> \n> If your use case is \"After using an argv_array for the first invocation,\n> truncate it while keeping the common ones that appear early, so that ones\n> that are specific to the second invocation can be pushed\", it strikes me\n> somewhat odd why you would want to specify \"how many to pop\".\n> \nWhy?  It seems perfectly logical to me to be able to, as a convienience, specify\nhow many items to pop, and the api call seems pleasantly symmetric to the\npush[f] calls.\n\n> Wouldn't argv_array_truncate() or argv_array_setlen() make more sense?\n> \nNo, truncate is vague about its meaning.  Truncate to zero would be useless, as\nits equivalent to the clear call at that point, and truncating to a specific\nvalue is exactly the same as what I have currently, minus the symmetry to the\npush[f] calls.  Likewise setlen doesn't seem to fit in properly, plus theres the\npossibility there of believing the api call might be able to set a length longer\nthan what exists in the array already, which, while silly, requires additional\nerror checking.  Popping a fixed number of elements off an argv_array that have\npreviously been pushed makes perfectly good sense to me.\n\n> \n> > +\tfor(num--; num>0; num--) {\n> \n> Gaah.\n> \nEeek :).  If you want something else equally....equal here, please ask for it.\nI prefer for loops, but if you would rather have a while loop here, I'm fine\nwith that.\n\nRegards\nNeil\n"},{"id":"188606","messageId":"20120405234527.GB8654@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vobr551vs.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-05T23:45:27Z","receivedAt":"2012-04-05T23:45:27Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Subject: Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]\n> \n> Please don't do this.  The tools do not strip the garbage at the end.\n> \n> Instead, do it like either one of these:\n> \n> \tSubject: [PATCH 3/5 (v2)] mumble mumble...\n> \tSubject: [PATCH v2 3/5] mumble mumble...\n> \n> The latter is more appropriate when resending everything, including the\n> ones that did not change from the earlier round.\n> \nThats fine, I typically use tools that strip everything inside all braces, I'll\nupdate this on my next re-roll.\n\n> > Since we'll be using git-cherry-pick to enhance git-rebase's ability to preserve\n> > empty commits, we open ourselves to the possibility of preserving commits that\n> > are made empty by a previous merge as well, which is almost certainly not what\n> > we want (most of the time).  To handle this, we can add the ignore-if-made-empty\n> > option.  If enabled, it will look at cherry-picked commits, and if the origional\n> > sha1 has the same tree as its parent, then the cherry-pick is comitted as an\n> > empty commit, otherwise the commit is skipped (because it previously made\n> > changes to the tree, but no longer does).\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> \n> > diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> > index c283d8c..bb7eb4a 100644\n> > --- a/Documentation/git-cherry-pick.txt\n> > +++ b/Documentation/git-cherry-pick.txt\n> > @@ -103,7 +103,7 @@ effect to your index in a row.\n> >  \tcherry-pick'ed commit, then a fast forward to this commit will\n> >  \tbe performed.\n> >  \n> > ---allow-empty:\n> > +--allow-empty:::\n> \n> A single colon is already buggy, but three colons is equally bad.  Please\n> fix that in the original point this bug was introduced.  I guess it was\n> 2/5 of this series?\n> \nCrap, thanks, I missed that.  I'll square that away\n\n\n> > @@ -112,6 +112,14 @@ effect to your index in a row.\n> >  \tcommits that meet the \"fast-forward\" requirement will be kept\n> >  \teven without this option.\n> >  \n> > +--ignore-if-made-empty::\n> > +\tIf the --allow-empty option is used, all empty commits are kept,\n> \n> Literal strings the user may type are typically set in tt font\n> (i.e. `--allow-empty`).\n> \nAck, ok.\n\n> > +\tincluding those which were made empty due to a previous change.\n> > +\tWhile this may be desireable, likely it is not.\n> \n> Mental note.  Up to this point, the reader is told that \"--allow-empty\"\n> alone is likely to do a wrong thing.\n> \n> > +\tThis option\n> > +\trestricts the scope of --allow-empty to only those commits which\n> > +\twere created as empty commits ...\n> \n> And the user is asked to give \"--ignore-if-made-empty\" in addition to\n> \"--allow-empty\" to get a saner and more likely to be useful behaviour.\n> Isn't that backwards?  This \"the other option is insane, and please make\n> it saner\" option needs a lot more typing than the more insane option.\n> \n> I would expect that \"--allow-empty\" would by default filter ones that are\n> originally non-empty but are made unnecessary (we are allowing empty\n> commits in the original history to be cherry-picked, but the general\n> principle that unnecessary commits must not be picked still is in effect).\n> If you want to give a user the other more insane mode of operation, it is\n> OK to let the user give a different option *instead* *of* the saner\n> \"--allow-empty\".\n> \n> Perhaps name that \"--keep-unnecessary-commit\" (it is no longer about\n> allowing empty commits in the original history to be picked; it is about\n> keeping unnecessary and irrelevant commits in the resulting history).\n> \n> And error out if both options are given.\n> \nYeah, ok.  I wasn't really thinking about the direct use case, as I had expected\nthe typical use to be in the rebase scripts, where this is already wired up, but\nI see your point.  I'll reverse the logic.\n\n> > +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n> > +{\n> > +\tstruct argv_array array;\n> > +\tint rc;\n> > +\n> > +\targv_array_init(&array);\n> > +\targv_array_push(&array, \"commit\");\n> > +\targv_array_push(&array, \"-n\");\n> > +\n> > +\tif ((!empty) && (opts->ignore_if_made_empty)) {\n> \n> Style: lose the extra and unnecessary parentheses, especially when the\n> expression inside them are so trivial, i.e.\n> \nOk\n\n> \tif (!empty && opts->ignore_if_made_empty) {\n> \n> although I suspect that redesign of the command line interface might make\n> it a moot point to polish this part of the code without major rethinking.\n> \n> > +\t\t/* Note: This implies --dry-run */\n> > +\t\targv_array_push(&array, \"--porcelain\");\n> > +\t\tif (run_command_v_opt(array.argv, RUN_GIT_CMD) == 1) {\n> \n> The only thing you want to check at this point is if the contents of the\n> index being committed is the same as the tree of HEAD.  Why do we even\n> want to incur this much overhead?\n> \n> Isn't running \"diff-index --cached HEAD\" sufficient?\nWell, I was looking at the git commit code to see what exactly --dry-run did,\nand I thought that it was roughly equivalent to diff-index.  But if its lower\noverhead to do a diff-index instead, I'll happily change it.\n\n> \n> > +\t\t\t/* The dry run exit code of 1 tells us this is\n> > + \t\t\t * an empty commit, just skip it.\n> > + \t\t\t */\n> \n> \t/*\n>          * Our multi-line comments are\n>          * formatted this way.\n>          */\n> \nOk.\n\n> > +\t\t\targv_array_clear(&array);\n> > +\t\t\treturn 0;\n> > +\t\t}\n> > +\t\targv_array_pop(&array, 1);\n> > +\t}\n> > +\n> >  \n> >  \tif (opts->signoff)\n> > +\t\targv_array_push(&array, \"-s\");\n> >  \tif (!opts->edit) {\n> > +\t\targv_array_push(&array, \"-F\");\n> > +\t\targv_array_push(&array, defmsg);\n> >  \t}\n> > +\t\n> >  \tif (opts->allow_empty)\n> > +\t\targv_array_push(&array, \"--allow-empty\");\n> > +\n> > +\n> > +\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n> > +\targv_array_clear(&array);\n> > +\treturn rc;\n> > +}\n> > +\n> > +static int is_origional_commit_empty(struct commit *commit)\n> \n> What is origional?\n> \nA spelling error :).   Thanks.\n\n> Is there a reason why this series is not marked as WIP or RFC?\n> \nBecause its not.  It works perfectly well, and its fairly close to done.  So far\nyour review has turned up one significant operational change, which is easily\nre-worked and a few stylistic nits.  Thats how review works, I don't see whats\nwrong with that. \n\n> I am starting to wonder if it is worth spending time on careful reviewing,\n> or it would be sufficient to give a cursory review quickly to give you\n> more time to polish your re-roll.\n> \nI'm not sure what you think is so egregious about this changeset, but if\nyou have a specific problem, please let me know.  We all make errors, thats why\nwe review work like this.  All your comment above does is toss a purposeless\ninsult into the conversation. \n \n> > +{\n> > +\tstruct argv_array argv_array;\n> > +\tstruct child_process cp;\n> > +\tchar ptree[41], pptree[41];\n> > +\tint pipefd[2];\n> > +\tFILE *output;\n> > +\tint ret = 0;\n> > +\n> > +\tif (pipe2(pipefd, 0) < 0)\n> > +\t\treturn 0;\n> > +\n> > +\toutput = xfdopen(pipefd[0], \"r\");\n> > +\n> > +\targv_array_init(&argv_array);\n> > +\tmemset(&cp, 0, sizeof(struct child_process));\n> >  \n> > -\targs[i] = NULL;\n> > +\targv_array_push(&argv_array, \"rev-parse\");\n> > +\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n> >  \n> > -\treturn run_command_v_opt(args, RUN_GIT_CMD);\n> > +\tcp.git_cmd = 1;\n> > +\tcp.no_stdin = 1;\n> > +\tcp.no_stderr = 1;\n> > +\tcp.out = pipefd[1];\n> > +\tcp.argv = argv_array.argv;\n> > +\n> > +\tif (start_command(&cp) < 0)\n> > +\t\tgoto out;\n> > +\n> > +\tif (fscanf(output, \"%s\\n\", ptree) < 1)\n> > +\t\tgoto out;\n> > +\n> > +\tfinish_command(&cp);\n> > +\n> > +\tfclose(output);\n> > +\tclose(pipefd[0]);\n> > +\targv_array_clear(&argv_array);\n> > +\n> > +\tif (pipe2(pipefd, 0) < 0)\n> \n> Huh?  \"man pipe2\" and see if it is portable.\n> \nCrud, I completely forgot that pipe2 was _GNU_SOURCE only.  I'll rework that,\nthanks.\n\nRegards\nNeil\n"},{"id":"188607","messageId":"20120406001200.GA6736@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"20120405232429.GA8654@hmsreliant.think-freely.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-06T00:12:00Z","receivedAt":"2012-04-06T00:12:00Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:\n> On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:\n> > Neil Horman <nhorman@tuxdriver.com> writes:\n> > \n> > > As a convienience, it would be nice if we could pop entries off the argv_array\n> > > structs so that if they had multiple uses in a function, we wouldn't have to\n> > > clear them and repopulate common entries.  This patch adds the argv_array_pop\n> > > function to do just that.  Common entries can be added to an argv_array first,\n> > > then useage specific ones can be added on the end and removed later on.\n> > >\n> > > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > \n> > \n> > > CC: Jeff King <peff@peff.net>\n> > > CC: Phil Hord <phil.hord@gmail.com>\n> > > CC: Junio C Hamano <gitster@pobox.com>\n> > > ---\n> > \n> > Please don't do \"Cc:\" here; they belong to your e-mail header.\n> > \n> You mean place them below the snip line?  I can do that.\n> \nActually, I can't do that, git-send-email looks for CC: in the patch text, and\ngit-format-patch automatically inserts the snip line.  I can put the cc's on the\ncommand line, but if git-send-email is parsing this out of the wrong place, that\nseems like a bug.  FWIW, CC's in this location are standard practice for kernel\npatch submissions.\nNeil\n"},{"id":"188608","messageId":"20120406001942.GA14224@sigill.intra.peff.net","threadId":"30112","inReplyTo":"20120405232429.GA8654@hmsreliant.think-freely.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-06T00:19:42Z","receivedAt":"2012-04-06T00:19:42Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:\n\n> > > CC: Jeff King <peff@peff.net>\n> > > CC: Phil Hord <phil.hord@gmail.com>\n> > > CC: Junio C Hamano <gitster@pobox.com>\n> > > ---\n> > \n> > Please don't do \"Cc:\" here; they belong to your e-mail header.\n> > \n> You mean place them below the snip line?  I can do that.\n\nNo, I think he means to drop them entirely; that information is already\nin the list of people you have cc'd in the email.\n\n> > > +int argv_array_pop(struct argv_array *array, unsigned int num)\n> > > +{\n> > > +\tif (num > array->argc)\n> > > +\t\treturn -1;\n> > \n> > If your use case is \"After using an argv_array for the first invocation,\n> > truncate it while keeping the common ones that appear early, so that ones\n> > that are specific to the second invocation can be pushed\", it strikes me\n> > somewhat odd why you would want to specify \"how many to pop\".\n> > \n> Why?  It seems perfectly logical to me to be able to, as a convienience, specify\n> how many items to pop, and the api call seems pleasantly symmetric to the\n> push[f] calls.\n\nI don't mind a \"pop\" call if there is a good use, but personally I find\nyour use case to be hard to read. Your patch 3/5 does this:\n\n  /* make a partial argv */\n  argv_array_init(&array);\n  argv_array_push(&array, \"commit\");\n  argv_array_push(&array, \"-n\");\n\n  /* now do some speculative command */\n  if (some_logic) {\n          argv_array_push(&array, \"--porcelain\");\n          if (run_command(array.argv)) {\n              argv_array_clear(&array);\n              return 0;\n          }\n          argv_array_pop(&array, 1);\n  }\n\n  /* and then possibly proceed to reuse part of the array */\n  argv_array_push(&array, ...);\n  argv_array_push(&array, ...);\n  run_command(array.argv);\n\nIt saves you having to repeat \"commit -n\", but at the expense of making\nthe logic much harder to read. I think this is much easier to read:\n\n  if (some_logic) {\n          const char *argv[] = { \"commit\", \"-n\", \"--porcelain\", NULL };\n          if (run_command(argv))\n                  return 0;\n  }\n\n  argv_array_init(&array);\n  argv_array_push(&array, \"commit\");\n  argv_array_push(&array, \"-n\");\n  argv_array_push(&array, /* other options */);\n  run_command(array.argv);\n\nYou repeat \"-n\", but it is very clear what goes into the speculative\ncommand and what goes into the final command (and there is no chance of\nthe \"1\" in your pop becoming stale and sending cruft to the real command).\n\nThat being said, I think Junio commented on 3/5 that \"git commit\n--porcelain\" is not the right way of doing your speculative command\nanyway, so the two commands would not end up sharing any argv anyway.\n\n> > > +\tfor(num--; num>0; num--) {\n> > \n> > Gaah.\n> > \n> Eeek :).  If you want something else equally....equal here, please ask for it.\n> I prefer for loops, but if you would rather have a while loop here, I'm fine\n> with that.\n\nI think he may have been responding to the style (lack of whitespace). I\nalso find a side-effecting initializer a little non-idiomatic. And\nindeed, I think it causes a bug in this case. \"num\" is an unsigned int.\nSo what happens to the loop when num is 0 coming in?\n\nI think a more traditional way of writing this would be:\n\n  while (num--) {\n          free((char **)array->argv[num);\n          array->argv[num] = NULL;\n  }\n\n-Peff\n"},{"id":"188615","messageId":"20120406011252.GA7204@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"20120406001942.GA14224@sigill.intra.peff.net","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-06T01:12:52Z","receivedAt":"2012-04-06T01:12:52Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 08:19:42PM -0400, Jeff King wrote:\n> On Thu, Apr 05, 2012 at 07:24:29PM -0400, Neil Horman wrote:\n> \n> > > > CC: Jeff King <peff@peff.net>\n> > > > CC: Phil Hord <phil.hord@gmail.com>\n> > > > CC: Junio C Hamano <gitster@pobox.com>\n> > > > ---\n> > > \n> > > Please don't do \"Cc:\" here; they belong to your e-mail header.\n> > > \n> > You mean place them below the snip line?  I can do that.\n> \n> No, I think he means to drop them entirely; that information is already\n> in the list of people you have cc'd in the email.\n> \nNo, its not, thats what I'm saying.  git send-email parses the above information\nto build the CC list.  I can take it out and add the cc's to the command line of\ngit-send-email, but if parsing the above info is incorrect, that seems like a\nbug that needs fixing, one which will get resistance, because its the standard\nway alot of other lists use the CC: tag.\n\n> > > > +int argv_array_pop(struct argv_array *array, unsigned int num)\n> > > > +{\n> > > > +\tif (num > array->argc)\n> > > > +\t\treturn -1;\n> > > \n> > > If your use case is \"After using an argv_array for the first invocation,\n> > > truncate it while keeping the common ones that appear early, so that ones\n> > > that are specific to the second invocation can be pushed\", it strikes me\n> > > somewhat odd why you would want to specify \"how many to pop\".\n> > > \n> > Why?  It seems perfectly logical to me to be able to, as a convienience, specify\n> > how many items to pop, and the api call seems pleasantly symmetric to the\n> > push[f] calls.\n> \n> I don't mind a \"pop\" call if there is a good use, but personally I find\n> your use case to be hard to read. Your patch 3/5 does this:\n> \n>   /* make a partial argv */\n>   argv_array_init(&array);\n>   argv_array_push(&array, \"commit\");\n>   argv_array_push(&array, \"-n\");\n> \n>   /* now do some speculative command */\n>   if (some_logic) {\n>           argv_array_push(&array, \"--porcelain\");\n>           if (run_command(array.argv)) {\n>               argv_array_clear(&array);\n>               return 0;\n>           }\n>           argv_array_pop(&array, 1);\n>   }\n> \n>   /* and then possibly proceed to reuse part of the array */\n>   argv_array_push(&array, ...);\n>   argv_array_push(&array, ...);\n>   run_command(array.argv);\n> \n> It saves you having to repeat \"commit -n\", but at the expense of making\n> the logic much harder to read. I think this is much easier to read:\n> \n>   if (some_logic) {\n>           const char *argv[] = { \"commit\", \"-n\", \"--porcelain\", NULL };\n>           if (run_command(argv))\n>                   return 0;\n>   }\n> \n>   argv_array_init(&array);\n>   argv_array_push(&array, \"commit\");\n>   argv_array_push(&array, \"-n\");\n>   argv_array_push(&array, /* other options */);\n>   run_command(array.argv);\n> \n> You repeat \"-n\", but it is very clear what goes into the speculative\n> command and what goes into the final command (and there is no chance of\n> the \"1\" in your pop becoming stale and sending cruft to the real command).\n> \nOk, I can see the use of the argv array above being more readable, but (I think\nyour) comment from the first iteration of this patch, suggested re-doing this\nlogic to use struct argv_array.  I do like the above better.  I'll redo that.\n \n> That being said, I think Junio commented on 3/5 that \"git commit\n> --porcelain\" is not the right way of doing your speculative command\n> anyway, so the two commands would not end up sharing any argv anyway.\n>\nI'm still not completely convinced about that, given that commit --porcelain\neffectively does a git diff-index, but I'll defer to the experts on that,\ndiff-index works just as well for this.  And if I use your above static array\nimplementation instead, I can get rid of the pop api addition entirely.\n \n> > > > +\tfor(num--; num>0; num--) {\n> > > \n> > > Gaah.\n> > > \n> > Eeek :).  If you want something else equally....equal here, please ask for it.\n> > I prefer for loops, but if you would rather have a while loop here, I'm fine\n> > with that.\n> \n> I think he may have been responding to the style (lack of whitespace). I\nThat was really my problem with it.  I appreciate the direct comment.  A note\nabout lack of whitespace is something I can work with, Gaah is not :)\n\n> also find a side-effecting initializer a little non-idiomatic. And\n> indeed, I think it causes a bug in this case. \"num\" is an unsigned int.\n> So what happens to the loop when num is 0 coming in?\n> \nThat should be caught by the case checking logic at the top of the function.\nAlthough I think you're right, the 1 case I think has an OBO error.  Its moot\nanyway, if I use your static array approach above, I'll remove all of this.\n\n> I think a more traditional way of writing this would be:\n> \n>   while (num--) {\n>           free((char **)array->argv[num);\n>           array->argv[num] = NULL;\n>   }\n> \nThats certainly another way to do it, and I'm happy to do that if its the\nconsensus.  I just happen to prefer for loops (for no particular reason, its\njust me).  But again, using your approach above, this will all get removed.\n\nThanks for the review.  I'll fix this up, and have a new version in a few days.\n\n\nBest\nNeil\n> -Peff\n> \n"},{"id":"188616","messageId":"7vvcld3bc7.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120405234527.GB8654@hmsreliant.think-freely.org","subject":"Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-06T01:20:24Z","receivedAt":"2012-04-06T01:20:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:\n>\n>> I am starting to wonder if it is worth spending time on careful reviewing,\n>> or it would be sufficient to give a cursory review quickly to give you\n>> more time to polish your re-roll.\n>> \n> I'm not sure what you think is so egregious about this changeset, but if\n> you have a specific problem, please let me know.\n\nThere is no insult involved. I just didn't know where to start, because\nthe series was littered with many issues from high level design (e.g. does\nthe command line interface and API addition make sense?) to low level\nstyles (e.g. does the new code imitate the style of the existing code\naround it?), and in between (e.g. pipe2() is never used in the codebase\nwithout this patch. Is it portable enough?). It was clear that it needed a\nlot more work to lose a WIP label (the quality standard in this project is\nslightly higher than \"the end result seems to compile--let's ship it\").\n\nIn other words, I was simply being honest.\n\n> We all make errors, thats why\n> we review work like this.  All your comment above does is toss a purposeless\n> insult into the conversation. \n\nMaking mistakes is one thing.  Sending a series that is not sufficiently\nproofread is a completely different matter.  The review process is not a\nreplacement for your own proofreading.  It comes after that.\n\nIf you did proofread the patch [3/5], you would have noticed that the fix\nyou made to the documentation is a fix for patch [2/5]. You are in much\nbetter position than I or other reviewers to notice it---after all, it is\nyour addition. The same for the typo in the mysteriously named function.\n\nHow else do you expect me to react to such a series?\n"},{"id":"188617","messageId":"7vobr53bbe.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120405232429.GA8654@hmsreliant.think-freely.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-06T01:20:53Z","receivedAt":"2012-04-06T01:20:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> On Thu, Apr 05, 2012 at 01:12:51PM -0700, Junio C Hamano wrote:\n>> Neil Horman <nhorman@tuxdriver.com> writes:\n>> \n>> > As a convienience, it would be nice if we could pop entries off the argv_array\n>> > structs so that if they had multiple uses in a function, we wouldn't have to\n>> > clear them and repopulate common entries.  This patch adds the argv_array_pop\n>> > function to do just that.  Common entries can be added to an argv_array first,\n>> > then useage specific ones can be added on the end and removed later on.\n>> >\n>> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n>> \n>> \n>> > CC: Jeff King <peff@peff.net>\n>> > CC: Phil Hord <phil.hord@gmail.com>\n>> > CC: Junio C Hamano <gitster@pobox.com>\n>> > ---\n>> \n>> Please don't do \"Cc:\" here; they belong to your e-mail header.\n>> \n> You mean place them below the snip line?  I can do that.\n\nNo.  When you review and fix typo in format-patch output, you can add\nthese to the e-mail header part and git-send-email will pick them up just\nfine.\n\n>> If your use case is \"After using an argv_array for the first invocation,\n>> truncate it while keeping the common ones that appear early, so that ones\n>> that are specific to the second invocation can be pushed\", it strikes me\n>> somewhat odd why you would want to specify \"how many to pop\".\n>> \n> Why?\n\nYou know you have N common ones.  You push some more, perhaps with a\nsequence of \"if (condition) argv_push();\" and use it.  Now it is time to\nreprepare it for the second usage.  Wouldn't it be more natural to say\n\n\targv_array_setlen(N);\n        /* start pushing the specific ones for next invocation */\n        argv_array_push();\n        if (condition)\n        \targv_array_push();\n\n>> > +\tfor(num--; num>0; num--) {\n>> \n>> Gaah.\n>> \n> Eeek :).  If you want something else equally....equal here, please ask for it.\n> I prefer for loops, but if you would rather have a while loop here, I'm fine\n> with that.\n\nPlease look at the existing \"for ()\" loop in the same file, and then go\nread the CodingGuidelines.\n"},{"id":"188619","messageId":"20120406022058.GA16264@sigill.intra.peff.net","threadId":"30112","inReplyTo":"7vobr53bbe.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-06T02:20:58Z","receivedAt":"2012-04-06T02:20:58Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2012 at 06:20:53PM -0700, Junio C Hamano wrote:\n\n> >> > CC: Jeff King <peff@peff.net>\n> >> > CC: Phil Hord <phil.hord@gmail.com>\n> >> > CC: Junio C Hamano <gitster@pobox.com>\n> >> > ---\n> >> \n> >> Please don't do \"Cc:\" here; they belong to your e-mail header.\n> >> \n> > You mean place them below the snip line?  I can do that.\n> \n> No.  When you review and fix typo in format-patch output, you can add\n> these to the e-mail header part and git-send-email will pick them up just\n> fine.\n\nI think there is a legitimate conflict of interest here.\n\nIt's not clear exactly what \"cc\" tags in a commit message mean, because\nit is really a per-project thing. I don't work on the kernel, but I\nalways took their cc tag to mean \"these are people interested in this\ntopic area\". Send-email helpfully picks up that hint and cc's them on\nthe emailed patch. And when the patch is applied, those cc lines remain,\nbecause people reading \"git log\" much later may find a bug in the patch,\nand it is helpful to tell them the people interested in the area.\n\nIn git.git, though, we don't typically use such cc tags. Perhaps because\nwe are a much smaller project than the kernel, or perhaps for other\nlogistical reasons. And even if we did, the cc list above does not\nreally meet the guideline I gave. They are people who happened to review\nyour patch or comment on the list, not people who are interested forever\nin a particular subsystem.\n\nSo from the maintainer's and the project's perspective, those cc lines\nare useless noise.\n\nBut from the submitter's point of view, it may be convenient to tell git\n\"these are people who have reviewed _this_ patch series\", and have it\nautomatically cc them on each iteration of the series without re-typing\ntheir addresses.  And because of the send-email behavior I mentioned\nabove, the \"cc\" tags are a convenient place to put it.\n\nSo it is a piece of information that is useful to the submitter, but not\nto the maintainer. Where can the submitter put it that will help\nthemselves, but not bother the maintainer?  I wonder if the right\nsolution would be an option for send-email to respect cc lines, but\nstrip them out of the body of the sent patch.\n\n-Peff\n"},{"id":"188627","messageId":"20120406041907.GA3843@burratino","threadId":"30112","inReplyTo":"20120406022058.GA16264@sigill.intra.peff.net","subject":"Cc tags in the commit message (Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2])","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2012-04-06T04:19:07Z","receivedAt":"2012-04-06T04:19:07Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Jeff King wrote:\n\n> It's not clear exactly what \"cc\" tags in a commit message mean, because\n> it is really a per-project thing. I don't work on the kernel, but I\n> always took their cc tag to mean \"these are people interested in this\n> topic area\".\n\nHere's a link from a previous time it came up: [1]\n\n:)\nJonathan\n\n[1] http://thread.gmane.org/gmane.comp.version-control.git/157707/focus=157757\n"},{"id":"188635","messageId":"7v4nsx2vu1.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120406022058.GA16264@sigill.intra.peff.net","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-06T06:55:18Z","receivedAt":"2012-04-06T06:55:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> So from the maintainer's and the project's perspective, those cc lines\n> are useless noise.\n> ...\n> So it is a piece of information that is useful to the submitter, but not\n> to the maintainer.\n\n... nor the user of the project history, as you said earlier.\n\nI agree that submitters would benefit from an automated way to propagate\nthese addresses from reroll to reroll, and in a larger workflow \"tweak and\nrecord while amending a commit for reroll\" would be a natural place to do\nso, so I can see why it is tempting to abuse Cc: in the body of the\nmessage, but not knowing other ways is not a good excuse for such an\nabuse.  A workable solution is already available [*1*]: commit with a\n\"---\" line followed by Cc: and whatever extra junk while amending.\n\nEven if it did not work to write \"---\" before the extra Cc:, I do not\nthink it is such a big deal, though.  As the output file from format-patch\nis meant to be read into an editor for final proof-reading, it shouldn't\nbe too much extra burden to move those Cc: at the end of the log message\nto the header part of the message while doing so anyway.\n\n\n[Footnote]\n\n*1* Here is a trivial demonstration.\n\nI amended the 1.7.10-rc4 on a throw-away branch to make \"git show -s\" show\nthis:\n\n-- >8 --\ncommit aaac56582ce1820551d48bf2b2364cb00f0345cb\nAuthor: Junio C Hamano <gitster@pobox.com>\nDate:   Tue Apr 3 09:25:49 2012 -0700\n\n    Git 1.7.10-rc4\n    \n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n    ---\n    Cc: Test user <junio@pobox.com>\n    \n    This is a cover letter for small one.\n-- 8< --\n\nFeeding output from \"git format-patch -1 HEAD\" for this patch to send-email\ndoes add the \"Test user\" to the list of recipients, like so:\n\n-- >8 --\n0001-Git-1.7.10-rc4.txt\n(body) Adding cc: Test user <junio@pobox.com> from line 'Cc: Test user <junio@pobox.com>'\nDry-OK. Log says:\nSendmail: /usr/bin/msmtp -f gitster@pobox.com -i git@vger.kernel.org junio@pobox.com\nFrom: Junio C Hamano <gitster@pobox.com>\nTo: git@vger.kernel.org\nCc: Test user <junio@pobox.com>\nSubject: [PATCH] Git 1.7.10-rc4\nDate: Thu,  5 Apr 2012 23:47:09 -0700\nMessage-Id: <1333694829-4295-1-git-send-email-gitster@pobox.com>\nX-Mailer: git-send-email 1.7.10.rc4.54.g1d5dd3\n\nResult: OK\n-- 8< --\n"},{"id":"188640","messageId":"20120406073314.GB27115@sigill.intra.peff.net","threadId":"30112","inReplyTo":"7v4nsx2vu1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-04-06T07:33:14Z","receivedAt":"2012-04-06T07:33:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 05, 2012 at 11:55:18PM -0700, Junio C Hamano wrote:\n\n> I agree that submitters would benefit from an automated way to propagate\n> these addresses from reroll to reroll, and in a larger workflow \"tweak and\n> record while amending a commit for reroll\" would be a natural place to do\n> so, so I can see why it is tempting to abuse Cc: in the body of the\n> message, but not knowing other ways is not a good excuse for such an\n> abuse.  A workable solution is already available [*1*]: commit with a\n> \"---\" line followed by Cc: and whatever extra junk while amending.\n\nI've played with that workflow before. While it's a neat trick, note\nthat something like \"format-patch -s\" will put the signoff at the end,\nlike:\n\n  commit subject\n\n  commit body\n  ---\n  Cc: whomever\n  Signed-off-by: you\n\nwhich is not what you want. We could perhaps teach it to be smarter\nabout finding a \"---\", though I worry about hurting people who do not\nuse an email-based workflow, since they otherwise don't have to care\nabout \"---\".\n\nAbout a year ago I had an RFC series to let \"git commit\" parse off the\n\"---\" bit and turn it into a git-note (mostly for keeping track of\nchanges to the series between versions). It does solve that problem, and\nresponse was reasonably positive. It does make things more complicated,\nthough, because IIRC you have to turn on note-rewriting manually to keep\nthe notes attached as you rebase.  Ultimately I didn't follow up because\nI've found that I just don't end up keeping a lot of notes. I tend to do\nthe re-roll and then send it out pretty soon afterward, so I just write\nany notes in the emails as they go out.\n\nFor complex \"cc\" lists and the like, I have a (fairly hacky) script that\ntakes an existing message as input and generates a format-patch series\nwith the to, cc, and in-reply-to fields filled in (and then I ship the\nresult out via my regular MUA after proof-reading and tweaking).\nPotentially git-send-email could do the same thing.\n\n-Peff\n"},{"id":"188663","messageId":"7vvclc24c0.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120406073314.GB27115@sigill.intra.peff.net","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-06T16:49:19Z","receivedAt":"2012-04-06T16:49:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Apr 05, 2012 at 11:55:18PM -0700, Junio C Hamano wrote:\n> ...\n> I've played with that workflow before. While it's a neat trick, note\n> that something like \"format-patch -s\" will put the signoff at the end,\n> like:\n>\n>   commit subject\n>\n>   commit body\n>   ---\n>   Cc: whomever\n>   Signed-off-by: you\n>\n> which is not what you want.\n\nWell, then \"don't do it then\".  The reason the Cc: was abused in this\nthread originally is about recording the people who reviewed, so you are\ndoing an amend of an existing commit in an editor.  Why wouldn't the\ncommit that was already reviewed at least once didn't have S-o-b in the\nfirst place?  In other words, isn't the \"-s\" option in \"format-patch\" a\nuseless feature creep that would only help those with broken workflows?\n\n> About a year ago I had an RFC series to let \"git commit\" parse off the\n> \"---\" bit and turn it into a git-note ...\n> ... Ultimately I didn't follow up because\n> I've found that I just don't end up keeping a lot of notes. I tend to do\n> the re-roll and then send it out pretty soon afterward, so I just write\n> any notes in the emails as they go out.\n>\n> For complex \"cc\" lists and the like, I have a (fairly hacky) script that\n> takes an existing message as input and generates a format-patch series\n> with the to, cc, and in-reply-to fields filled in (and then I ship the\n> result out via my regular MUA after proof-reading and tweaking).\n> Potentially git-send-email could do the same thing.\n\nPerhaps.\n"},{"id":"188672","messageId":"20120406180211.GA11939@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120406022058.GA16264@sigill.intra.peff.net","subject":"Re: [PATCH 1/5] argv-array: Add argv_array_pop function [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-06T18:02:11Z","receivedAt":"2012-04-06T18:02:11Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 10:20:58PM -0400, Jeff King wrote:\n> On Thu, Apr 05, 2012 at 06:20:53PM -0700, Junio C Hamano wrote:\n> \n> > >> > CC: Jeff King <peff@peff.net>\n> > >> > CC: Phil Hord <phil.hord@gmail.com>\n> > >> > CC: Junio C Hamano <gitster@pobox.com>\n> > >> > ---\n> > >> \n> > >> Please don't do \"Cc:\" here; they belong to your e-mail header.\n> > >> \n> > > You mean place them below the snip line?  I can do that.\n> > \n> > No.  When you review and fix typo in format-patch output, you can add\n> > these to the e-mail header part and git-send-email will pick them up just\n> > fine.\n> \n> I think there is a legitimate conflict of interest here.\n> \n> It's not clear exactly what \"cc\" tags in a commit message mean, because\n> it is really a per-project thing. I don't work on the kernel, but I\n> always took their cc tag to mean \"these are people interested in this\n> topic area\". Send-email helpfully picks up that hint and cc's them on\n> the emailed patch. And when the patch is applied, those cc lines remain,\n> because people reading \"git log\" much later may find a bug in the patch,\n> and it is helpful to tell them the people interested in the area.\n> \nThats more or less what its for.  Mostly CC's on a patch on lkml are meant to\ndirect peoples attention to patches for subsystems their interested in.  teh\nkernels get_maintainers script generates these typically.  With the volume of\ntraffic on lkml its often easy for patches to get misplaced by individual\nmaintainers.  Recording that info in the commit message, while possibly useful,\nis most often seen as a harmless side effect.\n\nThe major advantage of CC's in the commit log is that it lets you skip the\nformat-patch stage. I.E. you can just git-send-email directly and have all the\nright people CC-ed. Thats very handy when you have a large changeset and the CC\nlist differs for individual patches.\n\nNeil\n"},{"id":"188674","messageId":"20120406180627.GB11939@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vobr551vs.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-06T18:06:27Z","receivedAt":"2012-04-06T18:06:27Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 05, 2012 at 02:01:43PM -0700, Junio C Hamano wrote:\n><snip>\n\n> > +\tincluding those which were made empty due to a previous change.\n> > +\tWhile this may be desireable, likely it is not.\n> \n> Mental note.  Up to this point, the reader is told that \"--allow-empty\"\n> alone is likely to do a wrong thing.\n> \n> > +\tThis option\n> > +\trestricts the scope of --allow-empty to only those commits which\n> > +\twere created as empty commits ...\n> \n> And the user is asked to give \"--ignore-if-made-empty\" in addition to\n> \"--allow-empty\" to get a saner and more likely to be useful behaviour.\n> Isn't that backwards?  This \"the other option is insane, and please make\n> it saner\" option needs a lot more typing than the more insane option.\n> \n> I would expect that \"--allow-empty\" would by default filter ones that are\n> originally non-empty but are made unnecessary (we are allowing empty\n> commits in the original history to be cherry-picked, but the general\n> principle that unnecessary commits must not be picked still is in effect).\n> If you want to give a user the other more insane mode of operation, it is\n> OK to let the user give a different option *instead* *of* the saner\n> \"--allow-empty\".\n> \n> Perhaps name that \"--keep-unnecessary-commit\" (it is no longer about\n> allowing empty commits in the original history to be picked; it is about\n> keeping unnecessary and irrelevant commits in the resulting history).\n> \n> And error out if both options are given.\n> \nI'm working on this today, and in doing so, I don't think I like the one or the\nother option approach.  I think it makes more sense to use an --option /\n--option-harder model here.  Theres precident for this in a few other git\ncommand (git format-patch has --find-copies and --find-copies harder).  I think\nwe can do an --allow-empty option and a --keep-redundant-commits option, where\nthe former explicitly keeps commits that were non-empty but are now because\ntheir changes have already been applied.  the latter option then naturally\nimplies the former.\n\nNeil\n"},{"id":"188675","messageId":"4F7F363B.3090007@kdbg.org","threadId":"30112","inReplyTo":"1333654745-7898-4-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH 3/5] git-cherry-pick: Add ignore-if-made-empty option [v2]","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2012-04-06T18:30:19Z","receivedAt":"2012-04-06T18:30:19Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 05.04.2012 21:39, schrieb Neil Horman:\n> +\tif (pipe2(pipefd, 0) < 0)\n> +\t\treturn 0;\n> +\toutput = xfdopen(pipefd[0], \"r\");\n> +\tmemset(&cp, 0, sizeof(struct child_process));\n> +\t... setup cp ...\n> +\tif (start_command(&cp) < 0)\n> +\t\tgoto out;\n> +\tif (fscanf(output, \"%s\\n\", ptree)<  1)\n> +\t\tgoto out;\n> +\tfinish_command(&cp);\n> +\tfclose(output);\n> +\tclose(pipefd[0]);\n\nInstead of this sequence (I quoted only the relevant pieces), use the \nfollowing:\n\n\tmemset(&cp, 0, sizeof(struct child_process));\n\tcp.out = -1;\n\t... set other pieces in cp ...\n\tif (start_command(&cp) < 0)\n\t\tgoto out;\n\tread_in_full(cp.out, ptree, sizeof(ptree));\n\t/* add suitable error reporting above */\n\tclose(cp.out);\n\tif (!finish_command(&cp))\n\t\tgoto out;\n\ni.e.,\n\n1. let start_command create the pipe for you by setting cp.out = -1,\n2. avoid fscanf() if read_in_full() is equally simple to use,\n3. close the pipe before finish_command(),\n4. check the return code of finish_command().\n\n-- Hannes\n"},{"id":"188874","messageId":"1334072868-9435-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v3 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T15:47:44Z","receivedAt":"2012-04-10T15:47:44Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --keep-redundant-commits, which allows the user to also keep\ncommits that were made empty via conflict resolution.  It also enhances\ngit-rebase to add a --keep-empty option which enables rebases to preserve empty\ncommits. \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\nV3)\n\t* reversed the --ignore-if-empty-logic to by default only keep initially\n\tempty commits\n\n\t* replaced --ignore-if-empty with --keep-redundant-commits, to allow\n\tempty commits that are made empty via conflict resolution, in addition\n\tto commits that were created as empty\n\n\t* reworked is_original_commit_empty to be more efficient and portable\n\n\t* Misc sylistic and spelling cleanups\n\n"},{"id":"188876","messageId":"1334072868-9435-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334072868-9435-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T15:47:45Z","receivedAt":"2012-04-10T15:47:45Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operation.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/commit.c                  |    6 +++---\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 5 files changed, 20 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..730237a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty::\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 3714582..0cd10ab 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -56,10 +56,10 @@ N_(\"You asked to amend the most recent commit, but doing so would make\\n\"\n \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\");\n \n static const char empty_cherry_pick_advice[] =\n-N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\n\"\n-\"If you wish to commit it anyway, use:\\n\"\n+N_(\"The previous cherry-pick is empty.\\n\"\n+\"If the commit was created empty, please use:\\n\"\n \"\\n\"\n-\"    git commit --allow-empty\\n\"\n+\"    git cherry-pick --allow-empty\\n\"\n \"\\n\"\n \"Otherwise, please use 'git reset'\\n\");\n \ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"188875","messageId":"1334072868-9435-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334072868-9435-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T15:47:46Z","receivedAt":"2012-04-10T15:47:46Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"The git-cherry-pick --allow-empty command by default only preserves empty\ncommits that were originally empty, i.e only those commits for which\n<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are\nnon-empty, but were made empty by the inclusion of a prior commit on the current\nhistory are filtered out.  This option allows us to override that behavior and\ninclude redundant commits as empty commits in the change history.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |   12 ++++-\n builtin/commit.c                  |    5 ++\n builtin/revert.c                  |    8 +++-\n sequencer.c                       |  106 ++++++++++++++++++++++++++++++++-----\n sequencer.h                       |    1 +\n 5 files changed, 117 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 730237a..f96b8c5 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -110,7 +110,17 @@ effect to your index in a row.\n \tbehavior, allowing empty commits to be preserved automatically\n \tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n \tcommits that meet the \"fast-forward\" requirement will be kept\n-\teven without this option.\n+\teven without this option.  Note also, that use of this option only\n+\tkeeps commits that were initially empty (i.e. where for commit C\n+\tC^{tree} and C^^{tree} are equal).  Commits which are made empty due to\n+\ta previous commit are ignored.  To force the inclusion of those commits\n+\tuse `--keep-redundant-commits`\n+\n+--keep-redundant-commits::\n+\tIf a commit being cherry picked duplicates a commit already in the\n+\tcurrent history, it will result in an empty changeset.  By default these\n+\tredundant commits are ignored.  This option overrides that behavior and\n+\tcreates an empty commit object.  Implies `--allow-empty`\n \n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 0cd10ab..c386189 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -61,6 +61,11 @@ N_(\"The previous cherry-pick is empty.\\n\"\n \"\\n\"\n \"    git cherry-pick --allow-empty\\n\"\n \"\\n\"\n+\"If the commit was made empty via conflict resolution, and you wish\\n\"\n+\"to keep the now-empty commit anyway, use:\\n\"\n+\"\\n\"\n+\"    git cherry-pick --keep-redundant-commits\\n\"\n+\"\\n\"\n \"Otherwise, please use 'git reset'\\n\");\n \n static const char *use_message_buffer;\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..4f0d979 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n-\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve initially empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_if_made_empty, \"keep redundant, empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n+\t/* keep_if_made_empty implies allow_empty */\n+\tif (opts->keep_if_made_empty)\n+\t\topts->allow_empty = 1;\n+\n \t/* Set the subcommand */\n \tif (remove_state)\n \t\topts->subcommand = REPLAY_REMOVE_STATE;\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..5d033db 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n {\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+\tstruct argv_array array;\n+\tint rc;\n+\n+\tif (!empty && !opts->keep_if_made_empty) {\n+\t\tconst char *argv[] = { \"diff-index\", \"--quiet\", \"--exit-code\",\n+\t\t\t\t\t\"--cached\", \"HEAD\", NULL };\n+\n+\t\t/*\n+ \t\t * If we run git diff-index with the above option and it returns\n+ \t\t * zero, then there have been no changes made to the index by\n+ \t\t * this patch, i.e. its empty.  Since our previous empty test\n+ \t\t * indicated that this patch was not created empty, its been made\n+ \t\t * redundant.  Since keep_if_made_empty is not set, we just skip\n+ \t\t * it\n+ \t\t */\n+\t\tif (run_command_v_opt(argv, RUN_GIT_CMD) == 0)\n+\t\t\treturn 0;\n+\t}\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\t\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n \n-\targs[i] = NULL;\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n+\n+static int is_original_commit_empty(struct commit *commit)\n+{\n+\tstruct argv_array argv_array;\n+\tstruct child_process cp;\n+\tchar ptree[40], pptree[40];\n+\tint ret = 0;\n+\n+\targv_array_init(&argv_array);\n+\tmemset(&cp, 0, sizeof(struct child_process));\n+\n+\targv_array_push(&argv_array, \"rev-parse\");\n+\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n+\n+\tcp.git_cmd = 1;\n+\tcp.no_stdin = 1;\n+\tcp.no_stderr = 1;\n+\tcp.out = -1;\n+\tcp.argv = argv_array.argv;\n+\n+\tif (start_command(&cp) < 0)\n+\t\tgoto out;\n+\n+\tif (read_in_full(cp.out, ptree, sizeof(ptree)) < sizeof(ptree)) {\n+\t\tclose(cp.out);\n+\t\tgoto out;\n+\t}\n+\n+\tclose(cp.out);\n+\n+\tfinish_command(&cp);\n+\n+\targv_array_clear(&argv_array);\n+\n+\targv_array_push(&argv_array, \"rev-parse\");\n+\targv_array_pushf(&argv_array, \"%s^^{tree}\", sha1_to_hex(commit->object.sha1));\n+\tcp.out = -1;\n+\tcp.argv = argv_array.argv;\n+\n+\tif (start_command(&cp) < 0)\n+\t\tgoto out;\n+\n+\tif (read_in_full(cp.out, pptree, sizeof(pptree)) < sizeof(ptree)) {\n+\t\tclose(cp.out);\n+\t\tgoto out;\n+\t}\n+\n+\tclose(cp.out);\n+\n+\tfinish_command(&cp);\n+\n+\tif (!strncmp(ptree, pptree, sizeof(ptree)))\n+\t\tret = 1;\n+out:\n+\targv_array_clear(&argv_array);\t\n+\treturn ret;\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +366,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +492,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_original_commit_empty(commit);\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -435,7 +515,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n \t\tif (!opts->no_commit)\n-\t\t\tres = run_git_commit(defmsg, opts);\n+\t\t\tres = run_git_commit(defmsg, opts, empty_commit);\n \t}\n \n \tfree_message(&msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..862a79a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint keep_if_made_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"188877","messageId":"1334072868-9435-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334072868-9435-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v3 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T15:47:47Z","receivedAt":"2012-04-10T15:47:47Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --keep-redundant-commits\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n t/t3505-cherry-pick-empty.sh |   31 ++++++++++++++++++++++++++++++-\n 1 files changed, 30 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..9d419ae 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,28 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fourth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" && {\n+\t\tgit cherry-pick empty-branch2\n+\t\ttest \"$?\" = 1 \n+\t}\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --allow-empty empty-branch2\n+\t\ttest \"$?\" = 0\n+\t}\n+'\n+\n+test_expect_success 'cherry pick with --keep-redundant-commits' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --keep-redundant-commits HEAD^\n+\t\ttest \"$?\" = 0\n+\t}\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"188878","messageId":"1334072868-9435-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334072868-9435-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v3 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T15:47:48Z","receivedAt":"2012-04-10T15:47:48Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   35 ++++++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 55 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..040289c 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if test -n \"$keep_empty\" \n+then\n+\t# we have to do this the hard way.  git format-patch completely squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..597d60a 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,12 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\tptree=$(git rev-parse \"$1\"^{tree})\n+\tpptree=$(git rev-parse \"$1\"^^{tree})\n+\treturn $(test \"$ptree\" = \"$pptree\")\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +197,18 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n+\tif is_empty_commit $@ \n+\tthen\n+\t\tempty_args=\"--allow-empty\"\n+\tfi\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n+\tthen\n+\t\tcomment_out=\"# pick\"\n+\telse\n+\t\tcomment_out=\"pick\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +821,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +871,15 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\tcat >> \"$todo\" << EOF\n+\t# Note that commits which are empty at the time of rebasing are \n+\t# commented out. \n+EOF\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"188884","messageId":"7v62d7qzu9.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1334072868-9435-2-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-10T16:45:46Z","receivedAt":"2012-04-10T16:45:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> git cherry-pick fails when picking a non-ff commit that is empty.  The advice\n> given with the failure is that a git-commit --allow-empty should be issued to\n> explicitly add the empty commit during the cherry pick.  This option allows a\n> user to specify before hand that they want to keep the empty commit.  This\n> eliminates the need to issue both a cherry pick and a commit operation.\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> ---\n>  Documentation/git-cherry-pick.txt |    9 +++++++++\n>  builtin/commit.c                  |    6 +++---\n>  builtin/revert.c                  |    2 ++\n>  sequencer.c                       |    7 +++++--\n>  sequencer.h                       |    1 +\n>  5 files changed, 20 insertions(+), 5 deletions(-)\n>\n> diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> index fed5097..730237a 100644\n> --- a/Documentation/git-cherry-pick.txt\n> +++ b/Documentation/git-cherry-pick.txt\n> @@ -103,6 +103,15 @@ effect to your index in a row.\n>  \tcherry-pick'ed commit, then a fast forward to this commit will\n>  \tbe performed.\n>  \n> +--allow-empty::\n> +\tBy default, cherry-picking an empty commit will fail,\n> +\tindicating that an explicit invocation of `git commit\n> +\t--allow-empty` is required. This option overrides that\n> +\tbehavior, allowing empty commits to be preserved automatically\n> +\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n> +\tcommits that meet the \"fast-forward\" requirement will be kept\n> +\teven without this option.\n> +\n>  --strategy=<strategy>::\n>  \tUse the given merge strategy.  Should only be used once.\n>  \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index 3714582..0cd10ab 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -56,10 +56,10 @@ N_(\"You asked to amend the most recent commit, but doing so would make\\n\"\n>  \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\");\n>  \n>  static const char empty_cherry_pick_advice[] =\n> -N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\n\"\n> -\"If you wish to commit it anyway, use:\\n\"\n> +N_(\"The previous cherry-pick is empty.\\n\"\n> +\"If the commit was created empty, please use:\\n\"\n\nAfter reading this three times, I have to say that the updated wording do\nnot look like an improvement for two reasons.\n\n (1) After a failed cherry-pick, the index can match the current HEAD for\n     two reasons.  Either the original cherry-pick was attempting to pick\n     an empty commit (which is likely to be a mistake unless you are doing\n     something unusual like creating an empty commit in the first place),\n     or the change in the original commit was already found in the current\n     version (may be result of a conflict resolution).  The message before\n     your change used \"possibly\" to hint this, and if the reader gets it,\n     it is understandable why the reader is seeing this advise.  Updated\n     message loses this information by simply saying \"is empty\".\n\n (2) The message is given by the \"git commit\" command.  \"If the commit was\n     created empty\" looks confusing.  Even though I can understand that\n     \"the commit\" refers to the original commit the user tried to\n     cherry-pick before running this command while reviewing this patch, I\n     suspect that the reader who sees this message may not be able to tell\n     if the \"git commit\" command created a possibly empty commit and then\n     telling the user to do something further on _that_ commit, or if it\n     is referring to the commit the user tried to pick with the previous\n     \"git cherry-pick\" command.\n\nThat is, unless you are making \"git cherry-pick --allow-empty\" not to stop\nand leave it to \"git commit\" to clean it up.  If that were the case (which\nis not, after applying this patch alone), then this message will be issued\nonly when a conflict resolution resulted in an empty commit, so \"If the\ncommit you were trying to cherry-pick was empty to begin with\" would not\napply, either.\n"},{"id":"188883","messageId":"7vy5q3pl9i.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1334072868-9435-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-10T17:04:32Z","receivedAt":"2012-04-10T17:04:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> +\t/* keep_if_made_empty implies allow_empty */\n> +\tif (opts->keep_if_made_empty)\n> +\t\topts->allow_empty = 1;\n> +\n \nOK.\n\n> diff --git a/sequencer.c b/sequencer.c\n> index 71929ba..5d033db 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -13,6 +13,7 @@\n>  #include \"rerere.h\"\n>  #include \"merge-recursive.h\"\n>  #include \"refs.h\"\n> +#include \"argv-array.h\"\n>  \n>  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>  \n> @@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n>   * If we are revert, or if our cherry-pick results in a hand merge,\n>   * we had better say that the current user is responsible for that.\n>   */\n> -static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n> +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n>  {\n> -\t/* 7 is max possible length of our args array including NULL */\n> -\tconst char *args[7];\n> -\tint i = 0;\n> +\tstruct argv_array array;\n> +\tint rc;\n> +\n> +\tif (!empty && !opts->keep_if_made_empty) {\n> +\t\tconst char *argv[] = { \"diff-index\", \"--quiet\", \"--exit-code\",\n> +\t\t\t\t\t\"--cached\", \"HEAD\", NULL };\n> +\n> +\t\t/*\n> + \t\t * If we run git diff-index with the above option and it returns\n> + \t\t * zero, then there have been no changes made to the index by\n> + \t\t * this patch, i.e. its empty.  Since our previous empty test\n> + \t\t * indicated that this patch was not created empty, its been made\n> + \t\t * redundant.  Since keep_if_made_empty is not set, we just skip\n> + \t\t * it\n> + \t\t */\n> +\t\tif (run_command_v_opt(argv, RUN_GIT_CMD) == 0)\n> +\t\t\treturn 0;\n\nWouldn't it be far simpler to do this without forking diff-index?  I\nhaven't followed the codepath leading to this, but it should be very easy\nto find a commit object that corresponds to the current HEAD and peek the\ntree object in it to find out the current tree, and because the original\nfunction is going to run an as-is \"git commit\", the tree you are going to\ncommit should be available by calling cache_tree_update() like write-tree\ndoes.  If they match, you are trying to create an empty commit.  E.g. (error\nchecking elided):\n\n\tunsigned char head_sha1[20];\n\tstruct commit *head_commit;\n\n\tresolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL);\n        head_commit = lookup_commit(head_sha1);\n        parse_commit(head_commit);\n\n        if (!cache_tree_fully_valid(active_cache_tree))\n\t\tcache_tree_update(active_cache_tree, active_cache,\n\t\t\t\tactive_nr, 0);\n\treturn hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n\n> +static int is_original_commit_empty(struct commit *commit)\n> +{\n> +\tstruct argv_array argv_array;\n> +\tstruct child_process cp;\n> +\tchar ptree[40], pptree[40];\n> +\tint ret = 0;\n> +\n> +\targv_array_init(&argv_array);\n> +\tmemset(&cp, 0, sizeof(struct child_process));\n> +\n> +\targv_array_push(&argv_array, \"rev-parse\");\n> +\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n\nLikewise.  You have the commit object, so just make sure it was parsed,\nand peek its tree object.  Also do the same for its parent commit.  Now\nyou have two trees, so you can compare their object names.  E.g. (error\nchecking elided):\n\n\tconst unsigned char *ptree_sha1;\n\n\tparse_commit(commit);\n        if (commit->parents) {\n\t\tstruct commit *parent = commit->parents->item;\n                parse_commit(parent);\n                ptree_sha1 = parent->tree->object.sha1;\n\t} else {\n        \tptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */\n        }\n\treturn hashcmp(ptree_sha1, commit->tree->object.sha1);\n\nThe higher code structure of this patch looks good, but the lower level\nimplementation details are done way too inefficiently.\n"},{"id":"188894","messageId":"20120410181317.GA17776@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7v62d7qzu9.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T18:13:17Z","receivedAt":"2012-04-10T18:13:17Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > git cherry-pick fails when picking a non-ff commit that is empty.  The advice\n> > given with the failure is that a git-commit --allow-empty should be issued to\n> > explicitly add the empty commit during the cherry pick.  This option allows a\n> > user to specify before hand that they want to keep the empty commit.  This\n> > eliminates the need to issue both a cherry pick and a commit operation.\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > ---\n> >  Documentation/git-cherry-pick.txt |    9 +++++++++\n> >  builtin/commit.c                  |    6 +++---\n> >  builtin/revert.c                  |    2 ++\n> >  sequencer.c                       |    7 +++++--\n> >  sequencer.h                       |    1 +\n> >  5 files changed, 20 insertions(+), 5 deletions(-)\n> >\n> > diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\n> > index fed5097..730237a 100644\n> > --- a/Documentation/git-cherry-pick.txt\n> > +++ b/Documentation/git-cherry-pick.txt\n> > @@ -103,6 +103,15 @@ effect to your index in a row.\n> >  \tcherry-pick'ed commit, then a fast forward to this commit will\n> >  \tbe performed.\n> >  \n> > +--allow-empty::\n> > +\tBy default, cherry-picking an empty commit will fail,\n> > +\tindicating that an explicit invocation of `git commit\n> > +\t--allow-empty` is required. This option overrides that\n> > +\tbehavior, allowing empty commits to be preserved automatically\n> > +\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n> > +\tcommits that meet the \"fast-forward\" requirement will be kept\n> > +\teven without this option.\n> > +\n> >  --strategy=<strategy>::\n> >  \tUse the given merge strategy.  Should only be used once.\n> >  \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\n> > diff --git a/builtin/commit.c b/builtin/commit.c\n> > index 3714582..0cd10ab 100644\n> > --- a/builtin/commit.c\n> > +++ b/builtin/commit.c\n> > @@ -56,10 +56,10 @@ N_(\"You asked to amend the most recent commit, but doing so would make\\n\"\n> >  \"remove the commit entirely with \\\"git reset HEAD^\\\".\\n\");\n> >  \n> >  static const char empty_cherry_pick_advice[] =\n> > -N_(\"The previous cherry-pick is now empty, possibly due to conflict resolution.\\n\"\n> > -\"If you wish to commit it anyway, use:\\n\"\n> > +N_(\"The previous cherry-pick is empty.\\n\"\n> > +\"If the commit was created empty, please use:\\n\"\n> \n> After reading this three times, I have to say that the updated wording do\n> not look like an improvement for two reasons.\n> \n>  (1) After a failed cherry-pick, the index can match the current HEAD for\n>      two reasons.  Either the original cherry-pick was attempting to pick\n>      an empty commit (which is likely to be a mistake unless you are doing\n>      something unusual like creating an empty commit in the first place),\n>      or the change in the original commit was already found in the current\n>      version (may be result of a conflict resolution).  The message before\n>      your change used \"possibly\" to hint this, and if the reader gets it,\n>      it is understandable why the reader is seeing this advise.  Updated\n>      message loses this information by simply saying \"is empty\".\n> \nI can re-instate the possible language if you like, I don't have a problem with\nthat.\n\n>  (2) The message is given by the \"git commit\" command.  \"If the commit was\n>      created empty\" looks confusing.  Even though I can understand that\nIts coded within the git commit command code, but is only ever displayed if\nwhence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,\nthis will only be seen if they type git cherry-pick on the command line.\n\n>      \"the commit\" refers to the original commit the user tried to\n>      cherry-pick before running this command while reviewing this patch, I\n>      suspect that the reader who sees this message may not be able to tell\n>      if the \"git commit\" command created a possibly empty commit and then\n>      telling the user to do something further on _that_ commit, or if it\n>      is referring to the commit the user tried to pick with the previous\n>      \"git cherry-pick\" command.\n> \nGiven that this message is displayed because the index and HEAD have no changes\nleading to what would be an empty commit, which is by default no allowed unless\nexpressly enabled, I don't think its that confusing at all.  \"The commit\" can\nonly refer to the commit being cherry picked, since there is no other.\n\n> That is, unless you are making \"git cherry-pick --allow-empty\" not to stop\n> and leave it to \"git commit\" to clean it up.  If that were the case (which\n> is not, after applying this patch alone), then this message will be issued\n> only when a conflict resolution resulted in an empty commit, so \"If the\n> commit you were trying to cherry-pick was empty to begin with\" would not\n> apply, either.\n\nOk, I see what you're saying.  This advice makes sense if you issue git\ncherry-pick, but not if you issue git cherry-pick --allow-empty.  I think the\nadditional advice provided when you add in the keep-redundant-commits patch\nthough, assuming I re-add the possibly language above, yes?\nNeil\n\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> \n"},{"id":"188896","messageId":"20120410182523.GB17776@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vy5q3pl9i.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T18:25:24Z","receivedAt":"2012-04-10T18:25:24Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 10, 2012 at 10:04:32AM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > +\t/* keep_if_made_empty implies allow_empty */\n> > +\tif (opts->keep_if_made_empty)\n> > +\t\topts->allow_empty = 1;\n> > +\n>  \n> OK.\n> \n> > diff --git a/sequencer.c b/sequencer.c\n> > index 71929ba..5d033db 100644\n> > --- a/sequencer.c\n> > +++ b/sequencer.c\n> > @@ -13,6 +13,7 @@\n> >  #include \"rerere.h\"\n> >  #include \"merge-recursive.h\"\n> >  #include \"refs.h\"\n> > +#include \"argv-array.h\"\n> >  \n> >  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n> >  \n> > @@ -258,26 +259,102 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n> >   * If we are revert, or if our cherry-pick results in a hand merge,\n> >   * we had better say that the current user is responsible for that.\n> >   */\n> > -static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n> > +static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n> >  {\n> > -\t/* 7 is max possible length of our args array including NULL */\n> > -\tconst char *args[7];\n> > -\tint i = 0;\n> > +\tstruct argv_array array;\n> > +\tint rc;\n> > +\n> > +\tif (!empty && !opts->keep_if_made_empty) {\n> > +\t\tconst char *argv[] = { \"diff-index\", \"--quiet\", \"--exit-code\",\n> > +\t\t\t\t\t\"--cached\", \"HEAD\", NULL };\n> > +\n> > +\t\t/*\n> > + \t\t * If we run git diff-index with the above option and it returns\n> > + \t\t * zero, then there have been no changes made to the index by\n> > + \t\t * this patch, i.e. its empty.  Since our previous empty test\n> > + \t\t * indicated that this patch was not created empty, its been made\n> > + \t\t * redundant.  Since keep_if_made_empty is not set, we just skip\n> > + \t\t * it\n> > + \t\t */\n> > +\t\tif (run_command_v_opt(argv, RUN_GIT_CMD) == 0)\n> > +\t\t\treturn 0;\n> \n> Wouldn't it be far simpler to do this without forking diff-index?  I\n> haven't followed the codepath leading to this, but it should be very easy\n> to find a commit object that corresponds to the current HEAD and peek the\n> tree object in it to find out the current tree, and because the original\n> function is going to run an as-is \"git commit\", the tree you are going to\n> commit should be available by calling cache_tree_update() like write-tree\n> does.  If they match, you are trying to create an empty commit.  E.g. (error\n> checking elided):\n> \n> \tunsigned char head_sha1[20];\n> \tstruct commit *head_commit;\n> \n> \tresolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL);\n>         head_commit = lookup_commit(head_sha1);\n>         parse_commit(head_commit);\n> \n>         if (!cache_tree_fully_valid(active_cache_tree))\n> \t\tcache_tree_update(active_cache_tree, active_cache,\n> \t\t\t\tactive_nr, 0);\n> \treturn hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n> \n> > +static int is_original_commit_empty(struct commit *commit)\n> > +{\n> > +\tstruct argv_array argv_array;\n> > +\tstruct child_process cp;\n> > +\tchar ptree[40], pptree[40];\n> > +\tint ret = 0;\n> > +\n> > +\targv_array_init(&argv_array);\n> > +\tmemset(&cp, 0, sizeof(struct child_process));\n> > +\n> > +\targv_array_push(&argv_array, \"rev-parse\");\n> > +\targv_array_pushf(&argv_array, \"%s^{tree}\", sha1_to_hex(commit->object.sha1));\n> \n> Likewise.  You have the commit object, so just make sure it was parsed,\n> and peek its tree object.  Also do the same for its parent commit.  Now\n> you have two trees, so you can compare their object names.  E.g. (error\n> checking elided):\n> \nHonestly, I wasn't aware there was a faster way.  In my last version you\nsuggested using git diff-index and git rev-parse (allbeit the latter was for use\nin the git-rebase script, and I just reused it).  Regardless, I was going with\nyour previous suggestions.  I can re-do these to use these new suggestions.\n\nNeil\n"},{"id":"188903","messageId":"7vfwcbpem5.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120410181317.GA17776@hmsreliant.think-freely.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-10T19:32:18Z","receivedAt":"2012-04-10T19:32:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:\n> ...\n>>  (2) The message is given by the \"git commit\" command.  \"If the commit was\n>>      created empty\" looks confusing.  Even though I can understand that\n> Its coded within the git commit command code, but is only ever displayed if\n> whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,\n> this will only be seen if they type git cherry-pick on the command line.\n\nHere is what I tried, and I think you are wrong.\n\n\t$ git cherry-pick $some_commit\n        ... conflicts ...\n        $ edit so that the working tree matches HEAD\n        $ git commit -a\n        ... message from status ...\n        THE ADVICE IN QUEWSTION COMES HERE!!!\n"},{"id":"188904","messageId":"20120410200019.GC17776@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vfwcbpem5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T20:00:19Z","receivedAt":"2012-04-10T20:00:19Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:\n> > ...\n> >>  (2) The message is given by the \"git commit\" command.  \"If the commit was\n> >>      created empty\" looks confusing.  Even though I can understand that\n> > Its coded within the git commit command code, but is only ever displayed if\n> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,\n> > this will only be seen if they type git cherry-pick on the command line.\n> \n> Here is what I tried, and I think you are wrong.\n> \n> \t$ git cherry-pick $some_commit\n>         ... conflicts ...\n>         $ edit so that the working tree matches HEAD\n>         $ git commit -a\n>         ... message from status ...\n>         THE ADVICE IN QUEWSTION COMES HERE!!!\n> \n> \nOk, I admit I didn't really think of that case, but that seems to me to be the\ntrivial case, which is unlikely to be encountered.  If you do a git cherry-pick and\nhave conflicts, you by definition don't have a commit that is resolved to empty\n(at least not without manual intervention), nor do you have a commit which was\ninitially empty.  You really have to go out of your way to take a commit that\nconflicts, make it empty, and then commit it without realizing that its empty.\n\nI agree that seeing advice regarding git cherry-pick when you run git commit is\nawkward, but its no worse than seeing advice indicating you should run git\ncommit when you run git cherry-pick (i.e. the case in which you run git\ncherry-pick <C>, where <C> is empty an not fast-forward-able.\n\nPerhaps whats called for here is and advice differentiator?  I.e if git commit\nis run directly from the command line, issue advice relating to using git commit\n--allow-empty, otherwise issue advice relating to git cherry-pick.\n\nI think we could do that by looking at the parent process at run time, unless\ntheres a good way to differentiate by the sate information in .git\n\nThoughts?\nNeil\n \n"},{"id":"188906","messageId":"7v8vi3pbtf.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120410200019.GC17776@hmsreliant.think-freely.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-10T20:32:44Z","receivedAt":"2012-04-10T20:32:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:\n>> Neil Horman <nhorman@tuxdriver.com> writes:\n>> \n>> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:\n>> > ...\n>> >>  (2) The message is given by the \"git commit\" command.  \"If the commit was\n>> >>      created empty\" looks confusing.  Even though I can understand that\n>> > Its coded within the git commit command code, but is only ever displayed if\n>> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,\n>> > this will only be seen if they type git cherry-pick on the command line.\n>> \n>> Here is what I tried, and I think you are wrong.\n>> \n>> \t$ git cherry-pick $some_commit\n>>         ... conflicts ...\n>>         $ edit so that the working tree matches HEAD\n>>         $ git commit -a\n>>         ... message from status ...\n>>         THE ADVICE IN QUEWSTION COMES HERE!!!\n>> \n>> \n> Ok, I admit I didn't really think of that case, but that seems to me to be the\n> trivial case, which is unlikely to be encountered.  If you do a git cherry-pick and\n> have conflicts, you by definition don't have a commit that is resolved to empty...\n\nNot at all unlikely, especially in a distributed world.\n\nYou may have seen two patches but they make sense as one so that you apply\nto one branch as one change, while the branch you are cherry-picking from\nmay have these two changes as individual commits.  Neither of them will\napply cleanly to your tree, and your resolution will be \"keep mine---I\nalready have this\".\n"},{"id":"188907","messageId":"20120410203944.GA12139@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7v8vi3pbtf.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-10T20:39:44Z","receivedAt":"2012-04-10T20:39:44Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 10, 2012 at 01:32:44PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > On Tue, Apr 10, 2012 at 12:32:18PM -0700, Junio C Hamano wrote:\n> >> Neil Horman <nhorman@tuxdriver.com> writes:\n> >> \n> >> > On Tue, Apr 10, 2012 at 09:45:46AM -0700, Junio C Hamano wrote:\n> >> > ...\n> >> >>  (2) The message is given by the \"git commit\" command.  \"If the commit was\n> >> >>      created empty\" looks confusing.  Even though I can understand that\n> >> > Its coded within the git commit command code, but is only ever displayed if\n> >> > whence is GIT_CHERRY_PICK, so as far as I can see, from a users perspective,\n> >> > this will only be seen if they type git cherry-pick on the command line.\n> >> \n> >> Here is what I tried, and I think you are wrong.\n> >> \n> >> \t$ git cherry-pick $some_commit\n> >>         ... conflicts ...\n> >>         $ edit so that the working tree matches HEAD\n> >>         $ git commit -a\n> >>         ... message from status ...\n> >>         THE ADVICE IN QUEWSTION COMES HERE!!!\n> >> \n> >> \n> > Ok, I admit I didn't really think of that case, but that seems to me to be the\n> > trivial case, which is unlikely to be encountered.  If you do a git cherry-pick and\n> > have conflicts, you by definition don't have a commit that is resolved to empty...\n> \n> Not at all unlikely, especially in a distributed world.\n> \n> You may have seen two patches but they make sense as one so that you apply\n> to one branch as one change, while the branch you are cherry-picking from\n> may have these two changes as individual commits.  Neither of them will\n> apply cleanly to your tree, and your resolution will be \"keep mine---I\n> already have this\".\n> \n\nOk, fine.  What do you say to my proposal regarding the splitting of the device\ndependent on how we were executed?  It seems we can't use a single advice string\nin this case, as no matter which we choose there is a use case in which it fails\nto make sense.\nNeil\n"},{"id":"188908","messageId":"7v4nsrpa4i.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120410203944.GA12139@hmsreliant.think-freely.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-10T21:09:17Z","receivedAt":"2012-04-10T21:09:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> ...  What do you say to my proposal regarding the splitting of the device\n> dependent on how we were executed?  It seems we can't use a single advice string\n> in this case, as no matter which we choose there is a use case in which it fails\n> to make sense.\n\nWhen your cherry-pick got --allow-empty, it should pass --allow-empty to\nits inner invocation of commit if it is picking an originally empty\ncommit, and this advice will not trigger because commit will happily\ncommit the no-change change.\n\nWhen your cherry-pick got --allow-empty but not --keep-unnecessary-commit,\nits inner invocation of commit must not pass --allow-empty if it is _not_\npicking an originally empty commit.  Then the inner commit will fail if it\nauto resolves to no change, and the user sees the advice.  The current\nadvice text is appropriate for this case.\n\nWhen your cherry-pick did not get either of these flags, its inner\ninvocation of commit must not pass --allow-empty.  The user sees the\nadvice when the auto resolved result matches HEAD from the commit invoked\nby cherry-pick.  The current advice text is fine for this case, as we say\n\"possibly\", not \"we definitely know it was due to conflict resolution\".\n\nOr your cherry-pick may have failed due to a conflict, regardless of the\noptions like --allow-empty or --keep-unnecessary-commit given to it, and\nthe user may have run commit after resolving the conflict.  The current\nadvice text is fine for this case, too, as we say \"possibly\", and it\nindeed is what just happened.\n\nSo I do not think you need to change anything with respect to the advice\nmessage.\n\nAm I missing some other cases?\n"},{"id":"188919","messageId":"20120411004419.GA19616@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7v4nsrpa4i.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-11T00:44:20Z","receivedAt":"2012-04-11T00:44:20Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 10, 2012 at 02:09:17PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > ...  What do you say to my proposal regarding the splitting of the device\n> > dependent on how we were executed?  It seems we can't use a single advice string\n> > in this case, as no matter which we choose there is a use case in which it fails\n> > to make sense.\n> \n> When your cherry-pick got --allow-empty, it should pass --allow-empty to\n> its inner invocation of commit if it is picking an originally empty\n> commit, and this advice will not trigger because commit will happily\n> commit the no-change change.\n> \n> When your cherry-pick got --allow-empty but not --keep-unnecessary-commit,\n> its inner invocation of commit must not pass --allow-empty if it is _not_\n> picking an originally empty commit.  Then the inner commit will fail if it\n> auto resolves to no change, and the user sees the advice.  The current\n> advice text is appropriate for this case.\n> \n> When your cherry-pick did not get either of these flags, its inner\n> invocation of commit must not pass --allow-empty.  The user sees the\n> advice when the auto resolved result matches HEAD from the commit invoked\n> by cherry-pick.  The current advice text is fine for this case, as we say\n> \"possibly\", not \"we definitely know it was due to conflict resolution\".\n> \n> Or your cherry-pick may have failed due to a conflict, regardless of the\n> options like --allow-empty or --keep-unnecessary-commit given to it, and\n> the user may have run commit after resolving the conflict.  The current\n> advice text is fine for this case, too, as we say \"possibly\", and it\n> indeed is what just happened.\n> \n> So I do not think you need to change anything with respect to the advice\n> message.\n> \n> Am I missing some other cases?\n> \nNo, you covered all the cases, but I disagree with your assertion that the advice\nis correct (or at least optimal) in any of these cases. If a cherry-pick without\nany options is preformed and the commit is empty (regardless of the reason), the\nadvice given is that git commit --allow-empty should be used.  With the addition\nof these new options, thats not true any longer.  Instead of using git commit\n--allow-empty, you can use git cherry-pick --allow-empty.\n\nGiven your description above though, I'm ok rolling this back.  Regardless of my\ndisagreement, git commit --allow-empty still works just as well after the\naddition of these options, so while I still think its awkward to give git commit\nadvice on the result of a git cherry-pick operation,  its not any more\nproblematic than the issues you've pointed out with my change.  I'll roll this\nback in my next version and will look for a way to provide better advice in the\nfuture.\n\nRegards\nNeil\n\n> \n"},{"id":"188994","messageId":"7v62d6mcsa.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120411004419.GA19616@neilslaptop.think-freely.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-11T16:52:21Z","receivedAt":"2012-04-11T16:52:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> No, you covered all the cases, but I disagree with your assertion that the advice\n> is correct (or at least optimal) in any of these cases. If a cherry-pick without\n> any options is preformed and the commit is empty (regardless of the reason), the\n> advice given is that git commit --allow-empty should be used.  With the addition\n> of these new options, thats not true any longer.  Instead of using git commit\n> --allow-empty, you can use git cherry-pick --allow-empty.\n\nSorry, I am confused.  Do you mean that the sequence goes like this (with\nconcrete examples of command line args)?\n\n\t$ git cherry-pick nh/empty-rebase\n        ... stops because \"git show nh/empty-rebase\" is empty\n        $ git cherry-pick --allow-empty\n\nBut that cannot be correct, without --continue [*1*], i.e.\n\n\t$ git cherry-pick --allow-empty --continue\n\nno?  I didn't check, but if the command without --continue in the above\nsequence does not error out, I think it is a bug.\n\nI am actually OK with suggesting \"git cherry-pick --continue\", but then\n\"cherry-pick --allow-empty\" (or \"--keep-unnecessary-commits\") that punts\nand gives the control back to the user should leave enough clue for a\nlater invocation of itself so that it can realize that the original\ninvocation was made with \"--allow-empty\".  In other words, I am OK if the\ninteraction goes like this:\n\n\t$ git cherry-pick --keep-unnecessary-commits nh/empty-rebase\n        ... stops due to a conflict\n        $ edit builtin/revert.c\n        ... the result ends up being empty\n        $ git add -u ;# resolved\n        $ git cherry-pick --continue\n\n\n[Side note]\n\n*1* It was an original UI mistake to make the users conclude a \"git merge\"\nthat asked the user to help resolving the conflict with \"git commit\",\nwhich was inherited by \"git cherry-pick\" and \"git revert\", especially when\nthese three commands are merely a special \"possibly zero or one stoppage\"\ncase of more general sequencing commands like \"am\" and \"rebase\" that can\nstop zero or more times to ask the user for help and the way to resume\nthem is to re-run the same command with \"--continue\" option (and without\nany other arguments), e.g.\n\n\t$ git am -3 ./+nh.mbox\n        ... stops due to conflict and asks to resolve them\n        $ edit builtin/revert.c\n        $ git add builtin/revert.c\n        $ git am --continue\n\nand also discussed that in the longer-term it would be nice to teach the\noddball commands to honor \"--continue\".  \"am\" originally took \"--resolved\"\n(and it still does, and it will do so in the future) for the same purpose,\nand we taught it and \"cherry-pick\" and \"revert\" to honor \"--continue\".\nProbably we should start teaching \"merge\" to honor it as well to complete\nthe vision.\n"},{"id":"189011","messageId":"20120411182927.GA24833@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7v62d6mcsa.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-11T18:29:27Z","receivedAt":"2012-04-11T18:29:27Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Wed, Apr 11, 2012 at 09:52:21AM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > No, you covered all the cases, but I disagree with your assertion that the advice\n> > is correct (or at least optimal) in any of these cases. If a cherry-pick without\n> > any options is preformed and the commit is empty (regardless of the reason), the\n> > advice given is that git commit --allow-empty should be used.  With the addition\n> > of these new options, thats not true any longer.  Instead of using git commit\n> > --allow-empty, you can use git cherry-pick --allow-empty.\n> \n> Sorry, I am confused.  Do you mean that the sequence goes like this (with\n> concrete examples of command line args)?\n> \n> \t$ git cherry-pick nh/empty-rebase\n>         ... stops because \"git show nh/empty-rebase\" is empty\n>         $ git cherry-pick --allow-empty\n> \n\nNo, currently what happens is the following:\n$ git cherry-pick nh/empty-rebase\n       ... either gets accepted as empty if the cherry-pick qualifies for\nfast-forward, or stops if it doesn not, indicating the empty_cherry_pick advice\nthat git commit --allow-empty should be used.\n\nWhile that advice is accurate, in that a git commit --allow-empty will accept\nthe empty commit, it would seem (at least to me) preferable to offer guidance\nthat git cherry-pick should be used instead in this case, because that is the\ncommand the user was issuing.\n\n> But that cannot be correct, without --continue [*1*], i.e.\n> \n> \t$ git cherry-pick --allow-empty --continue\n> \n> no?  I didn't check, but if the command without --continue in the above\n> sequence does not error out, I think it is a bug.\n> \nNo, it errors out.  I'm sorry to have confused you.  The only point that I was\ntrying to make here is that, when running git cherry-pick, its seems awkward to\na user to get advice indicating that git commit --allow-empty should be run.  My\nchange was intended to resolve that so that advice no how to use cherry-pick\noptions to avoid the error was  issued instead.  Thats all.  I hadn't considered\nthe fact that manual resolution of a cherry-pick (where getting advice about git\ncommit makes more sense) was also a factor here\n\n> I am actually OK with suggesting \"git cherry-pick --continue\", but then\n> \"cherry-pick --allow-empty\" (or \"--keep-unnecessary-commits\") that punts\n> and gives the control back to the user should leave enough clue for a\n> later invocation of itself so that it can realize that the original\n> invocation was made with \"--allow-empty\".  In other words, I am OK if the\n> interaction goes like this:\n> \n> \t$ git cherry-pick --keep-unnecessary-commits nh/empty-rebase\n>         ... stops due to a conflict\n>         $ edit builtin/revert.c\n>         ... the result ends up being empty\n>         $ git add -u ;# resolved\n>         $ git cherry-pick --continue\n> \nNo, Id rather not do that thanks.  The intent of these options we really to\nautomate the rebase process, so rebasing doesn't stop on empty commits.  Using\nthe model above seems to disagree with that.\n\n> \n> [Side note]\n> \n> *1* It was an original UI mistake to make the users conclude a \"git merge\"\n> that asked the user to help resolving the conflict with \"git commit\",\n> which was inherited by \"git cherry-pick\" and \"git revert\", especially when\n> these three commands are merely a special \"possibly zero or one stoppage\"\n> case of more general sequencing commands like \"am\" and \"rebase\" that can\n> stop zero or more times to ask the user for help and the way to resume\n> them is to re-run the same command with \"--continue\" option (and without\n> any other arguments), e.g.\n> \n> \t$ git am -3 ./+nh.mbox\n>         ... stops due to conflict and asks to resolve them\n>         $ edit builtin/revert.c\n>         $ git add builtin/revert.c\n>         $ git am --continue\n> \n> and also discussed that in the longer-term it would be nice to teach the\n> oddball commands to honor \"--continue\".  \"am\" originally took \"--resolved\"\n> (and it still does, and it will do so in the future) for the same purpose,\n> and we taught it and \"cherry-pick\" and \"revert\" to honor \"--continue\".\n> Probably we should start teaching \"merge\" to honor it as well to complete\n> the vision.\n> \nI won't pretend to fully understand the implications of what you said on your\nside note here, but yes, from the ways I've used merge in the past, allowing it\nto continue would be very nice I think.\nNeil\n"},{"id":"189014","messageId":"7vy5q2je6i.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120411182927.GA24833@hmsreliant.think-freely.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-11T18:50:29Z","receivedAt":"2012-04-11T18:50:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n>> But that cannot be correct, without --continue [*1*], i.e.\n>> \n>> \t$ git cherry-pick --allow-empty --continue\n>> \n>> no?  I didn't check, but if the command without --continue in the above\n>> sequence does not error out, I think it is a bug.\n>> \n> No, it errors out.  I'm sorry to have confused you.  The only point that I was\n> trying to make here is that, when running git cherry-pick, its seems awkward to\n> a user to get advice indicating that git commit --allow-empty should be run.\n\nI was only saying that \"git cherry-pick --allow-empty\" is a *bad*\nsuggestion because it does *not* work and errors out, and you seem to\nagree with me on that point.  I also said I am OK if the suggestion for\nthis case were to run \"git cherry-pick --continue\".\n\nBut you sound like you are disagreeing with me; I am not sure where you\nfound what I said not agreeable.  So I am not sure what to say at this\npoint.\n"},{"id":"189017","messageId":"20120411185618.GC24833@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vy5q2je6i.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v3 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-11T18:56:19Z","receivedAt":"2012-04-11T18:56:19Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Wed, Apr 11, 2012 at 11:50:29AM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> >> But that cannot be correct, without --continue [*1*], i.e.\n> >> \n> >> \t$ git cherry-pick --allow-empty --continue\n> >> \n> >> no?  I didn't check, but if the command without --continue in the above\n> >> sequence does not error out, I think it is a bug.\n> >> \n> > No, it errors out.  I'm sorry to have confused you.  The only point that I was\n> > trying to make here is that, when running git cherry-pick, its seems awkward to\n> > a user to get advice indicating that git commit --allow-empty should be run.\n> \n> I was only saying that \"git cherry-pick --allow-empty\" is a *bad*\n> suggestion because it does *not* work and errors out, and you seem to\n> agree with me on that point.  I also said I am OK if the suggestion for\n> this case were to run \"git cherry-pick --continue\".\n> \n> But you sound like you are disagreeing with me; I am not sure where you\n> found what I said not agreeable.  So I am not sure what to say at this\n> point.\n> \nI'm sorry, I think I see where our mutual confusion is.  git cherry-pick\n--allow-empty _does_ error out on its own.  The advice that I rewrote was meant\nto imply that the cherry-pick command should have been rerun with the\n--allow-empty option, i.e.:\ngit cherry-pick --allow-empty <commit>\n\nI can see however, looking at from what I think was your point of view, how the\nadvice would have been bad, because taken strictly as given, it would fail.\n\nIts all moot however, I've reverted the advice in my tree here.  As soon as I\ncomplete testing of the optimization/rewites to git_run_commit and\nis_original_commit_empty, I'll have another set for review.\n\nRegards\nNeil\n"},{"id":"189203","messageId":"1334342707-3326-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v5 0/4]Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-13T18:45:03Z","receivedAt":"2012-04-13T18:45:03Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --keep-redundant-commits, which allows the user to also keep\ncommits that were made empty via conflict resolution.  It also enhances\ngit-rebase to add a --keep-empty option which enables rebases to preserve empty\ncommits. \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\nV3)\n\t* reversed the --ignore-if-empty-logic to by default only keep initially\n\tempty commits\n\n\t* replaced --ignore-if-empty with --keep-redundant-commits, to allow\n\tempty commits that are made empty via conflict resolution, in addition\n\tto commits that were created as empty\n\n\t* reworked is_original_commit_empty to be more efficient and portable\n\n\t* Misc sylistic and spelling cleanups\n\nV4)\n\t* Reverted the cherry-pick advice changes in V3 based on in-thread\n\tdiscussion\n\n\t* Rewrote my changes to is_original_commit_empty and run_git_commit to\n\tnot have to fork, making them more efficient.\n\nv5)\n\t* Additional help text clean up\n\t* Additional error checking added to run_git_commit code\n\t* Whitespace cleanup\n\t* Removed needed cache_tree freeing\n\t* Test case cleanup\n\t* Fixed regression in t3404 and t3416 - this turned out to be \n        a problem with the note that git rebase -i adds at the bottom\n\tof the rebase text.  It was inadvertently indented and caused the\n\ttest fake editor to misread the commit template.  The indentation \n\thas been corrected, and these two tests, as well as all the other\n\texpected tests pass now\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n"},{"id":"189204","messageId":"1334342707-3326-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334342707-3326-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v5 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-13T18:45:04Z","receivedAt":"2012-04-13T18:45:04Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operation.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..730237a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty::\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189205","messageId":"1334342707-3326-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334342707-3326-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-13T18:45:05Z","receivedAt":"2012-04-13T18:45:05Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"The git-cherry-pick --allow-empty command by default only preserves empty\ncommits that were originally empty, i.e only those commits for which\n<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are\nnon-empty, but were made empty by the inclusion of a prior commit on the current\nhistory are filtered out.  This option allows us to override that behavior and\ninclude redundant commits as empty commits in the change history.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |   12 +++++-\n builtin/revert.c                  |    8 +++-\n sequencer.c                       |   90 +++++++++++++++++++++++++++++++------\n sequencer.h                       |    1 +\n 4 files changed, 95 insertions(+), 16 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 730237a..0c004e9 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -110,7 +110,17 @@ effect to your index in a row.\n \tbehavior, allowing empty commits to be preserved automatically\n \tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n \tcommits that meet the \"fast-forward\" requirement will be kept\n-\teven without this option.\n+\teven without this option.  Note also, that use of this option only\n+\tkeeps commits that were initially empty (i.e. the commit recorded the\n+\tsame tree as its parent).  Commits which are made empty due to a\n+\tprevious commit are ignored.  To force the inclusion of those commits\n+\tuse `--keep-redundant-commits`.\n+\n+--keep-redundant-commits::\n+\tIf a commit being cherry picked duplicates a commit already in the\n+\tcurrent history, it will result in an empty changeset.  By default these\n+\tredundant commits are ignored.  This option overrides that behavior and\n+\tcreates an empty commit object.  Implies `--allow-empty`.\n \n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..4f0d979 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n-\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve initially empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_if_made_empty, \"keep redundant, empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n+\t/* keep_if_made_empty implies allow_empty */\n+\tif (opts->keep_if_made_empty)\n+\t\topts->allow_empty = 1;\n+\n \t/* Set the subcommand */\n \tif (remove_state)\n \t\topts->subcommand = REPLAY_REMOVE_STATE;\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..aefea66 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -258,26 +259,82 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n-{\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n+{\n+\tstruct argv_array array;\n+\tint rc;\n+\n+\tif (!empty && !opts->keep_if_made_empty) {\n+\t\tunsigned char head_sha1[20];\n+\t\tstruct commit *head_commit;\n+\n+\t\tif (!resolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL))\n+\t\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\n+\t\thead_commit = lookup_commit(head_sha1);\n+\t\tif (!head_commit || parse_commit(head_commit))\n+\t\t\treturn error(_(\"could not parse commit %s\\n\"),\n+\t\t\t\t     sha1_to_hex(head_commit->object.sha1));\n+\n+\t\tif (!active_cache_tree)\n+\t\t\tactive_cache_tree = cache_tree();\n+\n+\t\tif (!cache_tree_fully_valid(active_cache_tree))\n+\t\t\tif (cache_tree_update(active_cache_tree, active_cache,\n+\t\t\t\t\t  active_nr, 0))\n+\t\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\n+\t\trc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n+\n+\t\tif (rc)\n+\t\t\t/*\n+\t\t\t * The head tree and the parent tree match\n+\t\t\t * meaning the commit is empty.  Since it wasn't created\n+\t\t\t * empty (based on the previous test), we can conclude\n+\t\t\t * the commit has been made redundant.  Since we don't\n+\t\t\t * want to keep redundant commits, just skip this one\n+\t\t\t */\n+\t\t\treturn 0;\n+\t}\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n+\n+\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n+\n+static int is_original_commit_empty(struct commit *commit)\n+{\n+\tconst unsigned char *ptree_sha1;\n \n-\targs[i] = NULL;\n+\tif (parse_commit(commit))\n+\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\tif (commit->parents) {\n+\t\tstruct commit *parent = commit->parents->item;\n+\t\tif (parse_commit(parent))\n+\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\t\tsha1_to_hex(parent->object.sha1));\n+\t\tptree_sha1 = parent->tree->object.sha1;\n+\t} else {\n+\t\tptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */\n+\t}\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\treturn !hashcmp(ptree_sha1, commit->tree->object.sha1);\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +346,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +472,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_original_commit_empty(commit);\n+\tif (empty_commit < 0)\n+\t\treturn empty_commit;\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -435,7 +497,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n \t\tif (!opts->no_commit)\n-\t\t\tres = run_git_commit(defmsg, opts);\n+\t\t\tres = run_git_commit(defmsg, opts, empty_commit);\n \t}\n \n \tfree_message(&msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..862a79a 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint keep_if_made_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189206","messageId":"1334342707-3326-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334342707-3326-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-13T18:45:06Z","receivedAt":"2012-04-13T18:45:06Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --keep-redundant-commits\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n t/t3505-cherry-pick-empty.sh |   28 +++++++++++++++++++++++++++-\n 1 files changed, 27 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..5e3ad65 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,25 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fourth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" && {\n+\t\ttest_must_fail git cherry-pick empty-branch2\n+\t}\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --allow-empty empty-branch2\n+\t}\n+'\n+\n+test_expect_success 'cherry pick with --keep-redundant-commits' '\n+\tgit checkout master && {\n+\t\tgit cherry-pick --keep-redundant-commits HEAD^\n+\t}\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"189207","messageId":"1334342707-3326-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334342707-3326-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v5 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-13T18:45:07Z","receivedAt":"2012-04-13T18:45:07Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   32 +++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 52 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..04d8941 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if test -n \"$keep_empty\"\n+then\n+\t# we have to do this the hard way.  git format-patch completely squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..e3940be 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,12 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\tptree=$(git rev-parse \"$1\"^{tree})\n+\tpptree=$(git rev-parse \"$1\"^^{tree})\n+\treturn $(test \"$ptree\" = \"$pptree\")\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +197,18 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n+\tif is_empty_commit $@\n+\tthen\n+\t\tempty_args=\"--allow-empty\"\n+\tfi\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n+\tthen\n+\t\tcomment_out=\"# pick\"\n+\telse\n+\t\tcomment_out=\"pick\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +821,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +871,12 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\techo \"# Note that empty commits are commented out\" >> \"$todo\"\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"189321","messageId":"20120415093302.GA6263@ecki","threadId":"30112","inReplyTo":"1334342707-3326-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v5 4/4] git-rebase: add keep_empty flag","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-15T09:33:03Z","receivedAt":"2012-04-15T09:33:03Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Fri, Apr 13, 2012 at 02:45:07PM -0400, Neil Horman wrote:\n>\n> Add a command line switch to git-rebase to allow a user the ability to specify\n> that they want to keep any commits in a series that are empty.\n\nThanks. That should be useful.\n\n> +is_empty_commit() {\n> +     ptree=$(git rev-parse \"$1\"^{tree})\n> +     pptree=$(git rev-parse \"$1\"^^{tree})\n> +     return $(test \"$ptree\" = \"$pptree\")\n> +}\n> +\n\nWhat's the extra leading 'p' for? Any reason not to use 'tree' and\n'ptree'?\n\n>  pick_one () {\n>  \tff=--ff\n> +\n> +\tif is_empty_commit $@\n> +\tthen\n> +\t\tempty_args=\"--allow-empty\"\n> +\tfi\n> +\n>  \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n\nYou do not handle the case where pick_one is called with -n. I think you\nneed to move the case statement in front and then call is_empty_commit\n$sha1.\n\nNot that it matters after this change, but in general using $@ without\nquotes looks wrong to my eyes.\n\n> @@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n>  \tsed -n \"s/^>//p\" |\n>  while read -r shortsha1 rest\n>  do\n> +\n> +\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n> +\tthen\n> +\t\tcomment_out=\"# pick\"\n> +\telse\n> +\t\tcomment_out=\"pick\"\n> +\tfi\n> +\n>  \tif test t != \"$preserve_merges\"\n>  \tthen\n> -\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n> +\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n\nHow about setting comment_out=\"# \" or comment_out=\"\" instead and then\n\n printf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n\nThat would read more natural to me.\n"},{"id":"189322","messageId":"20120415093933.GB6263@ecki","threadId":"30112","inReplyTo":"1334342707-3326-4-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-15T09:39:35Z","receivedAt":"2012-04-15T09:39:35Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:\n>  \n> +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n> +\tgit checkout master &&\n> +\techo fourth >> file2 &&\n> +\tgit add file2 &&\n> +\tgit commit -m \"fourth\" && {\n> +\t\ttest_must_fail git cherry-pick empty-branch2\n> +\t}\n> +'\n\nYou don't need the braces. The same below.\n\n> +\n> +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> +\tgit checkout master && {\n> +\t\tgit cherry-pick --allow-empty empty-branch2\n> +\t}\n> +'\n> +\n> +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> +\tgit checkout master && {\n> +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> +\t}\n> +'\n\nAnd the expected result is that the HEAD commit is not removed, right?\nYou should check for that as well.\n\nAlso, please checkout empty-branch2^0 first, in order to make the test\nindependent of its predecessor.\n"},{"id":"189326","messageId":"20120415104212.GC6263@ecki","threadId":"30112","inReplyTo":"1334342707-3326-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-15T10:42:12Z","receivedAt":"2012-04-15T10:42:12Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Fri, Apr 13, 2012 at 02:45:05PM -0400, Neil Horman wrote:\n>\n> +                     OPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_if_made_empty, \"keep redundant, empty commits\"),\n\nFor consistency, I'd prefer if the variable name were the same as the\noption. Then I wouldn't have to keep the option<->variable translation\nin mind.\n\n>\n> +     if (!empty && !opts->keep_if_made_empty) {\n[...]\n> +                     return 0;\n[...]\n>       if (opts->allow_empty)\n> +             argv_array_push(&array, \"--allow-empty\");\n> +\n> +     rc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n\nI find it a bit strange, that if we cherry-pick a commit that was\nalready empty, we _do_ call git commit (and error out), but if we find a\ncommit that is made empty, we do _not_ call git commit and quietly\nsucceed (in not doing anything). But I suppose that is the legacy\nbehavior?\n\n> +\n> +\t\trc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n> +\n> +\t\tif (rc)\n\nrc is short for run_command, for which it stores the return value, no?\nLet's not abuse the variable like this and instead use the result\ndirectly:\n\n if (!hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1))\n\nIf you make the entire paragraph leading up to this a separate function,\nsay index_is_empty(), then the above would read more naturally like\nthis:\n\n if (!opts->keep_if_made_empty && !empty && index_is_empty())\n\n> +\t\t\t/*\n> +\t\t\t * The head tree and the parent tree match\n> +\t\t\t * meaning the commit is empty.  Since it wasn't created\n\nDon't you mean the head tree and the index?\n\n> +\t\t\t * empty (based on the previous test), we can conclude\n> +\t\t\t * the commit has been made redundant.  Since we don't\n> +\t\t\t * want to keep redundant commits, just skip this one\n> +\t\t\t */\n> +\t\t\treturn 0;\n> +\t}\n> +\n> +\targv_array_init(&array);\n> +\targv_array_push(&array, \"commit\");\n> +\targv_array_push(&array, \"-n\");\n>  \n> -\targs[i++] = \"commit\";\n> -\targs[i++] = \"-n\";\n>  \tif (opts->signoff)\n> -\t\targs[i++] = \"-s\";\n> +\t\targv_array_push(&array, \"-s\");\n>  \tif (!opts->edit) {\n> -\t\targs[i++] = \"-F\";\n> -\t\targs[i++] = defmsg;\n> +\t\targv_array_push(&array, \"-F\");\n> +\t\targv_array_push(&array, defmsg);\n>  \t}\n> +\n>  \tif (opts->allow_empty)\n> -\t\targs[i++] = \"--allow-empty\";\n> +\t\targv_array_push(&array, \"--allow-empty\");\n> +\n> +\n\nWhy two newlines?\n\n> +\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n> +\targv_array_clear(&array);\n> +\treturn rc;\n> +}\n\nLooks good to me otherwise.\n"},{"id":"189390","messageId":"20120416110402.GB13366@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120415093933.GB6263@ecki","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-16T11:04:02Z","receivedAt":"2012-04-16T11:04:02Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:\n> >  \n> > +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n> > +\tgit checkout master &&\n> > +\techo fourth >> file2 &&\n> > +\tgit add file2 &&\n> > +\tgit commit -m \"fourth\" && {\n> > +\t\ttest_must_fail git cherry-pick empty-branch2\n> > +\t}\n> > +'\n> \n> You don't need the braces. The same below.\n> \n> > +\n> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> > +\tgit checkout master && {\n> > +\t\tgit cherry-pick --allow-empty empty-branch2\n> > +\t}\n> > +'\n> > +\n> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> > +\tgit checkout master && {\n> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> > +\t}\n> > +'\n> \n> And the expected result is that the HEAD commit is not removed, right?\n> You should check for that as well.\n> \n> Also, please checkout empty-branch2^0 first, in order to make the test\n> independent of its predecessor.\n> \n\nACK, I'll fix these up, thanks\nNeil\n"},{"id":"189416","messageId":"20120416153827.GC13366@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120415104212.GC6263@ecki","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-16T15:38:27Z","receivedAt":"2012-04-16T15:38:27Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Sun, Apr 15, 2012 at 12:42:12PM +0200, Clemens Buchacher wrote:\n> On Fri, Apr 13, 2012 at 02:45:05PM -0400, Neil Horman wrote:\n> >\n> > +                     OPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_if_made_empty, \"keep redundant, empty commits\"),\n> \n> For consistency, I'd prefer if the variable name were the same as the\n> option. Then I wouldn't have to keep the option<->variable translation\n> in mind.\n> \nOk\n\n> >\n> > +     if (!empty && !opts->keep_if_made_empty) {\n> [...]\n> > +                     return 0;\n> [...]\n> >       if (opts->allow_empty)\n> > +             argv_array_push(&array, \"--allow-empty\");\n> > +\n> > +     rc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n> \n> I find it a bit strange, that if we cherry-pick a commit that was\n> already empty, we _do_ call git commit (and error out), but if we find a\n> commit that is made empty, we do _not_ call git commit and quietly\n> succeed (in not doing anything). But I suppose that is the legacy\n> behavior?\n> \nCorrect, more or less.  The legacy behavior is to call git commit unilaterally.\nWith this change, we still do that, but we pass --allow-empty to the commit\ncommand, allowing it to preserve the empty commit.  If we specify\nkeep-redundant-commits, we skip the check to see if the new commit is empty and\ncreate the new (now empty) commit.  The only change is that if we do not specify\nkeep-redundant-commits, we check to see if the commit is made empty in\ngit-cherry-pick and skip it if it is.  We could, instead of returning prior to\ncalling git-commit, use that test to override the keep_empty option below, so\nthat we don't pass --allow-empty to git-commit instead.  That would preserve the\nprior code path, but for no real advatage, as the outcome is the same, and this\nway saves us having to fork the git-commit command, which I think is\nadventageous.\n\n> > +\n> > +\t\trc = !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n> > +\n> > +\t\tif (rc)\n> \n> rc is short for run_command, for which it stores the return value, no?\n> Let's not abuse the variable like this and instead use the result\n> directly:\n> \nNo.  rc is short for return code, generically used to represent the value\nto be returned from a function. Its used in this fashion in any number of\nplaces, both in git and any other project. \n\n>  if (!hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1))\n> \n> If you make the entire paragraph leading up to this a separate function,\n> say index_is_empty(), then the above would read more naturally like\n> this:\n> \n>  if (!opts->keep_if_made_empty && !empty && index_is_empty())\n> \n> > +\t\t\t/*\n> > +\t\t\t * The head tree and the parent tree match\n> > +\t\t\t * meaning the commit is empty.  Since it wasn't created\n> \n> Don't you mean the head tree and the index?\n> \nyeah.\n\n> > +\t\t\t * empty (based on the previous test), we can conclude\n> > +\t\t\t * the commit has been made redundant.  Since we don't\n> > +\t\t\t * want to keep redundant commits, just skip this one\n> > +\t\t\t */\n> > +\t\t\treturn 0;\n> > +\t}\n> > +\n> > +\targv_array_init(&array);\n> > +\targv_array_push(&array, \"commit\");\n> > +\targv_array_push(&array, \"-n\");\n> >  \n> > -\targs[i++] = \"commit\";\n> > -\targs[i++] = \"-n\";\n> >  \tif (opts->signoff)\n> > -\t\targs[i++] = \"-s\";\n> > +\t\targv_array_push(&array, \"-s\");\n> >  \tif (!opts->edit) {\n> > -\t\targs[i++] = \"-F\";\n> > -\t\targs[i++] = defmsg;\n> > +\t\targv_array_push(&array, \"-F\");\n> > +\t\targv_array_push(&array, defmsg);\n> >  \t}\n> > +\n> >  \tif (opts->allow_empty)\n> > -\t\targs[i++] = \"--allow-empty\";\n> > +\t\targv_array_push(&array, \"--allow-empty\");\n> > +\n> > +\n> \n> Why two newlines?\n> \n> > +\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n> > +\targv_array_clear(&array);\n> > +\treturn rc;\n> > +}\n> \n> Looks good to me otherwise.\n> \n"},{"id":"189429","messageId":"20120416161431.GD13366@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120415093933.GB6263@ecki","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-16T16:14:31Z","receivedAt":"2012-04-16T16:14:31Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> On Fri, Apr 13, 2012 at 02:45:06PM -0400, Neil Horman wrote:\n> >  \n> > +test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n> > +\tgit checkout master &&\n> > +\techo fourth >> file2 &&\n> > +\tgit add file2 &&\n> > +\tgit commit -m \"fourth\" && {\n> > +\t\ttest_must_fail git cherry-pick empty-branch2\n> > +\t}\n> > +'\n> \n> You don't need the braces. The same below.\n> \nAck\n\n> > +\n> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> > +\tgit checkout master && {\n> > +\t\tgit cherry-pick --allow-empty empty-branch2\n> > +\t}\n> > +'\n> > +\n> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> > +\tgit checkout master && {\n> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> > +\t}\n> > +'\n> \n> And the expected result is that the HEAD commit is not removed, right?\n> You should check for that as well.\n> \n> Also, please checkout empty-branch2^0 first, in order to make the test\n> independent of its predecessor.\n> \n\nNot sure I follow what your saying here.  The expected result with both of these\ntests is that a new commit is created, referencing the current HEAD as the new\nHEAD's parent.  We could check that the current HEAD is note removed (ostensibly\nby recoding the value of the current head and comparing it to HEAD^ after the\ncherry pick, but that seems like expected behavior for any command that creates\na new commit, yet we don't check that anywhere else.  Why is here different?  Or\ndo you mean something else?\n\nAs for the checkout of empty-branch2^0, whats the purpose?  I'm just going to\ncheckout master right after that, making it moot.  The purpose of the test is to\napply a commit that is already in the working tree's history, ensuring that it\nresolves to an empty commit.  Theres nothing really dependent on the prior test\nthere.  If we edit the tests significantly, the contents of what that commit is\nmay change, but thats not overly relevant, as the result will still be the same\n(an empty commit).\n\nNeil\n \n"},{"id":"189431","messageId":"7vvckzws73.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120416161431.GD13366@hmsreliant.think-freely.org","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-16T16:35:12Z","receivedAt":"2012-04-16T16:35:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> ...\n>> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n>> > +\tgit checkout master && {\n>> > +\t\tgit cherry-pick --allow-empty empty-branch2\n>> > +\t}\n>> > +'\n>> > +\n>> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n>> > +\tgit checkout master && {\n>> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n>> > +\t}\n>> > +'\n>> \n>> And the expected result is that the HEAD commit is not removed, right?\n>> You should check for that as well.\n>> \n>> Also, please checkout empty-branch2^0 first, in order to make the test\n>> independent of its predecessor.\n>\n> Not sure I follow what your saying here.  The expected result with both of these\n> tests is that a new commit is created, referencing the current HEAD as the new\n> HEAD's parent.\n\nIf the request were \"checkout master^0 first\" I would understand.  The\nprecondition for the second test will be different depending on the first\none succeeds or not.  Perhaps that is what Clemens meant?\n"},{"id":"189432","messageId":"20120416164654.GE13366@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120415093302.GA6263@ecki","subject":"Re: [PATCH v5 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-16T16:46:54Z","receivedAt":"2012-04-16T16:46:54Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Sun, Apr 15, 2012 at 11:33:03AM +0200, Clemens Buchacher wrote:\n> On Fri, Apr 13, 2012 at 02:45:07PM -0400, Neil Horman wrote:\n> >\n> > Add a command line switch to git-rebase to allow a user the ability to specify\n> > that they want to keep any commits in a series that are empty.\n> \n> Thanks. That should be useful.\n> \n> > +is_empty_commit() {\n> > +     ptree=$(git rev-parse \"$1\"^{tree})\n> > +     pptree=$(git rev-parse \"$1\"^^{tree})\n> > +     return $(test \"$ptree\" = \"$pptree\")\n> > +}\n> > +\n> \n> What's the extra leading 'p' for? Any reason not to use 'tree' and\n> 'ptree'?\n> \nHold-over from when I did this in C (pointer to tree vs. pointer to parent\ntree).  I can remove the p though, as you right, it makes less sense in a shell\n\n> >  pick_one () {\n> >  \tff=--ff\n> > +\n> > +\tif is_empty_commit $@\n> > +\tthen\n> > +\t\tempty_args=\"--allow-empty\"\n> > +\tfi\n> > +\n> >  \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n> \n> You do not handle the case where pick_one is called with -n. I think you\n> need to move the case statement in front and then call is_empty_commit\n> $sha1.\n> \n> Not that it matters after this change, but in general using $@ without\n> quotes looks wrong to my eyes.\n> \nAck, to both points.\n\n> > @@ -780,9 +792,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n> >  \tsed -n \"s/^>//p\" |\n> >  while read -r shortsha1 rest\n> >  do\n> > +\n> > +\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n> > +\tthen\n> > +\t\tcomment_out=\"# pick\"\n> > +\telse\n> > +\t\tcomment_out=\"pick\"\n> > +\tfi\n> > +\n> >  \tif test t != \"$preserve_merges\"\n> >  \tthen\n> > -\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n> > +\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n> \n> How about setting comment_out=\"# \" or comment_out=\"\" instead and then\n> \n>  printf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n> \n> That would read more natural to me.\nYeah, I can do that\n> \n"},{"id":"189433","messageId":"20120416165024.GF13366@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"7vvckzws73.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-16T16:50:24Z","receivedAt":"2012-04-16T16:50:24Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> > ...\n> >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> >> > +\tgit checkout master && {\n> >> > +\t\tgit cherry-pick --allow-empty empty-branch2\n> >> > +\t}\n> >> > +'\n> >> > +\n> >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> >> > +\tgit checkout master && {\n> >> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> >> > +\t}\n> >> > +'\n> >> \n> >> And the expected result is that the HEAD commit is not removed, right?\n> >> You should check for that as well.\n> >> \n> >> Also, please checkout empty-branch2^0 first, in order to make the test\n> >> independent of its predecessor.\n> >\n> > Not sure I follow what your saying here.  The expected result with both of these\n> > tests is that a new commit is created, referencing the current HEAD as the new\n> > HEAD's parent.\n> \n> If the request were \"checkout master^0 first\" I would understand.  The\n> precondition for the second test will be different depending on the first\n> one succeeds or not.  Perhaps that is what Clemens meant?\n> \nPerhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects\nthese tests at all, nor do I grok the relevance to ensuring that the HEAD commit\nwasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you\nclarify your thoughts here please?\nNeil\n"},{"id":"189471","messageId":"20120416214247.GA5606@ecki","threadId":"30112","inReplyTo":"20120416165024.GF13366@hmsreliant.think-freely.org","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-16T21:42:49Z","receivedAt":"2012-04-16T21:42:49Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Mon, Apr 16, 2012 at 12:50:24PM -0400, Neil Horman wrote:\n> On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:\n> > Neil Horman <nhorman@tuxdriver.com> writes:\n> > \n> > > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> > > ...\n> > >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> > >> > +\tgit checkout master && {\n> > >> > +\t\tgit cherry-pick --allow-empty empty-branch2\n> > >> > +\t}\n> > >> > +'\n> > >> > +\n> > >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> > >> > +\tgit checkout master && {\n> > >> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> > >> > +\t}\n> > >> > +'\n> > >> \n> > >> And the expected result is that the HEAD commit is not removed, right?\n> > >> You should check for that as well.\n> > >> \n> > >> Also, please checkout empty-branch2^0 first, in order to make the test\n> > >> independent of its predecessor.\n> > >\n> > > Not sure I follow what your saying here.  The expected result with both of these\n> > > tests is that a new commit is created, referencing the current HEAD as the new\n> > > HEAD's parent.\n> > \n> > If the request were \"checkout master^0 first\" I would understand.  The\n> > precondition for the second test will be different depending on the first\n> > one succeeds or not.  Perhaps that is what Clemens meant?\n> > \n> Perhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects\n> these tests at all, nor do I grok the relevance to ensuring that the HEAD commit\n> wasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you\n> clarify your thoughts here please?\n\nIt seems that I was implying a lot more than I realized. What I meant\nwas that master and empty-branch2 are equivalent for the purposes of\nthat test (empty-branch2^ also is a non-empty commit [*1*]), but while\nmaster is a moving target, empty-branch2 is untouched. \n\nHowever, I just notice that empty-branch2 is also the root commit, so\nmaybe this will not work after all. But that should be easy to fix.\n\nAnd now I am also wondering why we have two tests for cherry picking an\nempty commit without --allow-empty (the one that you added and the one\nthat was there before). Is the non-ff part significant and if so, how?\nAnd why don't we need to test fast-forward cherry-pick with\n--allow-empty?\n"},{"id":"189483","messageId":"20120416221018.GB5606@ecki","threadId":"30112","inReplyTo":"20120416153827.GC13366@hmsreliant.think-freely.org","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-16T22:10:18Z","receivedAt":"2012-04-16T22:10:18Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:\n> > \n> > I find it a bit strange, that if we cherry-pick a commit that was\n> > already empty, we _do_ call git commit (and error out), but if we find a\n> > commit that is made empty, we do _not_ call git commit and quietly\n> > succeed (in not doing anything). But I suppose that is the legacy\n> > behavior?\n>\n> Correct, more or less.  The legacy behavior is to call git commit unilaterally.\n> [...] The only change is that if we do not specify\n> keep-redundant-commits, we check to see if the commit is made empty in\n> git-cherry-pick and skip it if it is.  We could, instead of returning prior to\n> calling git-commit, use that test to override the keep_empty option below, so\n> that we don't pass --allow-empty to git-commit instead.  That would preserve the\n> prior code path, but for no real advatage, as the outcome is the same, and this\n> way saves us having to fork the git-commit command, which I think is\n> adventageous.\n\nExcept that the outcome is not the same. With and without your changes,\ngit cherry-pick <empty-commit> fails. But with your changes, git\ncherry-pick <commit-will-become-empty> will succeed and do nothing,\nwhile before it would have failed exactly like git cherry-pick\n<empty-commit>.\n\nSo I am not arguing whether failing or skipping is the better default\nbehavior. But the legacy behavior is consistent between the empty-commit\nand commit-will-become-empty cases.  And if we change the behavior for\none, why not also for the other?\n"},{"id":"189515","messageId":"20120417104340.GA11462@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120416221018.GB5606@ecki","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T10:43:40Z","receivedAt":"2012-04-17T10:43:40Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 17, 2012 at 12:10:18AM +0200, Clemens Buchacher wrote:\n> On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:\n> > > \n> > > I find it a bit strange, that if we cherry-pick a commit that was\n> > > already empty, we _do_ call git commit (and error out), but if we find a\n> > > commit that is made empty, we do _not_ call git commit and quietly\n> > > succeed (in not doing anything). But I suppose that is the legacy\n> > > behavior?\n> >\n> > Correct, more or less.  The legacy behavior is to call git commit unilaterally.\n> > [...] The only change is that if we do not specify\n> > keep-redundant-commits, we check to see if the commit is made empty in\n> > git-cherry-pick and skip it if it is.  We could, instead of returning prior to\n> > calling git-commit, use that test to override the keep_empty option below, so\n> > that we don't pass --allow-empty to git-commit instead.  That would preserve the\n> > prior code path, but for no real advatage, as the outcome is the same, and this\n> > way saves us having to fork the git-commit command, which I think is\n> > adventageous.\n> \n> Except that the outcome is not the same. With and without your changes,\n> git cherry-pick <empty-commit> fails. But with your changes, git\n> cherry-pick <commit-will-become-empty> will succeed and do nothing,\n> while before it would have failed exactly like git cherry-pick\n> <empty-commit>.\n> \n> So I am not arguing whether failing or skipping is the better default\n> behavior. But the legacy behavior is consistent between the empty-commit\n> and commit-will-become-empty cases.  And if we change the behavior for\n> one, why not also for the other?\n> \n\nAh, I see what you're saying.  Yes, hadn't thought of that, Ok, I'll change the\nlogic to just toggle the addition of the --allow-empty flag to git commit.\nNeil\n"},{"id":"189517","messageId":"20120417105604.GB11462@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120416214247.GA5606@ecki","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T10:56:04Z","receivedAt":"2012-04-17T10:56:04Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:\n> On Mon, Apr 16, 2012 at 12:50:24PM -0400, Neil Horman wrote:\n> > On Mon, Apr 16, 2012 at 09:35:12AM -0700, Junio C Hamano wrote:\n> > > Neil Horman <nhorman@tuxdriver.com> writes:\n> > > \n> > > > On Sun, Apr 15, 2012 at 11:39:35AM +0200, Clemens Buchacher wrote:\n> > > > ...\n> > > >> > +test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n> > > >> > +\tgit checkout master && {\n> > > >> > +\t\tgit cherry-pick --allow-empty empty-branch2\n> > > >> > +\t}\n> > > >> > +'\n> > > >> > +\n> > > >> > +test_expect_success 'cherry pick with --keep-redundant-commits' '\n> > > >> > +\tgit checkout master && {\n> > > >> > +\t\tgit cherry-pick --keep-redundant-commits HEAD^\n> > > >> > +\t}\n> > > >> > +'\n> > > >> \n> > > >> And the expected result is that the HEAD commit is not removed, right?\n> > > >> You should check for that as well.\n> > > >> \n> > > >> Also, please checkout empty-branch2^0 first, in order to make the test\n> > > >> independent of its predecessor.\n> > > >\n> > > > Not sure I follow what your saying here.  The expected result with both of these\n> > > > tests is that a new commit is created, referencing the current HEAD as the new\n> > > > HEAD's parent.\n> > > \n> > > If the request were \"checkout master^0 first\" I would understand.  The\n> > > precondition for the second test will be different depending on the first\n> > > one succeeds or not.  Perhaps that is what Clemens meant?\n> > > \n> > Perhaps, but if so, I'm still not sure how a checkout of empty-branch2^0 affects\n> > these tests at all, nor do I grok the relevance to ensuring that the HEAD commit\n> > wasn't removed (as AIUI, cherry pick never does that anyway).  Clement, can you\n> > clarify your thoughts here please?\n> \n> It seems that I was implying a lot more than I realized. What I meant\n> was that master and empty-branch2 are equivalent for the purposes of\n> that test (empty-branch2^ also is a non-empty commit [*1*]), but while\n> master is a moving target, empty-branch2 is untouched. \n> \nfor the purposes of the --keep-redundant-commits however, the target is\nirrelevant.  The only requirement is that we cherry-pick a commit that is\nguaranteed to become empty when applied.  We certainly could do that on empty\nbranch2, but theres no advantage to doing so, and given that every other test\nattempts to cherry-pick to master, I rather like the consistency.\n\n> However, I just notice that empty-branch2 is also the root commit, so\n> maybe this will not work after all. But that should be easy to fix.\nIt is easy to fix, given your clarified description above, its just that IMO,\nits not broken.\n\n> \n> And now I am also wondering why we have two tests for cherry picking an\n> empty commit without --allow-empty (the one that you added and the one\n> that was there before). Is the non-ff part significant and if so, how?\n> And why don't we need to test fast-forward cherry-pick with\n> --allow-empty?\nthe difference is that the initial empty-branch doesn't just hold an empty\ncommit, but also contains no commit log entry on that empty commit, which\ngit-cherry-pick errors out on in the 'cherry-pick a commit with an empty\nmessage' test, and the 'cherry-pick an empty commit' test.\nI could modify the --allow-empty switch to include commits with\nno log message, but I didn't want to open that can of worms.\n\nThe test separation beyond that is the difference between a failing and a\nsuccessful test with an empty commit that still has a changelog entry.\n\nAs far as the ff logic goes.  If a cherry pick qualifies for fast forwarding,\nthen empty commits are automatically are allowed already.  Its only if a cherry\npick cannot be fast forwarded that its empty status is considered, hence the\ncreation of the 'fourth' commit in the new tests to ensure that the cherry pick\ndoesn't qualify as a fast forward.\n\nNeil\n \n> \n"},{"id":"189528","messageId":"7v3982pdoj.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"20120416221018.GB5606@ecki","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-17T15:42:52Z","receivedAt":"2012-04-17T15:42:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Clemens Buchacher <drizzd@aon.at> writes:\n\n> On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:\n> ...\n> Except that the outcome is not the same. With and without your changes,\n> git cherry-pick <empty-commit> fails. But with your changes, git\n> cherry-pick <commit-will-become-empty> will succeed and do nothing,\n> while before it would have failed exactly like git cherry-pick\n> <empty-commit>.\n>\n> So I am not arguing whether failing or skipping is the better default\n> behavior. But the legacy behavior is consistent between the empty-commit\n> and commit-will-become-empty cases.\n\nIs that particular \"consistency\" a good one, though?  If you had an empty\ncommit in the original range, it is a lot more likely that it was an error\nthat you would want to know about.  You may be the kind of person who\nvalue an empty commit in your history, using it as some kind of a mark in\nthe history, and in that case you would want to know that it is being\ndiscarded.  On the other hand, if a commit that did something in the\noriginal context turns out to be unnecessary in the replayed context, that\nis not something you would ever want to keep in the replayed context, and\nerroring out and forcing you to say \"yeah, I admit I do not want it\" would\njust be annoying.\n\nSo \"consistency\" between the two would actually be a mistake that we may\nwant to \"break\", I would think.\n"},{"id":"189545","messageId":"1334686809-17634-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v6 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T18:20:05Z","receivedAt":"2012-04-17T18:20:05Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --keep-redundant-commits, which allows the user to also keep\ncommits that were made empty via conflict resolution.  It also enhances\ngit-rebase to add a --keep-empty option which enables rebases to preserve empty\ncommits. \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\nV3)\n\t* reversed the --ignore-if-empty-logic to by default only keep initially\n\tempty commits\n\n\t* replaced --ignore-if-empty with --keep-redundant-commits, to allow\n\tempty commits that are made empty via conflict resolution, in addition\n\tto commits that were created as empty\n\n\t* reworked is_original_commit_empty to be more efficient and portable\n\n\t* Misc sylistic and spelling cleanups\n\nV4)\n\t* Reverted the cherry-pick advice changes in V3 based on in-thread\n\tdiscussion\n\n\t* Rewrote my changes to is_original_commit_empty and run_git_commit to\n\tnot have to fork, making them more efficient.\n\nv5)\n\t* Additional help text clean up\n\t* Additional error checking added to run_git_commit code\n\t* Whitespace cleanup\n\t* Removed needed cache_tree freeing\n\t* Test case cleanup\n\t* Fixed regression in t3404 and t3416 - this turned out to be \n        a problem with the note that git rebase -i adds at the bottom\n\tof the rebase text.  It was inadvertently indented and caused the\n\ttest fake editor to misread the commit template.  The indentation \n\thas been corrected, and these two tests, as well as all the other\n\texpected tests pass now\n\nv6)\n\t* synced keeep-redundant-commits option and variable name\n\t* fixed up some comment terminology\n\t* minor newline cleanup\n\t* Removed some unneeded braces from test code\n\t* minor syntatic cleanup in rebase scripts\n\n\t* Refactored empty index checking to make run_git_commit more readable\n\tI was also going to change the logic so that it operated more like git\n\tcherry-pick did before the patchset, but Junio's comments made me think\n\tthe new logic was preferable.\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n"},{"id":"189546","messageId":"1334686809-17634-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334686809-17634-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v6 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T18:20:06Z","receivedAt":"2012-04-17T18:20:06Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operation.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..730237a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty::\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189547","messageId":"1334686809-17634-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334686809-17634-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T18:20:07Z","receivedAt":"2012-04-17T18:20:07Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"The git-cherry-pick --allow-empty command by default only preserves empty\ncommits that were originally empty, i.e only those commits for which\n<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are\nnon-empty, but were made empty by the inclusion of a prior commit on the current\nhistory are filtered out.  This option allows us to override that behavior and\ninclude redundant commits as empty commits in the change history.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |   12 ++++-\n builtin/revert.c                  |    8 +++-\n sequencer.c                       |   97 ++++++++++++++++++++++++++++++++-----\n sequencer.h                       |    1 +\n 4 files changed, 103 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 730237a..0c004e9 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -110,7 +110,17 @@ effect to your index in a row.\n \tbehavior, allowing empty commits to be preserved automatically\n \tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n \tcommits that meet the \"fast-forward\" requirement will be kept\n-\teven without this option.\n+\teven without this option.  Note also, that use of this option only\n+\tkeeps commits that were initially empty (i.e. the commit recorded the\n+\tsame tree as its parent).  Commits which are made empty due to a\n+\tprevious commit are ignored.  To force the inclusion of those commits\n+\tuse `--keep-redundant-commits`.\n+\n+--keep-redundant-commits::\n+\tIf a commit being cherry picked duplicates a commit already in the\n+\tcurrent history, it will result in an empty changeset.  By default these\n+\tredundant commits are ignored.  This option overrides that behavior and\n+\tcreates an empty commit object.  Implies `--allow-empty`.\n \n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..f135502 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n-\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve initially empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_redundant_commits, \"keep redundant, empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n+\t/* keep_if_made_empty implies allow_empty */\n+\tif (opts->keep_redundant_commits)\n+\t\topts->allow_empty = 1;\n+\n \t/* Set the subcommand */\n \tif (remove_state)\n \t\topts->subcommand = REPLAY_REMOVE_STATE;\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..acc9c6d 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \treturn !clean;\n }\n \n+static int is_index_unchanged()\n+{\n+\tunsigned char head_sha1[20];\n+\tstruct commit *head_commit;\n+\n+\tif (!resolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL))\n+\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\n+\thead_commit = lookup_commit(head_sha1);\n+\tif (!head_commit || parse_commit(head_commit))\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(head_commit->object.sha1));\n+\n+\tif (!active_cache_tree)\n+\t\tactive_cache_tree = cache_tree();\n+\n+\tif (!cache_tree_fully_valid(active_cache_tree))\n+\t\tif (cache_tree_update(active_cache_tree, active_cache,\n+\t\t\t\t  active_nr, 0))\n+\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\n+\treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -258,26 +283,67 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  * If we are revert, or if our cherry-pick results in a hand merge,\n  * we had better say that the current user is responsible for that.\n  */\n-static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n+static int run_git_commit(const char *defmsg, struct replay_opts *opts, int empty)\n {\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+\tstruct argv_array array;\n+\tint rc;\n+\tint index_unchanged = is_index_unchanged();\n+\n+\t/*\n+\t * if index_unchanged is < 0, then we encountered an error\n+\t * trying to parse HEAD or the active_cache_tree, so bail out\n+\t */\n+\tif (index_unchanged < 0)\n+\t\treturn index_unchanged;\n+\n+\tif (!empty && !opts->keep_redundant_commits && index_unchanged)\n+\t\t\t/*\n+\t\t\t * The head tree and the index match\n+\t\t\t * meaning the commit is empty.  Since it wasn't created\n+\t\t\t * empty (based on the previous test), we can conclude\n+\t\t\t * the commit has been made redundant.  Since we don't\n+\t\t\t * want to keep redundant commits, we can just return\n+\t\t\t * here, skipping this commit\n+\t\t\t */\n+\t\t\treturn 0;\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n+\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n \n-\targs[i] = NULL;\n+static int is_original_commit_empty(struct commit *commit)\n+{\n+\tconst unsigned char *ptree_sha1;\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\tif (parse_commit(commit))\n+\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\tif (commit->parents) {\n+\t\tstruct commit *parent = commit->parents->item;\n+\t\tif (parse_commit(parent))\n+\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\t\tsha1_to_hex(parent->object.sha1));\n+\t\tptree_sha1 = parent->tree->object.sha1;\n+\t} else {\n+\t\tptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */\n+\t}\n+\n+\treturn !hashcmp(ptree_sha1, commit->tree->object.sha1);\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +355,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +481,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_original_commit_empty(commit);\n+\tif (empty_commit < 0)\n+\t\treturn empty_commit;\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -435,7 +506,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n \t\tif (!opts->no_commit)\n-\t\t\tres = run_git_commit(defmsg, opts);\n+\t\t\tres = run_git_commit(defmsg, opts, empty_commit);\n \t}\n \n \tfree_message(&msg);\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..aa5f17c 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint keep_redundant_commits;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189548","messageId":"1334686809-17634-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334686809-17634-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v6 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T18:20:08Z","receivedAt":"2012-04-17T18:20:08Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --keep-redundant-commits\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-\n 1 files changed, 24 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..d513127 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fourth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" &&\n+\ttest_must_fail git cherry-pick empty-branch2\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master &&\n+\tgit cherry-pick --allow-empty empty-branch2\n+'\n+\n+test_expect_success 'cherry pick with --keep-redundant-commits' '\n+\tgit checkout master &&\n+\tgit cherry-pick --keep-redundant-commits HEAD^\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"189549","messageId":"1334686809-17634-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334686809-17634-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-17T18:20:09Z","receivedAt":"2012-04-17T18:20:09Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   33 ++++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 53 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..04d8941 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if test -n \"$keep_empty\"\n+then\n+\t# we have to do this the hard way.  git format-patch completely squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..cef290b 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,12 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\ttree=$(git rev-parse \"$1\"^{tree})\n+\tptree=$(git rev-parse \"$1\"^^{tree})\n+\treturn $(test \"$tree\" = \"$ptree\")\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +197,19 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n+\n+\tif is_empty_commit \"$sha1\"\n+\tthen\n+\t\tempty_args=\"--allow-empty\"\n+\tfi\n+\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n+\tthen\n+\t\tcomment_out=\"# pick\"\n+\telse\n+\t\tcomment_out=\"pick\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +822,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s\\n' \"$comment_out $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +872,12 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\techo \"# Note that empty commits are commented out\" >> \"$todo\"\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"189573","messageId":"20120417213723.GA19908@ecki","threadId":"30112","inReplyTo":"7v3982pdoj.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-17T21:37:23Z","receivedAt":"2012-04-17T21:37:23Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Tue, Apr 17, 2012 at 08:42:52AM -0700, Junio C Hamano wrote:\n> Clemens Buchacher <drizzd@aon.at> writes:\n> \n> > On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:\n> > ...\n> > Except that the outcome is not the same. With and without your changes,\n> > git cherry-pick <empty-commit> fails. But with your changes, git\n> > cherry-pick <commit-will-become-empty> will succeed and do nothing,\n> > while before it would have failed exactly like git cherry-pick\n> > <empty-commit>.\n> >\n> > So I am not arguing whether failing or skipping is the better default\n> > behavior. But the legacy behavior is consistent between the empty-commit\n> > and commit-will-become-empty cases.\n> \n> Is that particular \"consistency\" a good one, though?  If you had an empty\n> commit in the original range, it is a lot more likely that it was an error\n> that you would want to know about.  You may be the kind of person who\n> value an empty commit in your history, using it as some kind of a mark in\n> the history, and in that case you would want to know that it is being\n> discarded.  On the other hand, if a commit that did something in the\n> original context turns out to be unnecessary in the replayed context, that\n> is not something you would ever want to keep in the replayed context, and\n> erroring out and forcing you to say \"yeah, I admit I do not want it\" would\n> just be annoying.\n\nYeah, that makes sense.\n\n> So \"consistency\" between the two would actually be a mistake that we may\n> want to \"break\", I would think.\n\nAgreed. But we should document the change in the commit message and\nmaybe add a comment, because it is really strange to read\n\n if (!empty && index_empty)\n \treturn \"it's all good\"\n\n if (empty)\n \treturn \"oh noes!\"\n\nwithout an explanation as to why empty and index_empty are so different.\nNeil, what do you think?\n"},{"id":"189575","messageId":"20120417213851.GA20082@ecki","threadId":"30112","inReplyTo":"20120417105604.GB11462@hmsreliant.think-freely.org","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-17T21:38:52Z","receivedAt":"2012-04-17T21:38:52Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Tue, Apr 17, 2012 at 06:56:04AM -0400, Neil Horman wrote:\n> On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:\n> > \n> > It seems that I was implying a lot more than I realized. What I meant\n> > was that master and empty-branch2 are equivalent for the purposes of\n> > that test (empty-branch2^ also is a non-empty commit [*1*]), but while\n> > master is a moving target, empty-branch2 is untouched. \n> > \n> for the purposes of the --keep-redundant-commits however, the target is\n> irrelevant.  The only requirement is that we cherry-pick a commit that is\n> guaranteed to become empty when applied.\n\nThat we agree on.\n\n> We certainly could do that on empty branch2, but theres no advantage\n> to doing so,\n\nThe advantage is that I do not have to read the other tests in order to\nunderstand what this test does, because contrary to the master branch,\nthey do not modify empty-branch2.\n\n> and given that every other test attempts to cherry-pick to master, I\n> rather like the consistency.\n\nWe could also consistently not use the master branch.\n\n> > However, I just notice that empty-branch2 is also the root commit, so\n> > maybe this will not work after all. But that should be easy to fix.\n>\n> It is easy to fix, given your clarified description above, its just that IMO,\n> its not broken.\n\nWell, I don't mind too badly if this doesn't go may way. But I hope that\nI managed at least to explain my point.\n"},{"id":"189576","messageId":"20120417214521.GB19908@ecki","threadId":"30112","inReplyTo":"1334686809-17634-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-17T21:45:22Z","receivedAt":"2012-04-17T21:45:22Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Tue, Apr 17, 2012 at 02:20:07PM -0400, Neil Horman wrote:\n>\n> +\tif (!empty && !opts->keep_redundant_commits && index_unchanged)\n> +\t\t\t/*\n> +\t\t\t * The head tree and the index match\n> +\t\t\t * meaning the commit is empty.  Since it wasn't created\n> +\t\t\t * empty (based on the previous test), we can conclude\n> +\t\t\t * the commit has been made redundant.  Since we don't\n> +\t\t\t * want to keep redundant commits, we can just return\n> +\t\t\t * here, skipping this commit\n> +\t\t\t */\n> +\t\t\treturn 0;\n\nYou can remove one level of indentation (yay!).\n"},{"id":"189577","messageId":"20120417214659.GC19908@ecki","threadId":"30112","inReplyTo":"1334686809-17634-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-17T21:47:01Z","receivedAt":"2012-04-17T21:47:01Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Tue, Apr 17, 2012 at 02:20:09PM -0400, Neil Horman wrote:\n>\n> @@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n>  \tsed -n \"s/^>//p\" |\n>  while read -r shortsha1 rest\n>  do\n> +\n> +\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n> +\tthen\n> +\t\tcomment_out=\"# pick\"\n> +\telse\n> +\t\tcomment_out=\"pick\"\n> +\tfi\n\nYou forgot to change this to comment_out=\"# \" and comment_out=\"\".\n"},{"id":"189613","messageId":"20120418104150.GA22172@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120417213723.GA19908@ecki","subject":"Re: [PATCH v5 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T10:41:50Z","receivedAt":"2012-04-18T10:41:50Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 17, 2012 at 11:37:23PM +0200, Clemens Buchacher wrote:\n> On Tue, Apr 17, 2012 at 08:42:52AM -0700, Junio C Hamano wrote:\n> > Clemens Buchacher <drizzd@aon.at> writes:\n> > \n> > > On Mon, Apr 16, 2012 at 11:38:27AM -0400, Neil Horman wrote:\n> > > ...\n> > > Except that the outcome is not the same. With and without your changes,\n> > > git cherry-pick <empty-commit> fails. But with your changes, git\n> > > cherry-pick <commit-will-become-empty> will succeed and do nothing,\n> > > while before it would have failed exactly like git cherry-pick\n> > > <empty-commit>.\n> > >\n> > > So I am not arguing whether failing or skipping is the better default\n> > > behavior. But the legacy behavior is consistent between the empty-commit\n> > > and commit-will-become-empty cases.\n> > \n> > Is that particular \"consistency\" a good one, though?  If you had an empty\n> > commit in the original range, it is a lot more likely that it was an error\n> > that you would want to know about.  You may be the kind of person who\n> > value an empty commit in your history, using it as some kind of a mark in\n> > the history, and in that case you would want to know that it is being\n> > discarded.  On the other hand, if a commit that did something in the\n> > original context turns out to be unnecessary in the replayed context, that\n> > is not something you would ever want to keep in the replayed context, and\n> > erroring out and forcing you to say \"yeah, I admit I do not want it\" would\n> > just be annoying.\n> \n> Yeah, that makes sense.\n> \n> > So \"consistency\" between the two would actually be a mistake that we may\n> > want to \"break\", I would think.\n> \n> Agreed. But we should document the change in the commit message and\n> maybe add a comment, because it is really strange to read\n> \n>  if (!empty && index_empty)\n>  \treturn \"it's all good\"\n> \n>  if (empty)\n>  \treturn \"oh noes!\"\n> \n> without an explanation as to why empty and index_empty are so different.\n> Neil, what do you think?\n> \nWell, I've got the comment in the code indicating what were doing, but sure,\nI can be more vebose in the commit message about whats going on.  I can probably\nrename the empty variable to indicate its meaning a bit more clearly and make\nthat code more readable.\nNeil\n"},{"id":"189614","messageId":"20120418104859.GB22172@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120417213851.GA20082@ecki","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T10:48:59Z","receivedAt":"2012-04-18T10:48:59Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 17, 2012 at 11:38:52PM +0200, Clemens Buchacher wrote:\n> On Tue, Apr 17, 2012 at 06:56:04AM -0400, Neil Horman wrote:\n> > On Mon, Apr 16, 2012 at 11:42:49PM +0200, Clemens Buchacher wrote:\n> > > \n> > > It seems that I was implying a lot more than I realized. What I meant\n> > > was that master and empty-branch2 are equivalent for the purposes of\n> > > that test (empty-branch2^ also is a non-empty commit [*1*]), but while\n> > > master is a moving target, empty-branch2 is untouched. \n> > > \n> > for the purposes of the --keep-redundant-commits however, the target is\n> > irrelevant.  The only requirement is that we cherry-pick a commit that is\n> > guaranteed to become empty when applied.\n> \n> That we agree on.\n> \n> > We certainly could do that on empty branch2, but theres no advantage\n> > to doing so,\n> \n> The advantage is that I do not have to read the other tests in order to\n> understand what this test does, because contrary to the master branch,\n> they do not modify empty-branch2.\n> \nBut empty-branch2, as the name implies, doesn't have a non-empty commit on it\nyet, and so theres nothing to cherry-pick on that branch that would 'become'\nempty.  We could fix that of course, but I'd worry that that would look odd\nagainst the other tests.\n\n> > and given that every other test attempts to cherry-pick to master, I\n> > rather like the consistency.\n> \n> We could also consistently not use the master branch.\n> \nYes, This would be my perferred solution I think.  That way we clarify the test\nto your satisfaction and keep the consistency of the test methodology.\n\n> > > However, I just notice that empty-branch2 is also the root commit, so\n> > > maybe this will not work after all. But that should be easy to fix.\n> >\n> > It is easy to fix, given your clarified description above, its just that IMO,\n> > its not broken.\n> \n> Well, I don't mind too badly if this doesn't go may way. But I hope that\n> I managed at least to explain my point.\n> \nYes, absolutely.  How about this:  Given that we agree on our ability to\nconsistently not use master above, what if we table this discussion for now,\nleave the tests as they are, and fix them all up in a separate patch set?  I\ndon't mind making the change your requesting at all, but I'd rather do it as\npart of modifying all the tests not to use master, and doing it in a separate\nchangeset, so we don't convolute what this series is doing.  Does that sound\nreasonable?\nNeil\n"},{"id":"189615","messageId":"20120418104919.GC22172@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120417214521.GB19908@ecki","subject":"Re: [PATCH v6 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T10:49:19Z","receivedAt":"2012-04-18T10:49:19Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 17, 2012 at 11:45:22PM +0200, Clemens Buchacher wrote:\n> On Tue, Apr 17, 2012 at 02:20:07PM -0400, Neil Horman wrote:\n> >\n> > +\tif (!empty && !opts->keep_redundant_commits && index_unchanged)\n> > +\t\t\t/*\n> > +\t\t\t * The head tree and the index match\n> > +\t\t\t * meaning the commit is empty.  Since it wasn't created\n> > +\t\t\t * empty (based on the previous test), we can conclude\n> > +\t\t\t * the commit has been made redundant.  Since we don't\n> > +\t\t\t * want to keep redundant commits, we can just return\n> > +\t\t\t * here, skipping this commit\n> > +\t\t\t */\n> > +\t\t\treturn 0;\n> \n> You can remove one level of indentation (yay!).\n>\nDoh!  Thanks.\nNeil\n"},{"id":"189617","messageId":"20120418105009.GD22172@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"20120417214659.GC19908@ecki","subject":"Re: [PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T10:50:09Z","receivedAt":"2012-04-18T10:50:09Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 17, 2012 at 11:47:01PM +0200, Clemens Buchacher wrote:\n> On Tue, Apr 17, 2012 at 02:20:09PM -0400, Neil Horman wrote:\n> >\n> > @@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n> >  \tsed -n \"s/^>//p\" |\n> >  while read -r shortsha1 rest\n> >  do\n> > +\n> > +\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n> > +\tthen\n> > +\t\tcomment_out=\"# pick\"\n> > +\telse\n> > +\t\tcomment_out=\"pick\"\n> > +\tfi\n> \n> You forgot to change this to comment_out=\"# \" and comment_out=\"\".\n> \n\nThanks, I'll fix that up when I modify the keep-redundant-commits commit message\nNeil\n"},{"id":"189640","messageId":"20120418183418.GA23447@ecki","threadId":"30112","inReplyTo":"20120418104859.GB22172@hmsreliant.think-freely.org","subject":"Re: [PATCH v5 3/4] git-cherry-pick: Add test to validate new options","fromName":"Clemens Buchacher","fromEmail":"drizzd@aon.at","sentAt":"2012-04-18T18:34:18Z","receivedAt":"2012-04-18T18:34:18Z","isPatch":true,"sender":{"key":"drizzd@gmx.net","avatar":"https://avatars.githubusercontent.com/u/59082?v=4"},"body":"On Wed, Apr 18, 2012 at 06:48:59AM -0400, Neil Horman wrote:\n>\n> Given that we agree on our ability to consistently not use master\n> above, what if we table this discussion for now, leave the tests as\n> they are, and fix them all up in a separate patch set? Does that sound\n> reasonable?\n\nAbsolutely.\n"},{"id":"189641","messageId":"1334776680-23460-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v7 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T19:17:56Z","receivedAt":"2012-04-18T19:17:56Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"\ngit's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --keep-redundant-commits, which allows the user to also keep\ncommits that were made empty via conflict resolution.  It also enhances\ngit-rebase to add a --keep-empty option which enables rebases to preserve empty\ncommits. \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\nV3)\n\t* reversed the --ignore-if-empty-logic to by default only keep initially\n\tempty commits\n\n\t* replaced --ignore-if-empty with --keep-redundant-commits, to allow\n\tempty commits that are made empty via conflict resolution, in addition\n\tto commits that were created as empty\n\n\t* reworked is_original_commit_empty to be more efficient and portable\n\n\t* Misc sylistic and spelling cleanups\n\nV4)\n\t* Reverted the cherry-pick advice changes in V3 based on in-thread\n\tdiscussion\n\n\t* Rewrote my changes to is_original_commit_empty and run_git_commit to\n\tnot have to fork, making them more efficient.\n\nv5)\n\t* Additional help text clean up\n\t* Additional error checking added to run_git_commit code\n\t* Whitespace cleanup\n\t* Removed needed cache_tree freeing\n\t* Test case cleanup\n\t* Fixed regression in t3404 and t3416 - this turned out to be \n        a problem with the note that git rebase -i adds at the bottom\n\tof the rebase text.  It was inadvertently indented and caused the\n\ttest fake editor to misread the commit template.  The indentation \n\thas been corrected, and these two tests, as well as all the other\n\texpected tests pass now\n\nv6)\n\t* synced keeep-redundant-commits option and variable name\n\t* fixed up some comment terminology\n\t* minor newline cleanup\n\t* Removed some unneeded braces from test code\n\t* minor syntatic cleanup in rebase scripts\n\n\t* Refactored empty index checking to make run_git_commit more readable\n\tI was also going to change the logic so that it operated more like git\n\tcherry-pick did before the patchset, but Junio's comments made me think\n\tthe new logic was preferable.\n\nv7)\n\t* Fixed up forgotten comment_out changes requested in\n\tgit-rebase--interactive\n\n\t* Made changelog comment for keep-redundant-commits patch more verbose\n\tso that it was clear that default behavior was changing\n\n\t* further refinement of detection of redundant commits, making\n\tdo_pick_commit and run_git_commit more readable\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n"},{"id":"189643","messageId":"1334776680-23460-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334776680-23460-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v7 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T19:17:57Z","receivedAt":"2012-04-18T19:17:57Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operation.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..730237a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty::\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189642","messageId":"1334776680-23460-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334776680-23460-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T19:17:58Z","receivedAt":"2012-04-18T19:17:58Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"The git-cherry-pick --allow-empty command by default only preserves empty\ncommits that were originally empty, i.e only those commits for which\n<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are\nnon-empty, but were made empty by the inclusion of a prior commit on the current\nhistory are filtered out.  This option allows us to override that behavior and\ninclude redundant commits as empty commits in the change history.\n\nNote that this patch changes the default behavior of git cherry-pick slightly.\nPrior to this patch all commits in a cherry-pick sequence were applied and git\ncommit was run.  The implication here was that, if a commit was redundant, and\nthe commit did not trigger the fast forward logic, the git commit operation, and\ntherefore the git cherry-pick operation would fail, displaying the cherry pick\nadvice (i.e. run git commit --allow-empty).  With this patch however, such\nredundant commits are automatically skipped without stopping, unless\n--keep-redundant-commits is specified, in which case, they are automatically\napplied as empty commits.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |   12 ++++-\n builtin/revert.c                  |    8 +++-\n sequencer.c                       |   94 ++++++++++++++++++++++++++++++++----\n sequencer.h                       |    1 +\n 4 files changed, 102 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 730237a..0c004e9 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -110,7 +110,17 @@ effect to your index in a row.\n \tbehavior, allowing empty commits to be preserved automatically\n \tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n \tcommits that meet the \"fast-forward\" requirement will be kept\n-\teven without this option.\n+\teven without this option.  Note also, that use of this option only\n+\tkeeps commits that were initially empty (i.e. the commit recorded the\n+\tsame tree as its parent).  Commits which are made empty due to a\n+\tprevious commit are ignored.  To force the inclusion of those commits\n+\tuse `--keep-redundant-commits`.\n+\n+--keep-redundant-commits::\n+\tIf a commit being cherry picked duplicates a commit already in the\n+\tcurrent history, it will result in an empty changeset.  By default these\n+\tredundant commits are ignored.  This option overrides that behavior and\n+\tcreates an empty commit object.  Implies `--allow-empty`.\n \n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..f135502 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n-\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve initially empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_redundant_commits, \"keep redundant, empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n+\t/* keep_if_made_empty implies allow_empty */\n+\tif (opts->keep_redundant_commits)\n+\t\topts->allow_empty = 1;\n+\n \t/* Set the subcommand */\n \tif (remove_state)\n \t\topts->subcommand = REPLAY_REMOVE_STATE;\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..e33dfbb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \treturn !clean;\n }\n \n+static int is_index_unchanged()\n+{\n+\tunsigned char head_sha1[20];\n+\tstruct commit *head_commit;\n+\n+\tif (!resolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL))\n+\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\n+\thead_commit = lookup_commit(head_sha1);\n+\tif (!head_commit || parse_commit(head_commit))\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(head_commit->object.sha1));\n+\n+\tif (!active_cache_tree)\n+\t\tactive_cache_tree = cache_tree();\n+\n+\tif (!cache_tree_fully_valid(active_cache_tree))\n+\t\tif (cache_tree_update(active_cache_tree, active_cache,\n+\t\t\t\t  active_nr, 0))\n+\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\n+\treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -260,24 +285,46 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+\tstruct argv_array array;\n+\tint rc;\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n \n-\targs[i] = NULL;\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n+\n+static int is_original_commit_empty(struct commit *commit)\n+{\n+\tconst unsigned char *ptree_sha1;\n+\n+\tif (parse_commit(commit))\n+\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\tif (commit->parents) {\n+\t\tstruct commit *parent = commit->parents->item;\n+\t\tif (parse_commit(parent))\n+\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\t\tsha1_to_hex(parent->object.sha1));\n+\t\tptree_sha1 = parent->tree->object.sha1;\n+\t} else {\n+\t\tptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */\n+\t}\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\treturn !hashcmp(ptree_sha1, commit->tree->object.sha1);\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +336,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n+\tint index_unchanged;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +463,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_original_commit_empty(commit);\n+\tif (empty_commit < 0)\n+\t\treturn empty_commit;\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -434,6 +487,25 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n+\t\tindex_unchanged = is_index_unchanged();\n+\t\t/*\n+\t\t * If index_unchanged is less than 0, that indicates we either\n+\t\t * couldn't parse HEAD or the index, so error out here.\n+\t\t */\n+\t\tif (index_unchanged < 0)\n+\t\t\treturn index_unchanged;\n+\n+\t\tif (!empty_commit && !opts->keep_redundant_commits && index_unchanged)\n+\t\t\t/*\n+\t\t\t * The head tree and the index match\n+\t\t\t * meaning the commit is empty.  Since it wasn't created\n+\t\t\t * empty (based on the previous test), we can conclude\n+\t\t\t * the commit has been made redundant.  Since we don't\n+\t\t\t * want to keep redundant commits, we can just return\n+\t\t\t * here, skipping this commit\n+\t\t\t */\n+\t\t\treturn 0;\n+\n \t\tif (!opts->no_commit)\n \t\t\tres = run_git_commit(defmsg, opts);\n \t}\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..aa5f17c 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint keep_redundant_commits;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189644","messageId":"1334776680-23460-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334776680-23460-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v7 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T19:17:59Z","receivedAt":"2012-04-18T19:17:59Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --keep-redundant-commits\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-\n 1 files changed, 24 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..d513127 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fourth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" &&\n+\ttest_must_fail git cherry-pick empty-branch2\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master &&\n+\tgit cherry-pick --allow-empty empty-branch2\n+'\n+\n+test_expect_success 'cherry pick with --keep-redundant-commits' '\n+\tgit checkout master &&\n+\tgit cherry-pick --keep-redundant-commits HEAD^\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"189645","messageId":"1334776680-23460-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334776680-23460-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-18T19:18:00Z","receivedAt":"2012-04-18T19:18:00Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   33 ++++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 53 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..04d8941 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if test -n \"$keep_empty\"\n+then\n+\t# we have to do this the hard way.  git format-patch completely squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..b7abe1e 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,12 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\ttree=$(git rev-parse \"$1\"^{tree})\n+\tptree=$(git rev-parse \"$1\"^^{tree})\n+\treturn $(test \"$tree\" = \"$ptree\")\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +197,19 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n+\n+\tif is_empty_commit \"$sha1\"\n+\tthen\n+\t\tempty_args=\"--allow-empty\"\n+\tfi\n+\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +793,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n+\tthen\n+\t\tcomment_out=\"#\"\n+\telse\n+\t\tcomment_out=\"\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +822,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +872,12 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\techo \"# Note that empty commits are commented out\" >> \"$todo\"\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"189673","messageId":"7vmx68k5oy.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1334686809-17634-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-18T22:58:53Z","receivedAt":"2012-04-18T22:58:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Add a command line switch to git-rebase to allow a user the ability to specify\n> that they want to keep any commits in a series that are empty.\n>\n> When git-rebase's type is am, then this option will automatically keep any\n> commit that has a tree object identical to its parent.\n>\n> This patch changes the default behavior of interactive rebases as well.  With\n> this patch, git-rebase -i will produce a revision set passed to\n> git-revision-editor, in which empty commits are commented out.  Empty commits\n> may be kept manually by uncommenting them.  If the new --keep-empty option is\n> used in an interactive rebase the empty commits will automatically all be\n> uncommented in the editor.\n>\n> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> ---\n\nThe earlier one in the series seem to be getting solid enough.  Nice.\n\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 5812222..cef290b 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -167,6 +167,12 @@ has_action () {\n>  \tsane_grep '^[^#]' \"$1\" >/dev/null\n>  }\n>  \n> +is_empty_commit() {\n> +\ttree=$(git rev-parse \"$1\"^{tree})\n> +\tptree=$(git rev-parse \"$1\"^^{tree})\n> +\treturn $(test \"$tree\" = \"$ptree\")\n> +}\n\nCould \"$1\" ever be a root commit without a parent?\n"},{"id":"189674","messageId":"7vfwc0k5nu.fsf@alter.siamese.dyndns.org","threadId":"30112","inReplyTo":"1334776680-23460-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v7 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-18T22:59:33Z","receivedAt":"2012-04-18T22:59:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> diff --git a/sequencer.c b/sequencer.c\n> index 71929ba..e33dfbb 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -13,6 +13,7 @@\n>  #include \"rerere.h\"\n>  #include \"merge-recursive.h\"\n>  #include \"refs.h\"\n> +#include \"argv-array.h\"\n>  \n>  #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n>  \n> @@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n>  \treturn !clean;\n>  }\n>  \n> +static int is_index_unchanged()\n> +{\n\nHmm... I am reasonably sure I fixed this when I queued the previous one to\n'pu'.\n\n\tstatic int is_index_unchanged(void)\n        {\n"},{"id":"189691","messageId":"4F8FE2CD.3070300@in.waw.pl","threadId":"30112","inReplyTo":"1334776680-23460-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Zbigniew Jędrzejewski-Szmek","fromEmail":"zbyszek@in.waw.pl","sentAt":"2012-04-19T10:02:53Z","receivedAt":"2012-04-19T10:02:53Z","isPatch":true,"sender":{"key":"zbyszek@in.waw.pl","avatar":"https://avatars.githubusercontent.com/u/349618?v=4"},"body":"On 04/18/2012 09:18 PM, Neil Horman wrote:\n> Add a command line switch to git-rebase to allow a user the ability to specify\n> that they want to keep any commits in a series that are empty.\n>\n> When git-rebase's type is am, then this option will automatically keep any\n> commit that has a tree object identical to its parent.\n>\n> This patch changes the default behavior of interactive rebases as well.  With\n> this patch, git-rebase -i will produce a revision set passed to\n> git-revision-editor, in which empty commits are commented out.  Empty commits\n> may be kept manually by uncommenting them.  If the new --keep-empty option is\n> used in an interactive rebase the empty commits will automatically all be\n> uncommented in the editor.\n>\n> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>\n\nHi,\nthis one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu \nand this v7).\n\nE.g. ./t3404-rebase-interactive.sh:\n\nok 1 - setup\nnot ok - 2 rebase -i with the exec command\nnot ok - 3 rebase -i with the exec command runs from tree root\nnot ok - 4 rebase -i with the exec command checks tree cleanness\nnot ok - 5 no changes are a nop\nnot ok - 6 test the [branch] option\nnot ok - 7 test --onto <branch>\nnot ok - 8 rebase on top of a non-conflicting commit\nnot ok - 9 reflog for the branch shows state before rebase\nnot ok - 10 exchange two commits\nnot ok - 11 stop on conflicting pick\nnot ok - 12 abort\nnot ok - 13 abort with error when new base cannot be checked out\nnot ok - 14 retain authorship\nnot ok - 15 squash\nnot ok - 16 retain authorship when squashing\nnot ok - 17 -p handles \"no changes\" gracefully\nnot ok 18 - exchange two commits with -p # TODO known breakage\nnot ok - 19 preserve merges with -p\nnot ok - 20 edit ancestor with -p\nnot ok - 21 --continue tries to commit\nnot ok - 22 verbose flag is heeded, even after --continue\nnot ok - 23 multi-squash only fires up editor once\nnot ok - 24 multi-fixup does not fire up editor\nnot ok - 25 commit message used after conflict\nnot ok - 26 commit message retained after conflict\nnot ok - 27 squash and fixup generate correct log messages\nnot ok - 28 squash ignores comments\nnot ok - 29 squash ignores blank lines\nnot ok - 30 squash works as expected\nnot ok - 31 interrupted squash works as expected\nnot ok - 32 interrupted squash works as expected (case 2)\nnot ok - 33 ignore patch if in upstream\nnot ok - 34 --continue tries to commit, even for \"edit\"\nnot ok - 35 aborted --continue does not squash commits after \"edit\"\nnot ok - 36 auto-amend only edited commits after \"edit\"\nnot ok - 37 clean error after failed \"exec\"\nnot ok - 38 rebase a detached HEAD\nnot ok - 39 rebase a commit violating pre-commit\nnot ok - 40 rebase with a file named HEAD in worktree\nok 41 - do \"noop\" when there is nothing to cherry-pick\nok 42 - submodule rebase setup\nnot ok - 43 submodule rebase -i\nok 44 - submodule conflict setup\nnot ok - 45 rebase -i continue with only submodule staged\nnot ok - 46 rebase -i continue with unstaged submodule\nnot ok - 47 avoid unnecessary reset\nnot ok - 48 reword\nok 49 - rebase -i can copy notes\nnot ok - 50 rebase -i can copy notes over a fixup\nnot ok - 51 rebase while detaching HEAD\nnot ok - 52 always cherry-pick with --no-ff\nok 53 - set up commits with funny messages\nnot ok - 54 rebase-i history with funny messages\n\nThe problem seems to be that git-rebase says \"Nothing to do\" and returns 1.\n\n-\nZbyszek\n"},{"id":"189694","messageId":"873980q6vm.fsf@thomas.inf.ethz.ch","threadId":"30112","inReplyTo":"4F8FE2CD.3070300@in.waw.pl","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2012-04-19T11:49:01Z","receivedAt":"2012-04-19T11:49:01Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> writes:\n\n> On 04/18/2012 09:18 PM, Neil Horman wrote:\n>> Add a command line switch to git-rebase to allow a user the ability to specify\n>> that they want to keep any commits in a series that are empty.\n>>\n>> When git-rebase's type is am, then this option will automatically keep any\n>> commit that has a tree object identical to its parent.\n>>\n>> This patch changes the default behavior of interactive rebases as well.  With\n>> this patch, git-rebase -i will produce a revision set passed to\n>> git-revision-editor, in which empty commits are commented out.  Empty commits\n>> may be kept manually by uncommenting them.  If the new --keep-empty option is\n>> used in an interactive rebase the empty commits will automatically all be\n>> uncommented in the editor.\n>>\n>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>\n>\n> Hi,\n> this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu\n> and this v7).\n\nProbably because of the strange return in this function:\n\n>> is_empty_commit() {\n>> \ttree=$(git rev-parse \"$1\"^{tree})\n>> \tptree=$(git rev-parse \"$1\"^^{tree})\n>> \treturn $(test \"$tree\" = \"$ptree\")\n>> }\n\nbash seems to pass on the exit status from $() to the caller, while dash\ndoesn't.  It seems bash is actually more correct here, because POSIX\nsays about 'return [n]': \n\n    EXIT STATUS\n       The value of the special parameter '?' shall be set to n, an\n       unsigned decimal integer, or to the exit status of the last\n       command executed if n is not specified.\n\nEither way, it should simply be spelled as\n\nis_empty_commit() {\n\ttree=$(git rev-parse \"$1\"^{tree})\n\tptree=$(git rev-parse \"$1\"^^{tree})\n\ttest \"$tree\" = \"$ptree\"\n}\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"189695","messageId":"4F9002CA.6040302@in.waw.pl","threadId":"30112","inReplyTo":"873980q6vm.fsf@thomas.inf.ethz.ch","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Zbigniew Jędrzejewski-Szmek","fromEmail":"zbyszek@in.waw.pl","sentAt":"2012-04-19T12:19:22Z","receivedAt":"2012-04-19T12:19:22Z","isPatch":true,"sender":{"key":"zbyszek@in.waw.pl","avatar":"https://avatars.githubusercontent.com/u/349618?v=4"},"body":"On 04/19/2012 01:49 PM, Thomas Rast wrote:\n> Zbigniew Jędrzejewski-Szmek<zbyszek@in.waw.pl>  writes:\n>\n>> On 04/18/2012 09:18 PM, Neil Horman wrote:\n>>> Add a command line switch to git-rebase to allow a user the ability to specify\n>>> that they want to keep any commits in a series that are empty.\n>>>\n>>> When git-rebase's type is am, then this option will automatically keep any\n>>> commit that has a tree object identical to its parent.\n>>>\n>>> This patch changes the default behavior of interactive rebases as well.  With\n>>> this patch, git-rebase -i will produce a revision set passed to\n>>> git-revision-editor, in which empty commits are commented out.  Empty commits\n>>> may be kept manually by uncommenting them.  If the new --keep-empty option is\n>>> used in an interactive rebase the empty commits will automatically all be\n>>> uncommented in the editor.\n>>>\n>>> Signed-off-by: Neil Horman<nhorman@tuxdriver.com>\n>>\n>> Hi,\n>> this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu\n>> and this v7).\n>\n> Probably because of the strange return in this function:\n>\n>>> is_empty_commit() {\n>>> \ttree=$(git rev-parse \"$1\"^{tree})\n>>> \tptree=$(git rev-parse \"$1\"^^{tree})\n>>> \treturn $(test \"$tree\" = \"$ptree\")\n>>> }\n>\n> bash seems to pass on the exit status from $() to the caller, while dash\n> doesn't.  It seems bash is actually more correct here, because POSIX\n> says about 'return [n]':\n>\n>      EXIT STATUS\n>         The value of the special parameter '?' shall be set to n, an\n>         unsigned decimal integer, or to the exit status of the last\n>         command executed if n is not specified.\n>\n> Either way, it should simply be spelled as\n>\n> is_empty_commit() {\n> \ttree=$(git rev-parse \"$1\"^{tree})\n> \tptree=$(git rev-parse \"$1\"^^{tree})\n> \ttest \"$tree\" = \"$ptree\"\n> }\nYes, this change fixes the problem (all tests pass).\n\nThanks!\n\nZbyszek\n"},{"id":"189698","messageId":"20120419130818.GA18339@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"7vmx68k5oy.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-19T13:08:18Z","receivedAt":"2012-04-19T13:08:18Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Wed, Apr 18, 2012 at 03:58:53PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Add a command line switch to git-rebase to allow a user the ability to specify\n> > that they want to keep any commits in a series that are empty.\n> >\n> > When git-rebase's type is am, then this option will automatically keep any\n> > commit that has a tree object identical to its parent.\n> >\n> > This patch changes the default behavior of interactive rebases as well.  With\n> > this patch, git-rebase -i will produce a revision set passed to\n> > git-revision-editor, in which empty commits are commented out.  Empty commits\n> > may be kept manually by uncommenting them.  If the new --keep-empty option is\n> > used in an interactive rebase the empty commits will automatically all be\n> > uncommented in the editor.\n> >\n> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>\n> > ---\n> \n> The earlier one in the series seem to be getting solid enough.  Nice.\n> \nThanks!\n\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index 5812222..cef290b 100644\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n> > @@ -167,6 +167,12 @@ has_action () {\n> >  \tsane_grep '^[^#]' \"$1\" >/dev/null\n> >  }\n> >  \n> > +is_empty_commit() {\n> > +\ttree=$(git rev-parse \"$1\"^{tree})\n> > +\tptree=$(git rev-parse \"$1\"^^{tree})\n> > +\treturn $(test \"$tree\" = \"$ptree\")\n> > +}\n> \n> Could \"$1\" ever be a root commit without a parent?\n> \nStrictly speaking, yes.  If that happens, however, the output of git rev-parse\nwill be an error message that includes the passed in revision.  since tree\npasses '^' while ptree passes '^^' the two revisions will always differ, and as\na result is_empty_commit will return false, and the existing behavior of git\nwill be followed.  So, yes, rebasing an empty tree would cause odd output in the\nrev-parse calls in is_empty_comit, but the behavior of git overall would be\nunaffected (which is not to say that rebasing an empty tree won't show odd\ncorner-case behavior, only that this changeset won't introduce any new odd\ncorner case behavior :) ).\n\nIf you like we can add additional checking to ensure that we explicitly catch\nrev-parse errors and abort the rebase imediately, but I don't think thats\nstrictly necessecary.  Would you prefer that?\n\nRegards\nNeil\n \n"},{"id":"189699","messageId":"20120419131211.GB18339@neilslaptop.think-freely.org","threadId":"30112","inReplyTo":"4F9002CA.6040302@in.waw.pl","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-19T13:12:12Z","receivedAt":"2012-04-19T13:12:12Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 19, 2012 at 02:19:22PM +0200, Zbigniew Jędrzejewski-Szmek wrote:\n> On 04/19/2012 01:49 PM, Thomas Rast wrote:\n> >Zbigniew Jędrzejewski-Szmek<zbyszek@in.waw.pl>  writes:\n> >\n> >>On 04/18/2012 09:18 PM, Neil Horman wrote:\n> >>>Add a command line switch to git-rebase to allow a user the ability to specify\n> >>>that they want to keep any commits in a series that are empty.\n> >>>\n> >>>When git-rebase's type is am, then this option will automatically keep any\n> >>>commit that has a tree object identical to its parent.\n> >>>\n> >>>This patch changes the default behavior of interactive rebases as well.  With\n> >>>this patch, git-rebase -i will produce a revision set passed to\n> >>>git-revision-editor, in which empty commits are commented out.  Empty commits\n> >>>may be kept manually by uncommenting them.  If the new --keep-empty option is\n> >>>used in an interactive rebase the empty commits will automatically all be\n> >>>uncommented in the editor.\n> >>>\n> >>>Signed-off-by: Neil Horman<nhorman@tuxdriver.com>\n> >>\n> >>Hi,\n> >>this one seems to breaks many tests when /bin/sh=dash. (Both v6 in pu\n> >>and this v7).\n> >\n> >Probably because of the strange return in this function:\n> >\n> >>>is_empty_commit() {\n> >>>\ttree=$(git rev-parse \"$1\"^{tree})\n> >>>\tptree=$(git rev-parse \"$1\"^^{tree})\n> >>>\treturn $(test \"$tree\" = \"$ptree\")\n> >>>}\n> >\n> >bash seems to pass on the exit status from $() to the caller, while dash\n> >doesn't.  It seems bash is actually more correct here, because POSIX\n> >says about 'return [n]':\n> >\n> >     EXIT STATUS\n> >        The value of the special parameter '?' shall be set to n, an\n> >        unsigned decimal integer, or to the exit status of the last\n> >        command executed if n is not specified.\n> >\n> >Either way, it should simply be spelled as\n> >\n> >is_empty_commit() {\n> >\ttree=$(git rev-parse \"$1\"^{tree})\n> >\tptree=$(git rev-parse \"$1\"^^{tree})\n> >\ttest \"$tree\" = \"$ptree\"\n> >}\n> Yes, this change fixes the problem (all tests pass).\n> \n> Thanks!\n> \n> Zbyszek\n> \nOk, I'll update it.\nNeil\n"},{"id":"189714","messageId":"xmqq7gxbsj5e.fsf@junio.mtv.corp.google.com","threadId":"30112","inReplyTo":"20120419130818.GA18339@neilslaptop.think-freely.org","subject":"Re: [PATCH v6 4/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"jch@google.com","sentAt":"2012-04-19T17:53:17Z","receivedAt":"2012-04-19T17:53:17Z","isPatch":true,"sender":{"key":"jch@google.com","avatar":null},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n>> > +is_empty_commit() {\n>> > +\ttree=$(git rev-parse \"$1\"^{tree})\n>> > +\tptree=$(git rev-parse \"$1\"^^{tree})\n>> > +\treturn $(test \"$tree\" = \"$ptree\")\n>> > +}\n>> \n>> Could \"$1\" ever be a root commit without a parent?\n>> \n> Strictly speaking, yes.  If that happens, however, the output of git rev-parse\n\nYou do not have to speak strictly to see that bug that surfaces internal\nerror message leaking to the end user.\n"},{"id":"189721","messageId":"xmqqty0fv97w.fsf@junio.mtv.corp.google.com","threadId":"30112","inReplyTo":"873980q6vm.fsf@thomas.inf.ethz.ch","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"jch@google.com","sentAt":"2012-04-19T18:59:31Z","receivedAt":"2012-04-19T18:59:31Z","isPatch":true,"sender":{"key":"jch@google.com","avatar":null},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Either way, it should simply be spelled as\n>\n> is_empty_commit() {\n> \ttree=$(git rev-parse \"$1\"^{tree})\n> \tptree=$(git rev-parse \"$1\"^^{tree})\n> \ttest \"$tree\" = \"$ptree\"\n> }\n\nThanks; will squash in something like this:\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 82042b1..8fe304f 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -168,9 +168,10 @@ has_action () {\n }\n \n is_empty_commit() {\n-\ttree=$(git rev-parse \"$1\"^{tree})\n-\tptree=$(git rev-parse \"$1\"^^{tree})\n-\treturn $(test \"$tree\" = \"$ptree\")\n+\ttree=$(git rev-parse \"$1\"^{tree} 2>/dev/null) &&\n+\tptree=$(git rev-parse \"$1\"^^{tree} 2>/dev/null) ||\n+\t\tdie \"$1: not a commit that can be picked\"\n+\ttest \"$tree\" = \"$ptree\"\n }\n \n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n"},{"id":"189722","messageId":"xmqqpqb3v8x7.fsf@junio.mtv.corp.google.com","threadId":"30112","inReplyTo":"xmqqty0fv97w.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"jch@google.com","sentAt":"2012-04-19T19:05:56Z","receivedAt":"2012-04-19T19:05:56Z","isPatch":true,"sender":{"key":"jch@google.com","avatar":null},"body":"Junio C Hamano <jch@google.com> writes:\n\n> Thomas Rast <trast@student.ethz.ch> writes:\n>\n>> Either way, it should simply be spelled as\n>>\n>> is_empty_commit() {\n>> \ttree=$(git rev-parse \"$1\"^{tree})\n>> \tptree=$(git rev-parse \"$1\"^^{tree})\n>> \ttest \"$tree\" = \"$ptree\"\n>> }\n>\n> Thanks; will squash in something like this:\n> ...\n\nEhh, not like that.  But something like this, as we need to be able to\npick \"root\" (t3412 insists on it).\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 82042b1..de71543 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -168,9 +168,11 @@ has_action () {\n }\n \n is_empty_commit() {\n-\ttree=$(git rev-parse \"$1\"^{tree})\n-\tptree=$(git rev-parse \"$1\"^^{tree})\n-\treturn $(test \"$tree\" = \"$ptree\")\n+\ttree=$(git rev-parse \"$1\"^{tree} 2>/dev/null) ||\n+\t\tdie \"$1: not a commit that can be picked\"\n+\tptree=$(git rev-parse \"$1\"^^{tree} 2>/dev/null) ||\n+\t\tptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n+\ttest \"$tree\" = \"$ptree\"\n }\n \n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n"},{"id":"189743","messageId":"20120420103503.GA15966@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"xmqqpqb3v8x7.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH v7 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T10:35:03Z","receivedAt":"2012-04-20T10:35:03Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Thu, Apr 19, 2012 at 12:05:56PM -0700, Junio C Hamano wrote:\n> Junio C Hamano <jch@google.com> writes:\n> \n> > Thomas Rast <trast@student.ethz.ch> writes:\n> >\n> >> Either way, it should simply be spelled as\n> >>\n> >> is_empty_commit() {\n> >> \ttree=$(git rev-parse \"$1\"^{tree})\n> >> \tptree=$(git rev-parse \"$1\"^^{tree})\n> >> \ttest \"$tree\" = \"$ptree\"\n> >> }\n> >\n> > Thanks; will squash in something like this:\n> > ...\n> \n> Ehh, not like that.  But something like this, as we need to be able to\n> pick \"root\" (t3412 insists on it).\n> \n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 82042b1..de71543 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -168,9 +168,11 @@ has_action () {\n>  }\n>  \n>  is_empty_commit() {\n> -\ttree=$(git rev-parse \"$1\"^{tree})\n> -\tptree=$(git rev-parse \"$1\"^^{tree})\n> -\treturn $(test \"$tree\" = \"$ptree\")\n> +\ttree=$(git rev-parse \"$1\"^{tree} 2>/dev/null) ||\n> +\t\tdie \"$1: not a commit that can be picked\"\n> +\tptree=$(git rev-parse \"$1\"^^{tree} 2>/dev/null) ||\n> +\t\tptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n> +\ttest \"$tree\" = \"$ptree\"\n>  }\n>  \n>  # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n> \n\nWhat about this?\nis_empty_commit() {\n        tree=$(git rev-parse -q --verify \"$1\"^{tree})\n        ptree=$(git rev-parse -q --verify \"$1\"^^{tree})\n\n        # Note that if either rev-parse commands fail, the output \n        # of that command will be an empty string.  If that happens\n        # We should just return 0, to indicate the commit is non-empty\n        # and let the rest of the git rebase logic handle it.\n        if test  -z \"$tree\"  -o  -z \"$ptree\"\n        then\n                return 0\n        fi\n\n        return test \"$tree\" = \"$ptree\"\n}\n"},{"id":"189749","messageId":"1334932577-31232-1-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1333136922-12872-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v8 0/4] Enhance git-rebases flexibiilty in handling empty commits","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T14:36:13Z","receivedAt":"2012-04-20T14:36:13Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git's ability to handle empty commits is somewhat lacking, especially when\npreforming a rebase.  Nominally empty commits are undesireable entries, the \nresult of commits that are made empty by prior commits covering the same changs.\nBut occasionally, empty commits are useful to developers (e.g. inserting notes \ninto the development history without changing any code along the way).  In these\ncases its desireable to easily preserve empty commits during operations like \nrebases.\n\nThis patch series enhances git to do just that.  It adds two options to the \ngit-cherry-pick command, --allow-empty, which allows git cherry-pick to preserve\nan empty commit, even if the fast forward logic isn't applicable during the \noperation, and --keep-redundant-commits, which allows the user to also keep\ncommits that were made empty via conflict resolution.  It also enhances\ngit-rebase to add a --keep-empty option which enables rebases to preserve empty\ncommits. \n\nI've tested these operations out myself here and they work well for me\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n\n---\nChange notes:\n\nBased on version 1 feedback from this list, the following changes have been made\n\nV2)\n\t* Changed --keep-empty to --allow-empty in the git cherry-pick command\n\n\t* Converted run_git_commit to use argv_array\n\n\t* Updated cherry-pick --allow-empty description in man page\n\t\n\t* added ignore-if-made-empty option to git-cherry-pick\n\n\t* Added test to test suite to validate the new cherry-pick options\n\n\t* Updated git-rebase man page to be less verbose and more accurate in the\n\tdescription of the keep-empty option\n\n\t* squashed the addition of the keep-empty flag in git-rebase down to one\n\tcommit from 3\n\n\t* fixed up coding style in git-rebase script\n\n\t* Optimized detection of empty commits\n\n\t* Only augmented git-rebase-editor message if empty commits are\n\tpossible\n\t\nV3)\n\t* reversed the --ignore-if-empty-logic to by default only keep initially\n\tempty commits\n\n\t* replaced --ignore-if-empty with --keep-redundant-commits, to allow\n\tempty commits that are made empty via conflict resolution, in addition\n\tto commits that were created as empty\n\n\t* reworked is_original_commit_empty to be more efficient and portable\n\n\t* Misc sylistic and spelling cleanups\n\nV4)\n\t* Reverted the cherry-pick advice changes in V3 based on in-thread\n\tdiscussion\n\n\t* Rewrote my changes to is_original_commit_empty and run_git_commit to\n\tnot have to fork, making them more efficient.\n\nv5)\n\t* Additional help text clean up\n\t* Additional error checking added to run_git_commit code\n\t* Whitespace cleanup\n\t* Removed needed cache_tree freeing\n\t* Test case cleanup\n\t* Fixed regression in t3404 and t3416 - this turned out to be \n        a problem with the note that git rebase -i adds at the bottom\n\tof the rebase text.  It was inadvertently indented and caused the\n\ttest fake editor to misread the commit template.  The indentation \n\thas been corrected, and these two tests, as well as all the other\n\texpected tests pass now\n\nv6)\n\t* synced keeep-redundant-commits option and variable name\n\t* fixed up some comment terminology\n\t* minor newline cleanup\n\t* Removed some unneeded braces from test code\n\t* minor syntatic cleanup in rebase scripts\n\n\t* Refactored empty index checking to make run_git_commit more readable\n\tI was also going to change the logic so that it operated more like git\n\tcherry-pick did before the patchset, but Junio's comments made me think\n\tthe new logic was preferable.\n\nv7)\n\t* Fixed up forgotten comment_out changes requested in\n\tgit-rebase--interactive\n\n\t* Made changelog comment for keep-redundant-commits patch more verbose\n\tso that it was clear that default behavior was changing\n\n\t* further refinement of detection of redundant commits, making\n\tdo_pick_commit and run_git_commit more readable\n\nv8)\n\t* Fixed git-rebase--interactive so that is_empty_commit doesn't choke on\n\troot commit\n\n\t* Minor stylistic change to is_index_unchanged\n\n\t* Fixed is_empty_commit to test tree and ptree such that it works with\n\tshells other than bash\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n--\nTo unsubscribe from this list: send the line \"unsubscribe git\" in\nthe body of a message to majordomo@vger.kernel.org\nMore majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n"},{"id":"189752","messageId":"1334932577-31232-2-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334932577-31232-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v8 1/4] git-cherry-pick: add allow-empty option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T14:36:14Z","receivedAt":"2012-04-20T14:36:14Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"git cherry-pick fails when picking a non-ff commit that is empty.  The advice\ngiven with the failure is that a git-commit --allow-empty should be issued to\nexplicitly add the empty commit during the cherry pick.  This option allows a\nuser to specify before hand that they want to keep the empty commit.  This\neliminates the need to issue both a cherry pick and a commit operation.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |    9 +++++++++\n builtin/revert.c                  |    2 ++\n sequencer.c                       |    7 +++++--\n sequencer.h                       |    1 +\n 4 files changed, 17 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex fed5097..730237a 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -103,6 +103,15 @@ effect to your index in a row.\n \tcherry-pick'ed commit, then a fast forward to this commit will\n \tbe performed.\n \n+--allow-empty::\n+\tBy default, cherry-picking an empty commit will fail,\n+\tindicating that an explicit invocation of `git commit\n+\t--allow-empty` is required. This option overrides that\n+\tbehavior, allowing empty commits to be preserved automatically\n+\tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n+\tcommits that meet the \"fast-forward\" requirement will be kept\n+\teven without this option.\n+\n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\n \tSee the MERGE STRATEGIES section in linkgit:git-merge[1]\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex e6840f2..06b00e6 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -114,12 +114,14 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\ndiff --git a/sequencer.c b/sequencer.c\nindex a37846a..71929ba 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -260,8 +260,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 6 is max possible length of our args array including NULL */\n-\tconst char *args[6];\n+\t/* 7 is max possible length of our args array including NULL */\n+\tconst char *args[7];\n \tint i = 0;\n \n \targs[i++] = \"commit\";\n@@ -272,6 +272,9 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n \t\targs[i++] = \"-F\";\n \t\targs[i++] = defmsg;\n \t}\n+\tif (opts->allow_empty)\n+\t\targs[i++] = \"--allow-empty\";\n+\n \targs[i] = NULL;\n \n \treturn run_command_v_opt(args, RUN_GIT_CMD);\ndiff --git a/sequencer.h b/sequencer.h\nindex bb4b138..e2cd725 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -29,6 +29,7 @@ struct replay_opts {\n \tint signoff;\n \tint allow_ff;\n \tint allow_rerere_auto;\n+\tint allow_empty;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189753","messageId":"1334932577-31232-3-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334932577-31232-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T14:36:15Z","receivedAt":"2012-04-20T14:36:15Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"The git-cherry-pick --allow-empty command by default only preserves empty\ncommits that were originally empty, i.e only those commits for which\n<commit>^{tree} and <commit>^^{tree} are equal.  By default commits which are\nnon-empty, but were made empty by the inclusion of a prior commit on the current\nhistory are filtered out.  This option allows us to override that behavior and\ninclude redundant commits as empty commits in the change history.\n\nNote that this patch changes the default behavior of git cherry-pick slightly.\nPrior to this patch all commits in a cherry-pick sequence were applied and git\ncommit was run.  The implication here was that, if a commit was redundant, and\nthe commit did not trigger the fast forward logic, the git commit operation, and\ntherefore the git cherry-pick operation would fail, displaying the cherry pick\nadvice (i.e. run git commit --allow-empty).  With this patch however, such\nredundant commits are automatically skipped without stopping, unless\n--keep-redundant-commits is specified, in which case, they are automatically\napplied as empty commits.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-cherry-pick.txt |   12 ++++-\n builtin/revert.c                  |    8 +++-\n sequencer.c                       |   94 ++++++++++++++++++++++++++++++++----\n sequencer.h                       |    1 +\n 4 files changed, 102 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 730237a..0c004e9 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -110,7 +110,17 @@ effect to your index in a row.\n \tbehavior, allowing empty commits to be preserved automatically\n \tin a cherry-pick. Note that when \"--ff\" is in effect, empty\n \tcommits that meet the \"fast-forward\" requirement will be kept\n-\teven without this option.\n+\teven without this option.  Note also, that use of this option only\n+\tkeeps commits that were initially empty (i.e. the commit recorded the\n+\tsame tree as its parent).  Commits which are made empty due to a\n+\tprevious commit are ignored.  To force the inclusion of those commits\n+\tuse `--keep-redundant-commits`.\n+\n+--keep-redundant-commits::\n+\tIf a commit being cherry picked duplicates a commit already in the\n+\tcurrent history, it will result in an empty changeset.  By default these\n+\tredundant commits are ignored.  This option overrides that behavior and\n+\tcreates an empty commit object.  Implies `--allow-empty`.\n \n --strategy=<strategy>::\n \tUse the given merge strategy.  Should only be used once.\ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex 06b00e6..f135502 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -115,13 +115,15 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\tOPT_END(),\n \t\tOPT_END(),\n \t\tOPT_END(),\n+\t\tOPT_END(),\n \t};\n \n \tif (opts->action == REPLAY_PICK) {\n \t\tstruct option cp_extra[] = {\n \t\t\tOPT_BOOLEAN('x', NULL, &opts->record_origin, \"append commit name\"),\n \t\t\tOPT_BOOLEAN(0, \"ff\", &opts->allow_ff, \"allow fast-forward\"),\n-\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"allow-empty\", &opts->allow_empty, \"preserve initially empty commits\"),\n+\t\t\tOPT_BOOLEAN(0, \"keep-redundant-commits\", &opts->keep_redundant_commits, \"keep redundant, empty commits\"),\n \t\t\tOPT_END(),\n \t\t};\n \t\tif (parse_options_concat(options, ARRAY_SIZE(options), cp_extra))\n@@ -139,6 +141,10 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n+\t/* keep_if_made_empty implies allow_empty */\n+\tif (opts->keep_redundant_commits)\n+\t\topts->allow_empty = 1;\n+\n \t/* Set the subcommand */\n \tif (remove_state)\n \t\topts->subcommand = REPLAY_REMOVE_STATE;\ndiff --git a/sequencer.c b/sequencer.c\nindex 71929ba..4e3af82 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -13,6 +13,7 @@\n #include \"rerere.h\"\n #include \"merge-recursive.h\"\n #include \"refs.h\"\n+#include \"argv-array.h\"\n \n #define GIT_REFLOG_ACTION \"GIT_REFLOG_ACTION\"\n \n@@ -251,6 +252,30 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n \treturn !clean;\n }\n \n+static int is_index_unchanged(void)\n+{\n+\tunsigned char head_sha1[20];\n+\tstruct commit *head_commit;\n+\n+\tif (!resolve_ref_unsafe(\"HEAD\", head_sha1, 1, NULL))\n+\t\treturn error(_(\"Could not resolve HEAD commit\\n\"));\n+\n+\thead_commit = lookup_commit(head_sha1);\n+\tif (!head_commit || parse_commit(head_commit))\n+\t\treturn error(_(\"could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(head_commit->object.sha1));\n+\n+\tif (!active_cache_tree)\n+\t\tactive_cache_tree = cache_tree();\n+\n+\tif (!cache_tree_fully_valid(active_cache_tree))\n+\t\tif (cache_tree_update(active_cache_tree, active_cache,\n+\t\t\t\t  active_nr, 0))\n+\t\t\treturn error(_(\"Unable to update cache tree\\n\"));\n+\n+\treturn !hashcmp(active_cache_tree->sha1, head_commit->tree->object.sha1);\n+}\n+\n /*\n  * If we are cherry-pick, and if the merge did not result in\n  * hand-editing, we will hit this commit and inherit the original\n@@ -260,24 +285,46 @@ static int do_recursive_merge(struct commit *base, struct commit *next,\n  */\n static int run_git_commit(const char *defmsg, struct replay_opts *opts)\n {\n-\t/* 7 is max possible length of our args array including NULL */\n-\tconst char *args[7];\n-\tint i = 0;\n+\tstruct argv_array array;\n+\tint rc;\n+\n+\targv_array_init(&array);\n+\targv_array_push(&array, \"commit\");\n+\targv_array_push(&array, \"-n\");\n \n-\targs[i++] = \"commit\";\n-\targs[i++] = \"-n\";\n \tif (opts->signoff)\n-\t\targs[i++] = \"-s\";\n+\t\targv_array_push(&array, \"-s\");\n \tif (!opts->edit) {\n-\t\targs[i++] = \"-F\";\n-\t\targs[i++] = defmsg;\n+\t\targv_array_push(&array, \"-F\");\n+\t\targv_array_push(&array, defmsg);\n \t}\n+\n \tif (opts->allow_empty)\n-\t\targs[i++] = \"--allow-empty\";\n+\t\targv_array_push(&array, \"--allow-empty\");\n \n-\targs[i] = NULL;\n+\trc = run_command_v_opt(array.argv, RUN_GIT_CMD);\n+\targv_array_clear(&array);\n+\treturn rc;\n+}\n+\n+static int is_original_commit_empty(struct commit *commit)\n+{\n+\tconst unsigned char *ptree_sha1;\n+\n+\tif (parse_commit(commit))\n+\t\treturn error(_(\"Could not parse commit %s\\n\"),\n+\t\t\t     sha1_to_hex(commit->object.sha1));\n+\tif (commit->parents) {\n+\t\tstruct commit *parent = commit->parents->item;\n+\t\tif (parse_commit(parent))\n+\t\t\treturn error(_(\"Could not parse parent commit %s\\n\"),\n+\t\t\t\tsha1_to_hex(parent->object.sha1));\n+\t\tptree_sha1 = parent->tree->object.sha1;\n+\t} else {\n+\t\tptree_sha1 = EMPTY_TREE_SHA1_BIN; /* commit is root */\n+\t}\n \n-\treturn run_command_v_opt(args, RUN_GIT_CMD);\n+\treturn !hashcmp(ptree_sha1, commit->tree->object.sha1);\n }\n \n static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n@@ -289,6 +336,8 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \tchar *defmsg = NULL;\n \tstruct strbuf msgbuf = STRBUF_INIT;\n \tint res;\n+\tint empty_commit;\n+\tint index_unchanged;\n \n \tif (opts->no_commit) {\n \t\t/*\n@@ -414,6 +463,10 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tfree_commit_list(remotes);\n \t}\n \n+\tempty_commit = is_original_commit_empty(commit);\n+\tif (empty_commit < 0)\n+\t\treturn empty_commit;\n+\n \t/*\n \t * If the merge was clean or if it failed due to conflict, we write\n \t * CHERRY_PICK_HEAD for the subsequent invocation of commit to use.\n@@ -434,6 +487,25 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)\n \t\tprint_advice(res == 1, opts);\n \t\trerere(opts->allow_rerere_auto);\n \t} else {\n+\t\tindex_unchanged = is_index_unchanged();\n+\t\t/*\n+\t\t * If index_unchanged is less than 0, that indicates we either\n+\t\t * couldn't parse HEAD or the index, so error out here.\n+\t\t */\n+\t\tif (index_unchanged < 0)\n+\t\t\treturn index_unchanged;\n+\n+\t\tif (!empty_commit && !opts->keep_redundant_commits && index_unchanged)\n+\t\t\t/*\n+\t\t\t * The head tree and the index match\n+\t\t\t * meaning the commit is empty.  Since it wasn't created\n+\t\t\t * empty (based on the previous test), we can conclude\n+\t\t\t * the commit has been made redundant.  Since we don't\n+\t\t\t * want to keep redundant commits, we can just return\n+\t\t\t * here, skipping this commit\n+\t\t\t */\n+\t\t\treturn 0;\n+\n \t\tif (!opts->no_commit)\n \t\t\tres = run_git_commit(defmsg, opts);\n \t}\ndiff --git a/sequencer.h b/sequencer.h\nindex e2cd725..aa5f17c 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -30,6 +30,7 @@ struct replay_opts {\n \tint allow_ff;\n \tint allow_rerere_auto;\n \tint allow_empty;\n+\tint keep_redundant_commits;\n \n \tint mainline;\n \n-- \n1.7.7.6\n"},{"id":"189751","messageId":"1334932577-31232-4-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334932577-31232-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v8 3/4] git-cherry-pick: Add test to validate new options","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T14:36:16Z","receivedAt":"2012-04-20T14:36:16Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Since we've added the --allow-empty and --keep-redundant-commits\noptions to git cherry-pick we should also add a test to ensure that its working\nproperly.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n t/t3505-cherry-pick-empty.sh |   25 ++++++++++++++++++++++++-\n 1 files changed, 24 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex c10b28c..d513127 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -18,7 +18,12 @@ test_expect_success setup '\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n-\tgit commit --allow-empty-message -m \"\"\n+\tgit commit --allow-empty-message -m \"\" &&\n+\n+\tgit checkout master &&\n+\tgit checkout -b empty-branch2 &&\n+\ttest_tick &&\n+\tgit commit --allow-empty -m \"empty\"\n \n '\n \n@@ -48,4 +53,22 @@ test_expect_success 'index lockfile was removed' '\n \n '\n \n+test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n+\tgit checkout master &&\n+\techo fourth >> file2 &&\n+\tgit add file2 &&\n+\tgit commit -m \"fourth\" &&\n+\ttest_must_fail git cherry-pick empty-branch2\n+'\n+\n+test_expect_success 'cherry pick an empty non-ff commit with --allow-empty' '\n+\tgit checkout master &&\n+\tgit cherry-pick --allow-empty empty-branch2\n+'\n+\n+test_expect_success 'cherry pick with --keep-redundant-commits' '\n+\tgit checkout master &&\n+\tgit cherry-pick --keep-redundant-commits HEAD^\n+'\n+\n test_done\n-- \n1.7.7.6\n"},{"id":"189750","messageId":"1334932577-31232-5-git-send-email-nhorman@tuxdriver.com","threadId":"30112","inReplyTo":"1334932577-31232-1-git-send-email-nhorman@tuxdriver.com","subject":"[PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T14:36:17Z","receivedAt":"2012-04-20T14:36:17Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"Add a command line switch to git-rebase to allow a user the ability to specify\nthat they want to keep any commits in a series that are empty.\n\nWhen git-rebase's type is am, then this option will automatically keep any\ncommit that has a tree object identical to its parent.\n\nThis patch changes the default behavior of interactive rebases as well.  With\nthis patch, git-rebase -i will produce a revision set passed to\ngit-revision-editor, in which empty commits are commented out.  Empty commits\nmay be kept manually by uncommenting them.  If the new --keep-empty option is\nused in an interactive rebase the empty commits will automatically all be\nuncommented in the editor.\n\nSigned-off-by: Neil Horman <nhorman@tuxdriver.com>\n---\n Documentation/git-rebase.txt |    4 ++++\n git-rebase--am.sh            |   19 ++++++++++++++-----\n git-rebase--interactive.sh   |   36 +++++++++++++++++++++++++++++++++---\n git-rebase.sh                |    5 +++++\n 4 files changed, 56 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 504945c..131c35d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+--keep-empty::\n+\tKeep the commits that do not change anything from its\n+\tparents in the result.\n+\n --skip::\n \tRestart the rebasing process by skipping the current patch.\n \ndiff --git a/git-rebase--am.sh b/git-rebase--am.sh\nindex c815a24..04d8941 100644\n--- a/git-rebase--am.sh\n+++ b/git-rebase--am.sh\n@@ -20,11 +20,20 @@ esac\n \n test -n \"$rebase_root\" && root_flag=--root\n \n-git format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t--src-prefix=a/ --dst-prefix=b/ \\\n-\t--no-renames $root_flag \"$revisions\" |\n-git am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\" &&\n-move_to_original_branch\n+if test -n \"$keep_empty\"\n+then\n+\t# we have to do this the hard way.  git format-patch completely squashes\n+\t# empty commits and even if it didn't the format doesn't really lend\n+\t# itself well to recording empty patches.  fortunately, cherry-pick\n+\t# makes this easy\n+\tgit cherry-pick --allow-empty \"$revisions\"\n+else\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t--src-prefix=a/ --dst-prefix=b/ \\\n+\t\t--no-renames $root_flag \"$revisions\" |\n+\tgit am $git_am_opt --rebasing --resolvemsg=\"$resolvemsg\"\n+fi && move_to_original_branch\n+\n ret=$?\n test 0 != $ret -a -d \"$state_dir\" && write_basic_state\n exit $ret\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 5812222..ef263e0 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -167,6 +167,15 @@ has_action () {\n \tsane_grep '^[^#]' \"$1\" >/dev/null\n }\n \n+is_empty_commit() {\n+\ttree=$(git rev-parse -q --verify \"$1\"^{tree} 2>/dev/null ||\n+\t\tdie \"$1: not a commit that can be picked\")\n+\tptree=$(git rev-parse -q --verify \"$1\"^^{tree} 2>/dev/null ||\n+\t\tptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)\n+\n+\treturn test \"$tree\" = \"$ptree\"\n+}\n+\n # Run command with GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, and\n # GIT_AUTHOR_DATE exported from the current environment.\n do_with_author () {\n@@ -191,12 +200,19 @@ git_sequence_editor () {\n \n pick_one () {\n \tff=--ff\n+\n \tcase \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n \tcase \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n+\n+\tif is_empty_commit \"$sha1\"\n+\tthen\n+\t\tempty_args=\"--allow-empty\"\n+\tfi\n+\n \ttest -d \"$rewritten\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n-\toutput git cherry-pick $ff \"$@\"\n+\toutput git cherry-pick $empty_args $ff \"$@\"\n }\n \n pick_one_preserving_merges () {\n@@ -780,9 +796,17 @@ git rev-list $merges_option --pretty=oneline --abbrev-commit \\\n \tsed -n \"s/^>//p\" |\n while read -r shortsha1 rest\n do\n+\n+\tif test -z \"$keep_empty\" && is_empty_commit $shortsha1\n+\tthen\n+\t\tcomment_out=\"#\"\n+\telse\n+\t\tcomment_out=\"\"\n+\tfi\n+\n \tif test t != \"$preserve_merges\"\n \tthen\n-\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\tprintf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n \telse\n \t\tsha1=$(git rev-parse $shortsha1)\n \t\tif test -z \"$rebase_root\"\n@@ -801,7 +825,7 @@ do\n \t\tif test f = \"$preserve\"\n \t\tthen\n \t\t\ttouch \"$rewritten\"/$sha1\n-\t\t\tprintf '%s\\n' \"pick $shortsha1 $rest\" >> \"$todo\"\n+\t\t\tprintf '%s%s\\n' \"$comment_out\" \"pick $shortsha1 $rest\" >> \"$todo\"\n \t\tfi\n \tfi\n done\n@@ -851,6 +875,12 @@ cat >> \"$todo\" << EOF\n #\n EOF\n \n+if test -z \"$keep_empty\"\n+then\n+\techo \"# Note that empty commits are commented out\" >> \"$todo\"\n+fi\n+\n+\n has_action \"$todo\" ||\n \tdie_abort \"Nothing to do\"\n \ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 69c1374..24a2840 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -43,6 +43,7 @@ s,strategy=!       use the given merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n+k,keep-empty\t   preserve empty commits during rebase\n f,force-rebase!    force rebase even if branch is up to date\n X,strategy-option=! pass the argument through to the merge strategy\n stat!              display a diffstat of what changed upstream\n@@ -97,6 +98,7 @@ state_dir=\n action=\n preserve_merges=\n autosquash=\n+keep_empty=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n \n read_basic_state () {\n@@ -220,6 +222,9 @@ do\n \t-i)\n \t\tinteractive_rebase=explicit\n \t\t;;\n+\t-k)\n+\t\tkeep_empty=yes\n+\t\t;;\n \t-p)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-- \n1.7.7.6\n"},{"id":"189771","messageId":"xmqqvckumcoq.fsf@junio.mtv.corp.google.com","threadId":"30112","inReplyTo":"1334932577-31232-3-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-20T19:21:41Z","receivedAt":"2012-04-20T19:21:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Looks good, modulo perhaps these fixes on top.\n\n - It would be better to say \"dropped\" to stress that we inspect and\n   actively discard, instead of saying \"ignored\".\n\n - There is no need to use \"changeset\", the term glossary even\n   discourages, to make sense of the sentence.\n\n - There was still a stray keep_if_made_empty.\n\n - s/Add keep/add keep/ on the title as well.\n\nNo need to resend, unless you have fixes other than the following does.\n\ndiff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt\nindex 0c004e9..3d25a20 100644\n--- a/Documentation/git-cherry-pick.txt\n+++ b/Documentation/git-cherry-pick.txt\n@@ -113,12 +113,12 @@ effect to your index in a row.\n \teven without this option.  Note also, that use of this option only\n \tkeeps commits that were initially empty (i.e. the commit recorded the\n \tsame tree as its parent).  Commits which are made empty due to a\n-\tprevious commit are ignored.  To force the inclusion of those commits\n+\tprevious commit are dropped.  To force the inclusion of those commits\n \tuse `--keep-redundant-commits`.\n \n --keep-redundant-commits::\n \tIf a commit being cherry picked duplicates a commit already in the\n-\tcurrent history, it will result in an empty changeset.  By default these\n+\tcurrent history, it will become empty.  By default these\n \tredundant commits are ignored.  This option overrides that behavior and\n \tcreates an empty commit object.  Implies `--allow-empty`.\n \ndiff --git a/builtin/revert.c b/builtin/revert.c\nindex f135502..b0b9b1a 100644\n--- a/builtin/revert.c\n+++ b/builtin/revert.c\n@@ -141,7 +141,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)\n \t\t\t\t\"--abort\", rollback,\n \t\t\t\tNULL);\n \n-\t/* keep_if_made_empty implies allow_empty */\n+\t/* implies allow_empty */\n \tif (opts->keep_redundant_commits)\n \t\topts->allow_empty = 1;\n \n"},{"id":"189773","messageId":"20120420195634.GE15966@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"xmqqvckumcoq.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH v8 2/4] git-cherry-pick: Add keep-redundant-commits option","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-20T19:56:34Z","receivedAt":"2012-04-20T19:56:34Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Fri, Apr 20, 2012 at 12:21:41PM -0700, Junio C Hamano wrote:\n> Looks good, modulo perhaps these fixes on top.\n> \n>  - It would be better to say \"dropped\" to stress that we inspect and\n>    actively discard, instead of saying \"ignored\".\n> \n>  - There is no need to use \"changeset\", the term glossary even\n>    discourages, to make sense of the sentence.\n> \n>  - There was still a stray keep_if_made_empty.\n> \n>  - s/Add keep/add keep/ on the title as well.\n> \n> No need to resend, unless you have fixes other than the following does.\n> \nNope I'm good, if you can work those changes in.  Thanks!\nNeil\n\n> \n"},{"id":"190042","messageId":"xmqqipgoeewl.fsf@junio.mtv.corp.google.com","threadId":"30112","inReplyTo":"1334932577-31232-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-04-25T01:50:26Z","receivedAt":"2012-04-25T01:50:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Neil Horman <nhorman@tuxdriver.com> writes:\n\n> Add a command line switch to git-rebase to allow a user the ability to specify\n> that they want to keep any commits in a series that are empty.\n> ...\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 5812222..ef263e0 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -167,6 +167,15 @@ has_action () {\n>  \tsane_grep '^[^#]' \"$1\" >/dev/null\n>  }\n>  \n> +is_empty_commit() {\n> +\ttree=$(git rev-parse -q --verify \"$1\"^{tree} 2>/dev/null ||\n> +\t\tdie \"$1: not a commit that can be picked\")\n> +\tptree=$(git rev-parse -q --verify \"$1\"^^{tree} 2>/dev/null ||\n> +\t\tptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)\n> +\n> +\treturn test \"$tree\" = \"$ptree\"\n> +}\n\nI've amended the above and removed \"return \" from the last line.\n\nThe series is now in 'next', so if we need further enhancement or fixup,\nthey need to come as incremental updates, not as replacements.\n\nThanks.\n"},{"id":"190049","messageId":"20120425103828.GA18895@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"xmqqipgoeewl.fsf@junio.mtv.corp.google.com","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-04-25T10:38:28Z","receivedAt":"2012-04-25T10:38:28Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Tue, Apr 24, 2012 at 06:50:26PM -0700, Junio C Hamano wrote:\n> Neil Horman <nhorman@tuxdriver.com> writes:\n> \n> > Add a command line switch to git-rebase to allow a user the ability to specify\n> > that they want to keep any commits in a series that are empty.\n> > ...\n> > diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> > index 5812222..ef263e0 100644\n> > --- a/git-rebase--interactive.sh\n> > +++ b/git-rebase--interactive.sh\n> > @@ -167,6 +167,15 @@ has_action () {\n> >  \tsane_grep '^[^#]' \"$1\" >/dev/null\n> >  }\n> >  \n> > +is_empty_commit() {\n> > +\ttree=$(git rev-parse -q --verify \"$1\"^{tree} 2>/dev/null ||\n> > +\t\tdie \"$1: not a commit that can be picked\")\n> > +\tptree=$(git rev-parse -q --verify \"$1\"^^{tree} 2>/dev/null ||\n> > +\t\tptree=4b825dc642cb6eb9a060e54bf8d69288fbee4904)\n> > +\n> > +\treturn test \"$tree\" = \"$ptree\"\n> > +}\n> \n> I've amended the above and removed \"return \" from the last line.\n> \n> The series is now in 'next', so if we need further enhancement or fixup,\n> they need to come as incremental updates, not as replacements.\n> \n> Thanks.\n> \nFastastic, thank you!\nNeil\n"},{"id":"195248","messageId":"CAOeW2eEchYzRYYUBySKg5xYY3vBDy8GVcAd=ay-HoAGDLZtORw@mail.gmail.com","threadId":"30112","inReplyTo":"1334932577-31232-5-git-send-email-nhorman@tuxdriver.com","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Martin von Zweigbergk","fromEmail":"martin.von.zweigbergk@gmail.com","sentAt":"2012-07-18T06:20:51Z","receivedAt":"2012-07-18T06:20:51Z","isPatch":true,"sender":{"key":"martinvonz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:\n>  pick_one () {\n>         ff=--ff\n> +\n>         case \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n>         case \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n>         output git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n> +\n> +       if is_empty_commit \"$sha1\"\n> +       then\n> +               empty_args=\"--allow-empty\"\n> +       fi\n> +\n>         test -d \"$rewritten\" &&\n>                 pick_one_preserving_merges \"$@\" && return\n> -       output git cherry-pick $ff \"$@\"\n> +       output git cherry-pick $empty_args $ff \"$@\"\n\nThe is_empty_commit check seems to mean that if $sha1 is an \"empty\"\ncommit, we pass the --allow-empty option to cherry-pick. If it's not\nempty, we don't. The word \"allow\" in \"allow-empty\" suggests that even\nif the commit is not empty, cherry-pick would not mind. So, can we\nalways pass \"allow-empty\" to cherry-pick (i.e. even if the commit to\npick is not empty)?\n\nSorry I'm commenting so late; I didn't have time to look at your\npatches when you sent them, but I'm currently working on the code\ntouched by this patch.\n"},{"id":"195251","messageId":"5006614E.8090601@viscovery.net","threadId":"30112","inReplyTo":"CAOeW2eEchYzRYYUBySKg5xYY3vBDy8GVcAd=ay-HoAGDLZtORw@mail.gmail.com","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2012-07-18T07:10:06Z","receivedAt":"2012-07-18T07:10:06Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:\n> On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:\n>>  pick_one () {\n>>         ff=--ff\n>> +\n>>         case \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n>>         case \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n>>         output git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n>> +\n>> +       if is_empty_commit \"$sha1\"\n>> +       then\n>> +               empty_args=\"--allow-empty\"\n>> +       fi\n>> +\n>>         test -d \"$rewritten\" &&\n>>                 pick_one_preserving_merges \"$@\" && return\n>> -       output git cherry-pick $ff \"$@\"\n>> +       output git cherry-pick $empty_args $ff \"$@\"\n> \n> The is_empty_commit check seems to mean that if $sha1 is an \"empty\"\n> commit, we pass the --allow-empty option to cherry-pick. If it's not\n> empty, we don't. The word \"allow\" in \"allow-empty\" suggests that even\n> if the commit is not empty, cherry-pick would not mind. So, can we\n> always pass \"allow-empty\" to cherry-pick (i.e. even if the commit to\n> pick is not empty)?\n\nI don't think so. If the commit is not empty, but all its changes are\nalready in HEAD, then it will become \"empty\" when cherry-picked to HEAD.\nIn such a case, we usually do not want to record an empty commit, but stop\nrebase to give to user a chance to deal with the situation.\n\n-- Hannes\n"},{"id":"195252","messageId":"CAOeW2eHvDMkX++L386aXaUsMPVbmL-9GvioiUAPGX8PjJ8TNTA@mail.gmail.com","threadId":"30112","inReplyTo":"5006614E.8090601@viscovery.net","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Martin von Zweigbergk","fromEmail":"martin.von.zweigbergk@gmail.com","sentAt":"2012-07-18T07:16:47Z","receivedAt":"2012-07-18T07:16:47Z","isPatch":true,"sender":{"key":"martinvonz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"On Wed, Jul 18, 2012 at 12:10 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:\n>> On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:\n>>>  pick_one () {\n>>>         ff=--ff\n>>> +\n>>>         case \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n>>>         case \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n>>>         output git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n>>> +\n>>> +       if is_empty_commit \"$sha1\"\n>>> +       then\n>>> +               empty_args=\"--allow-empty\"\n>>> +       fi\n>>> +\n>>>         test -d \"$rewritten\" &&\n>>>                 pick_one_preserving_merges \"$@\" && return\n>>> -       output git cherry-pick $ff \"$@\"\n>>> +       output git cherry-pick $empty_args $ff \"$@\"\n>>\n>> The is_empty_commit check seems to mean that if $sha1 is an \"empty\"\n>> commit, we pass the --allow-empty option to cherry-pick. If it's not\n>> empty, we don't. The word \"allow\" in \"allow-empty\" suggests that even\n>> if the commit is not empty, cherry-pick would not mind. So, can we\n>> always pass \"allow-empty\" to cherry-pick (i.e. even if the commit to\n>> pick is not empty)?\n>\n> I don't think so. If the commit is not empty, but all its changes are\n> already in HEAD, then it will become \"empty\" when cherry-picked to HEAD.\n> In such a case, we usually do not want to record an empty commit, but stop\n> rebase to give to user a chance to deal with the situation.\n\nAh, makes sense. Thanks!\n"},{"id":"195277","messageId":"20120718121758.GA25563@hmsreliant.think-freely.org","threadId":"30112","inReplyTo":"5006614E.8090601@viscovery.net","subject":"Re: [PATCH v8 4/4] git-rebase: add keep_empty flag","fromName":"Neil Horman","fromEmail":"nhorman@tuxdriver.com","sentAt":"2012-07-18T12:17:58Z","receivedAt":"2012-07-18T12:17:58Z","isPatch":true,"sender":{"key":"nhorman@tuxdriver.com","avatar":"https://avatars.githubusercontent.com/u/1032926?v=4"},"body":"On Wed, Jul 18, 2012 at 09:10:06AM +0200, Johannes Sixt wrote:\n> Am 7/18/2012 8:20, schrieb Martin von Zweigbergk:\n> > On Fri, Apr 20, 2012 at 7:36 AM, Neil Horman <nhorman@tuxdriver.com> wrote:\n> >>  pick_one () {\n> >>         ff=--ff\n> >> +\n> >>         case \"$1\" in -n) sha1=$2; ff= ;; *) sha1=$1 ;; esac\n> >>         case \"$force_rebase\" in '') ;; ?*) ff= ;; esac\n> >>         output git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n> >> +\n> >> +       if is_empty_commit \"$sha1\"\n> >> +       then\n> >> +               empty_args=\"--allow-empty\"\n> >> +       fi\n> >> +\n> >>         test -d \"$rewritten\" &&\n> >>                 pick_one_preserving_merges \"$@\" && return\n> >> -       output git cherry-pick $ff \"$@\"\n> >> +       output git cherry-pick $empty_args $ff \"$@\"\n> > \n> > The is_empty_commit check seems to mean that if $sha1 is an \"empty\"\n> > commit, we pass the --allow-empty option to cherry-pick. If it's not\n> > empty, we don't. The word \"allow\" in \"allow-empty\" suggests that even\n> > if the commit is not empty, cherry-pick would not mind. So, can we\n> > always pass \"allow-empty\" to cherry-pick (i.e. even if the commit to\n> > pick is not empty)?\n> \n> I don't think so. If the commit is not empty, but all its changes are\n> already in HEAD, then it will become \"empty\" when cherry-picked to HEAD.\n> In such a case, we usually do not want to record an empty commit, but stop\n> rebase to give to user a chance to deal with the situation.\n> \n> -- Hannes\n> \n\nYes, this is the meaning.  \"Allow\" was used in the sense of a filter, in that we\nare allowing an empty commit to make it into the history, whereas a rebase or\ncherry-pick would normally exclude it.\nNeil\n"}]}