{"thread":{"id":"41012","subject":"(unknown)","startedAt":"2015-12-16T03:02:45Z","lastAt":"2015-12-18T17:35:23Z","messageCount":5,"participants":["David Greene","Junio C Hamano","Patrick Steinhardt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"274544","messageId":"1450234966-28796-1-git-send-email-greened@obbligato.org","threadId":"41012","inReplyTo":null,"subject":"(unknown)","fromName":"David Greene","fromEmail":"greened@obbligato.org","sentAt":"2015-12-16T03:02:45Z","receivedAt":"2015-12-16T03:02:45Z","isPatch":false,"sender":{"key":"greened@obbligato.org","avatar":"https://avatars.githubusercontent.com/u/5291869?v=4"},"body":"\nThis patch isn't ready for prime-time yet but I wanted to get it out\nfor some discussion.\n\nWhile cleaning up and enhancing git-subtree, I've come across the\nneed to have rebase behave nicely in the case of empty and redundant\ncommits.  There's a case in pick_one_preserving_merges where\ngit-cherry pick is used to process the rebase and if cherry-pick\nfails, the rebase aborts.  This change does two things:\n\n- If --keep-empty is specified, invoke cherry-pick with --allow-empty.\n\n- If new option --keep-redundant is specified, invoke cherry-pick with\n  --keep-redundant-commits.\n\nThis allows the rebase to go forward without intrruption in the\nincluded tests.\n\nI will also need a third option that has cherry-pick ignore redundant\ncommits and remove them from the history.  Unfortunately, I can't\nmake out exactly how to do that in commit.c, which is where I gather\nthe cherry-pick stuff happens.  I'll need some help with that if\nthere's general agreement that this is a useful enhancement.\n\nDuring the course of developing this, I've encountered some\nstrange rebase behavior.  I'll send another message about that.\n\nI'd appreciate feedback on this direction and any help with the\ncherry-pick stuff.  Thanks!\n\n                         -David\n"},{"id":"274545","messageId":"1450234966-28796-2-git-send-email-greened@obbligato.org","threadId":"41012","inReplyTo":"1450234966-28796-1-git-send-email-greened@obbligato.org","subject":"[PATCH] Support rebase --keep-empty and --keep-redundant","fromName":"David Greene","fromEmail":"greened@obbligato.org","sentAt":"2015-12-16T03:02:46Z","receivedAt":"2015-12-16T03:02:46Z","isPatch":true,"sender":{"key":"greened@obbligato.org","avatar":"https://avatars.githubusercontent.com/u/5291869?v=4"},"body":"From: \"David A. Greene\" <greened@obbligato.org>\n\nTeach rebase how to invoke cherry-pick to keep empty commits.\n\nAdd a new option --keep-redundant equivalent to cherry-pick's\n--keep-redundant-commits.  With this option, rebase will\npreserve empty commits generated as a result of the merging\nprocess.\n\nSigned-off-by: David A. Greene <greened@obbligato.org>\n---\n git-rebase--interactive.sh |  11 +++-\n git-rebase.sh              |   5 ++\n t/t3427-rebase-empty.sh    | 127 +++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 142 insertions(+), 1 deletion(-)\n create mode 100755 t/t3427-rebase-empty.sh\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex b938a6d..8466cb9 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -393,7 +393,16 @@ pick_one_preserving_merges () {\n \t\t\techo \"$sha1 $(git rev-parse HEAD^0)\" >> \"$rewritten_list\"\n \t\t\t;;\n \t\t*)\n-\t\t\toutput eval git cherry-pick \\\n+\t\t\tcherry_keep_empty=\n+\t\t\tif test -n \"$keep_empty\"; then\n+\t\t\t\tcherry_keep_empty=\"--allow-empty\"\n+\t\t\tfi\n+\t\t\tcherry_keep_redundant=\n+\t\t\tif test -n \"$keep_redundant\"; then\n+\t\t\t\tcherry_keep_redundant=\"--keep-redundant-commits\"\n+\t\t\tfi\n+\t\t\toutput eval git cherry-pick \"$cherry_keep_empty\" \\\n+\t\t\t\t\"$cherry_keep_redundant\" \\\n \t\t\t\t${gpg_sign_opt:+$(git rev-parse --sq-quote \"$gpg_sign_opt\")} \\\n \t\t\t\t\"$strategy_args\" \"$@\" ||\n \t\t\t\tdie_with_patch $sha1 \"Could not pick $sha1\"\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex af7ba5f..1eae688 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -24,6 +24,7 @@ m,merge!           use merging strategies to rebase\n i,interactive!     let the user edit the list of commits to rebase\n x,exec=!           add exec lines after each commit of the editable list\n k,keep-empty\t   preserve empty commits during rebase\n+keep-redundant     preserve redundant 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@@ -86,6 +87,7 @@ action=\n preserve_merges=\n autosquash=\n keep_empty=\n+keep_redundant=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n gpg_sign_opt=\n \n@@ -255,6 +257,9 @@ do\n \t--keep-empty)\n \t\tkeep_empty=yes\n \t\t;;\n+\t--keep-redundant)\n+\t\tkeep_redundant=yes\n+\t\t;;\n \t--preserve-merges)\n \t\tpreserve_merges=t\n \t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\ndiff --git a/t/t3427-rebase-empty.sh b/t/t3427-rebase-empty.sh\nnew file mode 100755\nindex 0000000..9e67e00\n--- /dev/null\n+++ b/t/t3427-rebase-empty.sh\n@@ -0,0 +1,127 @@\n+#!/bin/sh\n+\n+test_description='git rebase tests for empty commits\n+\n+This test runs git rebase and tests handling of empty commits.\n+'\n+. ./test-lib.sh\n+\n+addfile() {\n+    name=$1\n+    echo $(basename ${name}) > ${name}\n+    ${git} add ${name}\n+    ${git} commit -m \"Add $(basename ${name})\"\n+}\n+\n+check_equal()\n+{\n+\ttest_debug 'echo'\n+\ttest_debug \"echo \\\"check a:\\\" \\\"{$1}\\\"\"\n+\ttest_debug \"echo \\\"      b:\\\" \\\"{$2}\\\"\"\n+\tif [ \"$1\" = \"$2\" ]; then\n+\t\treturn 0\n+\telse\n+\t\treturn 1\n+\tfi\n+}\n+\n+last_commit_message()\n+{\n+\tgit log --pretty=format:%s -1\n+}\n+\n+test_expect_success 'setup' '\n+\ttest_commit README &&\n+\tmkdir files &&\n+\tcd files &&\n+\tgit init &&\n+\ttest_commit master1 &&\n+\ttest_commit master2 &&\n+\ttest_commit master3 &&\n+\tcd .. &&\n+\ttest_debug \"echo Add project master to master\" &&\n+\tgit fetch files master &&\n+\tgit branch files-master FETCH_HEAD &&\n+\ttest_debug \"echo Add subtree master to master via subtree\" &&\n+\tgit read-tree --prefix=files_subtree files-master &&\n+\tgit checkout -- files_subtree &&\n+\ttree=$(git write-tree) &&\n+\thead=$(git rev-parse HEAD) &&\n+\trev=$(git rev-parse --verify files-master^0) &&\n+\tcommit=$(git commit-tree -p ${head} -p ${rev} -m \"Add subproject master\" ${tree}) &&\n+\tgit reset ${commit} &&\n+\tcd files_subtree &&\n+\ttest_commit master4 &&\n+\tcd .. &&\n+\ttest_commit files_subtree/master5\n+'\n+\n+# Does not preserve master4 and master5.\n+#test_expect_success 'Rebase default' '\n+#\tgit checkout -b rebase-default master &&\n+#\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+#\tgit commit -m \"Empty commit\" --allow-empty &&\n+#\tgit rebase -Xsubtree=files_subtree  --preserve-merges --onto files-master master &&\n+#\tcheck_equal \"$(last_commit_message)\" \"files_subtree/master5\"\n+#'\n+\n+test_expect_success 'Rebase --root' '\n+\tgit checkout -b rebase-default-root master &&\n+\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+\tgit commit -m \"Empty commit\" --allow-empty &&\n+\ttest_must_fail git rebase -Xsubtree=files_subtree  --preserve-merges --onto files-master --root &&\n+\tgit rebase --abort\n+'\n+\n+# Does not preserve master4, master5 and empty.\n+#test_expect_success 'Rebase --keep-empty' '\n+#\tgit checkout -b rebase-keep-empty master &&\n+#\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+#\tgit commit -m \"Empty commit\" --allow-empty &&\n+#\tgit rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master master &&\n+#\tcheck_equal \"$(last_commit_message)\" \"Empty commit\"\n+#'\n+\n+test_expect_success 'Rebase --keep-empty --root' '\n+\tgit checkout -b rebase-keep-empty-root master &&\n+\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+\tgit commit -m \"Empty commit\" --allow-empty &&\n+\ttest_must_fail git rebase -Xsubtree=files_subtree --keep-empty --preserve-merges --onto files-master --root &&\n+\tgit rebase --abort\n+'\n+\n+# Does not preserve master4 and master5.\n+#test_expect_success 'Rebase --keep-redundant' '\n+#\tgit checkout -b rebase-keep-redundant master &&\n+#\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+#\tgit commit -m \"Empty commit\" --allow-empty &&\n+#\tgit rebase -Xsubtree=files_subtree --keep-redundant --preserve-merges --onto files-master master &&\n+#\tcheck_equal \"$(last_commit_message)\" \"files_subtree/master5\"\n+#'\n+\n+test_expect_success 'Rebase --keep-redundant --root' '\n+\tgit checkout -b rebase-keep-redundant-root master &&\n+\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+\tgit commit -m \"Empty commit\" --allow-empty &&\n+\tgit rebase -Xsubtree=files_subtree --keep-redundant --preserve-merges --onto files-master --root &&\n+\tcheck_equal \"$(last_commit_message)\" \"files_subtree/master5\"\n+'\n+\n+# Does not preserve master4, master5 and empty.\n+#test_expect_success 'Rebase --keep-empty --keep-redundant' '\n+#\tgit checkout -b rebase-keep-empty-keep-redundant master &&\n+#\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+#\tgit commit -m \"Empty commit\" --allow-empty &&\n+#\tgit rebase -Xsubtree=files_subtree --keep-empty --keep-redundant --preserve-merges --onto files-master master &&\n+#\tcheck_equal \"$(last_commit_message)\" \"Empty commit\"\n+#'\n+\n+test_expect_success 'Rebase --keep-empty --keep-redundant --root' '\n+\tgit checkout -b rebase-keep-empty-keep-redundant-root master &&\n+\tgit filter-branch --prune-empty -f --subdirectory-filter files_subtree &&\n+\tgit commit -m \"Empty commit\" --allow-empty &&\n+\tgit rebase -Xsubtree=files_subtree --keep-empty --keep-redundant --preserve-merges --onto files-master --root &&\n+\tcheck_equal \"$(last_commit_message)\" \"Empty commit\"\n+'\n+\n+test_done\n-- \n2.6.1\n"},{"id":"274550","messageId":"xmqqsi33djfl.fsf@gitster.mtv.corp.google.com","threadId":"41012","inReplyTo":"1450234966-28796-1-git-send-email-greened@obbligato.org","subject":"Re: (unknown)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-12-16T05:57:50Z","receivedAt":"2015-12-16T05:57:50Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"David Greene <greened@obbligato.org> writes:\n\n> - If new option --keep-redundant is specified, invoke cherry-pick with\n>   --keep-redundant-commits.\n\nThis came up in the past several weeks, I think; you would need to\ndisable patch-equivalence based commit filtering if you really want\nto do a --keep-redundant that is reproducible and/or reliable.\n"},{"id":"274561","messageId":"20151216084406.GA3241@pks-pc","threadId":"41012","inReplyTo":"xmqqsi33djfl.fsf@gitster.mtv.corp.google.com","subject":"Re: (unknown)","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2015-12-16T08:44:06Z","receivedAt":"2015-12-16T08:44:06Z","isPatch":false,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Dec 15, 2015 at 09:57:50PM -0800, Junio C Hamano wrote:\n> David Greene <greened@obbligato.org> writes:\n> \n> > - If new option --keep-redundant is specified, invoke cherry-pick with\n> >   --keep-redundant-commits.\n> \n> This came up in the past several weeks, I think; you would need to\n> disable patch-equivalence based commit filtering if you really want\n> to do a --keep-redundant that is reproducible and/or reliable.\n\nHere are the links to the previous proposal [1] and following\ndiscussion [2] (see 'ps/rebase-keep-empty') if you are\ninterested.\n\nPatrick\n\n[1]: http://thread.gmane.org/gmane.comp.version-control.git/281515\n[2]: http://thread.gmane.org/gmane.comp.version-control.git/281917\n"},{"id":"274722","messageId":"nngr3ij3bj8.fsf@lnx-dag.us.cray.com","threadId":"41012","inReplyTo":"20151216084406.GA3241@pks-pc","subject":"Re: (unknown)","fromName":"David Greene","fromEmail":"greened@obbligato.org","sentAt":"2015-12-18T17:35:23Z","receivedAt":"2015-12-18T17:35:23Z","isPatch":false,"sender":{"key":"greened@obbligato.org","avatar":"https://avatars.githubusercontent.com/u/5291869?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Tue, Dec 15, 2015 at 09:57:50PM -0800, Junio C Hamano wrote:\n>> David Greene <greened@obbligato.org> writes:\n>> \n>> > - If new option --keep-redundant is specified, invoke cherry-pick with\n>> >   --keep-redundant-commits.\n>> \n>> This came up in the past several weeks, I think; you would need to\n>> disable patch-equivalence based commit filtering if you really want\n>> to do a --keep-redundant that is reproducible and/or reliable.\n>\n> Here are the links to the previous proposal [1] and following\n> discussion [2] (see 'ps/rebase-keep-empty') if you are\n> interested.\n>\n> Patrick\n>\n> [1]: http://thread.gmane.org/gmane.comp.version-control.git/281515[2]: http://thread.gmane.org/gmane.comp.version-control.git/281917\n\nThanks.  That makes total sense.\n\nI actually would prefer a behavior where cherry-pick would just drop\nredundant commits rather than stopping and asking the user to reset.\nThe problem is that rebase --preserve-merges seems to force the drop to\nuse cherry-pick and cherry-pick doesn't behave well (from a scripting\nperspective) in the presence of redundant commits.\n\nAs it is, it's difficult to rebase as part of a scripted operation due\nto this issue.\n\nAny ideas on how to teach cherry-pick to automatically drop such\ncommits?\n\n                           -David\n"}]}