{"thread":{"id":"48665","subject":"RFC: rebase inconsistency in 2.18 -- course of action?","startedAt":"2018-06-07T04:58:55Z","lastAt":"2019-01-22T15:37:24Z","messageCount":130,"participants":["Elijah Newren","Johannes Schindelin","Phillip Wood","Junio C Hamano","Eric Sunshine","SZEDER Gábor","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"349583","messageId":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","threadId":"48665","inReplyTo":null,"subject":"RFC: rebase inconsistency in 2.18 -- course of action?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T04:58:50Z","receivedAt":"2018-06-07T04:58:55Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi everyone,\n\nWe've got a small rebase problem; I'm curious for thoughts about the\nbest course of action.  I'll provide several options below.\n\nIn short, while interactive-based and merge-based rebases handle\ndirectory rename detection fine, am-based rebases do not.  This\ninconsistency may frustrate or surprise users.\n\n=== Demonstration Example ===\n\nLet's say we have a repo with three commits -- an original commit\n('O'), and two branches based off of it, A and B with an extra commit\neach:\n\n  O: has files l, x/a, x/b, x/c\n  A: renames l -> lt, x/ -> y/\n  B: modifies l, adds x/d\n\nIf I checkout B and run\n\n  git rebase --interactive A\n\nand don't bother editing the list of commits at all but just save,\nthen I end up with lt, y/{a, b, c, d} as expected.  However, if I run\n\n  git rebase A\n\nthen I end up with lt, y/{a, b, c} and x/d; d is in the wrong place.\n\n=== Problem explanation ===\n\nam-based rebases suffer from a reduced ability to detect directory\nrenames upstream, which is fundamental to the fact that it throws away\ninformation about the history: in particular, it dispenses with the\noriginal commits involved by turning them into patches, and without\nthe knowledge of the original commits we cannot determine a proper\nmerge base.\n\nThe am-based rebase will proceed after generating patches by\ncommit-wise first trying git-apply, and if that fails it will attempt\na 3-way merge.  Since am has no knowledge of original commits, it\ninstead reconstructs a provisional merge base using\nbuild_fake_ancestor() which will only contain the original versions of\nthe files modified in the patch.  Without the full list of files in\nthe real merge base, renames of any missing files cannot be detected.\nDirectory rename detection works by looking at individual file renames\nand deducing when a full directory has been renamed.\n\nTrying to modify build_fake_ancestor() to instead create a merge base\nthat includes common file information by looking for a commit that\ncontained all the same blobs as the pre-image of the patch would\nrequire a very expensive search through history, and may choose a\nwrong commit from among the several it finds.  (Also, regular am\noutside of rebase may not find any commit that matches, forcing it to\nsomehow choose a near-fit).  Further, this would only work when the\nfallback to a 3-way merge is triggered (i.e. when git-apply fails),\nwhich may not happen for some patches. (For example, if the l->lt\nchange were not in the example, then git-apply would succeed and\nincorrectly place d in x/, so we'd never even hit the 3-way fallback.)\n\nIn short, the am machinery simply doesn't have the necessary\ninformation to properly detect directory renames, except when other\nfiles involved in the renames upstream were also modified on the side\nwith the new file additions.\n\n=== Possible solutions ===\n\n1. Just accept it as a known shortcoming.\n\n2. Revert directory rename detection from master...again.\n\n   (Please, please, let's not pick this one.)\n\n3. Claim it's not a bug at all.  In particular, the git-rebase(1) manpage\n   states for the `--merge` option:\n\n       Use merging strategies to rebase.  When the recursive (default)\n       merge strategy is used, this allows rebase to be aware of\n       renames on the upstream side.\n\n   While \"renames\" is precisely why rebase --merge was added in commit\n   58634dbff822 back on 2006-06-21, am-based rebases gained the\n   ability to handle normal (non-directory) renames back in commit\n   18cdf802ca6e from 2008-11-10.  So folks might be used to and expect\n   their simple rebases to handle renames the same as --merge or\n   --interactive rebases do.\n\n4. Edit the 2.18 release notes.  Point out that directory renames can\n   be detected by cherry-pick, merge, and rebases with either the -i\n   or -m options (or any rebase option that implies either -i or -m);\n   but not always by other rebases.  Folks may want to set pull.rebase\n   to 'interactive' and just get used to immediately saving the\n   popped-up list of commits and exiting to avoid this problem.\n\n   Also, there's no good way to avoid this problem when using git-am\n   directly.  At best, we can tell users to carefully select which\n   older commit base to apply the patches on top of and then\n   immediately run rebase --merge afterward.\n\n5. Add an --am option to git-rebase, and make it not be the default\n   (though make it be triggered by am-specific options like\n   --whitespace or -C).  For the default, use either:\n\n     5a. do_merge=t\n\n     5b. interactive_rebase=implied\n\n   As a slight aside, since there are only a few small changes\n   necessary to make git-rebase--interactive handle ALL functionality\n   from git-rebase--merge, we could take 5b one step further and\n   delete git-rebase--merge and have one less rebase type.\n\n   Either 5a or 5b may have a minor performance hit here, though\n   personally I don't see this as a major factor.  But I'm happy to\n   discuss at a high level if folks are curious (exact figures would\n   depend heavily on the repo, size of commits, etc.)\n\n6. Since there's not much time left before 2.18, do (1) and (4) for\n   now, and (5) for 2.19.  Continue doing (1) or (3) for git-am itself.\n\n7. Other solutions I haven't thought of?\n\n=== Final Notes ===\n\nI have patches implementing 5b, including the bonus removal of\ngit-rebase--merge.  However:\n\n  * while my patches apply cleanly on master or next, there are lots\n    of minor conflicts for the final two patches with ag/rebase-p in\n    pu (in fact, even master conflicts with ag/rebase-p).  So I'm\n    curious if I should wait off on sending these patches until that\n    topic advances.\n\n  * My first 9 patches are 7 independent fixes and cleanups, so I'll\n    send those out shortly.\n\n\nThanks for reading this far,\nElijah\n"},{"id":"349584","messageId":"20180607050454.19438-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH] t3401: add directory rename testcases for rebase and am","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:04:54Z","receivedAt":"2018-06-07T05:05:05Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Add a simple directory rename testcase, in conjunction with each of the\ntypes of rebases:\n  git-rebase--interactive\n  git-rebase--am\n  git-rebase--merge\nand also use the same testcase for\n  git am --3way\n\nThis demonstrates an inconsistency between the different rebase backends\nand which can detect the directory rename.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3401-rebase-and-am-rename.sh | 105 ++++++++++++++++++++++++++++++++\n 1 file changed, 105 insertions(+)\n create mode 100755 t/t3401-rebase-and-am-rename.sh\n\ndiff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh\nnew file mode 100755\nindex 0000000000..8f832957fc\n--- /dev/null\n+++ b/t/t3401-rebase-and-am-rename.sh\n@@ -0,0 +1,105 @@\n+#!/bin/sh\n+\n+test_description='git rebase + directory rename tests'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'setup testcase' '\n+\ttest_create_repo dir-rename &&\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tmkdir x &&\n+\t\ttest_seq  1 10 >x/a &&\n+\t\ttest_seq 11 20 >x/b &&\n+\t\ttest_seq 21 30 >x/c &&\n+\t\ttest_write_lines a b c d e f g h i >l &&\n+\t\tgit add x l &&\n+\t\tgit commit -m \"Initial\" &&\n+\n+\t\tgit branch O &&\n+\t\tgit branch A &&\n+\t\tgit branch B &&\n+\n+\t\tgit checkout A &&\n+\t\tgit mv x y &&\n+\t\tgit mv l letters &&\n+\t\tgit commit -m \"Rename x to y, l to letters\" &&\n+\n+\t\tgit checkout B &&\n+\t\techo j >>l &&\n+\t\ttest_seq 31 40 >x/d &&\n+\t\tgit add l x/d &&\n+\t\tgit commit -m \"Modify l, add x/d\"\n+\t)\n+'\n+\n+test_expect_success 'rebase --interactive: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tset_fake_editor &&\n+\t\tFAKE_LINES=\"1\" git rebase --interactive A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'rebase (am): directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_success 'rebase --merge: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase --merge A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'am: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout A^0 &&\n+\n+\t\tgit format-patch -1 B &&\n+\n+\t\tgit am --3way 0001*.patch &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_done\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349585","messageId":"20180607050525.19494-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH] apply: fix grammar error in comment","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:05:25Z","receivedAt":"2018-06-07T05:05:34Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Signed-off-by: Elijah Newren <newren@gmail.com>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex d79e61591b..85f2c92740 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -4053,7 +4053,7 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)\n \treturn get_oid_hex(p->old_sha1_prefix, oid);\n }\n \n-/* Build an index that contains the just the files needed for a 3way merge */\n+/* Build an index that contains just the files needed for a 3way merge */\n static int build_fake_ancestor(struct apply_state *state, struct patch *list)\n {\n \tstruct patch *patch;\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349586","messageId":"20180607050550.19546-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH] t5407: fix test to cover intended arguments","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:05:50Z","receivedAt":"2018-06-07T05:05:59Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Test 8 in t5407 appears to be an accidental exact duplicate of of test 5;\nthe testcode is identical and has identical repo state, but the test\ndescription is different and suggests that rebase -m followed by rebase\n--skip was what was actually supposed to be tested.  Modify the test to\ninclude the -m option.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t5407-post-rewrite-hook.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 7a48236e87..9b2a274c71 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -113,7 +113,7 @@ test_expect_success 'git rebase -m' '\n test_expect_success 'git rebase -m --skip' '\n \tgit reset --hard D &&\n \tclear_hook_input &&\n-\ttest_must_fail git rebase --onto A B &&\n+\ttest_must_fail git rebase -m --onto A B &&\n \ttest_must_fail git rebase --skip &&\n \techo D > foo &&\n \tgit add foo &&\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349587","messageId":"20180607050615.19598-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:06:15Z","receivedAt":"2018-06-07T05:06:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"<Comments for after diffstat:>\nI tend to think git-rebase--merge is less popular than the other rebase\ntypes, leading to it being more overlooked and less well tested than the\nother ones.  This git-$cmd usage seems to support that argument.\n\nAnyway, this patch may be irrelevant if others agree with my goal to\ndelete git-rebase--merge and implement --merge on top of the --interactive\nmachinery, but sending it along in case others don't agree with that goal.\n</Comments>\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase--merge.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--merge.sh b/git-rebase--merge.sh\nindex cf4c042214..aa2f2f0872 100644\n--- a/git-rebase--merge.sh\n+++ b/git-rebase--merge.sh\n@@ -71,7 +71,7 @@ call_merge () {\n \ttest -z \"$strategy\" && strategy=recursive\n \t# If cmt doesn't have a parent, don't include it as a base\n \tbase=$(git rev-parse --verify --quiet $cmt^)\n-\teval 'git-merge-$strategy' $strategy_opts $base ' -- \"$hd\" \"$cmt\"'\n+\teval 'git merge-$strategy' $strategy_opts $base ' -- \"$hd\" \"$cmt\"'\n \trv=$?\n \tcase \"$rv\" in\n \t0)\n@@ -88,7 +88,7 @@ call_merge () {\n \t\t;;\n \t*)\n \t\tdie \"Unknown exit code ($rv) from command:\" \\\n-\t\t\t\"git-merge-$strategy $cmt^ -- HEAD $cmt\"\n+\t\t\t\"git merge-$strategy $cmt^ -- HEAD $cmt\"\n \t\t;;\n \tesac\n }\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349588","messageId":"20180607050654.19663-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180607050654.19663-1-newren@gmail.com","subject":"[PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:06:54Z","receivedAt":"2018-06-07T05:07:06Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has three different types: am, merge, and interactive, all of\nwhich are implemented in terms of separate scripts.  am builds on git-am,\nmerge builds on git-merge-recursive, and interactive builds on\ngit-cherry-pick.  We make use of features in those lower-level commands in\nthe different rebase types, but those features don't exist in all of the\nlower level commands so we have a range of incompatibilities.  Previously,\nwe just accepted nearly any argument and silently ignored whichever ones\nweren't implemented for the type of rebase specified.  Change this so the\nincompatibilities are documented, included in the testsuite, and tested\nfor at runtime with an appropriate error message shown.\n\nSome exceptions I left out:\n\n  * --merge and --interactive are technically incompatible since they are\n    supposed to run different underlying scripts, but with a few small\n    changes, --interactive can do everything that --merge can.  In fact,\n    I'll shortly be sending another patch to remove git-rebase--merge and\n    reimplement it on top of git-rebase--interactive.\n\n  * One could argue that --interactive and --quiet are incompatible since\n    --interactive doesn't implement a --quiet mode (perhaps since\n    cherry-pick itself does not implement one).  However, the interactive\n    mode is more quiet than the other modes in general with progress\n    messages, so one could argue that it's already quiet.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt           | 15 +++++++++++++--\n git-rebase.sh                          | 17 +++++++++++++++++\n t/t3422-rebase-incompatible-options.sh | 10 +++++-----\n 3 files changed, 35 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0e20a66e73..451252c173 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -243,6 +243,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n++\n+This uses the `--interactive` machinery internally, and as such,\n+anything that is incompatible with --interactive is incompatible\n+with this option.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n@@ -324,6 +328,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n+\tIncompatible with the --merge and --interactive options, or\n+\tanything that implies those options or their machinery.\n \n -f::\n --force-rebase::\n@@ -355,13 +361,15 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option.\n+\tIncompatible with the --merge and --interactive options, or\n+\tanything that implies those options or their machinery.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option.\n+\tIncompatible with the --merge and --interactive options, or\n+\tanything that implies those options or their machinery.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n@@ -400,6 +408,9 @@ The `--rebase-merges` mode is similar in spirit to `--preserve-merges`, but\n in contrast to that option works well in interactive rebases: commits can be\n reordered, inserted and dropped at will.\n +\n+This uses the `--interactive` machinery internally, but it can be run\n+without an explicit `--interactive`.\n++\n It is currently only possible to recreate the merge commits using the\n `recursive` merge strategy; Different merge strategies can be used only via\n explicit `exec git merge -s <strategy> [...]` commands.\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..f1dbecba18 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -503,6 +503,23 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n+if test -n \"$git_am_opt\"; then\n+\tincompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n+\tif test -n \"$interactive_rebase\"\n+\tthen\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$do_merge\"; then\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n if test -n \"$signoff\"\n then\n \ttest -n \"$preserve_merges\" &&\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 04cdae921b..66a83363bf 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -34,27 +34,27 @@ test_expect_success 'setup' '\n test_run_rebase () {\n \topt=$1\n \tshift\n-\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\ttest_expect_success \"$opt incompatible with --merge\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --merge A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\ttest_expect_success \"$opt incompatible with --interactive\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --interactive A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\ttest_expect_success \"$opt incompatible with --exec\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --exec 'true' A\n \t\"\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349589","messageId":"20180607050654.19663-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH 1/2] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:06:53Z","receivedAt":"2018-06-07T05:07:08Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase is split into three types: am, merge, and interactive.  Various\noptions imply different types, and which mode we are using determine which\nsub-script (git-rebase--$type) is executed to finish the work.  Not all\noptions work with all types, so add tests for combinations where we expect\nto receive an error rather than having options be silently ignored.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3422-rebase-incompatible-options.sh | 69 ++++++++++++++++++++++++++\n 1 file changed, 69 insertions(+)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nnew file mode 100755\nindex 0000000000..04cdae921b\n--- /dev/null\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -0,0 +1,69 @@\n+#!/bin/sh\n+\n+test_description='test if rebase detects and aborts on incompatible options'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_seq 2 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m orig &&\n+\n+\tgit branch A &&\n+\tgit branch B &&\n+\n+\tgit checkout A &&\n+\ttest_seq 1 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m A &&\n+\n+\tgit checkout B &&\n+\t# This is indented with HT SP HT.\n+\techo \"\t \tfoo();\" >>foo &&\n+\tgit add foo &&\n+\tgit commit -m B\n+'\n+\n+#\n+# Rebase has lots of useful options like --whitepsace=fix, which are\n+# actually all built in terms of flags to git-am.  Since neither\n+# --merge nor --interactive (nor any options that imply those two) use\n+# git-am, using them together will result in flags like --whitespace=fix\n+# being ignored.  Make sure rebase warns the user and aborts instead.\n+#\n+\n+test_run_rebase () {\n+\topt=$1\n+\tshift\n+\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --merge A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --interactive A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --exec 'true' A\n+\t\"\n+\n+}\n+\n+test_run_rebase --whitespace=fix\n+test_run_rebase --ignore-whitespace\n+test_run_rebase --committer-date-is-author-date\n+test_run_rebase -C4\n+\n+test_done\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349590","messageId":"20180607050747.19726-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:07:47Z","receivedAt":"2018-06-07T05:07:58Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Signed-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh | 6 +-----\n 1 file changed, 1 insertion(+), 5 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..a56b286372 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -276,6 +276,7 @@ do\n \t\t;;\n \t--keep-empty)\n \t\tkeep_empty=yes\n+\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n \t\t;;\n \t--allow-empty-message)\n \t\tallow_empty_message=--allow-empty-message\n@@ -480,11 +481,6 @@ then\n \ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n fi\n \n-if test -n \"$keep_empty\"\n-then\n-\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n-fi\n-\n if test -n \"$interactive_rebase\"\n then\n \ttype=interactive\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349591","messageId":"20180607050845.19779-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[PATCH 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:08:44Z","receivedAt":"2018-06-07T05:08:56Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"We are not passing the same args to merge strategies when we are doing an\n--interactive rebase as we do with a --merge rebase.  The merge strategy\nshould not need to be aware of which type of rebase is in effect.  Add a\ntestcase which checks for the appropriate args.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3418-rebase-continue.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 03bf1b8a3b..872022106f 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n+test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+\trm -fr .git/rebase-* &&\n+\tgit reset --hard commit-new-file-F2-on-topic-branch &&\n+\ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n+\ttest_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n+\tmkdir test-bin &&\n+\tcat >test-bin/git-merge-funny <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$@\" >>funny.args\n+\tcase \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n+\tcase \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n+\tcase \"\\$4\" in --) ;; *) exit 2 ;; esac\n+\tshift 2 &&\n+\t>funny.was.run &&\n+\texec git merge-recursive \"\\$@\"\n+\tEOF\n+\tchmod +x test-bin/git-merge-funny &&\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n+\t) &&\n+\ttest -f funny.was.run &&\n+\trm funny.was.run &&\n+\techo \"Resolved\" >F2 &&\n+\tgit add F2 &&\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\tgit rebase --continue\n+\t) &&\n+\ttest -f funny.was.run\n+'\n+\n test_expect_success 'rebase passes merge strategy options correctly' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F3-on-topic-branch &&\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349592","messageId":"20180607050845.19779-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180607050845.19779-1-newren@gmail.com","subject":"[PATCH 2/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:08:45Z","receivedAt":"2018-06-07T05:08:57Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase.sh wrote stuff like\n  '--ours'  '--renormalize'\nto .git/rebase-merge/strategy_opts.  Note the double spaces.\n\ngit-rebase--interactive uses sequencer.c to parse that file, and\nsequencer.c used split_cmdline() to get the individual strategy options.\nAfter splitting, sequencer.c prefixed each \"option\" with a double dash,\nso, concatenating all its options would result in:\n  -- --ours -- --renormalize\n\nSo, when it ended up calling try_merge_strategy(), that in turn would run\n  git merge-$strategy -- --ours -- --renormalize $merge_base -- $head $remote\n\ninstead of the expected\n  git merge-$strategy --ours --renormalize $merge_base -- $head $remote\n\nRemove the extra spaces so that split_cmdline() will work as expected.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh              | 2 +-\n sequencer.c                | 7 ++++++-\n t/t3418-rebase-continue.sh | 2 +-\n 3 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..224d5ebc29 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -316,7 +316,7 @@ do\n \t\tdo_merge=t\n \t\t;;\n \t--strategy-option=*)\n-\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n+\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n \t\tdo_merge=t\n \t\ttest -z \"$strategy\" && strategy=recursive\n \t\t;;\ndiff --git a/sequencer.c b/sequencer.c\nindex cca968043e..a2843e3906 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2203,6 +2203,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n {\n \tint i;\n+\tchar *strategy_opts_string;\n \n \tstrbuf_reset(buf);\n \tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n@@ -2211,7 +2212,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n \t\treturn;\n \n-\topts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);\n+\tstrategy_opts_string = buf->buf;\n+\tif (*strategy_opts_string == ' ')\n+\t\tstrategy_opts_string++;\n+\topts->xopts_nr = split_cmdline(strategy_opts_string,\n+\t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n \t\tconst char *arg = opts->xopts[i];\n \ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 872022106f..7ca6cbc415 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,7 +74,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n-test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+test_expect_success 'rebase -i --continue handles merge strategy and options' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F2-on-topic-branch &&\n \ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n-- \n2.18.0.rc0.46.g9cee8fce43\n\n"},{"id":"349598","messageId":"CABPp-BEJncFwszHvEX1U9FGz6AwjOEb2mTj0=iNt+60m8uB_2A@mail.gmail.com","threadId":"48665","inReplyTo":"20180607050615.19598-1-newren@gmail.com","subject":"Re: [PATCH] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T05:24:34Z","receivedAt":"2018-06-07T05:24:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 6, 2018 at 10:06 PM, Elijah Newren <newren@gmail.com> wrote:\n> <Comments for after diffstat:>\n> I tend to think git-rebase--merge is less popular than the other rebase\n> types, leading to it being more overlooked and less well tested than the\n> other ones.  This git-$cmd usage seems to support that argument.\n>\n> Anyway, this patch may be irrelevant if others agree with my goal to\n> delete git-rebase--merge and implement --merge on top of the --interactive\n> machinery, but sending it along in case others don't agree with that goal.\n> </Comments>\n\nI would forget to pull that out of the commit message area and put\nthat next to the diffstat in the email.  Whoops.\n\nOh, well.\n"},{"id":"349648","messageId":"20180607171344.23331-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180607171344.23331-1-newren@gmail.com","subject":"[RFC PATCH 1/3] git-rebase, sequencer: add a --quiet option for the interactive machinery","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T17:13:42Z","receivedAt":"2018-06-07T17:13:57Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"While 'quiet' and 'interactive' may sound like antonyms, the interactive\nmachinery actually has logic that implements several\ninteractive_rebase=implied cases (--exec, --keep-empty, --rebase-merges)\nwhich won't pop up an editor.  Further, we want to make the interactive\nmachinery also take over for git-rebase--merge and become the default\nmerge strategy, so it makes sense for these other cases to have a quiet\noption.\n\ngit-rebase--interactive was already somewhat quieter than\ngit-rebase--merge and git-rebase--am, possibly because cherry-pick has\njust traditionally been quieter.  As such, we only drop a few\ninformational messages -- \"Rebasing (n/m)\" and \"Succesfully rebased...\"\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase--interactive.sh |  9 +++++++--\n git-rebase.sh              |  2 +-\n sequencer.c                | 19 +++++++++++++------\n sequencer.h                |  1 +\n 4 files changed, 22 insertions(+), 9 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 06a7b79307..1f2401f702 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -139,8 +139,12 @@ mark_action_done () {\n \tif test \"$last_count\" != \"$new_count\"\n \tthen\n \t\tlast_count=$new_count\n-\t\teval_gettext \"Rebasing (\\$new_count/\\$total)\"; printf \"\\r\"\n-\t\ttest -z \"$verbose\" || echo\n+\t\tif test -z \"$GIT_QUIET\"\n+\t\tthen\n+\t\t\teval_gettext \"Rebasing (\\$new_count/\\$total)\";\n+\t\t\tprintf \"\\r\"\n+\t\t\ttest -z \"$verbose\" || echo\n+\t\tfi\n \tfi\n }\n \n@@ -713,6 +717,7 @@ Commit or stash your changes, and then run\n \t\t\"$hook\" rebase < \"$rewritten_list\"\n \t\ttrue # we don't care if this hook failed\n \tfi &&\n+\t\ttest -z \"$GIT_QUIET\" &&\n \t\twarn \"$(eval_gettext \"Successfully rebased and updated \\$head_name.\")\"\n \n \treturn 1 # not failure; just to break the do_rest loop\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 7d1612b31b..b639c0d4fe 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -136,7 +136,7 @@ write_basic_state () {\n \techo \"$head_name\" > \"$state_dir\"/head-name &&\n \techo \"$onto\" > \"$state_dir\"/onto &&\n \techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n-\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n+\ttest t = \"$GIT_QUIET\" && : > \"$state_dir\"/quiet\n \ttest t = \"$verbose\" && : > \"$state_dir\"/verbose\n \ttest -n \"$strategy\" && echo \"$strategy\" > \"$state_dir\"/strategy\n \ttest -n \"$strategy_opts\" && echo \"$strategy_opts\" > \\\ndiff --git a/sequencer.c b/sequencer.c\nindex a2843e3906..d418d40bee 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -143,6 +143,7 @@ static GIT_PATH_FUNC(rebase_path_refs_to_delete, \"rebase-merge/refs-to-delete\")\n static GIT_PATH_FUNC(rebase_path_gpg_sign_opt, \"rebase-merge/gpg_sign_opt\")\n static GIT_PATH_FUNC(rebase_path_orig_head, \"rebase-merge/orig-head\")\n static GIT_PATH_FUNC(rebase_path_verbose, \"rebase-merge/verbose\")\n+static GIT_PATH_FUNC(rebase_path_quiet, \"rebase-merge/quiet\")\n static GIT_PATH_FUNC(rebase_path_signoff, \"rebase-merge/signoff\")\n static GIT_PATH_FUNC(rebase_path_head_name, \"rebase-merge/head-name\")\n static GIT_PATH_FUNC(rebase_path_onto, \"rebase-merge/onto\")\n@@ -2251,6 +2252,9 @@ static int read_populate_opts(struct replay_opts *opts)\n \t\tif (file_exists(rebase_path_verbose()))\n \t\t\topts->verbose = 1;\n \n+\t\tif (file_exists(rebase_path_quiet()))\n+\t\t\topts->quiet = 1;\n+\n \t\tif (file_exists(rebase_path_signoff())) {\n \t\t\topts->allow_ff = 0;\n \t\t\topts->signoff = 1;\n@@ -3171,10 +3175,11 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t\t\t\tfprintf(f, \"%d\\n\", todo_list->done_nr);\n \t\t\t\t\tfclose(f);\n \t\t\t\t}\n-\t\t\t\tfprintf(stderr, \"Rebasing (%d/%d)%s\",\n-\t\t\t\t\ttodo_list->done_nr,\n-\t\t\t\t\ttodo_list->total_nr,\n-\t\t\t\t\topts->verbose ? \"\\n\" : \"\\r\");\n+\t\t\t\tif (!opts->quiet)\n+\t\t\t\t\tfprintf(stderr, \"Rebasing (%d/%d)%s\",\n+\t\t\t\t\t\ttodo_list->done_nr,\n+\t\t\t\t\t\ttodo_list->total_nr,\n+\t\t\t\t\t\topts->verbose ? \"\\n\" : \"\\r\");\n \t\t\t}\n \t\t\tunlink(rebase_path_message());\n \t\t\tunlink(rebase_path_author_script());\n@@ -3385,8 +3390,10 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)\n \t\t}\n \t\tapply_autostash(opts);\n \n-\t\tfprintf(stderr, \"Successfully rebased and updated %s.\\n\",\n-\t\t\thead_ref.buf);\n+\t\tif (!opts->quiet)\n+\t\t\tfprintf(stderr,\n+\t\t\t\t\"Successfully rebased and updated %s.\\n\",\n+\t\t\t\thead_ref.buf);\n \n \t\tstrbuf_release(&buf);\n \t\tstrbuf_release(&head_ref);\ndiff --git a/sequencer.h b/sequencer.h\nindex c5787c6b56..da652a421f 100644\n--- a/sequencer.h\n+++ b/sequencer.h\n@@ -33,6 +33,7 @@ struct replay_opts {\n \tint allow_empty_message;\n \tint keep_redundant_commits;\n \tint verbose;\n+\tint quiet;\n \n \tint mainline;\n \n-- \n2.18.0.rc1.12.g2996b9442d\n\n"},{"id":"349649","messageId":"20180607171344.23331-4-newren@gmail.com","threadId":"48665","inReplyTo":"20180607171344.23331-1-newren@gmail.com","subject":"[RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T17:13:44Z","receivedAt":"2018-06-07T17:14:00Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"am-based rebases suffer from an reduced ability to detect directory\nrenames upstream, which is fundamental to the fact that it throws away\ninformation about the history: in particular, it dispenses with the\noriginal commits involved by turning them into patches, and without the\nknowledge of the original commits we cannot determine a proper merge base.\n\nThe am-based rebase will proceed by first trying git-apply, and, only if\nit fails, will try to reconstruct a provisional merge base using\nbuild_fake_ancestor().  This fake ancestor will ONLY contain the files\nmodified in the patch; without the full list of files in the real merge\nbase, renames of any missing files cannot be detected.  Directory rename\ndetection works by looking at individual file renames and deducing when a\nfull directory has been renamed.\n\nTrying to modify build_fake_ancestor() to instead create a merge base that\nincludes common file information by looking for a commit that contained\nall the same blobs as the pre-image of the patch would require a very\nexpensive search through history, may find the wrong commit, and outside\nof rebase may not find any commit that matches.\n\nBut we had all the relevant information to start.  So, instead of\nattempting to fix am which just doesn't have the relevant information,\ninstead note its strength and weaknesses, and change the default rebase\nmachinery to interactive since it does not suffer from the same problems.\n\nDocumentation updates:\n\n  Several documentation updates were made as part of previous patches to\n  note which sets of options were incompatible.  However, adding a new\n  --am option allows us to make it clear which options imply this\n  machinery and simplify the discussion of incompatible sets of options\n  significantly.\n\ntestcase modification nodes:\n  t3400: git-rebase--interactive.sh explicitly captures output and\n         adds die \"could not detach HEAD\"; adjust to match\n  t3401: fixes directory rename detection problems for rebase by default,\n         though --am still fails on it\n  t3404: testcase said it was for a non-interactive rebase, so add --am\n  t3407: instead of having one test per rebase type, also add an extra one\n         for the default rebase type.  That'll duplicate --merge for now,\n         but will make switching default machinery again in the future\n         clearer, if we ever choose to do so.  Also, previously there was\n         a conspicuously missing test for all --quit combinations.\n  t3420: command output varies by type of rebase and this test script\n         has lots of helper functions providing the appropriate\n         expectation.  Make sure we call the relevant one.\n  t3425: Similar to t3407, add default rebase type to list of types to\n         test.  See also comments about t3425 in the switchover of\n         --merge to the interactive machinery.\n  t5407: This suite has tests for different rebase types, so specify some\n         are --am ones.\n  t5520: interactive rebases capture and reprint informational message\n         about conflicts to stdout rather than stderr.  Also, patches for\n         interactive rebases are stored differently under .git than for\n         am rebases.\n  t9903: Add another testcase for am rebases.  Prompt for default rebases\n         is now REBASE-m.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt      | 26 ++++++++++++--------------\n git-rebase.sh                     | 30 +++++++++++++++++++++---------\n t/t3400-rebase.sh                 |  7 ++++---\n t/t3401-rebase-and-am-rename.sh   | 18 +++++++++++++++++-\n t/t3404-rebase-interactive.sh     |  2 +-\n t/t3407-rebase-abort.sh           | 28 +++++++++++++++++++++++++++-\n t/t3420-rebase-autostash.sh       | 15 ++++++++++-----\n t/t3425-rebase-topology-merges.sh |  9 ++++++---\n t/t5407-post-rewrite-hook.sh      |  4 ++--\n t/t5520-pull.sh                   |  9 ++++++---\n t/t9903-bash-prompt.sh            | 12 +++++++++++-\n 11 files changed, 117 insertions(+), 43 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 28d1658d7a..6cfb7479fd 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -240,13 +240,16 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \toriginal branch. The index and working tree are also left\n \tunchanged as a result.\n \n+--am:\n+\tUse git-am internally to rebase.  This may run faster, but have\n+\tproblems with rename detection on the upstream side.\n+\tIncompatible with the --interactive option, or anything that\n+\tuses the `--interactive` machinery.\n+\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n-+\n-This uses the `--interactive` machinery internally, and as such,\n-anything that is incompatible with --interactive is incompatible\n-with this option.\n+\tThis uses the `--interactive` machinery internally.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n@@ -268,7 +271,7 @@ with this option.\n --merge::\n \tUse merging strategies to rebase.  When the recursive (default) merge\n \tstrategy is used, this allows rebase to be aware of renames on the\n-\tupstream side.\n+\tupstream side.  This is the default.\n +\n Note that a rebase merge works by replaying each commit from the working\n branch on top of the <upstream> branch.  Because of this, when a merge\n@@ -276,9 +279,7 @@ conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n +\n-This uses the `--interactive` machinery internally, and as such,\n-anything that is incompatible with --interactive is incompatible\n-with this option.\n+This uses the `--interactive` machinery internally.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -332,8 +333,7 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n-\tIncompatible with the --interactive option, or anything that\n-\tuses the `--interactive` machinery.\n+\tImplies --am.\n \n -f::\n --force-rebase::\n@@ -365,15 +365,13 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option, or anything that\n-\tuses the `--interactive` machinery.\n+\tImplies --am.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option, or anything that\n-\tuses the `--interactive` machinery.\n+\tImplies --am.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 5ac1dee30b..c8c3d0d05a 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -21,7 +21,8 @@ r,rebase-merges?   try to rebase merges instead of skipping them\n p,preserve-merges! try to recreate merges instead of ignoring them\n 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+am                 use git-am to rebase\n+m,merge!           use merging strategies to rebase; this is the default\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@@ -69,6 +70,7 @@ unset restrict_revision\n cmd=\n strategy=\n strategy_opts=\n+use_am=\n do_merge=\n merge_dir=\"$GIT_DIR\"/rebase-merge\n apply_dir=\"$GIT_DIR\"/rebase-apply\n@@ -311,6 +313,9 @@ do\n \t--no-fork-point)\n \t\tfork_point=\n \t\t;;\n+\t--am)\n+\t\tuse_am=t\n+\t\t;;\n \t--merge)\n \t\tdo_merge=t\n \t\t;;\n@@ -479,6 +484,7 @@ then\n \ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n fi\n \n+interactive_only_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n actually_interactive=\n if test -n \"$interactive_rebase\"\n then\n@@ -490,9 +496,18 @@ then\n \tinteractive_rebase=implied\n \ttype=interactive\n \tstate_dir=\"$merge_dir\"\n-else\n+elif test -n \"$use_am\"\n+then\n \ttype=am\n \tstate_dir=\"$apply_dir\"\n+elif test -n \"$interactive_only_opts\"\n+then\n+\ttype=am\n+\tstate_dir=\"$apply_dir\"\n+else\n+\tinteractive_rebase=implied\n+\ttype=interactive\n+\tstate_dir=\"$merge_dir\"\n fi\n \n if test -t 2 && test -z \"$GIT_QUIET\"\n@@ -500,14 +515,11 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n-if test -n \"$git_am_opt\"; then\n-\tincompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n-\tif test -n \"$incompatible_opts\"\n+if test -n \"$interactive_only_opts\"\n+then\n+\tif test -n \"$actually_interactive\" || test \"$do_merge\"\n \tthen\n-\t\tif test -n \"$actually_interactive\" || test \"$do_merge\"\n-\t\tthen\n-\t\t\tdie \"$(gettext \"error: cannot combine am options ($incompatible_opts) with either interactive or merge options\")\"\n-\t\tfi\n+\t\tdie \"$(gettext \"error: cannot combine am options ($interactive_only_opts) with either interactive or merge options\")\"\n \tfi\n fi\n \ndiff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh\nindex 72d9564747..03713572d6 100755\n--- a/t/t3400-rebase.sh\n+++ b/t/t3400-rebase.sh\n@@ -136,8 +136,9 @@ test_expect_success 'setup: recover' '\n test_expect_success 'Show verbose error when HEAD could not be detached' '\n \t>B &&\n \ttest_must_fail git rebase topic 2>output.err >output.out &&\n-\ttest_i18ngrep \"The following untracked working tree files would be overwritten by checkout:\" output.err &&\n-\ttest_i18ngrep B output.err\n+\ttest_i18ngrep \"The following untracked working tree files would be overwritten by checkout:\" output.out &&\n+\ttest_i18ngrep B output.out &&\n+\ttest_i18ngrep \"could not detach HEAD\" output.err\n '\n rm -f B\n \n@@ -289,7 +290,7 @@ test_expect_success 'rebase--am.sh and --show-current-patch' '\n \t\tgit tag two &&\n \t\ttest_must_fail git rebase --onto init HEAD^ &&\n \t\tGIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr &&\n-\t\tgrep \"show.*$(git rev-parse two)\" stderr\n+\t\tgrep \"show REBASE_HEAD\" stderr\n \t)\n '\n \ndiff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh\nindex ec87439bc6..6b54031201 100755\n--- a/t/t3401-rebase-and-am-rename.sh\n+++ b/t/t3401-rebase-and-am-rename.sh\n@@ -54,7 +54,7 @@ test_expect_success 'rebase --interactive: directory rename detected' '\n \t)\n '\n \n-test_expect_failure 'rebase (am): directory rename detected' '\n+test_expect_success 'rebase (default): directory rename detected' '\n \t(\n \t\tcd dir-rename &&\n \n@@ -70,6 +70,22 @@ test_expect_failure 'rebase (am): directory rename detected' '\n \t)\n '\n \n+test_expect_failure 'rebase --am: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase --am A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n test_expect_success 'rebase --merge: directory rename detected' '\n \t(\n \t\tcd dir-rename &&\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex c65826ddac..116060204e 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -975,7 +975,7 @@ test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-int\n \tgit reset --hard &&\n \tgit checkout conflict-branch &&\n \tset_fake_editor &&\n-\ttest_must_fail git rebase --onto HEAD~2 HEAD~ &&\n+\ttest_must_fail git rebase --am --onto HEAD~2 HEAD~ &&\n \ttest_must_fail git rebase --edit-todo &&\n \tgit rebase --abort\n '\ndiff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh\nindex 910f218284..33084b17f5 100755\n--- a/t/t3407-rebase-abort.sh\n+++ b/t/t3407-rebase-abort.sh\n@@ -96,14 +96,28 @@ testrebase() {\n \t'\n }\n \n-testrebase \"\" .git/rebase-apply\n+testrebase \" --am\" .git/rebase-apply\n+testrebase \"\" .git/rebase-merge\n testrebase \" --merge\" .git/rebase-merge\n+testrebase \" --interactive\" .git/rebase-merge\n \n test_expect_success 'rebase --quit' '\n \tcd \"$work_dir\" &&\n \t# Clean up the state from the previous one\n \tgit reset --hard pre-rebase &&\n \ttest_must_fail git rebase master &&\n+\ttest_path_is_dir .git/rebase-merge &&\n+\thead_before=$(git rev-parse HEAD) &&\n+\tgit rebase --quit &&\n+\ttest $(git rev-parse HEAD) = $head_before &&\n+\ttest ! -d .git/rebase-merge\n+'\n+\n+test_expect_success 'rebase --am --quit' '\n+\tcd \"$work_dir\" &&\n+\t# Clean up the state from the previous one\n+\tgit reset --hard pre-rebase &&\n+\ttest_must_fail git rebase --am master &&\n \ttest_path_is_dir .git/rebase-apply &&\n \thead_before=$(git rev-parse HEAD) &&\n \tgit rebase --quit &&\n@@ -123,4 +137,16 @@ test_expect_success 'rebase --merge --quit' '\n \ttest ! -d .git/rebase-merge\n '\n \n+test_expect_success 'rebase --interactive --quit' '\n+\tcd \"$work_dir\" &&\n+\t# Clean up the state from the previous one\n+\tgit reset --hard pre-rebase &&\n+\ttest_must_fail git rebase --interactive master &&\n+\ttest_path_is_dir .git/rebase-merge &&\n+\thead_before=$(git rev-parse HEAD) &&\n+\tgit rebase --quit &&\n+\ttest $(git rev-parse HEAD) = $head_before &&\n+\ttest ! -d .git/rebase-merge\n+'\n+\n test_done\ndiff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh\nindex c465713672..9af0d27435 100755\n--- a/t/t3420-rebase-autostash.sh\n+++ b/t/t3420-rebase-autostash.sh\n@@ -104,8 +104,10 @@ testrebase () {\n \n \ttest_expect_success \"rebase$type --autostash: check output\" '\n \t\ttest_when_finished git branch -D rebased-feature-branch &&\n-\t\tsuffix=${type#\\ --} && suffix=${suffix:-am} &&\n-\t\tif test ${suffix} = \"merge\"; then\n+\t\tsuffix=${type#\\ --} &&\n+\t\tif test ${suffix} = \"am\"; then\n+\t\t\tsuffix=am\n+\t\telse\n \t\t\tsuffix=interactive\n \t\tfi &&\n \t\tcreate_expected_success_$suffix &&\n@@ -204,8 +206,10 @@ testrebase () {\n \n \ttest_expect_success \"rebase$type: check output with conflicting stash\" '\n \t\ttest_when_finished git branch -D rebased-feature-branch &&\n-\t\tsuffix=${type#\\ --} && suffix=${suffix:-am} &&\n-\t\tif test ${suffix} = \"merge\"; then\n+\t\tsuffix=${type#\\ --} &&\n+\t\tif test ${suffix} = \"am\"; then\n+\t\t\tsuffix=am\n+\t\telse\n \t\t\tsuffix=interactive\n \t\tfi &&\n \t\tcreate_expected_failure_$suffix &&\n@@ -235,7 +239,8 @@ test_expect_success \"rebase: noop rebase\" '\n \tgit checkout feature-branch\n '\n \n-testrebase \"\" .git/rebase-apply\n+testrebase \" --am\" .git/rebase-apply\n+testrebase \"\" .git/rebase-merge\n testrebase \" --merge\" .git/rebase-merge\n testrebase \" --interactive\" .git/rebase-merge\n \ndiff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh\nindex cd505c0711..8fd14c86d3 100755\n--- a/t/t3425-rebase-topology-merges.sh\n+++ b/t/t3425-rebase-topology-merges.sh\n@@ -71,7 +71,8 @@ test_run_rebase () {\n \t\"\n }\n #TODO: make order consistent across all flavors of rebase\n-test_run_rebase success 'e n o' ''\n+test_run_rebase success 'e n o' --am\n+test_run_rebase success 'n o e' ''\n test_run_rebase success 'n o e' -m\n test_run_rebase success 'n o e' -i\n \n@@ -88,7 +89,8 @@ test_run_rebase () {\n \t\"\n }\n #TODO: make order consistent across all flavors of rebase\n-test_run_rebase success 'd e n o' ''\n+test_run_rebase success 'd e n o' --am\n+test_run_rebase success 'd n o e' ''\n test_run_rebase success 'd n o e' -m\n test_run_rebase success 'd n o e' -i\n \n@@ -105,7 +107,8 @@ test_run_rebase () {\n \t\"\n }\n #TODO: make order consistent across all flavors of rebase\n-test_run_rebase success 'd e n o' ''\n+test_run_rebase success 'd e n o' --am\n+test_run_rebase success 'd n o e' ''\n test_run_rebase success 'd n o e' -m\n test_run_rebase success 'd n o e' -i\n \ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 145c61251d..f5b5f4f04c 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -71,7 +71,7 @@ test_expect_success 'git rebase' '\n test_expect_success 'git rebase --skip' '\n \tgit reset --hard D &&\n \tclear_hook_input &&\n-\ttest_must_fail git rebase --onto A B &&\n+\ttest_must_fail git rebase --am --onto A B &&\n \ttest_must_fail git rebase --skip &&\n \techo D > foo &&\n \tgit add foo &&\n@@ -86,7 +86,7 @@ test_expect_success 'git rebase --skip' '\n test_expect_success 'git rebase --skip the last one' '\n \tgit reset --hard F &&\n \tclear_hook_input &&\n-\ttest_must_fail git rebase --onto D A &&\n+\ttest_must_fail git rebase --am --onto D A &&\n \tgit rebase --skip &&\n \techo rebase >expected.args &&\n \tcat >expected.data <<-EOF &&\ndiff --git a/t/t5520-pull.sh b/t/t5520-pull.sh\nindex 59c4b778d3..d7c915a209 100755\n--- a/t/t5520-pull.sh\n+++ b/t/t5520-pull.sh\n@@ -305,7 +305,7 @@ test_expect_success '--rebase with conflicts shows advice' '\n \ttest_tick &&\n \tgit commit -m \"Create conflict\" seq.txt &&\n \ttest_must_fail git pull --rebase . seq 2>err >out &&\n-\ttest_i18ngrep \"Resolve all conflicts manually\" out\n+\ttest_i18ngrep \"Resolve all conflicts manually\" err\n '\n \n test_expect_success 'failed --rebase shows advice' '\n@@ -319,7 +319,7 @@ test_expect_success 'failed --rebase shows advice' '\n \tgit checkout -f -b fails-to-rebase HEAD^ &&\n \ttest_commit v2-without-cr file \"2\" file2-lf &&\n \ttest_must_fail git pull --rebase . diverging 2>err >out &&\n-\ttest_i18ngrep \"Resolve all conflicts manually\" out\n+\ttest_i18ngrep \"Resolve all conflicts manually\" err\n '\n \n test_expect_success '--rebase fails with multiple branches' '\n@@ -671,7 +671,10 @@ test_expect_success 'setup for avoiding reapplying old patches' '\n test_expect_success 'git pull --rebase does not reapply old patches' '\n \t(cd dst &&\n \t test_must_fail git pull --rebase &&\n-\t test 1 = $(find .git/rebase-apply -name \"000*\" | wc -l)\n+\t cat .git/rebase-merge/done .git/rebase-merge/git-rebase-todo >work &&\n+\t grep -v -e \\# -e ^$ work >patches &&\n+\t test_line_count = 1 patches &&\n+\t rm -f work patches\n \t)\n '\n \ndiff --git a/t/t9903-bash-prompt.sh b/t/t9903-bash-prompt.sh\nindex c3b89ae783..29a83ae8cf 100755\n--- a/t/t9903-bash-prompt.sh\n+++ b/t/t9903-bash-prompt.sh\n@@ -192,10 +192,20 @@ test_expect_success 'prompt - rebase merge' '\n \ttest_cmp expected \"$actual\"\n '\n \n-test_expect_success 'prompt - rebase' '\n+test_expect_success 'prompt - rebase am' '\n \tprintf \" (b2|REBASE 1/3)\" >expected &&\n \tgit checkout b2 &&\n \ttest_when_finished \"git checkout master\" &&\n+\ttest_must_fail git rebase --am b1 b2 &&\n+\ttest_when_finished \"git rebase --abort\" &&\n+\t__git_ps1 >\"$actual\" &&\n+\ttest_cmp expected \"$actual\"\n+'\n+\n+test_expect_success 'prompt - rebase' '\n+\tprintf \" (b2|REBASE-m 1/3)\" >expected &&\n+\tgit checkout b2 &&\n+\ttest_when_finished \"git checkout master\" &&\n \ttest_must_fail git rebase b1 b2 &&\n \ttest_when_finished \"git rebase --abort\" &&\n \t__git_ps1 >\"$actual\" &&\n-- \n2.18.0.rc1.12.g2996b9442d\n\n"},{"id":"349650","messageId":"20180607171344.23331-1-newren@gmail.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"[RFC PATCH 0/3] Send more rebases through interactive machinery","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T17:13:41Z","receivedAt":"2018-06-07T17:14:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"This series:\n\n  * deletes git-rebase--merge, making git-rebase--interactive handle\n    those cases instead\n  * adds an --am option to git rebase, and changes the rebase default\n    from using git-rebase--am to git-rebase--interactive, fixing\n    directory rename detection for default rebases.\n\nHowever:\n\n  * this series has several minor conflicts with ag/rebase-p in pu.\n    But it's just an RFC for now; I can re-roll on top of that after\n    getting some feedback.\n\n  * this series depends on the other preparatory fixups under\n      https://public-inbox.org/git/CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com/\n    To get this series with the preparatory fixups:\n\nFetch-It-Via: git fetch https://github.com/newren/git rebase-new-default\n\nElijah Newren (3):\n  git-rebase, sequencer: add a --quiet option for the interactive\n    machinery\n  rebase: Implement --merge via git-rebase--interactive\n  git-rebase.sh: make git-rebase--interactive the default\n\n .gitignore                        |   1 -\n Documentation/git-rebase.txt      |  24 +++--\n Makefile                          |   1 -\n git-rebase--interactive.sh        |  14 ++-\n git-rebase--merge.sh              | 164 ------------------------------\n git-rebase.sh                     |  75 ++++++++------\n sequencer.c                       |  19 ++--\n sequencer.h                       |   1 +\n\nYes, there are a significant number of testcase changes below.  See\nthe relevant commit messages where I explain why each was changed.\n\n t/t3400-rebase.sh                 |   7 +-\n t/t3401-rebase-and-am-rename.sh   |  18 +++-\n t/t3404-rebase-interactive.sh     |   2 +-\n t/t3406-rebase-message.sh         |   7 +-\n t/t3407-rebase-abort.sh           |  28 ++++-\n t/t3420-rebase-autostash.sh       |  89 +++-------------\n t/t3421-rebase-topology-linear.sh |  10 +-\n t/t3425-rebase-topology-merges.sh |  15 +--\n t/t5407-post-rewrite-hook.sh      |   5 +-\n t/t5520-pull.sh                   |   9 +-\n t/t9903-bash-prompt.sh            |  12 ++-\n 19 files changed, 180 insertions(+), 321 deletions(-)\n delete mode 100644 git-rebase--merge.sh\n\n-- \n2.18.0.rc1.12.g2996b9442d\n"},{"id":"349651","messageId":"20180607171344.23331-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180607171344.23331-1-newren@gmail.com","subject":"[RFC PATCH 2/3] rebase: Implement --merge via git-rebase--interactive","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-07T17:13:43Z","receivedAt":"2018-06-07T17:14:05Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Interactive rebases are implemented in terms of cherry-pick rather than\nthe merge-recursive builtin, but cherry-pick also calls into the recursive\nmerge machinery by default and can accept special merge strategies and/or\nspecial strategy options.  As such, there really is not any need for\nhaving both git-rebase--merge and git-rebase--interactive anymore.\n\nDelete git-rebase--merge.sh and have the --merge option call in to\ngit-rebase--interactive.  Add one new variable ($actually_interactive) to\nhelp keep cases separate, and adjust the detection of the special\ncircumstances under which a rebase boils down to a simple fast forward so\nthat it keeps working with the new structure.\n\nNote that this change fixes a few known test failures (see t3421).\n\ntestcase modification notes:\n  t3406: --interactive and --merge had slightly different progress output\n         while running; adjust a test to match\n  t3420: tests of precise output while running, but rebase--am,\n         rebase--merge, and rebase--interactive all were built on very\n         different commands (am, merge-recursive, cherry-pick), so the\n         tests expected different output for each type.  Now we expect\n         --merge and --interactive to have the same output.\n  t3421: --interactive fixes some bugs in --merge!  Wahoo!\n  t3425: topology linearization was inconsistent across flavors of rebase,\n         as already noted in a TODO comment in the testcase.  This was not\n         considered a bug before, so getting a different linearization due\n         to switching out backends should not be considered a bug now.\n  t5407: different rebase types varied slightly in how many times checkout\n         or commit or equivalents were called based on a quick comparison\n         of this tests and previous ones which covered different rebase\n         flavors.  I think this is just attributable to this difference.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n .gitignore                        |   1 -\n Documentation/git-rebase.txt      |  16 +--\n Makefile                          |   1 -\n git-rebase--interactive.sh        |   5 +-\n git-rebase--merge.sh              | 164 ------------------------------\n git-rebase.sh                     |  49 ++++-----\n t/t3406-rebase-message.sh         |   7 +-\n t/t3420-rebase-autostash.sh       |  78 ++------------\n t/t3421-rebase-topology-linear.sh |  10 +-\n t/t3425-rebase-topology-merges.sh |   6 +-\n t/t5407-post-rewrite-hook.sh      |   1 +\n 11 files changed, 55 insertions(+), 283 deletions(-)\n delete mode 100644 git-rebase--merge.sh\n\ndiff --git a/.gitignore b/.gitignore\nindex 388cc4beee..747be69d10 100644\n--- a/.gitignore\n+++ b/.gitignore\n@@ -118,7 +118,6 @@\n /git-rebase--am\n /git-rebase--helper\n /git-rebase--interactive\n-/git-rebase--merge\n /git-receive-pack\n /git-reflog\n /git-remote\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 451252c173..28d1658d7a 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -275,6 +275,10 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n++\n+This uses the `--interactive` machinery internally, and as such,\n+anything that is incompatible with --interactive is incompatible\n+with this option.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -328,8 +332,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n-\tIncompatible with the --merge and --interactive options, or\n-\tanything that implies those options or their machinery.\n+\tIncompatible with the --interactive option, or anything that\n+\tuses the `--interactive` machinery.\n \n -f::\n --force-rebase::\n@@ -361,15 +365,15 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --merge and --interactive options, or\n-\tanything that implies those options or their machinery.\n+\tIncompatible with the --interactive option, or anything that\n+\tuses the `--interactive` machinery.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --merge and --interactive options, or\n-\tanything that implies those options or their machinery.\n+\tIncompatible with the --interactive option, or anything that\n+\tuses the `--interactive` machinery.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\ndiff --git a/Makefile b/Makefile\nindex 1d27f36365..8d24aaf638 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -620,7 +620,6 @@ SCRIPT_LIB += git-mergetool--lib\n SCRIPT_LIB += git-parse-remote\n SCRIPT_LIB += git-rebase--am\n SCRIPT_LIB += git-rebase--interactive\n-SCRIPT_LIB += git-rebase--merge\n SCRIPT_LIB += git-sh-setup\n SCRIPT_LIB += git-sh-i18n\n \ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 1f2401f702..dcc4a26a78 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -885,7 +885,10 @@ init_basic_state () {\n \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n \n-\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n+\tif test -n \"$actually_interactive\"\n+\tthen\n+\t\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n+\tfi\n \twrite_basic_state\n }\n \ndiff --git a/git-rebase--merge.sh b/git-rebase--merge.sh\ndeleted file mode 100644\nindex aa2f2f0872..0000000000\n--- a/git-rebase--merge.sh\n+++ /dev/null\n@@ -1,164 +0,0 @@\n-# This shell script fragment is sourced by git-rebase to implement\n-# its merge-based non-interactive mode that copes well with renamed\n-# files.\n-#\n-# Copyright (c) 2010 Junio C Hamano.\n-#\n-\n-prec=4\n-\n-read_state () {\n-\tonto_name=$(cat \"$state_dir\"/onto_name) &&\n-\tend=$(cat \"$state_dir\"/end) &&\n-\tmsgnum=$(cat \"$state_dir\"/msgnum)\n-}\n-\n-continue_merge () {\n-\ttest -d \"$state_dir\" || die \"$state_dir directory does not exist\"\n-\n-\tunmerged=$(git ls-files -u)\n-\tif test -n \"$unmerged\"\n-\tthen\n-\t\techo \"You still have unmerged paths in your index\"\n-\t\techo \"did you forget to use git add?\"\n-\t\tdie \"$resolvemsg\"\n-\tfi\n-\n-\tcmt=$(cat \"$state_dir/current\")\n-\tif ! git diff-index --quiet --ignore-submodules HEAD --\n-\tthen\n-\t\tif ! git commit ${gpg_sign_opt:+\"$gpg_sign_opt\"} $signoff $allow_empty_message \\\n-\t\t\t--no-verify -C \"$cmt\"\n-\t\tthen\n-\t\t\techo \"Commit failed, please do not call \\\"git commit\\\"\"\n-\t\t\techo \"directly, but instead do one of the following: \"\n-\t\t\tdie \"$resolvemsg\"\n-\t\tfi\n-\t\tif test -z \"$GIT_QUIET\"\n-\t\tthen\n-\t\t\tprintf \"Committed: %0${prec}d \" $msgnum\n-\t\tfi\n-\t\techo \"$cmt $(git rev-parse HEAD^0)\" >> \"$state_dir/rewritten\"\n-\telse\n-\t\tif test -z \"$GIT_QUIET\"\n-\t\tthen\n-\t\t\tprintf \"Already applied: %0${prec}d \" $msgnum\n-\t\tfi\n-\tfi\n-\ttest -z \"$GIT_QUIET\" &&\n-\tGIT_PAGER='' git log --format=%s -1 \"$cmt\"\n-\n-\t# onto the next patch:\n-\tmsgnum=$(($msgnum + 1))\n-\techo \"$msgnum\" >\"$state_dir/msgnum\"\n-}\n-\n-call_merge () {\n-\tmsgnum=\"$1\"\n-\techo \"$msgnum\" >\"$state_dir/msgnum\"\n-\tcmt=\"$(cat \"$state_dir/cmt.$msgnum\")\"\n-\techo \"$cmt\" > \"$state_dir/current\"\n-\tgit update-ref REBASE_HEAD \"$cmt\"\n-\thd=$(git rev-parse --verify HEAD)\n-\tcmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)\n-\teval GITHEAD_$cmt='\"${cmt_name##refs/heads/}~$(($end - $msgnum))\"'\n-\teval GITHEAD_$hd='$onto_name'\n-\texport GITHEAD_$cmt GITHEAD_$hd\n-\tif test -n \"$GIT_QUIET\"\n-\tthen\n-\t\tGIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY\n-\tfi\n-\ttest -z \"$strategy\" && strategy=recursive\n-\t# If cmt doesn't have a parent, don't include it as a base\n-\tbase=$(git rev-parse --verify --quiet $cmt^)\n-\teval 'git merge-$strategy' $strategy_opts $base ' -- \"$hd\" \"$cmt\"'\n-\trv=$?\n-\tcase \"$rv\" in\n-\t0)\n-\t\tunset GITHEAD_$cmt GITHEAD_$hd\n-\t\treturn\n-\t\t;;\n-\t1)\n-\t\tgit rerere $allow_rerere_autoupdate\n-\t\tdie \"$resolvemsg\"\n-\t\t;;\n-\t2)\n-\t\techo \"Strategy: $strategy failed, try another\" 1>&2\n-\t\tdie \"$resolvemsg\"\n-\t\t;;\n-\t*)\n-\t\tdie \"Unknown exit code ($rv) from command:\" \\\n-\t\t\t\"git merge-$strategy $cmt^ -- HEAD $cmt\"\n-\t\t;;\n-\tesac\n-}\n-\n-finish_rb_merge () {\n-\tmove_to_original_branch\n-\tif test -s \"$state_dir\"/rewritten\n-\tthen\n-\t\tgit notes copy --for-rewrite=rebase <\"$state_dir\"/rewritten\n-\t\thook=\"$(git rev-parse --git-path hooks/post-rewrite)\"\n-\t\ttest -x \"$hook\" && \"$hook\" rebase <\"$state_dir\"/rewritten\n-\tfi\n-\tsay All done.\n-}\n-\n-git_rebase__merge () {\n-\n-case \"$action\" in\n-continue)\n-\tread_state\n-\tcontinue_merge\n-\twhile test \"$msgnum\" -le \"$end\"\n-\tdo\n-\t\tcall_merge \"$msgnum\"\n-\t\tcontinue_merge\n-\tdone\n-\tfinish_rb_merge\n-\treturn\n-\t;;\n-skip)\n-\tread_state\n-\tgit rerere clear\n-\tmsgnum=$(($msgnum + 1))\n-\twhile test \"$msgnum\" -le \"$end\"\n-\tdo\n-\t\tcall_merge \"$msgnum\"\n-\t\tcontinue_merge\n-\tdone\n-\tfinish_rb_merge\n-\treturn\n-\t;;\n-show-current-patch)\n-\texec git show REBASE_HEAD --\n-\t;;\n-esac\n-\n-mkdir -p \"$state_dir\"\n-echo \"$onto_name\" > \"$state_dir/onto_name\"\n-write_basic_state\n-rm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n-\n-msgnum=0\n-for cmt in $(git rev-list --reverse --no-merges \"$revisions\")\n-do\n-\tmsgnum=$(($msgnum + 1))\n-\techo \"$cmt\" > \"$state_dir/cmt.$msgnum\"\n-done\n-\n-echo 1 >\"$state_dir/msgnum\"\n-echo $msgnum >\"$state_dir/end\"\n-\n-end=$msgnum\n-msgnum=1\n-\n-while test \"$msgnum\" -le \"$end\"\n-do\n-\tcall_merge \"$msgnum\"\n-\tcontinue_merge\n-done\n-\n-finish_rb_merge\n-\n-}\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex b639c0d4fe..5ac1dee30b 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -239,12 +239,10 @@ then\n \tstate_dir=\"$apply_dir\"\n elif test -d \"$merge_dir\"\n then\n+\ttype=interactive\n \tif test -f \"$merge_dir\"/interactive\n \tthen\n-\t\ttype=interactive\n \t\tinteractive_rebase=explicit\n-\telse\n-\t\ttype=merge\n \tfi\n \tstate_dir=\"$merge_dir\"\n fi\n@@ -481,13 +479,16 @@ then\n \ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n fi\n \n+actually_interactive=\n if test -n \"$interactive_rebase\"\n then\n \ttype=interactive\n+\tactually_interactive=t\n \tstate_dir=\"$merge_dir\"\n elif test -n \"$do_merge\"\n then\n-\ttype=merge\n+\tinteractive_rebase=implied\n+\ttype=interactive\n \tstate_dir=\"$merge_dir\"\n else\n \ttype=am\n@@ -501,17 +502,11 @@ fi\n \n if test -n \"$git_am_opt\"; then\n \tincompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n-\tif test -n \"$interactive_rebase\"\n+\tif test -n \"$incompatible_opts\"\n \tthen\n-\t\tif test -n \"$incompatible_opts\"\n+\t\tif test -n \"$actually_interactive\" || test \"$do_merge\"\n \t\tthen\n-\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n-\t\tfi\n-\tfi\n-\tif test -n \"$do_merge\"; then\n-\t\tif test -n \"$incompatible_opts\"\n-\t\tthen\n-\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\t\tdie \"$(gettext \"error: cannot combine am options ($incompatible_opts) with either interactive or merge options\")\"\n \t\tfi\n \tfi\n fi\n@@ -660,7 +655,7 @@ require_clean_work_tree \"rebase\" \"$(gettext \"Please commit or stash them.\")\"\n # but this should be done only when upstream and onto are the same\n # and if this is not an interactive rebase.\n mb=$(git merge-base \"$onto\" \"$orig_head\")\n-if test \"$type\" != interactive && test \"$upstream\" = \"$onto\" &&\n+if test -z \"$actually_interactive\" && test \"$upstream\" = \"$onto\" &&\n \ttest \"$mb\" = \"$onto\" && test -z \"$restrict_revision\" &&\n \t# linear history?\n \t! (git rev-list --parents \"$onto\"..\"$orig_head\" | sane_grep \" .* \") > /dev/null\n@@ -704,6 +699,22 @@ then\n \tGIT_PAGER='' git diff --stat --summary \"$mb\" \"$onto\"\n fi\n \n+if test -z \"$actually_interactive\"\n+then\n+\t# If the $onto is a proper descendant of the tip of the branch, then\n+\t# we just fast-forwarded.\n+\tif test \"$mb\" = \"$orig_head\"\n+\tthen\n+\t\tsay \"$(eval_gettext \"Fast-forwarded \\$branch_name to \\$onto_name.\")\"\n+\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\" \\\n+\t\t\tgit checkout -q \"$onto^0\" || die \"could not detach HEAD\"\n+\t\tgit update-ref ORIG_HEAD $orig_head\n+\t\tmove_to_original_branch\n+\t\tfinish_rebase\n+\t\texit 0\n+\tfi\n+fi\n+\n test \"$type\" = interactive && run_specific_rebase\n \n # Detach HEAD and reset the tree\n@@ -713,16 +724,6 @@ GIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\" \\\n \tgit checkout -q \"$onto^0\" || die \"could not detach HEAD\"\n git update-ref ORIG_HEAD $orig_head\n \n-# If the $onto is a proper descendant of the tip of the branch, then\n-# we just fast-forwarded.\n-if test \"$mb\" = \"$orig_head\"\n-then\n-\tsay \"$(eval_gettext \"Fast-forwarded \\$branch_name to \\$onto_name.\")\"\n-\tmove_to_original_branch\n-\tfinish_rebase\n-\texit 0\n-fi\n-\n if test -n \"$rebase_root\"\n then\n \trevisions=\"$onto..$orig_head\"\ndiff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\nindex 0392e36d23..04d6c71899 100755\n--- a/t/t3406-rebase-message.sh\n+++ b/t/t3406-rebase-message.sh\n@@ -17,14 +17,9 @@ test_expect_success 'setup' '\n \tgit tag start\n '\n \n-cat >expect <<\\EOF\n-Already applied: 0001 A\n-Already applied: 0002 B\n-Committed: 0003 Z\n-EOF\n-\n test_expect_success 'rebase -m' '\n \tgit rebase -m master >report &&\n+\t>expect &&\n \tsed -n -e \"/^Already applied: /p\" \\\n \t\t-e \"/^Committed: /p\" report >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh\nindex e243700660..c465713672 100755\n--- a/t/t3420-rebase-autostash.sh\n+++ b/t/t3420-rebase-autostash.sh\n@@ -53,41 +53,6 @@ create_expected_success_interactive () {\n \tEOF\n }\n \n-create_expected_success_merge () {\n-\tcat >expected <<-EOF\n-\t$(grep \"^Created autostash: [0-9a-f][0-9a-f]*\\$\" actual)\n-\tHEAD is now at $(git rev-parse --short feature-branch) third commit\n-\tFirst, rewinding head to replay your work on top of it...\n-\tMerging unrelated-onto-branch with HEAD~1\n-\tMerging:\n-\t$(git rev-parse --short unrelated-onto-branch) unrelated commit\n-\t$(git rev-parse --short feature-branch^) second commit\n-\tfound 1 common ancestor:\n-\t$(git rev-parse --short feature-branch~2) initial commit\n-\t[detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit\n-\t Author: A U Thor <author@example.com>\n-\t Date: Thu Apr 7 15:14:13 2005 -0700\n-\t 2 files changed, 2 insertions(+)\n-\t create mode 100644 file1\n-\t create mode 100644 file2\n-\tCommitted: 0001 second commit\n-\tMerging unrelated-onto-branch with HEAD~0\n-\tMerging:\n-\t$(git rev-parse --short rebased-feature-branch~1) second commit\n-\t$(git rev-parse --short feature-branch) third commit\n-\tfound 1 common ancestor:\n-\t$(git rev-parse --short feature-branch~1) second commit\n-\t[detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit\n-\t Author: A U Thor <author@example.com>\n-\t Date: Thu Apr 7 15:15:13 2005 -0700\n-\t 1 file changed, 1 insertion(+)\n-\t create mode 100644 file3\n-\tCommitted: 0002 third commit\n-\tAll done.\n-\tApplied autostash.\n-\tEOF\n-}\n-\n create_expected_failure_am () {\n \tcat >expected <<-EOF\n \t$(grep \"^Created autostash: [0-9a-f][0-9a-f]*\\$\" actual)\n@@ -112,43 +77,6 @@ create_expected_failure_interactive () {\n \tEOF\n }\n \n-create_expected_failure_merge () {\n-\tcat >expected <<-EOF\n-\t$(grep \"^Created autostash: [0-9a-f][0-9a-f]*\\$\" actual)\n-\tHEAD is now at $(git rev-parse --short feature-branch) third commit\n-\tFirst, rewinding head to replay your work on top of it...\n-\tMerging unrelated-onto-branch with HEAD~1\n-\tMerging:\n-\t$(git rev-parse --short unrelated-onto-branch) unrelated commit\n-\t$(git rev-parse --short feature-branch^) second commit\n-\tfound 1 common ancestor:\n-\t$(git rev-parse --short feature-branch~2) initial commit\n-\t[detached HEAD $(git rev-parse --short rebased-feature-branch~1)] second commit\n-\t Author: A U Thor <author@example.com>\n-\t Date: Thu Apr 7 15:14:13 2005 -0700\n-\t 2 files changed, 2 insertions(+)\n-\t create mode 100644 file1\n-\t create mode 100644 file2\n-\tCommitted: 0001 second commit\n-\tMerging unrelated-onto-branch with HEAD~0\n-\tMerging:\n-\t$(git rev-parse --short rebased-feature-branch~1) second commit\n-\t$(git rev-parse --short feature-branch) third commit\n-\tfound 1 common ancestor:\n-\t$(git rev-parse --short feature-branch~1) second commit\n-\t[detached HEAD $(git rev-parse --short rebased-feature-branch)] third commit\n-\t Author: A U Thor <author@example.com>\n-\t Date: Thu Apr 7 15:15:13 2005 -0700\n-\t 1 file changed, 1 insertion(+)\n-\t create mode 100644 file3\n-\tCommitted: 0002 third commit\n-\tAll done.\n-\tApplying autostash resulted in conflicts.\n-\tYour changes are safe in the stash.\n-\tYou can run \"git stash pop\" or \"git stash drop\" at any time.\n-\tEOF\n-}\n-\n testrebase () {\n \ttype=$1\n \tdotest=$2\n@@ -177,6 +105,9 @@ testrebase () {\n \ttest_expect_success \"rebase$type --autostash: check output\" '\n \t\ttest_when_finished git branch -D rebased-feature-branch &&\n \t\tsuffix=${type#\\ --} && suffix=${suffix:-am} &&\n+\t\tif test ${suffix} = \"merge\"; then\n+\t\t\tsuffix=interactive\n+\t\tfi &&\n \t\tcreate_expected_success_$suffix &&\n \t\ttest_i18ncmp expected actual\n \t'\n@@ -274,6 +205,9 @@ testrebase () {\n \ttest_expect_success \"rebase$type: check output with conflicting stash\" '\n \t\ttest_when_finished git branch -D rebased-feature-branch &&\n \t\tsuffix=${type#\\ --} && suffix=${suffix:-am} &&\n+\t\tif test ${suffix} = \"merge\"; then\n+\t\t\tsuffix=interactive\n+\t\tfi &&\n \t\tcreate_expected_failure_$suffix &&\n \t\ttest_i18ncmp expected actual\n \t'\ndiff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh\nindex 99b2aac921..911ef49f70 100755\n--- a/t/t3421-rebase-topology-linear.sh\n+++ b/t/t3421-rebase-topology-linear.sh\n@@ -111,7 +111,7 @@ test_run_rebase () {\n \t\"\n }\n test_run_rebase success ''\n-test_run_rebase failure -m\n+test_run_rebase success -m\n test_run_rebase success -i\n test_run_rebase success -p\n \n@@ -126,7 +126,7 @@ test_run_rebase () {\n \t\"\n }\n test_run_rebase success ''\n-test_run_rebase failure -m\n+test_run_rebase success -m\n test_run_rebase success -i\n test_run_rebase success -p\n \n@@ -141,7 +141,7 @@ test_run_rebase () {\n \t\"\n }\n test_run_rebase success ''\n-test_run_rebase failure -m\n+test_run_rebase success -m\n test_run_rebase success -i\n test_run_rebase success -p\n \n@@ -284,7 +284,7 @@ test_run_rebase () {\n \t\"\n }\n test_run_rebase success ''\n-test_run_rebase failure -m\n+test_run_rebase success -m\n test_run_rebase success -i\n test_run_rebase success -p\n \n@@ -315,7 +315,7 @@ test_run_rebase () {\n \t\"\n }\n test_run_rebase success ''\n-test_run_rebase failure -m\n+test_run_rebase success -m\n test_run_rebase success -i\n test_run_rebase failure -p\n \ndiff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh\nindex 846f85c27e..cd505c0711 100755\n--- a/t/t3425-rebase-topology-merges.sh\n+++ b/t/t3425-rebase-topology-merges.sh\n@@ -72,7 +72,7 @@ test_run_rebase () {\n }\n #TODO: make order consistent across all flavors of rebase\n test_run_rebase success 'e n o' ''\n-test_run_rebase success 'e n o' -m\n+test_run_rebase success 'n o e' -m\n test_run_rebase success 'n o e' -i\n \n test_run_rebase () {\n@@ -89,7 +89,7 @@ test_run_rebase () {\n }\n #TODO: make order consistent across all flavors of rebase\n test_run_rebase success 'd e n o' ''\n-test_run_rebase success 'd e n o' -m\n+test_run_rebase success 'd n o e' -m\n test_run_rebase success 'd n o e' -i\n \n test_run_rebase () {\n@@ -106,7 +106,7 @@ test_run_rebase () {\n }\n #TODO: make order consistent across all flavors of rebase\n test_run_rebase success 'd e n o' ''\n-test_run_rebase success 'd e n o' -m\n+test_run_rebase success 'd n o e' -m\n test_run_rebase success 'd n o e' -i\n \n test_expect_success \"rebase -p is no-op in non-linear history\" \"\ndiff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\nindex 9b2a274c71..145c61251d 100755\n--- a/t/t5407-post-rewrite-hook.sh\n+++ b/t/t5407-post-rewrite-hook.sh\n@@ -120,6 +120,7 @@ test_expect_success 'git rebase -m --skip' '\n \tgit rebase --continue &&\n \techo rebase >expected.args &&\n \tcat >expected.data <<-EOF &&\n+\t$(git rev-parse C) $(git rev-parse HEAD^)\n \t$(git rev-parse D) $(git rev-parse HEAD)\n \tEOF\n \tverify_hook_input\n-- \n2.18.0.rc1.12.g2996b9442d\n\n"},{"id":"349832","messageId":"nycvar.QRO.7.76.6.1806092336320.77@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"20180607171344.23331-2-newren@gmail.com","subject":"Re: [RFC PATCH 1/3] git-rebase, sequencer: add a --quiet option for the interactive machinery","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-06-09T21:45:46Z","receivedAt":"2018-06-09T21:46:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Thu, 7 Jun 2018, Elijah Newren wrote:\n\n> While 'quiet' and 'interactive' may sound like antonyms, the interactive\n> machinery actually has logic that implements several\n> interactive_rebase=implied cases (--exec, --keep-empty, --rebase-merges)\n> which won't pop up an editor.  Further, we want to make the interactive\n> machinery also take over for git-rebase--merge and become the default\n> merge strategy, so it makes sense for these other cases to have a quiet\n> option.\n> \n> git-rebase--interactive was already somewhat quieter than\n> git-rebase--merge and git-rebase--am, possibly because cherry-pick has\n> just traditionally been quieter.  As such, we only drop a few\n> informational messages -- \"Rebasing (n/m)\" and \"Succesfully rebased...\"\n\nMakes sense. As long as it is coordinated with Alban and Pratik, as both\nof their GSoC projects are affected by this.\n\nIn particular Pratik's project, I think, would actually *benefit* from\nyour work, as it might even make it possible to turn all modes but\n--preserve-merges into pure builtin code, which would be awesome.\n\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 06a7b79307..1f2401f702 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -139,8 +139,12 @@ mark_action_done () {\n>  \tif test \"$last_count\" != \"$new_count\"\n>  \tthen\n>  \t\tlast_count=$new_count\n> -\t\teval_gettext \"Rebasing (\\$new_count/\\$total)\"; printf \"\\r\"\n> -\t\ttest -z \"$verbose\" || echo\n> +\t\tif test -z \"$GIT_QUIET\"\n> +\t\tthen\n> +\t\t\teval_gettext \"Rebasing (\\$new_count/\\$total)\";\n> +\t\t\tprintf \"\\r\"\n> +\t\t\ttest -z \"$verbose\" || echo\n> +\t\tfi\n>  \tfi\n>  }\n>  \n> @@ -713,6 +717,7 @@ Commit or stash your changes, and then run\n>  \t\t\"$hook\" rebase < \"$rewritten_list\"\n>  \t\ttrue # we don't care if this hook failed\n>  \tfi &&\n> +\t\ttest -z \"$GIT_QUIET\" &&\n>  \t\twarn \"$(eval_gettext \"Successfully rebased and updated \\$head_name.\")\"\n\nIn general, I tried the statements to return success at all times. That\nmeans that\n\n\t\ttest -n \"$GIT_QUIET\" ||\n\nwould be better in this case.\n\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 7d1612b31b..b639c0d4fe 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -136,7 +136,7 @@ write_basic_state () {\n>  \techo \"$head_name\" > \"$state_dir\"/head-name &&\n>  \techo \"$onto\" > \"$state_dir\"/onto &&\n>  \techo \"$orig_head\" > \"$state_dir\"/orig-head &&\n> -\techo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n> +\ttest t = \"$GIT_QUIET\" && : > \"$state_dir\"/quiet\n\nMaybe it would be better to `echo t` into that file? That way, scripts\nthat used the value in that file would continue to work. (But maybe there\nwere no scripts that could use it, as only the interactive rebase allows\nscripting, and it did not handle that flag before?)\n\nThe rest looks obviously good.\n\nThank you!\nDscho\n"},{"id":"349833","messageId":"nycvar.QRO.7.76.6.1806092348390.77@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"20180607171344.23331-3-newren@gmail.com","subject":"Re: [RFC PATCH 2/3] rebase: Implement --merge via git-rebase--interactive","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-06-09T22:04:13Z","receivedAt":"2018-06-09T22:11:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Thu, 7 Jun 2018, Elijah Newren wrote:\n\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 451252c173..28d1658d7a 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -275,6 +275,10 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n>  conflict happens, the side reported as 'ours' is the so-far rebased\n>  series, starting with <upstream>, and 'theirs' is the working branch.  In\n>  other words, the sides are swapped.\n> ++\n> +This uses the `--interactive` machinery internally, and as such,\n> +anything that is incompatible with --interactive is incompatible\n> +with this option.\n\nI am not sure I like this change, as it describes an implementation detail\nthat users should neither know, nor care about, nor rely on.\n\n> @@ -328,8 +332,8 @@ which makes little sense.\n>  \tand after each change.  When fewer lines of surrounding\n>  \tcontext exist they all must match.  By default no context is\n>  \tever ignored.\n> -\tIncompatible with the --merge and --interactive options, or\n> -\tanything that implies those options or their machinery.\n> +\tIncompatible with the --interactive option, or anything that\n> +\tuses the `--interactive` machinery.\n>  \n>  -f::\n>  --force-rebase::\n> @@ -361,15 +365,15 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n>  --whitespace=<option>::\n>  \tThese flag are passed to the 'git apply' program\n>  \t(see linkgit:git-apply[1]) that applies the patch.\n> -\tIncompatible with the --merge and --interactive options, or\n> -\tanything that implies those options or their machinery.\n> +\tIncompatible with the --interactive option, or anything that\n> +\tuses the `--interactive` machinery.\n>  \n>  --committer-date-is-author-date::\n>  --ignore-date::\n>  \tThese flags are passed to 'git am' to easily change the dates\n>  \tof the rebased commits (see linkgit:git-am[1]).\n> -\tIncompatible with the --merge and --interactive options, or\n> -\tanything that implies those options or their machinery.\n> +\tIncompatible with the --interactive option, or anything that\n> +\tuses the `--interactive` machinery.\n>  \n>  --signoff::\n>  \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n\nFor above-mentioned reason, I'd suggest dropping these three hunks.\n\n> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n> index 1f2401f702..dcc4a26a78 100644\n> --- a/git-rebase--interactive.sh\n> +++ b/git-rebase--interactive.sh\n> @@ -885,7 +885,10 @@ init_basic_state () {\n>  \tmkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n>  \trm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n>  \n> -\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n> +\tif test -n \"$actually_interactive\"\n> +\tthen\n> +\t\t: > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n> +\tfi\n\nDo we really care at this stage? IOW what breaks if we still write that\nfile, even in --merge mode?\n\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index b639c0d4fe..5ac1dee30b 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -239,12 +239,10 @@ then\n>  \tstate_dir=\"$apply_dir\"\n>  elif test -d \"$merge_dir\"\n>  then\n> +\ttype=interactive\n>  \tif test -f \"$merge_dir\"/interactive\n>  \tthen\n> -\t\ttype=interactive\n>  \t\tinteractive_rebase=explicit\n> -\telse\n> -\t\ttype=merge\n>  \tfi\n>  \tstate_dir=\"$merge_dir\"\n>  fi\n\nThis makes me think even more that we don't care...\n\n> @@ -481,13 +479,16 @@ then\n>  \ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n>  fi\n>  \n> +actually_interactive=\n>  if test -n \"$interactive_rebase\"\n>  then\n>  \ttype=interactive\n> +\tactually_interactive=t\n>  \tstate_dir=\"$merge_dir\"\n>  elif test -n \"$do_merge\"\n>  then\n> -\ttype=merge\n> +\tinteractive_rebase=implied\n> +\ttype=interactive\n>  \tstate_dir=\"$merge_dir\"\n>  else\n>  \ttype=am\n> @@ -501,17 +502,11 @@ fi\n>  \n>  if test -n \"$git_am_opt\"; then\n>  \tincompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n> -\tif test -n \"$interactive_rebase\"\n> +\tif test -n \"$incompatible_opts\"\n\nDid you not mean to turn this into a test for actually_interactve ||\ndo_merge?\n\n>  \tthen\n> -\t\tif test -n \"$incompatible_opts\"\n> +\t\tif test -n \"$actually_interactive\" || test \"$do_merge\"\n\nThis could now be combined with the previous if (and the `-n` could be\nadded to the latter test):\n\n\tif test -n \"$actually_interactive\" -o -n \"$do_merge\" &&\n\t\ttest -n \"$incompatible_opts\"\n\nThe indentation would change, but this hunk is already confusing to read,\nanyway, so...\n\n>  \t\tthen\n> -\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n> -\t\tfi\n> -\tfi\n> -\tif test -n \"$do_merge\"; then\n> -\t\tif test -n \"$incompatible_opts\"\n> -\t\tthen\n> -\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n> +\t\t\tdie \"$(gettext \"error: cannot combine am options ($incompatible_opts) with either interactive or merge options\")\"\n>  \t\tfi\n>  \tfi\n>  fi\n> @@ -660,7 +655,7 @@ require_clean_work_tree \"rebase\" \"$(gettext \"Please commit or stash them.\")\"\n>  # but this should be done only when upstream and onto are the same\n>  # and if this is not an interactive rebase.\n>  mb=$(git merge-base \"$onto\" \"$orig_head\")\n> -if test \"$type\" != interactive && test \"$upstream\" = \"$onto\" &&\n> +if test -z \"$actually_interactive\" && test \"$upstream\" = \"$onto\" &&\n>  \ttest \"$mb\" = \"$onto\" && test -z \"$restrict_revision\" &&\n>  \t# linear history?\n>  \t! (git rev-list --parents \"$onto\"..\"$orig_head\" | sane_grep \" .* \") > /dev/null\n> @@ -704,6 +699,22 @@ then\n>  \tGIT_PAGER='' git diff --stat --summary \"$mb\" \"$onto\"\n>  fi\n>  \n> +if test -z \"$actually_interactive\"\n> +then\n> +\t# If the $onto is a proper descendant of the tip of the branch, then\n> +\t# we just fast-forwarded.\n> +\tif test \"$mb\" = \"$orig_head\"\n> +\tthen\n\nLikewise, this would be easier to read as\n\n\tif test -z \"$actually_interactive\" && test \"$mb\" = \"$orig_head\"\n\nAlso: how certain are we that \"$mb\" does not start with a dash? We may\nhave to use the `test a\"$mb\" = a\"$orig_head\"` trick here... But I guess\nthis is moved code, so if it is buggy, it was buggy before.\n\n> +\t\tsay \"$(eval_gettext \"Fast-forwarded \\$branch_name to \\$onto_name.\")\"\n> +\t\tGIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\" \\\n> +\t\t\tgit checkout -q \"$onto^0\" || die \"could not detach HEAD\"\n> +\t\tgit update-ref ORIG_HEAD $orig_head\n> +\t\tmove_to_original_branch\n> +\t\tfinish_rebase\n> +\t\texit 0\n> +\tfi\n> +fi\n> +\n>  test \"$type\" = interactive && run_specific_rebase\n>  \n>  # Detach HEAD and reset the tree\n> @@ -713,16 +724,6 @@ GIT_REFLOG_ACTION=\"$GIT_REFLOG_ACTION: checkout $onto_name\" \\\n>  \tgit checkout -q \"$onto^0\" || die \"could not detach HEAD\"\n>  git update-ref ORIG_HEAD $orig_head\n>  \n> -# If the $onto is a proper descendant of the tip of the branch, then\n> -# we just fast-forwarded.\n> -if test \"$mb\" = \"$orig_head\"\n> -then\n> -\tsay \"$(eval_gettext \"Fast-forwarded \\$branch_name to \\$onto_name.\")\"\n> -\tmove_to_original_branch\n> -\tfinish_rebase\n> -\texit 0\n> -fi\n> -\n>  if test -n \"$rebase_root\"\n>  then\n>  \trevisions=\"$onto..$orig_head\"\n> diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\n> index 0392e36d23..04d6c71899 100755\n> --- a/t/t3406-rebase-message.sh\n> +++ b/t/t3406-rebase-message.sh\n> @@ -17,14 +17,9 @@ test_expect_success 'setup' '\n>  \tgit tag start\n>  '\n>  \n> -cat >expect <<\\EOF\n> -Already applied: 0001 A\n> -Already applied: 0002 B\n> -Committed: 0003 Z\n> -EOF\n> -\n>  test_expect_success 'rebase -m' '\n>  \tgit rebase -m master >report &&\n> +\t>expect &&\n>  \tsed -n -e \"/^Already applied: /p\" \\\n>  \t\t-e \"/^Committed: /p\" report >actual &&\n>  \ttest_cmp expect actual\n\nThis might be called a regression... I don't know any user of `git rebase\n-m`, but I guess if I was one, I would like to keep seeing those messages.\n\nIt *should* be relatively easy to tell the sequencer.c to issue these\nmessages, I think. But it would be more work.\n\n> diff --git a/t/t3421-rebase-topology-linear.sh b/t/t3421-rebase-topology-linear.sh\n> index 99b2aac921..911ef49f70 100755\n> --- a/t/t3421-rebase-topology-linear.sh\n> +++ b/t/t3421-rebase-topology-linear.sh\n> @@ -111,7 +111,7 @@ test_run_rebase () {\n>  \t\"\n>  }\n>  test_run_rebase success ''\n> -test_run_rebase failure -m\n> +test_run_rebase success -m\n>  test_run_rebase success -i\n>  test_run_rebase success -p\n>  \n> @@ -126,7 +126,7 @@ test_run_rebase () {\n>  \t\"\n>  }\n>  test_run_rebase success ''\n> -test_run_rebase failure -m\n> +test_run_rebase success -m\n>  test_run_rebase success -i\n>  test_run_rebase success -p\n>  \n> @@ -141,7 +141,7 @@ test_run_rebase () {\n>  \t\"\n>  }\n>  test_run_rebase success ''\n> -test_run_rebase failure -m\n> +test_run_rebase success -m\n>  test_run_rebase success -i\n>  test_run_rebase success -p\n>  \n> @@ -284,7 +284,7 @@ test_run_rebase () {\n>  \t\"\n>  }\n>  test_run_rebase success ''\n> -test_run_rebase failure -m\n> +test_run_rebase success -m\n>  test_run_rebase success -i\n>  test_run_rebase success -p\n>  \n> @@ -315,7 +315,7 @@ test_run_rebase () {\n>  \t\"\n>  }\n>  test_run_rebase success ''\n> -test_run_rebase failure -m\n> +test_run_rebase success -m\n>  test_run_rebase success -i\n>  test_run_rebase failure -p\n\nNeat!\n\n> diff --git a/t/t3425-rebase-topology-merges.sh b/t/t3425-rebase-topology-merges.sh\n> index 846f85c27e..cd505c0711 100755\n> --- a/t/t3425-rebase-topology-merges.sh\n> +++ b/t/t3425-rebase-topology-merges.sh\n> @@ -72,7 +72,7 @@ test_run_rebase () {\n>  }\n>  #TODO: make order consistent across all flavors of rebase\n>  test_run_rebase success 'e n o' ''\n> -test_run_rebase success 'e n o' -m\n> +test_run_rebase success 'n o e' -m\n>  test_run_rebase success 'n o e' -i\n>  \n>  test_run_rebase () {\n> @@ -89,7 +89,7 @@ test_run_rebase () {\n>  }\n>  #TODO: make order consistent across all flavors of rebase\n>  test_run_rebase success 'd e n o' ''\n> -test_run_rebase success 'd e n o' -m\n> +test_run_rebase success 'd n o e' -m\n>  test_run_rebase success 'd n o e' -i\n>  \n>  test_run_rebase () {\n> @@ -106,7 +106,7 @@ test_run_rebase () {\n>  }\n>  #TODO: make order consistent across all flavors of rebase\n>  test_run_rebase success 'd e n o' ''\n> -test_run_rebase success 'd e n o' -m\n> +test_run_rebase success 'd n o e' -m\n>  test_run_rebase success 'd n o e' -i\n\nNice!\n\n>  test_expect_success \"rebase -p is no-op in non-linear history\" \"\n> diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\n> index 9b2a274c71..145c61251d 100755\n> --- a/t/t5407-post-rewrite-hook.sh\n> +++ b/t/t5407-post-rewrite-hook.sh\n> @@ -120,6 +120,7 @@ test_expect_success 'git rebase -m --skip' '\n>  \tgit rebase --continue &&\n>  \techo rebase >expected.args &&\n>  \tcat >expected.data <<-EOF &&\n> +\t$(git rev-parse C) $(git rev-parse HEAD^)\n>  \t$(git rev-parse D) $(git rev-parse HEAD)\n>  \tEOF\n>  \tverify_hook_input\n\nThis is a bit sad, because it seems to suggest that we now do more\nunnecessary work here, or is my reading incorrect?\n\nThanks,\nDscho\n"},{"id":"349834","messageId":"nycvar.QRO.7.76.6.1806100006000.77@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"20180607171344.23331-4-newren@gmail.com","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-06-09T22:11:00Z","receivedAt":"2018-06-09T22:11:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Thu, 7 Jun 2018, Elijah Newren wrote:\n\n> am-based rebases suffer from an reduced ability to detect directory\n> renames upstream, which is fundamental to the fact that it throws away\n> information about the history: in particular, it dispenses with the\n> original commits involved by turning them into patches, and without the\n> knowledge of the original commits we cannot determine a proper merge base.\n> \n> The am-based rebase will proceed by first trying git-apply, and, only if\n> it fails, will try to reconstruct a provisional merge base using\n> build_fake_ancestor().  This fake ancestor will ONLY contain the files\n> modified in the patch; without the full list of files in the real merge\n> base, renames of any missing files cannot be detected.  Directory rename\n> detection works by looking at individual file renames and deducing when a\n> full directory has been renamed.\n> \n> Trying to modify build_fake_ancestor() to instead create a merge base that\n> includes common file information by looking for a commit that contained\n> all the same blobs as the pre-image of the patch would require a very\n> expensive search through history, may find the wrong commit, and outside\n> of rebase may not find any commit that matches.\n> \n> But we had all the relevant information to start.  So, instead of\n> attempting to fix am which just doesn't have the relevant information,\n> instead note its strength and weaknesses, and change the default rebase\n> machinery to interactive since it does not suffer from the same problems.\n\nI'll let Eric comment on the grammar, and I'll comment on the idea behind\nthis commit instead.\n\nIMHO `git rebase -i` is still too slow to be a true replacement for `git\nrebase --am` for the cases where it serves the user well. Maybe we should\nwork on making `rebase -i` faster, first?\n\nI imagine, for example, that it might make *tons* of sense to avoid\nwriting out the index and worktree files all the time. That was necessary\nin the shell script version because if the ridiculous limitations we\nsubjected ourselves to, such as: no object-oriented state worth\nmentioning, only string-based processing, etc. But we could now start to\ndo everything in memory (*maybe* write out the new blob/tree/commit\nobjects immediately, but maybe not) until the time when we either have\nsucceeded in the rebase, or when there was a problem and we have to exit\nwith an error. And only then write the files and the index.\n\nIn any case, I think that the rather noticeable change of the default\nwould probably necessitate a deprecation phase.\n\nCiao,\nDscho\n"},{"id":"349838","messageId":"CABPp-BHHgtmtn=menfk5L5s9nmG1NkNa9rfw-_kjvm+U8tUo1Q@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1806092336320.77@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 1/3] git-rebase, sequencer: add a --quiet option for the interactive machinery","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-09T23:05:21Z","receivedAt":"2018-06-09T23:05:25Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Sat, Jun 9, 2018 at 2:45 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Thu, 7 Jun 2018, Elijah Newren wrote:\n>\n>> While 'quiet' and 'interactive' may sound like antonyms, the interactive\n>> machinery actually has logic that implements several\n>> interactive_rebase=implied cases (--exec, --keep-empty, --rebase-merges)\n>> which won't pop up an editor.  Further, we want to make the interactive\n>> machinery also take over for git-rebase--merge and become the default\n>> merge strategy, so it makes sense for these other cases to have a quiet\n>> option.\n>>\n>> git-rebase--interactive was already somewhat quieter than\n>> git-rebase--merge and git-rebase--am, possibly because cherry-pick has\n>> just traditionally been quieter.  As such, we only drop a few\n>> informational messages -- \"Rebasing (n/m)\" and \"Succesfully rebased...\"\n>\n> Makes sense. As long as it is coordinated with Alban and Pratik, as both\n> of their GSoC projects are affected by this.\n\nI had Alban cc'ed, and had looked briefly at the GSoC projects but\nsomehow missed that Pratik was also working in the area.  Adding him\nto cc.\n\n> In particular Pratik's project, I think, would actually *benefit* from\n> your work, as it might even make it possible to turn all modes but\n> --preserve-merges into pure builtin code, which would be awesome.\n\n:-)\n\n>> @@ -713,6 +717,7 @@ Commit or stash your changes, and then run\n>>               \"$hook\" rebase < \"$rewritten_list\"\n>>               true # we don't care if this hook failed\n>>       fi &&\n>> +             test -z \"$GIT_QUIET\" &&\n>>               warn \"$(eval_gettext \"Successfully rebased and updated \\$head_name.\")\"\n>\n> In general, I tried the statements to return success at all times. That\n> means that\n>\n>                 test -n \"$GIT_QUIET\" ||\n>\n> would be better in this case.\n\nGood point, I'll switch it over.\n\n>> diff --git a/git-rebase.sh b/git-rebase.sh\n>> index 7d1612b31b..b639c0d4fe 100755\n>> --- a/git-rebase.sh\n>> +++ b/git-rebase.sh\n>> @@ -136,7 +136,7 @@ write_basic_state () {\n>>       echo \"$head_name\" > \"$state_dir\"/head-name &&\n>>       echo \"$onto\" > \"$state_dir\"/onto &&\n>>       echo \"$orig_head\" > \"$state_dir\"/orig-head &&\n>> -     echo \"$GIT_QUIET\" > \"$state_dir\"/quiet &&\n>> +     test t = \"$GIT_QUIET\" && : > \"$state_dir\"/quiet\n>\n> Maybe it would be better to `echo t` into that file? That way, scripts\n> that used the value in that file would continue to work. (But maybe there\n> were no scripts that could use it, as only the interactive rebase allows\n> scripting, and it did not handle that flag before?)\n\nRight, I don't think we had users before, and I'd rather make the code\na little more self-consistent.  In particular, since\n$state_dir/verbose work based off the presence of the file rather than\nthe contents, I'd rather we just did the same for $state_dir/quiet.\n\nHowever, there is one bug here; in order to make it like verbose, I\nneed to also make the following change:\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex c8c3d0d05a..8f0c7a4738 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -119,7 +119,7 @@ read_basic_state () {\n        else\n                orig_head=$(cat \"$state_dir\"/head)\n        fi &&\n-       GIT_QUIET=$(cat \"$state_dir\"/quiet) &&\n+       test -f \"$state_dir\"/quiet && GIT_QUIET=t\n        test -f \"$state_dir\"/verbose && verbose=t\n        test -f \"$state_dir\"/strategy && strategy=\"$(cat \"$state_dir\"/strategy)\"\n        test -f \"$state_dir\"/strategy_opts &&\n\n\n> The rest looks obviously good.\n\n\nThanks!\nElijah\n"},{"id":"349842","messageId":"CABPp-BG6WFCBm0u+=Jxi2PGYgKHPifEcxpSkrPBoM39-49dKDw@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1806092348390.77@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 2/3] rebase: Implement --merge via git-rebase--interactive","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-10T01:14:48Z","receivedAt":"2018-06-10T01:15:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Sat, Jun 9, 2018 at 3:04 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Thu, 7 Jun 2018, Elijah Newren wrote:\n>\n>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>> index 451252c173..28d1658d7a 100644\n>> --- a/Documentation/git-rebase.txt\n>> +++ b/Documentation/git-rebase.txt\n>> @@ -275,6 +275,10 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n>>  conflict happens, the side reported as 'ours' is the so-far rebased\n>>  series, starting with <upstream>, and 'theirs' is the working branch.  In\n>>  other words, the sides are swapped.\n>> ++\n>> +This uses the `--interactive` machinery internally, and as such,\n>> +anything that is incompatible with --interactive is incompatible\n>> +with this option.\n>\n> I am not sure I like this change, as it describes an implementation detail\n> that users should neither know, nor care about, nor rely on.\n\nLet me back up for just a second to see if I can point out the real\nproblem I'm trying to address here, which you may have a better\nsolution for.  What should happen if a user runs\n   git rebase --merge --whitespace=fix\n?\n\ngit currently silently ignores the --whitepsace=fix argument, leaving\nthe whitespace damage present at the end of the rebase.  Same goes for\n--interactive combined with any am-specific options  (Fix proposed at\nhttps://public-inbox.org/git/20180607050654.19663-2-newren@gmail.com/).\nThis silent ignoring of some options depending on which other options\nwere specified has caused me problems in the past.\n\nSo, while I totally agree with you that users shouldn't need to know\nimplementation details, they do need to know how to use commands and\nwhich options go well together and which are mutually incompatible.\nDo you have any suggestions on alternate wording that would convey the\nsets of mutually incompatible options without talking about\nimplementation details?  Would you rather only address that in the\ncode and not mention it in the documentation?\n\nSee also https://public-inbox.org/git/20180607050654.19663-1-newren@gmail.com/,\nwhich proposes testcases for these incompatibility sets.\n\n\n>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>> index 1f2401f702..dcc4a26a78 100644\n>> --- a/git-rebase--interactive.sh\n>> +++ b/git-rebase--interactive.sh\n>> @@ -885,7 +885,10 @@ init_basic_state () {\n>>       mkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n>>       rm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n>>\n>> -     : > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n>> +     if test -n \"$actually_interactive\"\n>> +     then\n>> +             : > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n>> +     fi\n>\n> Do we really care at this stage? IOW what breaks if we still write that\n> file, even in --merge mode?\n\nTwo things will change if we do that:\n  * bash prompt will be different for those using git-prompt.sh\n(REBASE-m vs. REBASE-i).\n  * git-status output is no longer the same ('rebase in progress' vs.\n'interactive rebase in progress...last command done:...pick 0dea123 my\nwonderful commit')\n\nI don't think the prompt is a big deal.  The status output might not\nbe either, but showing the \"last command done\" may be weird to someone\nthat never saw or edited a list of commands.  (Then again, that same\nargument could be made for users of --exec, --rebase-merges, or\n--keep-empty without an explicit --interactive)\n\nOpinions on whether these two difference matter?  If others don't\nthink these differences are significant, I'm happy to update any\nnecessary testcases and just unconditionally create the\n$state_dir/interactive file.\n\n\n>> @@ -501,17 +502,11 @@ fi\n>>\n>>  if test -n \"$git_am_opt\"; then\n>>       incompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n>> -     if test -n \"$interactive_rebase\"\n>> +     if test -n \"$incompatible_opts\"\n>\n> Did you not mean to turn this into a test for actually_interactve ||\n> do_merge?\n>\n>>       then\n>> -             if test -n \"$incompatible_opts\"\n>> +             if test -n \"$actually_interactive\" || test \"$do_merge\"\n>\n> This could now be combined with the previous if (and the `-n` could be\n> added to the latter test):\n>\n>         if test -n \"$actually_interactive\" -o -n \"$do_merge\" &&\n>                 test -n \"$incompatible_opts\"\n>\n> The indentation would change, but this hunk is already confusing to read,\n> anyway, so...\n\nI'm happy to switch the order of the nesting as you suggest and agree\nthat it would make it easier to read.  However, I hesitate to combine\nthe two if-lines.  When I read your combined suggested line, I parsed\nit as follows (using invalid pseduo-syntax just to convey grouping):\n\n  ( -n \"$actually_interactive ) || ( -n \"$do_merge\" && -n \"$incompatible_opts\" )\n\nGranted, I parsed it wrong, putting the parentheses in the wrong\nplaces, and bash parses it as you intended.  While you may have\nprecedence and left- vs. right- associativity rules down pat, I\nclearly didn't.  If we combine the lines, I'll probably mis-read them\nagain when I see them in a year or more.\n\n>> @@ -704,6 +699,22 @@ then\n>>       GIT_PAGER='' git diff --stat --summary \"$mb\" \"$onto\"\n>>  fi\n>>\n>> +if test -z \"$actually_interactive\"\n>> +then\n>> +     # If the $onto is a proper descendant of the tip of the branch, then\n>> +     # we just fast-forwarded.\n>> +     if test \"$mb\" = \"$orig_head\"\n>> +     then\n>\n> Likewise, this would be easier to read as\n>\n>         if test -z \"$actually_interactive\" && test \"$mb\" = \"$orig_head\"\n\nGood point, I'll fix that up.\n\n> Also: how certain are we that \"$mb\" does not start with a dash? We may\n> have to use the `test a\"$mb\" = a\"$orig_head\"` trick here... But I guess\n> this is moved code, so if it is buggy, it was buggy before.\n\nFrom earlier in the file,\nmb=$(git merge-base ...)\n\nSo, unless we're expecting the output of git-merge-base to change in\nthe future to include leading dashes, we shouldn't hit any issues.  I\ncan make the change you suggest if you're worried, though.\n\n>> diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\n>> index 0392e36d23..04d6c71899 100755\n>> --- a/t/t3406-rebase-message.sh\n>> +++ b/t/t3406-rebase-message.sh\n>> @@ -17,14 +17,9 @@ test_expect_success 'setup' '\n>>       git tag start\n>>  '\n>>\n>> -cat >expect <<\\EOF\n>> -Already applied: 0001 A\n>> -Already applied: 0002 B\n>> -Committed: 0003 Z\n>> -EOF\n>> -\n>>  test_expect_success 'rebase -m' '\n>>       git rebase -m master >report &&\n>> +     >expect &&\n>>       sed -n -e \"/^Already applied: /p\" \\\n>>               -e \"/^Committed: /p\" report >actual &&\n>>       test_cmp expect actual\n>\n> This might be called a regression... I don't know any user of `git rebase\n> -m`, but I guess if I was one, I would like to keep seeing those messages.\n>\n> It *should* be relatively easy to tell the sequencer.c to issue these\n> messages, I think. But it would be more work.\n\nYou may well be right.  Here's where my thinking came from...\n\nam-based, interactive-based, and merge-based rebases have lots of\nlittle ways in which they have differed, this being just one of them.\nIt was sometimes hard making a judgement call when writing this series\nabout whether any given deviation was a difference I wanted to smooth\nover or a difference I wanted to perpetuate between various flags.\nFurther, if it was a difference I wanted to smooth over, then I had to\ndecide which of the current behaviors was 'correct'.\n\nIn this particular case, I basically went off perceived usage.\nam-based rebases have lots of special flags relevant to it only\n(--whitespace, -C, etc.) and is the default, so it clearly has lots of\nusers.  interactive-based rebases are pretty prominent too, and have\nvery specific special capabilities the other modes don't.  In\ncontrast, merge-based rebases can't do a single thing that interactive\ncan't; and unless you're using a special merge strategy, for the last\n10 years merge-based rebases haven't been able to do anything a normal\nam-based rebase couldn't.  merge-based rebases were added in mid-2006\nto handle renames, but am-based rebases gained that ability at the end\nof 2008.  Basically, rebase -m was dormant and useless...until\ndirectory rename detection became a thing this cycle.  (Also, in\nconfig options and documentation merge tends to be overlooked; just a\nsingle example is that pull.rebase can be set to interactive, but not\nto merge.)\n\nAnyway, with this in mind, I didn't think those extra messages were\nall that important.  If others disagree I can look into adding them --\nthat'd also make the --quiet mode more useful for interactive, since\nthere'd be more messages for it to strip out.\n\n>>  test_expect_success \"rebase -p is no-op in non-linear history\" \"\n>> diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\n>> index 9b2a274c71..145c61251d 100755\n>> --- a/t/t5407-post-rewrite-hook.sh\n>> +++ b/t/t5407-post-rewrite-hook.sh\n>> @@ -120,6 +120,7 @@ test_expect_success 'git rebase -m --skip' '\n>>       git rebase --continue &&\n>>       echo rebase >expected.args &&\n>>       cat >expected.data <<-EOF &&\n>> +     $(git rev-parse C) $(git rev-parse HEAD^)\n>>       $(git rev-parse D) $(git rev-parse HEAD)\n>>       EOF\n>>       verify_hook_input\n>\n> This is a bit sad, because it seems to suggest that we now do more\n> unnecessary work here, or is my reading incorrect?\n\nI agree that it's a bit sad.  I spent a while looking at this testcase\nand puzzling over what it meant, and my commit message pointed out\nthat I wasn't quite sure where it came from:\n\n      t5407: different rebase types varied slightly in how many times checkout\n             or commit or equivalents were called based on a quick comparison\n             of this tests and previous ones which covered different rebase\n             flavors.  I think this is just attributable to this difference.\n\nIt would be nice to avoid the extra work, but I'm worried tackling\nthat might cause me to step on toes of folks doing the rewrite of\ninteractive rebases from shell to C.  Maybe I should just add a TODO\nnote in the testcase, similar to the one in t3425 near a few lines I\ntouched in this patch?\n\n\nThanks for the detailed feedback and suggestions!\n\nElijah\n"},{"id":"349843","messageId":"CABPp-BHa+sxuFBa3EmSyio28ytF_ORn950Keh1P=L-VxXtOwMw@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1806100006000.77@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-10T01:31:16Z","receivedAt":"2018-06-10T01:38:44Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Sat, Jun 9, 2018 at 3:11 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Thu, 7 Jun 2018, Elijah Newren wrote:\n>\n>> am-based rebases suffer from an reduced ability to detect directory\n>> renames upstream, which is fundamental to the fact that it throws away\n>> information about the history: in particular, it dispenses with the\n>> original commits involved by turning them into patches, and without the\n>> knowledge of the original commits we cannot determine a proper merge base.\n>>\n>> The am-based rebase will proceed by first trying git-apply, and, only if\n>> it fails, will try to reconstruct a provisional merge base using\n>> build_fake_ancestor().  This fake ancestor will ONLY contain the files\n>> modified in the patch; without the full list of files in the real merge\n>> base, renames of any missing files cannot be detected.  Directory rename\n>> detection works by looking at individual file renames and deducing when a\n>> full directory has been renamed.\n>>\n>> Trying to modify build_fake_ancestor() to instead create a merge base that\n>> includes common file information by looking for a commit that contained\n>> all the same blobs as the pre-image of the patch would require a very\n>> expensive search through history, may find the wrong commit, and outside\n>> of rebase may not find any commit that matches.\n>>\n>> But we had all the relevant information to start.  So, instead of\n>> attempting to fix am which just doesn't have the relevant information,\n>> instead note its strength and weaknesses, and change the default rebase\n>> machinery to interactive since it does not suffer from the same problems.\n>\n> I'll let Eric comment on the grammar, and I'll comment on the idea behind\n> this commit instead.\n\nGoing to dump the hard job on Eric, eh?  ;-)\n\n> IMHO `git rebase -i` is still too slow to be a true replacement for `git\n> rebase --am` for the cases where it serves the user well. Maybe we should\n> work on making `rebase -i` faster, first?\n\nThat sounds fair.\n\n> I imagine, for example, that it might make *tons* of sense to avoid\n> writing out the index and worktree files all the time. That was necessary\n> in the shell script version because if the ridiculous limitations we\n> subjected ourselves to, such as: no object-oriented state worth\n> mentioning, only string-based processing, etc. But we could now start to\n> do everything in memory (*maybe* write out the new blob/tree/commit\n> objects immediately, but maybe not) until the time when we either have\n> succeeded in the rebase, or when there was a problem and we have to exit\n> with an error. And only then write the files and the index.\n\nHmm...are you still planning on using cherry-pick (internally rather\nthan forking, of course)?  Because cherry-pick uses the\nmerge-recursive machinery, and the merge-recursive machinery doesn't\nhave a nice way of avoiding writing to the working tree or index.\nFixing that is on my radar; see the first block of\nhttps://public-inbox.org/git/CABPp-BG2fZHm3s-yrzxyGj3Eh+O7_LHLz5pgstHhG2drigSyRA@mail.gmail.com/\n(reading up until \"At this point, I'd rather just fix the design flaw\nrather than complicate the code further.\")\n\nHowever, also covered in my plans is a few things to speed up the\nmerge-recursive machinery, which should provide some other performance\nbenefits for interactive rebases.\n\n> In any case, I think that the rather noticeable change of the default\n> would probably necessitate a deprecation phase.\n\nWhy is it a \"rather noticable change of the default\"?  If we popped up\nthe editor and asked the user to edit the list of options, I'd agree,\nor if folks thought that it was significantly slower by a big enough\nmargin (though you already suggested waiting and making sure we don't\ndo that).  What else remains that qualifies?\n\n(Okay, the default behavior to just skip empty patches rather than\nhalt the rebase and ask the user to advise is different, but we could\nfix that up too.  Is there anything else?)\n"},{"id":"349865","messageId":"8f19c8c2-d050-2d51-756d-d78b9f2bd335@talktalk.net","threadId":"48665","inReplyTo":"20180607050747.19726-1-newren@gmail.com","subject":"Re: [PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-10T19:26:47Z","receivedAt":"2018-06-10T19:26:54Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\nOn 07/06/18 06:07, Elijah Newren wrote:\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>   git-rebase.sh | 6 +-----\n>   1 file changed, 1 insertion(+), 5 deletions(-)\n> \n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 40be59ecc4..a56b286372 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -276,6 +276,7 @@ do\n>   \t\t;;\n>   \t--keep-empty)\n>   \t\tkeep_empty=yes\n> +\t\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n\nI think you need to wait until all the options have been parsed before \nsetting the implied interactive rebase in case the user specifies has \n'--keep-empty' in an alias and specifies '--no-keep-empty' with some am \noptions on the command line.\n\nBest Wishes\n\nPhillip\n>   \t\t;;\n>   \t--allow-empty-message)\n>   \t\tallow_empty_message=--allow-empty-message\n> @@ -480,11 +481,6 @@ then\n>   \ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n>   fi\n>   \n> -if test -n \"$keep_empty\"\n> -then\n> -\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n> -fi\n> -\n>   if test -n \"$interactive_rebase\"\n>   then\n>   \ttype=interactive\n> \n\n"},{"id":"349866","messageId":"cec770a8-28ee-d546-8c27-905d2fcdb0c8@talktalk.net","threadId":"48665","inReplyTo":"20180607050654.19663-2-newren@gmail.com","subject":"Re: [PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-10T19:40:24Z","receivedAt":"2018-06-10T19:40:30Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 07/06/18 06:06, Elijah Newren wrote:\n> git rebase has three different types: am, merge, and interactive, all of\n> which are implemented in terms of separate scripts.  am builds on git-am,\n> merge builds on git-merge-recursive, and interactive builds on\n> git-cherry-pick.  We make use of features in those lower-level commands in\n> the different rebase types, but those features don't exist in all of the\n> lower level commands so we have a range of incompatibilities.  Previously,\n> we just accepted nearly any argument and silently ignored whichever ones\n> weren't implemented for the type of rebase specified.  Change this so the\n> incompatibilities are documented, included in the testsuite, and tested\n> for at runtime with an appropriate error message shown.\n\nI think this is a great improvement, it has always bothered me that \nrebase silently ignored the am options when they're given with \ninteractive ones.\n> \n> Some exceptions I left out:\n> \n>    * --merge and --interactive are technically incompatible since they are\n>      supposed to run different underlying scripts, but with a few small\n>      changes, --interactive can do everything that --merge can.  In fact,\n>      I'll shortly be sending another patch to remove git-rebase--merge and\n>      reimplement it on top of git-rebase--interactive.\n\nExcellent I've wondered about doing that but never got round to it. One \nthing I was slightly concerned about was that someone maybe parsing the \noutput of git-rebase--merge and they'll get a nasty shock when that \noutput changes as a result of using the sequencer.\n\n> \n>    * One could argue that --interactive and --quiet are incompatible since\n>      --interactive doesn't implement a --quiet mode (perhaps since\n>      cherry-pick itself does not implement one).  However, the interactive\n>      mode is more quiet than the other modes in general with progress\n>      messages, so one could argue that it's already quiet.\n> \n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>   Documentation/git-rebase.txt           | 15 +++++++++++++--\n>   git-rebase.sh                          | 17 +++++++++++++++++\n>   t/t3422-rebase-incompatible-options.sh | 10 +++++-----\n>   3 files changed, 35 insertions(+), 7 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 0e20a66e73..451252c173 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -243,6 +243,10 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n>   --keep-empty::\n>   \tKeep the commits that do not change anything from its\n>   \tparents in the result.\n> ++\n> +This uses the `--interactive` machinery internally, and as such,\n> +anything that is incompatible with --interactive is incompatible\n> +with this option.\n>   \n>   --allow-empty-message::\n>   \tBy default, rebasing commits with an empty message will fail.\n> @@ -324,6 +328,8 @@ which makes little sense.\n>   \tand after each change.  When fewer lines of surrounding\n>   \tcontext exist they all must match.  By default no context is\n>   \tever ignored.\n> +\tIncompatible with the --merge and --interactive options, or\n> +\tanything that implies those options or their machinery.\n\nstruct replay_opts has an allow_empty_message member so I'm not sure \nthat's true.\n\n>   -f::\n>   --force-rebase::\n> @@ -355,13 +361,15 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n>   --whitespace=<option>::\n>   \tThese flag are passed to the 'git apply' program\n>   \t(see linkgit:git-apply[1]) that applies the patch.\n> -\tIncompatible with the --interactive option.\n> +\tIncompatible with the --merge and --interactive options, or\n> +\tanything that implies those options or their machinery.\n\nI wonder if it is better just to list the incompatible options it might \nbe a bit long but it would be nicer for the user than them having to \nwork out which options imply --interactive.\n\n>   --committer-date-is-author-date::\n>   --ignore-date::\n>   \tThese flags are passed to 'git am' to easily change the dates\n>   \tof the rebased commits (see linkgit:git-am[1]).\n> -\tIncompatible with the --interactive option.\n> +\tIncompatible with the --merge and --interactive options, or\n> +\tanything that implies those options or their machinery.\n>   \n>   --signoff::\n>   \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n> @@ -400,6 +408,9 @@ The `--rebase-merges` mode is similar in spirit to `--preserve-merges`, but\n>   in contrast to that option works well in interactive rebases: commits can be\n>   reordered, inserted and dropped at will.\n>   +\n> +This uses the `--interactive` machinery internally, but it can be run\n> +without an explicit `--interactive`.\n> ++\n\nWithout more context it's hard to judge but I'm not sure this adds \nanything useful\n\n>   It is currently only possible to recreate the merge commits using the\n>   `recursive` merge strategy; Different merge strategies can be used only via\n>   explicit `exec git merge -s <strategy> [...]` commands.\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 40be59ecc4..f1dbecba18 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -503,6 +503,23 @@ then\n>   \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n>   fi\n>   \n> +if test -n \"$git_am_opt\"; then\n> +\tincompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n\nI think the style guide recommends $() over ``\n\n> +\tif test -n \"$interactive_rebase\"\n> +\tthen\n> +\t\tif test -n \"$incompatible_opts\"\n> +\t\tthen\n> +\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n> +\t\tfi\n> +\tfi\n> +\tif test -n \"$do_merge\"; then\n> +\t\tif test -n \"$incompatible_opts\"\n> +\t\tthen\n> +\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n> +\t\tfi\n> +\tfi\n> +fi\n> +\n>   if test -n \"$signoff\"\n>   then\n>   \ttest -n \"$preserve_merges\" &&\n> diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\n> index 04cdae921b..66a83363bf 100755\n> --- a/t/t3422-rebase-incompatible-options.sh\n> +++ b/t/t3422-rebase-incompatible-options.sh\n> @@ -34,27 +34,27 @@ test_expect_success 'setup' '\n>   test_run_rebase () {\n>   \topt=$1\n>   \tshift\n> -\ttest_expect_failure \"$opt incompatible with --merge\" \"\n> +\ttest_expect_success \"$opt incompatible with --merge\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git rebase $opt --merge A\n>   \t\"\n>   \n> -\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n> +\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git rebase $opt --strategy=ours A\n>   \t\"\n>   \n> -\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n> +\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git rebase $opt --strategy=ours A\n>   \t\"\n>   \n> -\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n> +\ttest_expect_success \"$opt incompatible with --interactive\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git rebase $opt --interactive A\n>   \t\"\n>   \n> -\ttest_expect_failure \"$opt incompatible with --exec\" \"\n> +\ttest_expect_success \"$opt incompatible with --exec\" \"\n>   \t\tgit checkout B^0 &&\n>   \t\ttest_must_fail git rebase $opt --exec 'true' A\n>   \t\"\n> \n\n"},{"id":"349888","messageId":"0930b19b-4a19-5948-71b0-c8c9c5ac9b68@talktalk.net","threadId":"48665","inReplyTo":"CABPp-BG6WFCBm0u+=Jxi2PGYgKHPifEcxpSkrPBoM39-49dKDw@mail.gmail.com","subject":"Re: [RFC PATCH 2/3] rebase: Implement --merge via git-rebase--interactive","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-11T09:54:39Z","receivedAt":"2018-06-11T09:54:44Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 10/06/18 02:14, Elijah Newren wrote:\n> \n> Hi Dscho,\n> \n> On Sat, Jun 9, 2018 at 3:04 PM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n>> On Thu, 7 Jun 2018, Elijah Newren wrote:\n>>\n>>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>>> index 451252c173..28d1658d7a 100644\n>>> --- a/Documentation/git-rebase.txt\n>>> +++ b/Documentation/git-rebase.txt\n>>> @@ -275,6 +275,10 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n>>>  conflict happens, the side reported as 'ours' is the so-far rebased\n>>>  series, starting with <upstream>, and 'theirs' is the working branch.  In\n>>>  other words, the sides are swapped.\n>>> ++\n>>> +This uses the `--interactive` machinery internally, and as such,\n>>> +anything that is incompatible with --interactive is incompatible\n>>> +with this option.\n>>\n>> I am not sure I like this change, as it describes an implementation detail\n>> that users should neither know, nor care about, nor rely on.\n> \n> Let me back up for just a second to see if I can point out the real\n> problem I'm trying to address here, which you may have a better\n> solution for.  What should happen if a user runs\n>    git rebase --merge --whitespace=fix\n> ?\n> \n> git currently silently ignores the --whitepsace=fix argument, leaving\n> the whitespace damage present at the end of the rebase.  Same goes for\n> --interactive combined with any am-specific options  (Fix proposed at\n> https://public-inbox.org/git/20180607050654.19663-2-newren@gmail.com/).\n> This silent ignoring of some options depending on which other options\n> were specified has caused me problems in the past.\n> \n> So, while I totally agree with you that users shouldn't need to know\n> implementation details, they do need to know how to use commands and\n> which options go well together and which are mutually incompatible.\n> Do you have any suggestions on alternate wording that would convey the\n> sets of mutually incompatible options without talking about\n> implementation details?  Would you rather only address that in the\n> code and not mention it in the documentation?\n> \n> See also https://public-inbox.org/git/20180607050654.19663-1-newren@gmail.com/,\n> which proposes testcases for these incompatibility sets.\n> \n> \n>>> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\n>>> index 1f2401f702..dcc4a26a78 100644\n>>> --- a/git-rebase--interactive.sh\n>>> +++ b/git-rebase--interactive.sh\n>>> @@ -885,7 +885,10 @@ init_basic_state () {\n>>>       mkdir -p \"$state_dir\" || die \"$(eval_gettext \"Could not create temporary \\$state_dir\")\"\n>>>       rm -f \"$(git rev-parse --git-path REBASE_HEAD)\"\n>>>\n>>> -     : > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n>>> +     if test -n \"$actually_interactive\"\n>>> +     then\n>>> +             : > \"$state_dir\"/interactive || die \"$(gettext \"Could not mark as interactive\")\"\n>>> +     fi\n>>\n>> Do we really care at this stage? IOW what breaks if we still write that\n>> file, even in --merge mode?\n> \n> Two things will change if we do that:\n>   * bash prompt will be different for those using git-prompt.sh\n> (REBASE-m vs. REBASE-i).\n>   * git-status output is no longer the same ('rebase in progress' vs.\n> 'interactive rebase in progress...last command done:...pick 0dea123 my\n> wonderful commit')\n> \n> I don't think the prompt is a big deal.  The status output might not\n> be either, but showing the \"last command done\" may be weird to someone\n> that never saw or edited a list of commands.  (Then again, that same\n> argument could be made for users of --exec, --rebase-merges, or\n> --keep-empty without an explicit --interactive)\n> \n> Opinions on whether these two difference matter?  If others don't\n> think these differences are significant, I'm happy to update any\n> necessary testcases and just unconditionally create the\n> $state_dir/interactive file.\n\nI'm inclined to agree that it should just write the file\nunconditionally. As you point out it already does this for other things\nthat aren't \"interactive\" as far as the user is concerned. Someone could\nalways add an file to indicate the \"real\" mode later that would work for\nall the implicit interactive rebase cases if it was important to them.\n\nBest Wishes\n\nPhillip\n\n> \n>>> @@ -501,17 +502,11 @@ fi\n>>>\n>>>  if test -n \"$git_am_opt\"; then\n>>>       incompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n>>> -     if test -n \"$interactive_rebase\"\n>>> +     if test -n \"$incompatible_opts\"\n>>\n>> Did you not mean to turn this into a test for actually_interactve ||\n>> do_merge?\n>>\n>>>       then\n>>> -             if test -n \"$incompatible_opts\"\n>>> +             if test -n \"$actually_interactive\" || test \"$do_merge\"\n>>\n>> This could now be combined with the previous if (and the `-n` could be\n>> added to the latter test):\n>>\n>>         if test -n \"$actually_interactive\" -o -n \"$do_merge\" &&\n>>                 test -n \"$incompatible_opts\"\n>>\n>> The indentation would change, but this hunk is already confusing to read,\n>> anyway, so...\n> \n> I'm happy to switch the order of the nesting as you suggest and agree\n> that it would make it easier to read.  However, I hesitate to combine\n> the two if-lines.  When I read your combined suggested line, I parsed\n> it as follows (using invalid pseduo-syntax just to convey grouping):\n> \n>   ( -n \"$actually_interactive ) || ( -n \"$do_merge\" && -n \"$incompatible_opts\" )\n> \n> Granted, I parsed it wrong, putting the parentheses in the wrong\n> places, and bash parses it as you intended.  While you may have\n> precedence and left- vs. right- associativity rules down pat, I\n> clearly didn't.  If we combine the lines, I'll probably mis-read them\n> again when I see them in a year or more.\n> \n>>> @@ -704,6 +699,22 @@ then\n>>>       GIT_PAGER='' git diff --stat --summary \"$mb\" \"$onto\"\n>>>  fi\n>>>\n>>> +if test -z \"$actually_interactive\"\n>>> +then\n>>> +     # If the $onto is a proper descendant of the tip of the branch, then\n>>> +     # we just fast-forwarded.\n>>> +     if test \"$mb\" = \"$orig_head\"\n>>> +     then\n>>\n>> Likewise, this would be easier to read as\n>>\n>>         if test -z \"$actually_interactive\" && test \"$mb\" = \"$orig_head\"\n> \n> Good point, I'll fix that up.\n> \n>> Also: how certain are we that \"$mb\" does not start with a dash? We may\n>> have to use the `test a\"$mb\" = a\"$orig_head\"` trick here... But I guess\n>> this is moved code, so if it is buggy, it was buggy before.\n> \n> From earlier in the file,\n> mb=$(git merge-base ...)\n> \n> So, unless we're expecting the output of git-merge-base to change in\n> the future to include leading dashes, we shouldn't hit any issues.  I\n> can make the change you suggest if you're worried, though.\n> \n>>> diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh\n>>> index 0392e36d23..04d6c71899 100755\n>>> --- a/t/t3406-rebase-message.sh\n>>> +++ b/t/t3406-rebase-message.sh\n>>> @@ -17,14 +17,9 @@ test_expect_success 'setup' '\n>>>       git tag start\n>>>  '\n>>>\n>>> -cat >expect <<\\EOF\n>>> -Already applied: 0001 A\n>>> -Already applied: 0002 B\n>>> -Committed: 0003 Z\n>>> -EOF\n>>> -\n>>>  test_expect_success 'rebase -m' '\n>>>       git rebase -m master >report &&\n>>> +     >expect &&\n>>>       sed -n -e \"/^Already applied: /p\" \\\n>>>               -e \"/^Committed: /p\" report >actual &&\n>>>       test_cmp expect actual\n>>\n>> This might be called a regression... I don't know any user of `git rebase\n>> -m`, but I guess if I was one, I would like to keep seeing those messages.\n>>\n>> It *should* be relatively easy to tell the sequencer.c to issue these\n>> messages, I think. But it would be more work.\n> \n> You may well be right.  Here's where my thinking came from...\n> \n> am-based, interactive-based, and merge-based rebases have lots of\n> little ways in which they have differed, this being just one of them.\n> It was sometimes hard making a judgement call when writing this series\n> about whether any given deviation was a difference I wanted to smooth\n> over or a difference I wanted to perpetuate between various flags.\n> Further, if it was a difference I wanted to smooth over, then I had to\n> decide which of the current behaviors was 'correct'.\n> \n> In this particular case, I basically went off perceived usage.\n> am-based rebases have lots of special flags relevant to it only\n> (--whitespace, -C, etc.) and is the default, so it clearly has lots of\n> users.  interactive-based rebases are pretty prominent too, and have\n> very specific special capabilities the other modes don't.  In\n> contrast, merge-based rebases can't do a single thing that interactive\n> can't; and unless you're using a special merge strategy, for the last\n> 10 years merge-based rebases haven't been able to do anything a normal\n> am-based rebase couldn't.  merge-based rebases were added in mid-2006\n> to handle renames, but am-based rebases gained that ability at the end\n> of 2008.  Basically, rebase -m was dormant and useless...until\n> directory rename detection became a thing this cycle.  (Also, in\n> config options and documentation merge tends to be overlooked; just a\n> single example is that pull.rebase can be set to interactive, but not\n> to merge.)\n> \n> Anyway, with this in mind, I didn't think those extra messages were\n> all that important.  If others disagree I can look into adding them --\n> that'd also make the --quiet mode more useful for interactive, since\n> there'd be more messages for it to strip out.\n> \n>>>  test_expect_success \"rebase -p is no-op in non-linear history\" \"\n>>> diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh\n>>> index 9b2a274c71..145c61251d 100755\n>>> --- a/t/t5407-post-rewrite-hook.sh\n>>> +++ b/t/t5407-post-rewrite-hook.sh\n>>> @@ -120,6 +120,7 @@ test_expect_success 'git rebase -m --skip' '\n>>>       git rebase --continue &&\n>>>       echo rebase >expected.args &&\n>>>       cat >expected.data <<-EOF &&\n>>> +     $(git rev-parse C) $(git rev-parse HEAD^)\n>>>       $(git rev-parse D) $(git rev-parse HEAD)\n>>>       EOF\n>>>       verify_hook_input\n>>\n>> This is a bit sad, because it seems to suggest that we now do more\n>> unnecessary work here, or is my reading incorrect?\n> \n> I agree that it's a bit sad.  I spent a while looking at this testcase\n> and puzzling over what it meant, and my commit message pointed out\n> that I wasn't quite sure where it came from:\n> \n>       t5407: different rebase types varied slightly in how many times checkout\n>              or commit or equivalents were called based on a quick comparison\n>              of this tests and previous ones which covered different rebase\n>              flavors.  I think this is just attributable to this difference.\n> \n> It would be nice to avoid the extra work, but I'm worried tackling\n> that might cause me to step on toes of folks doing the rewrite of\n> interactive rebases from shell to C.  Maybe I should just add a TODO\n> note in the testcase, similar to the one in t3425 near a few lines I\n> touched in this patch?\n> \n> \n> Thanks for the detailed feedback and suggestions!\n> \n> Elijah\n> \n\n"},{"id":"349898","messageId":"CABPp-BF7POrGTRbVOZ-AGjRHKcpExMQcA4uSPvrRONbnG2CE8w@mail.gmail.com","threadId":"48665","inReplyTo":"8f19c8c2-d050-2d51-756d-d78b9f2bd335@talktalk.net","subject":"Re: [PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T14:42:26Z","receivedAt":"2018-06-11T14:42:31Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip,\n\nOn Sun, Jun 10, 2018 at 12:26 PM, Phillip Wood\n<phillip.wood@talktalk.net> wrote:\n> On 07/06/18 06:07, Elijah Newren wrote:\n>>\n>> Signed-off-by: Elijah Newren <newren@gmail.com>\n>> ---\n>>   git-rebase.sh | 6 +-----\n>>   1 file changed, 1 insertion(+), 5 deletions(-)\n>>\n>> diff --git a/git-rebase.sh b/git-rebase.sh\n>> index 40be59ecc4..a56b286372 100755\n>> --- a/git-rebase.sh\n>> +++ b/git-rebase.sh\n>> @@ -276,6 +276,7 @@ do\n>>                 ;;\n>>         --keep-empty)\n>>                 keep_empty=yes\n>> +               test -z \"$interactive_rebase\" &&\n>> interactive_rebase=implied\n>\n>\n> I think you need to wait until all the options have been parsed before\n> setting the implied interactive rebase in case the user specifies has\n> '--keep-empty' in an alias and specifies '--no-keep-empty' with some am\n> options on the command line.\n\nAh, indeed you are right.  Let's drop this patch then.\n\nHowever, we have a bigger problem with empty commits, in that there\nare really three modes rather than two:\n  * Automatically drop empty commits (default for am-based rebase)\n  * Automatically keep empty commits (as done with --keep-empty)\n  * Halt the rebase and tell the user how to specify if they want to\nkeep it (default for interactive rebases)\n\nCurrently, only the first option is available to am-based rebases, and\nonly the second two options are available to interactive-based\nrebases.  But if we want to make all three available to\ninteractive-based rebases, what should the command line option look\nlike?  --empty={drop,ask,keep}?\n\n(And deprecate but continue to support --[no-]keep-empty?)\n\nAnd should the two rebase modes really have a different default?  What\nshould the default be?\n"},{"id":"349900","messageId":"7e3d71e6-ae97-f47b-382c-085f6a281792@talktalk.net","threadId":"48665","inReplyTo":"CABPp-BF7POrGTRbVOZ-AGjRHKcpExMQcA4uSPvrRONbnG2CE8w@mail.gmail.com","subject":"Re: [PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-11T15:16:45Z","receivedAt":"2018-06-11T15:16:53Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 11/06/18 15:42, Elijah Newren wrote:\n> Hi Phillip,\n> \n> On Sun, Jun 10, 2018 at 12:26 PM, Phillip Wood\n> <phillip.wood@talktalk.net> wrote:\n>> On 07/06/18 06:07, Elijah Newren wrote:\n>>>\n>>> Signed-off-by: Elijah Newren <newren@gmail.com>\n>>> ---\n>>>    git-rebase.sh | 6 +-----\n>>>    1 file changed, 1 insertion(+), 5 deletions(-)\n>>>\n>>> diff --git a/git-rebase.sh b/git-rebase.sh\n>>> index 40be59ecc4..a56b286372 100755\n>>> --- a/git-rebase.sh\n>>> +++ b/git-rebase.sh\n>>> @@ -276,6 +276,7 @@ do\n>>>                  ;;\n>>>          --keep-empty)\n>>>                  keep_empty=yes\n>>> +               test -z \"$interactive_rebase\" &&\n>>> interactive_rebase=implied\n>>\n>>\n>> I think you need to wait until all the options have been parsed before\n>> setting the implied interactive rebase in case the user specifies has\n>> '--keep-empty' in an alias and specifies '--no-keep-empty' with some am\n>> options on the command line.\n> \n> Ah, indeed you are right.  Let's drop this patch then.\n> \n> However, we have a bigger problem with empty commits, in that there\n> are really three modes rather than two:\n>    * Automatically drop empty commits (default for am-based rebase)\n>    * Automatically keep empty commits (as done with --keep-empty)\n>    * Halt the rebase and tell the user how to specify if they want to\n> keep it (default for interactive rebases)\n> \n> Currently, only the first option is available to am-based rebases, and\n> only the second two options are available to interactive-based\n> rebases.  \n\nI'm not sure that's the case, my understanding is that for an \ninteractive rebase unless you give '--keep-empty' then any empty commits \nwill be commented out in the todo list and therefore dropped unless \nthey're uncommented when editing the list. The third case happens when a \ncommit becomes empty when it's rebased (i.e. the original commit is not \nempty), I'm not sure what the am backend does for this. cherry-pick has \n'--keep-redundant-commits' for this case but that has never been added \nto rebase.\n\nBest Wishes\n\nPhillip\n\nBut if we want to make all three available to\n> interactive-based rebases, what should the command line option look\n> like?  --empty={drop,ask,keep}?\n> \n> (And deprecate but continue to support --[no-]keep-empty?)\n> \n> And should the two rebase modes really have a different default?  What\n> should the default be?\n> \n\n"},{"id":"349901","messageId":"CABPp-BG7sR6NvHf4=ZOwxRh-KKR8QEVwB=D5p9DE_h1oDgRvoA@mail.gmail.com","threadId":"48665","inReplyTo":"cec770a8-28ee-d546-8c27-905d2fcdb0c8@talktalk.net","subject":"Re: [PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T15:19:49Z","receivedAt":"2018-06-11T15:19:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip\n\nOn Sun, Jun 10, 2018 at 12:40 PM, Phillip Wood\n<phillip.wood@talktalk.net> wrote:\n\n>>   Documentation/git-rebase.txt           | 15 +++++++++++++--\n>>   git-rebase.sh                          | 17 +++++++++++++++++\n>>   t/t3422-rebase-incompatible-options.sh | 10 +++++-----\n>>   3 files changed, 35 insertions(+), 7 deletions(-)\n>>\n>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>> index 0e20a66e73..451252c173 100644\n>> --- a/Documentation/git-rebase.txt\n>> +++ b/Documentation/git-rebase.txt\n>> @@ -243,6 +243,10 @@ leave out at most one of A and B, in which case it\n>> defaults to HEAD.\n>>   --keep-empty::\n>>         Keep the commits that do not change anything from its\n>>         parents in the result.\n>> ++\n>> +This uses the `--interactive` machinery internally, and as such,\n>> +anything that is incompatible with --interactive is incompatible\n>> +with this option.\n>>     --allow-empty-message::\n>>         By default, rebasing commits with an empty message will fail.\n>> @@ -324,6 +328,8 @@ which makes little sense.\n>>         and after each change.  When fewer lines of surrounding\n>>         context exist they all must match.  By default no context is\n>>         ever ignored.\n>> +       Incompatible with the --merge and --interactive options, or\n>> +       anything that implies those options or their machinery.\n>\n>\n> struct replay_opts has an allow_empty_message member so I'm not sure that's\n> true.\n\nI think you were confused by the way the patch broke up.  The jump to\nline 328 means that this comment is about the -C option, not the\n--allow-empty-message option.\n\nHowever, I probably should add a comment next to the\n--allow-empty-message option, to not the reverse is true, i.e. that\nit's incompatible with am-based rebases.  (git-rebase--am.sh ignores\nthe allow_empty_message variable set in git-rebase.sh, unlike\ngit-rebase--interactive.sh and git-rebase--merge.sh)\n\n>>   -f::\n>>   --force-rebase::\n>> @@ -355,13 +361,15 @@ default is `--no-fork-point`, otherwise the default\n>> is `--fork-point`.\n>>   --whitespace=<option>::\n>>         These flag are passed to the 'git apply' program\n>>         (see linkgit:git-apply[1]) that applies the patch.\n>> -       Incompatible with the --interactive option.\n>> +       Incompatible with the --merge and --interactive options, or\n>> +       anything that implies those options or their machinery.\n>\n>\n> I wonder if it is better just to list the incompatible options it might be a\n> bit long but it would be nicer for the user than them having to work out\n> which options imply --interactive.\n\nThat could work.  Would this be done at the end of the 'OPTIONS'\nsection of the manpage?  Should I create an 'INCOMPATIBLE OPTIONS'\nsection that follows the 'OPTIONS' section?\n\n>>   --committer-date-is-author-date::\n>>   --ignore-date::\n>>         These flags are passed to 'git am' to easily change the dates\n>>         of the rebased commits (see linkgit:git-am[1]).\n>> -       Incompatible with the --interactive option.\n>> +       Incompatible with the --merge and --interactive options, or\n>> +       anything that implies those options or their machinery.\n>>     --signoff::\n>>         Add a Signed-off-by: trailer to all the rebased commits. Note\n>> @@ -400,6 +408,9 @@ The `--rebase-merges` mode is similar in spirit to\n>> `--preserve-merges`, but\n>>   in contrast to that option works well in interactive rebases: commits\n>> can be\n>>   reordered, inserted and dropped at will.\n>>   +\n>> +This uses the `--interactive` machinery internally, but it can be run\n>> +without an explicit `--interactive`.\n>> ++\n>\n> Without more context it's hard to judge but I'm not sure this adds anything\n> useful\n\nHmm, yeah.  I noted that --exec had similar wording, noted that\n--preserve-merges had something along the same lines but as a warning,\nand didn't see the similar wording for --rebase-merges -- I somehow\nmissed the paragraph right above where I added these lines.  Oops.\nAnyway, I'll pull it out.\n\n>>   It is currently only possible to recreate the merge commits using the\n>>   `recursive` merge strategy; Different merge strategies can be used only\n>> via\n>>   explicit `exec git merge -s <strategy> [...]` commands.\n>> diff --git a/git-rebase.sh b/git-rebase.sh\n>> index 40be59ecc4..f1dbecba18 100755\n>> --- a/git-rebase.sh\n>> +++ b/git-rebase.sh\n>> @@ -503,6 +503,23 @@ then\n>>         git_format_patch_opt=\"$git_format_patch_opt --progress\"\n>>   fi\n>>   +if test -n \"$git_am_opt\"; then\n>> +       incompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n>\n>\n> I think the style guide recommends $() over ``\n\nWill fix.\n\n\nThanks for taking a look!\n\nElijah\n"},{"id":"349903","messageId":"CABPp-BF6HapQ=tcWu4j=L-sjgTRbdLnhYXBWwdWm+oThav_zJw@mail.gmail.com","threadId":"48665","inReplyTo":"cec770a8-28ee-d546-8c27-905d2fcdb0c8@talktalk.net","subject":"Re: [PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T15:49:14Z","receivedAt":"2018-06-11T15:49:18Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Another thing I missed...\n\nOn Sun, Jun 10, 2018 at 12:40 PM, Phillip Wood\n<phillip.wood@talktalk.net> wrote:\n> On 07/06/18 06:06, Elijah Newren wrote:\n\n>> Some exceptions I left out:\n>>\n>>    * --merge and --interactive are technically incompatible since they are\n>>      supposed to run different underlying scripts, but with a few small\n>>      changes, --interactive can do everything that --merge can.  In fact,\n>>      I'll shortly be sending another patch to remove git-rebase--merge and\n>>      reimplement it on top of git-rebase--interactive.\n>\n> Excellent I've wondered about doing that but never got round to it. One\n> thing I was slightly concerned about was that someone maybe parsing the\n> output of git-rebase--merge and they'll get a nasty shock when that output\n> changes as a result of using the sequencer.\n\nI can see the minor worry, but I think upon inspection it's not\nsomething that concerns me, for a few reasons:\n\nIn terms of use, given that rebase --merge was introduced to handle\nrenames in mid-2006, but plain rebase has been able to handle them\nsince late 2008 (though directory renames changes that again), the\nutility of rebase --merge has been somewhat limited.  I think that\nlimits the exposure.  But to address the 'break' more directly...\n\nIf we were to agree that we needed to support folks parsing rebase\noutput, that would be a really strict requirement that I think would\nprevent lots of fixes.  And if so, it's one we've violated a number of\ntimes.  For example, I certainly wasn't thinking about rebase when I\nmodified messages in merge-recursive.c over the years, but they'd leak\nthrough for rebase --merge.  (Those messages would not leak through to\nrebase --interactive as much, since the sequencer sets o.buffer_output\nand then only conditionally shows the output.)  Also, changes that\nhave occurred in the past, like adding 'git gc --auto' to rebase,\nmodifying error messages directly found in git-rebase--merge.sh would\nhave been considered breaks.\n\nFinally, looking over all the differences in output while fixing up\ntestcases makes me think we've done much less around designing the\noutput based on what we want the user to see, and more around what\nminimal fixups can we do to these lower level commands that provide\nuseful functionality to the user?  We linearize history differently\nfor different rebase modes, have different entries in the reflog\ndepending on which mode, and we often times implement features for\njust one mode and then sometimes add it to others.  In fact, I think\nthe primary reason that am-based and merge-based rebases had a --quiet\noption and the interactive rebases didn't, is mostly attributable to\nthe defaults of the lower level commands these three were built on top\nof (git-am vs. git-merge-recursive vs. git-cherry-pick).  The noiser\ntwo merited a quiet option, and the option was never added for the\nlast one.\n\nAnyway, that's my rationale.  I'm curious to hear if folks disagree or\nsee things I'm overlooking or have reasons I might be weighting\ntradeoffs less than optimally.\n"},{"id":"349904","messageId":"560d4128-e088-6028-9f39-5cfcb3e329b8@talktalk.net","threadId":"48665","inReplyTo":"CABPp-BG7sR6NvHf4=ZOwxRh-KKR8QEVwB=D5p9DE_h1oDgRvoA@mail.gmail.com","subject":"Re: [PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-11T15:59:20Z","receivedAt":"2018-06-11T15:59:28Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/06/18 16:19, Elijah Newren wrote:\n> Hi Phillip\n> \n> On Sun, Jun 10, 2018 at 12:40 PM, Phillip Wood\n> <phillip.wood@talktalk.net> wrote:\n> \n>>>    Documentation/git-rebase.txt           | 15 +++++++++++++--\n>>>    git-rebase.sh                          | 17 +++++++++++++++++\n>>>    t/t3422-rebase-incompatible-options.sh | 10 +++++-----\n>>>    3 files changed, 35 insertions(+), 7 deletions(-)\n>>>\n>>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>>> index 0e20a66e73..451252c173 100644\n>>> --- a/Documentation/git-rebase.txt\n>>> +++ b/Documentation/git-rebase.txt\n>>> @@ -243,6 +243,10 @@ leave out at most one of A and B, in which case it\n>>> defaults to HEAD.\n>>>    --keep-empty::\n>>>          Keep the commits that do not change anything from its\n>>>          parents in the result.\n>>> ++\n>>> +This uses the `--interactive` machinery internally, and as such,\n>>> +anything that is incompatible with --interactive is incompatible\n>>> +with this option.\n>>>      --allow-empty-message::\n>>>          By default, rebasing commits with an empty message will fail.\n>>> @@ -324,6 +328,8 @@ which makes little sense.\n>>>          and after each change.  When fewer lines of surrounding\n>>>          context exist they all must match.  By default no context is\n>>>          ever ignored.\n>>> +       Incompatible with the --merge and --interactive options, or\n>>> +       anything that implies those options or their machinery.\n>>\n>>\n>> struct replay_opts has an allow_empty_message member so I'm not sure that's\n>> true.\n> \n> I think you were confused by the way the patch broke up.  The jump to\n> line 328 means that this comment is about the -C option, not the\n> --allow-empty-message option.\n\nAh you're right, I missed the hunk header\n\n> However, I probably should add a comment next to the\n> --allow-empty-message option, to not the reverse is true, i.e. that\n> it's incompatible with am-based rebases.  (git-rebase--am.sh ignores\n> the allow_empty_message variable set in git-rebase.sh, unlike\n> git-rebase--interactive.sh and git-rebase--merge.sh)\n\nThat sounds like a good idea\n\n>>>    -f::\n>>>    --force-rebase::\n>>> @@ -355,13 +361,15 @@ default is `--no-fork-point`, otherwise the default\n>>> is `--fork-point`.\n>>>    --whitespace=<option>::\n>>>          These flag are passed to the 'git apply' program\n>>>          (see linkgit:git-apply[1]) that applies the patch.\n>>> -       Incompatible with the --interactive option.\n>>> +       Incompatible with the --merge and --interactive options, or\n>>> +       anything that implies those options or their machinery.\n>>\n>>\n>> I wonder if it is better just to list the incompatible options it might be a\n>> bit long but it would be nicer for the user than them having to work out\n>> which options imply --interactive.\n> \n> That could work.  Would this be done at the end of the 'OPTIONS'\n> section of the manpage?  Should I create an 'INCOMPATIBLE OPTIONS'\n> section that follows the 'OPTIONS' section?\n\nI think that would be the best way of doing it, maybe with a note in the \ndescription of the am options to check in that section to see what they \ncan be safely combined with.\n\n>>>    --committer-date-is-author-date::\n>>>    --ignore-date::\n>>>          These flags are passed to 'git am' to easily change the dates\n>>>          of the rebased commits (see linkgit:git-am[1]).\n>>> -       Incompatible with the --interactive option.\n>>> +       Incompatible with the --merge and --interactive options, or\n>>> +       anything that implies those options or their machinery.\n>>>      --signoff::\n>>>          Add a Signed-off-by: trailer to all the rebased commits. Note\n>>> @@ -400,6 +408,9 @@ The `--rebase-merges` mode is similar in spirit to\n>>> `--preserve-merges`, but\n>>>    in contrast to that option works well in interactive rebases: commits\n>>> can be\n>>>    reordered, inserted and dropped at will.\n>>>    +\n>>> +This uses the `--interactive` machinery internally, but it can be run\n>>> +without an explicit `--interactive`.\n>>> ++\n>>\n>> Without more context it's hard to judge but I'm not sure this adds anything\n>> useful\n> \n> Hmm, yeah.  I noted that --exec had similar wording, noted that\n> --preserve-merges had something along the same lines but as a warning,\n> and didn't see the similar wording for --rebase-merges -- I somehow\n> missed the paragraph right above where I added these lines.  Oops.\n> Anyway, I'll pull it out.\n\nIf we can get a good description of which options are compatible with \nwhat then hopefully we can remove the existing references to implicit \ninteractive and am, the user should only have to worry about which \noptions are compatible.\n\n>>>    It is currently only possible to recreate the merge commits using the\n>>>    `recursive` merge strategy; Different merge strategies can be used only\n>>> via\n>>>    explicit `exec git merge -s <strategy> [...]` commands.\n>>> diff --git a/git-rebase.sh b/git-rebase.sh\n>>> index 40be59ecc4..f1dbecba18 100755\n>>> --- a/git-rebase.sh\n>>> +++ b/git-rebase.sh\n>>> @@ -503,6 +503,23 @@ then\n>>>          git_format_patch_opt=\"$git_format_patch_opt --progress\"\n>>>    fi\n>>>    +if test -n \"$git_am_opt\"; then\n>>> +       incompatible_opts=`echo \"$git_am_opt\" | sed -e 's/ -q//'`\n>>\n>>\n>> I think the style guide recommends $() over ``\n> \n> Will fix.\n> \n> \n> Thanks for taking a look!\n\nThanks for working on this, it should make things simpler for user's to \nunderstand\n\nBest Wishes\n\nPhillip\n> Elijah\n> \n\n"},{"id":"349907","messageId":"CABPp-BEuZDHDAxixrUUXyzbpBXoVfWhfdJR1g9eFN9MSAMjh_Q@mail.gmail.com","threadId":"48665","inReplyTo":"7e3d71e6-ae97-f47b-382c-085f6a281792@talktalk.net","subject":"Re: [PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T16:08:55Z","receivedAt":"2018-06-11T16:09:00Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip,\n\nOn Mon, Jun 11, 2018 at 8:16 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n> On 11/06/18 15:42, Elijah Newren wrote:\n\n>> However, we have a bigger problem with empty commits, in that there\n>> are really three modes rather than two:\n>>    * Automatically drop empty commits (default for am-based rebase)\n>>    * Automatically keep empty commits (as done with --keep-empty)\n>>    * Halt the rebase and tell the user how to specify if they want to\n>> keep it (default for interactive rebases)\n>>\n>> Currently, only the first option is available to am-based rebases, and\n>> only the second two options are available to interactive-based\n>> rebases.\n>\n>\n> I'm not sure that's the case, my understanding is that for an interactive\n> rebase unless you give '--keep-empty' then any empty commits will be\n> commented out in the todo list and therefore dropped unless they're\n> uncommented when editing the list.\n\nAh, yes, you are right; I was implicitly thinking about cases where\nthe commit became empty rather than when the commit started\nempty...and mis-read --keep-empty (which as I learned now is only for\nstarted-empty cases).\n\n> The third case happens when a commit\n> becomes empty when it's rebased (i.e. the original commit is not empty), I'm\n> not sure what the am backend does for this.\n\nThe am backend does not halt the rebase; it simply drops the commit\nand says \"No changes -- Patch already applied.\"\n\nIt has always seemed jarring and confusing to me that one rebase mode\nstops and asks the user what to do and the other assumes.  I think\nboth should have the same default (and have options to pick the\nalternate behavior).\n\nI'm less certain what the default should be, though.\n\n> cherry-pick has\n> '--keep-redundant-commits' for this case but that has never been added to\n> rebase.\n\nThanks for the pointer.\n"},{"id":"349919","messageId":"xmqq4li9cj52.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"CABPp-BGxaroePB6aKWAkZeADLB7VE3y1CPy2RyNwpn=+C01g3A@mail.gmail.com","subject":"Re: RFC: rebase inconsistency in 2.18 -- course of action?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-11T17:44:57Z","receivedAt":"2018-06-11T17:45:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> In short, while interactive-based and merge-based rebases handle\n> directory rename detection fine, am-based rebases do not.  This\n> inconsistency may frustrate or surprise users.\n\nFWIW, I actually do not quite think it is universally a good idea to\ninfer that I would have added the path X/F I added to my branch at\nY/F instead if I were on vacation while somebody else first moved\nother paths X/A, X/B, etc. to Y/A, Y/B, etc., and I would even\nimagine that I would be frustrated if my X/F, which the somebody\nelse wasn't even aware of, were moved to Y/F without even telling\nme.  So in that sense, doing such extra and unasked-for \"moves\"\nduring a rebase may be a bug, not a feature.\n\nIn any case, I think I'll have to delay -rc2 by a few days to catch\nup, so I won't be looking at any topic (including this one) that is\nnot about 2.18-rc regressions for a few days.  Please do not get\nupset if people with RFC patches do not hear from me until the\nfinal.\n\nThanks.\n"},{"id":"349935","messageId":"CABPp-BF4gbwVRHA3D1vqXuSnh3aS9XVLqtEUEmfmLDKPccyxtA@mail.gmail.com","threadId":"48665","inReplyTo":"xmqq4li9cj52.fsf@gitster-ct.c.googlers.com","subject":"Re: RFC: rebase inconsistency in 2.18 -- course of action?","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-11T20:17:21Z","receivedAt":"2018-06-11T20:17:27Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Junio,\n\nOn Mon, Jun 11, 2018 at 10:44 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> In short, while interactive-based and merge-based rebases handle\n>> directory rename detection fine, am-based rebases do not.  This\n>> inconsistency may frustrate or surprise users.\n>\n> FWIW, I actually do not quite think it is universally a good idea to\n> infer that I would have added the path X/F I added to my branch at\n> Y/F instead if I were on vacation while somebody else first moved\n> other paths X/A, X/B, etc. to Y/A, Y/B, etc., and I would even\n> imagine that I would be frustrated if my X/F, which the somebody\n> else wasn't even aware of, were moved to Y/F without even telling\n> me.  So in that sense, doing such extra and unasked-for \"moves\"\n> during a rebase may be a bug, not a feature.\n\nSo...I'm a little confused.  Am I correct to understand that you're\narguing that directory rename detection is an anti-feature and it\nshouldn't have been merged in the first place?  Or that it doesn't\ngive appropriate output/warning, and it should have configuration\nflags?  Or are you trying to make a distinction between am-based\nrebases vs.any one of rebase -i, rebase -m, cherry-pick, and merge [-s\nrecursive]?\n\nI was leaning towards \"this inconsistency is no big deal; we can\naddress it later\", but now you have me wondering about a different\nangle.\n\n> In any case, I think I'll have to delay -rc2 by a few days to catch\n> up, so I won't be looking at any topic (including this one) that is\n> not about 2.18-rc regressions for a few days.  Please do not get\n> upset if people with RFC patches do not hear from me until the\n> final.\n\nI emailed about this rebase inconsistency because I was worried that\n*an* inconsistency between the various rebase types was bad.  But the\nmore I've dug, the more I've found they are inconsistent in lots of\nways anyway (levels and types of output, reflog entries, automatically\ndropping became-empty patches vs. halting and asking the user,\naccepting commits with empty commit messages vs. requiring an\n--allow-empty-message flag to do so, large sets of mutually\nincompatible options, etc.)  Adding one more inconsistency is feeling\nless worrisome to me.  I'd still like to lessen all these\ninconsistencies between rebase types, but my current opinion is that\nit's not that big a deal and my patches can all wait for the 2.19\ncycle to start.\n"},{"id":"349975","messageId":"cd30ac59-4715-dc33-6de4-aa009134ac87@talktalk.net","threadId":"48665","inReplyTo":"CABPp-BF6HapQ=tcWu4j=L-sjgTRbdLnhYXBWwdWm+oThav_zJw@mail.gmail.com","subject":"Re: [PATCH 2/2] git-rebase: error out when incompatible options passed","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-12T09:45:39Z","receivedAt":"2018-06-12T09:45:46Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/06/18 16:49, Elijah Newren wrote:\n> Another thing I missed...\n> \n> On Sun, Jun 10, 2018 at 12:40 PM, Phillip Wood\n> <phillip.wood@talktalk.net> wrote:\n>> On 07/06/18 06:06, Elijah Newren wrote:\n> \n>>> Some exceptions I left out:\n>>>\n>>>    * --merge and --interactive are technically incompatible since they are\n>>>      supposed to run different underlying scripts, but with a few small\n>>>      changes, --interactive can do everything that --merge can.  In fact,\n>>>      I'll shortly be sending another patch to remove git-rebase--merge and\n>>>      reimplement it on top of git-rebase--interactive.\n>>\n>> Excellent I've wondered about doing that but never got round to it. One\n>> thing I was slightly concerned about was that someone maybe parsing the\n>> output of git-rebase--merge and they'll get a nasty shock when that output\n>> changes as a result of using the sequencer.\n> \n> I can see the minor worry, but I think upon inspection it's not\n> something that concerns me, for a few reasons:\n> \n> In terms of use, given that rebase --merge was introduced to handle\n> renames in mid-2006, but plain rebase has been able to handle them\n> since late 2008 (though directory renames changes that again), the\n> utility of rebase --merge has been somewhat limited.  I think that\n> limits the exposure.  But to address the 'break' more directly...\n> \n> If we were to agree that we needed to support folks parsing rebase\n> output, that would be a really strict requirement that I think would\n> prevent lots of fixes.  And if so, it's one we've violated a number of\n> times.  For example, I certainly wasn't thinking about rebase when I\n> modified messages in merge-recursive.c over the years, but they'd leak\n> through for rebase --merge.  (Those messages would not leak through to\n> rebase --interactive as much, since the sequencer sets o.buffer_output\n> and then only conditionally shows the output.)  Also, changes that\n> have occurred in the past, like adding 'git gc --auto' to rebase,\n> modifying error messages directly found in git-rebase--merge.sh would\n> have been considered breaks.\n> \n> Finally, looking over all the differences in output while fixing up\n> testcases makes me think we've done much less around designing the\n> output based on what we want the user to see, and more around what\n> minimal fixups can we do to these lower level commands that provide\n> useful functionality to the user?  We linearize history differently\n> for different rebase modes, have different entries in the reflog\n> depending on which mode, and we often times implement features for\n> just one mode and then sometimes add it to others.  In fact, I think\n> the primary reason that am-based and merge-based rebases had a --quiet\n> option and the interactive rebases didn't, is mostly attributable to\n> the defaults of the lower level commands these three were built on top\n> of (git-am vs. git-merge-recursive vs. git-cherry-pick).  The noiser\n> two merited a quiet option, and the option was never added for the\n> last one.\n> \n> Anyway, that's my rationale.  I'm curious to hear if folks disagree or\n> see things I'm overlooking or have reasons I might be weighting\n> tradeoffs less than optimally.\n> \n\nI agree that there are already plenty of inconsistencies, (it's great to\nsee you reducing them). If we can avoid emulating the ouput of\ngit-rebase--merge.sh in sequencer.c that would definitely be my\npreferred option (the code is already a bit hard to follow in places\nwhere there it's doing slightly different things for cherry-pick and\nrebase -i). Hopefully no one is relying on the output, as you say it's\njust whatever the underlying plumbing prints rather than designed for a\nspecific purpose.\n\nBest Wishes\n\nPhillip\n"},{"id":"349980","messageId":"c0e55982-0d75-0efe-4976-f48cb4bf5779@talktalk.net","threadId":"48665","inReplyTo":"CABPp-BEuZDHDAxixrUUXyzbpBXoVfWhfdJR1g9eFN9MSAMjh_Q@mail.gmail.com","subject":"Re: [PATCH] git-rebase.sh: handle keep-empty like all other options","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-12T09:53:41Z","receivedAt":"2018-06-12T09:53:46Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/06/18 17:08, Elijah Newren wrote:\n> Hi Phillip,\n> \n> On Mon, Jun 11, 2018 at 8:16 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n>> On 11/06/18 15:42, Elijah Newren wrote:\n> \n>>> However, we have a bigger problem with empty commits, in that there\n>>> are really three modes rather than two:\n>>>    * Automatically drop empty commits (default for am-based rebase)\n>>>    * Automatically keep empty commits (as done with --keep-empty)\n>>>    * Halt the rebase and tell the user how to specify if they want to\n>>> keep it (default for interactive rebases)\n>>>\n>>> Currently, only the first option is available to am-based rebases, and\n>>> only the second two options are available to interactive-based\n>>> rebases.\n>>\n>>\n>> I'm not sure that's the case, my understanding is that for an interactive\n>> rebase unless you give '--keep-empty' then any empty commits will be\n>> commented out in the todo list and therefore dropped unless they're\n>> uncommented when editing the list.\n> \n> Ah, yes, you are right; I was implicitly thinking about cases where\n> the commit became empty rather than when the commit started\n> empty...and mis-read --keep-empty (which as I learned now is only for\n> started-empty cases).\n> \n>> The third case happens when a commit\n>> becomes empty when it's rebased (i.e. the original commit is not empty), I'm\n>> not sure what the am backend does for this.\n> \n> The am backend does not halt the rebase; it simply drops the commit\n> and says \"No changes -- Patch already applied.\"\n> \n> It has always seemed jarring and confusing to me that one rebase mode\n> stops and asks the user what to do and the other assumes.  I think\n> both should have the same default (and have options to pick the\n> alternate behavior).\n> \n> I'm less certain what the default should be, though.\n\nI'm not really sure either, on the one hand most of the time it is\nconvenient for rebase just to skip over it, on the other if you have\nsome important information in the commit message or a note then maybe\nyou want rebase to stop so you can selvage that information.\n\n> \n>> cherry-pick has\n>> '--keep-redundant-commits' for this case but that has never been added to\n>> rebase.\n\nOn path forwards is to always stop, and implement\n--keep-redundant-commits for rebase. That would be very easy for\ninteractive rebases as it shares the same code as cherry-pick. I've just\nhad a quick look at builtin/am.c and I think it would be fairly\nstraightforward to add some code to check if it's rebasing and stop if\nthe patch is already applied.\n\nBest Wishes\n\nPhillip\n\n> Thanks for the pointer.\n> \n\n"},{"id":"350342","messageId":"20180617055856.22838-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180607050654.19663-1-newren@gmail.com","subject":"[RFC PATCH v2 0/7] Document/fix/warn about rebase incompatibilities and inconsistences","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:49Z","receivedAt":"2018-06-17T05:59:07Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase has lots of options that are mutually incompatible.  Even among\naspects of its behavior that is common to all rebase types, it has a number\nof inconsistencies.  This series tries to document, fix, and/or warn users\nabout many of these.\n\nI have a much higher than average expectation that folks will object\nto some of these patches.  I've tried to divide them up so that any parts\nwe decide to drop or redo can be more easily excised.\n\nNo branch-diff; because it's a significant re-work; instead I'll comment\nbriefly on the individual patches...\n\n\nElijah Newren (7):\n  git-rebase.txt: document incompatible options\n\nBoth Dscho (on a related patch series) and Phillip suggested changing the\ndocumentation to avoid implementational details.  I instead made a separate\nsection with sets of incompatible options...but it still mentions the\ndifferent backends while doing so.  Does that seem alright?\n\n  git-rebase.sh: update help messages a bit\n\nMinor tweaks to `git rebase -h` output.\n\n  t3422: new testcases for checking when incompatible options passed\n\nThe one unmodified patch from the first round.\n\n  git-rebase: error out when incompatible options passed\n\nAlmost the same as the first round, except:\n  * Documentation pulled into a separate patch (patch 1)\n  * $() instead of ``\n\n  git-rebase.txt: document behavioral inconsistencies between modes\n\nAdd another section to the documentation for aspects that ideally\nshould be common between all modes but are handled differently.\n\n  git-rebase.txt: address confusion between --no-ff vs --force-rebase\n\nThis came up on the list not that long ago; fix the documentation.\n\n  git-rebase: make --allow-empty-message the default\n\nAddress the easiest of the inconsistencies, assuming the am-based backend\nhas the correct default and the merge-based and interactive-based backends\nare the ones that need to change.\n\n Documentation/git-rebase.txt           | 154 ++++++++++++++++++++-----\n git-rebase.sh                          |  25 +++-\n t/t3404-rebase-interactive.sh          |   7 +-\n t/t3405-rebase-malformed.sh            |  11 +-\n t/t3422-rebase-incompatible-options.sh |  69 +++++++++++\n 5 files changed, 224 insertions(+), 42 deletions(-)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n"},{"id":"350343","messageId":"20180617055856.22838-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 1/7] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:50Z","receivedAt":"2018-06-17T05:59:12Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has many options that only work with one of its three backends.\nIt also has a few other pairs of incompatible options.  Document these.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 84 ++++++++++++++++++++++++++++++++----\n 1 file changed, 76 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0e20a66e73..adccc15284 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n \tThis option overrides that behavior, allowing commits with empty\n \tmessages to be rebased.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --skip::\n \tRestart the rebasing process by skipping the current patch.\n@@ -271,6 +275,8 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -280,8 +286,10 @@ other words, the sides are swapped.\n +\n Because 'git rebase' replays each commit from the working branch\n on top of the <upstream> branch using the given strategy, using\n-the 'ours' strategy simply discards all patches from the <branch>,\n+the 'ours' strategy simply empties all patches from the <branch>,\n which makes little sense.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -X <strategy-option>::\n --strategy-option=<strategy-option>::\n@@ -289,6 +297,8 @@ which makes little sense.\n \tThis implies `--merge` and, if no strategy has been\n \tspecified, `-s recursive`.  Note the reversal of 'ours' and\n \t'theirs' as noted above for the `-m` option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -S[<keyid>]::\n --gpg-sign[=<keyid>]::\n@@ -324,6 +334,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -f::\n --force-rebase::\n@@ -355,19 +367,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n \tthat if `--interactive` is given then only commits marked to be\n-\tpicked, edited or reworded will have the trailer added. Incompatible\n-\twith the `--preserve-merges` option.\n+\tpicked, edited or reworded will have the trailer added.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -i::\n --interactive::\n@@ -378,6 +393,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n The commit list format can be changed by setting the configuration option\n rebase.instructionFormat.  A customized instruction format will automatically\n have the long commit hash prepended to the format.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -r::\n --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::\n@@ -404,7 +421,7 @@ It is currently only possible to recreate the merge commits using the\n `recursive` merge strategy; Different merge strategies can be used only via\n explicit `exec git merge -s <strategy> [...]` commands.\n +\n-See also REBASING MERGES below.\n+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.\n \n -p::\n --preserve-merges::\n@@ -415,6 +432,8 @@ See also REBASING MERGES below.\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n idea unless you know what you are doing (see BUGS below).\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -x <cmd>::\n --exec <cmd>::\n@@ -437,6 +456,8 @@ squash/fixup series.\n +\n This uses the `--interactive` machinery internally, but it can be run\n without an explicit `--interactive`.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --root::\n \tRebase all commits reachable from <branch>, instead of\n@@ -447,6 +468,8 @@ without an explicit `--interactive`.\n \tWhen used together with both --onto and --preserve-merges,\n \t'all' root commits will be rewritten to have <newbase> as parent\n \tinstead.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n@@ -461,11 +484,11 @@ without an explicit `--interactive`.\n \ttoo.  The recommended way to create fixup/squash commits is by using\n \tthe `--fixup`/`--squash` options of linkgit:git-commit[1].\n +\n-This option is only valid when the `--interactive` option is used.\n-+\n If the `--autosquash` option is enabled by default using the\n configuration variable `rebase.autoSquash`, this option can be\n used to override and disable this setting.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autostash::\n --no-autostash::\n@@ -487,6 +510,51 @@ recreates the topic branch with fresh commits so it can be remerged\n successfully without needing to \"revert the reversion\" (see the\n link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n \n+INCOMPATIBLE OPTIONS\n+--------------------\n+\n+git-rebase has many flags that are incompatible with each other,\n+predominantly due to the fact that it has three different underlying\n+implementations:\n+\n+ * one based on linkgit:git-am[1] (the default)\n+ * one based on linkgit:git-merge-recursive[1] (merge backend)\n+ * one based on linkgit:git-cherry-pick[1] (interactive backend)\n+\n+Flags only understood by the am backend:\n+\n+ * --committer-date-is-author-date\n+ * --ignore-date\n+ * --whitespace\n+ * --ignore-whitespace\n+ * -C\n+\n+Flags understood by both merge and interactive backends:\n+\n+ * --merge\n+ * --strategy\n+ * --strategy-option\n+ * --allow-empty-message\n+\n+Flags only understood by the interactive backend:\n+\n+ * --[no-]autosquash\n+ * --rebase-merges\n+ * --preserve-merges\n+ * --interactive\n+ * --exec\n+ * --keep-empty\n+ * --autosquash\n+ * --edit-todo\n+ * --root + --onto\n+\n+Other incompatible flag pairs:\n+\n+ * --preserve-merges && --interactive\n+ * --preserve-merges && --signoff\n+ * --preserve-merges && --rebase-merges\n+ * --rebase-merges && --strategy\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350344","messageId":"20180617055856.22838-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 2/7] git-rebase.sh: update help messages a bit","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:51Z","receivedAt":"2018-06-17T05:59:12Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"signoff is not specific to the am-backend.  Also, re-order a few options\nto make like things (e.g. strategy and strategy-option) be near each\nother.\n---\n git-rebase.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..bf71b7fa20 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -20,23 +20,23 @@ onto=!             rebase onto given branch instead of upstream\n r,rebase-merges?   try to rebase merges instead of skipping them\n p,preserve-merges! try to recreate merges instead of ignoring them\n s,strategy=!       use the given merge strategy\n+X,strategy-option=! pass the argument through to the merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n+f,force-rebase!    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 x,exec=!           add exec lines after each commit of the editable list\n k,keep-empty\t   preserve empty commits during rebase\n allow-empty-message allow rebasing commits with empty messages\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 n,no-stat!         do not show diffstat of what changed upstream\n verify             allow pre-rebase hook to run\n rerere-autoupdate  allow rerere to update index with resolved conflicts\n root!              rebase all reachable commits up to the root(s)\n autosquash         move commits that begin with squash!/fixup! under -i\n+signoff            add a Signed-off-by: line to each commit\n committer-date-is-author-date! passed to 'git am'\n ignore-date!       passed to 'git am'\n-signoff            passed to 'git am'\n whitespace=!       passed to 'git apply'\n ignore-whitespace! passed to 'git apply'\n C=!                passed to 'git apply'\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350345","messageId":"20180617055856.22838-4-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 3/7] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:52Z","receivedAt":"2018-06-17T05:59:16Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase is split into three types: am, merge, and interactive.  Various\noptions imply different types, and which mode we are using determine which\nsub-script (git-rebase--$type) is executed to finish the work.  Not all\noptions work with all types, so add tests for combinations where we expect\nto receive an error rather than having options be silently ignored.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3422-rebase-incompatible-options.sh | 69 ++++++++++++++++++++++++++\n 1 file changed, 69 insertions(+)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nnew file mode 100755\nindex 0000000000..04cdae921b\n--- /dev/null\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -0,0 +1,69 @@\n+#!/bin/sh\n+\n+test_description='test if rebase detects and aborts on incompatible options'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_seq 2 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m orig &&\n+\n+\tgit branch A &&\n+\tgit branch B &&\n+\n+\tgit checkout A &&\n+\ttest_seq 1 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m A &&\n+\n+\tgit checkout B &&\n+\t# This is indented with HT SP HT.\n+\techo \"\t \tfoo();\" >>foo &&\n+\tgit add foo &&\n+\tgit commit -m B\n+'\n+\n+#\n+# Rebase has lots of useful options like --whitepsace=fix, which are\n+# actually all built in terms of flags to git-am.  Since neither\n+# --merge nor --interactive (nor any options that imply those two) use\n+# git-am, using them together will result in flags like --whitespace=fix\n+# being ignored.  Make sure rebase warns the user and aborts instead.\n+#\n+\n+test_run_rebase () {\n+\topt=$1\n+\tshift\n+\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --merge A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --interactive A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --exec 'true' A\n+\t\"\n+\n+}\n+\n+test_run_rebase --whitespace=fix\n+test_run_rebase --ignore-whitespace\n+test_run_rebase --committer-date-is-author-date\n+test_run_rebase -C4\n+\n+test_done\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350346","messageId":"20180617055856.22838-5-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 4/7] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:53Z","receivedAt":"2018-06-17T05:59:18Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has three different types: am, merge, and interactive, all of\nwhich are implemented in terms of separate scripts.  am builds on git-am,\nmerge builds on git-merge-recursive, and interactive builds on\ngit-cherry-pick.  We make use of features in those lower-level commands in\nthe different rebase types, but those features don't exist in all of the\nlower level commands so we have a range of incompatibilities.  Previously,\nwe just accepted nearly any argument and silently ignored whichever ones\nweren't implemented for the type of rebase specified.  Change this so the\nincompatibilities are documented, included in the testsuite, and tested\nfor at runtime with an appropriate error message shown.\n\nSome exceptions I left out:\n\n  * --merge and --interactive are technically incompatible since they are\n    supposed to run different underlying scripts, but with a few small\n    changes, --interactive can do everything that --merge can.  In fact,\n    I'll shortly be sending another patch to remove git-rebase--merge and\n    reimplement it on top of git-rebase--interactive.\n\n  * One could argue that --interactive and --quiet are incompatible since\n    --interactive doesn't implement a --quiet mode (perhaps since\n    cherry-pick itself does not implement one).  However, the interactive\n    mode is more quiet than the other modes in general with progress\n    messages, so one could argue that it's already quiet.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh                          | 17 +++++++++++++++++\n t/t3422-rebase-incompatible-options.sh | 10 +++++-----\n 2 files changed, 22 insertions(+), 5 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex bf71b7fa20..5f891214fa 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -503,6 +503,23 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n+if test -n \"$git_am_opt\"; then\n+\tincompatible_opts=$(echo \"$git_am_opt\" | sed -e 's/ -q//')\n+\tif test -n \"$interactive_rebase\"\n+\tthen\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$do_merge\"; then\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n if test -n \"$signoff\"\n then\n \ttest -n \"$preserve_merges\" &&\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 04cdae921b..66a83363bf 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -34,27 +34,27 @@ test_expect_success 'setup' '\n test_run_rebase () {\n \topt=$1\n \tshift\n-\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\ttest_expect_success \"$opt incompatible with --merge\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --merge A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\ttest_expect_success \"$opt incompatible with --interactive\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --interactive A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\ttest_expect_success \"$opt incompatible with --exec\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --exec 'true' A\n \t\"\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350347","messageId":"20180617055856.22838-8-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 7/7] git-rebase: make --allow-empty-message the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:56Z","receivedAt":"2018-06-17T05:59:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"am-based rebases already apply commits with an empty commit message\nwithout requiring the user to specify an extra flag.  Make merge-based and\ninteractive-based rebases behave the same.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt  | 10 ----------\n git-rebase.sh                 |  2 +-\n t/t3404-rebase-interactive.sh |  7 ++++---\n t/t3405-rebase-malformed.sh   | 11 +++--------\n 4 files changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 7a2ed9efdc..a5608f481f 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -562,16 +562,6 @@ BEHAVIORAL INCONSISTENCIES\n     The --keep-empty option exists for interactive rebases to allow\n     it to keep commits that started empty.\n \n-  * empty commit messages:\n-\n-    am-based rebase will silently apply commits with empty commit\n-    messages.\n-\n-    merge-based and interactive-based rebases will by default halt\n-    on any such commits.  The --allow-empty-message option exists to\n-    allow interactive-based rebases to apply such commits without\n-    halting.\n-\n   * directory rename detection:\n \n     merge-based and interactive-based rebases work fine with\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 5f891214fa..bf033da4e5 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -95,7 +95,7 @@ rebase_cousins=\n preserve_merges=\n autosquash=\n keep_empty=\n-allow_empty_message=\n+allow_empty_message=--allow-empty-message\n signoff=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n case \"$(git config --bool commit.gpgsign)\" in\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex c65826ddac..f84fa63b15 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n '\n \n test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n+\ttest_when_finished \"git rebase --abort\" &&\n \told=$(git rev-parse HEAD) &&\n \ttest_tick &&\n \tset_fake_editor &&\n \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n \techo \"edited again\" > file7 &&\n \tgit add file7 &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n-\ttest $old = $(git rev-parse HEAD) &&\n-\tgit rebase --abort\n+\techo all the things >>conflict &&\n+\ttest_must_fail git rebase --continue &&\n+\ttest $old = $(git rev-parse HEAD)\n '\n \n test_expect_success 'auto-amend only edited commits after \"edit\"' '\ndiff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\nindex cb7c6de84a..da94dddc86 100755\n--- a/t/t3405-rebase-malformed.sh\n+++ b/t/t3405-rebase-malformed.sh\n@@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n '\n \n test_expect_success 'rebase -m commit with empty message' '\n-\ttest_must_fail git rebase -m master empty-message-merge &&\n-\tgit rebase --abort &&\n-\tgit rebase -m --allow-empty-message master empty-message-merge\n+\tgit rebase -m master empty-message-merge\n '\n \n test_expect_success 'rebase -i commit with empty message' '\n \tgit checkout diff-in-message &&\n \tset_fake_editor &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i HEAD^ &&\n-\tgit rebase --abort &&\n-\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i --allow-empty-message HEAD^\n+\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n+\t\tgit rebase -i HEAD^\n '\n \n test_done\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350348","messageId":"20180617055856.22838-7-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 6/7] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:55Z","receivedAt":"2018-06-17T05:59:21Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\nrebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\nworked for the am and merge backends, but wasn't a valid option for the\ninteractive backend.\n\nrebase was taught the --no-ff option for interactive rebases in commit\nb499549401cb (\"Teach rebase the --no-ff option.\", 2010-03-24), to do the\nexact same thing as --force-rebase does for non-interactive rebases.  This\ncommit explicitly documented the fact that --force-rebase was incompatible\nwith --interactive, though it made --no-ff a synonym for --force-rebase\nfor non-interactive rebases.  The choice of a new option was based on the\nfact that \"force rebase\" didn't sound like an appropriate term for the\ninteractive machinery.\n\nIn commit 6bb4e485cff8 (\"rebase: align variable names\", 2011-02-06), the\nseparate parsing of command line options in the different rebase scripts\nwas removed, and whether on accident or because the author noticed that\nthese options did the same thing, the options became synonyms and both\nwere accepted by all three rebase types.\n\nIn commit 2d26d533a012 (\"Documentation/git-rebase.txt: -f forces a rebase\nthat would otherwise be a no-op\", 2014-08-12), which reworded the\ndescription of the --force-rebase option, the (no-longer correct) sentence\nstating that --force-rebase was incompatible with --interactive was\nfinally removed.\n\nFinally, as explained at\nhttps://public-inbox.org/git/98279912-0f52-969d-44a6-22242039387f@xiplink.com\n\n    In the original discussion around this option [1], at one point I\n    proposed teaching rebase--interactive to respect --force-rebase\n    instead of adding a new option [2].  Ultimately --no-ff was chosen as\n    the better user interface design [3], because an interactive rebase\n    can't be \"forced\" to run.\n\nWe have accepted both --no-ff and --force-rebase as full synonyms for all\nthree rebase types for over seven years.  Documenting them differently\nand in ways that suggest they might not be quite synonyms simply leads to\nconfusion.  Adjust the documentation to match reality.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 35 ++++++++++-------------------------\n 1 file changed, 10 insertions(+), 25 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0dbfab06d0..7a2ed9efdc 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -337,16 +337,18 @@ See also INCOMPATIBLE OPTIONS below.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n--f::\n+--no-ff::\n --force-rebase::\n-\tForce a rebase even if the current branch is up to date and\n-\tthe command without `--force` would return without doing anything.\n+-f::\n+\tIndividually replay all rebased commits instead of fast-forwarding\n+\tover the unchanged ones.  This ensures that the entire history of\n+\tthe rebased branch is composed of new commits.\n +\n-You may find this (or --no-ff with an interactive rebase) helpful after\n-reverting a topic branch merge, as this option recreates the topic branch with\n-fresh commits so it can be remerged successfully without needing to \"revert\n-the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n+You may find this helpful after reverting a topic branch merge, as this option\n+recreates the topic branch with fresh commits so it can be remerged\n+successfully without needing to \"revert the reversion\" (see the\n+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for\n+details).\n \n --fork-point::\n --no-fork-point::\n@@ -498,18 +500,6 @@ See also INCOMPATIBLE OPTIONS below.\n \twith care: the final stash application after a successful\n \trebase might result in non-trivial conflicts.\n \n---no-ff::\n-\tWith --interactive, cherry-pick all rebased commits instead of\n-\tfast-forwarding over the unchanged ones.  This ensures that the\n-\tentire history of the rebased branch is composed of new commits.\n-+\n-Without --interactive, this is a synonym for --force-rebase.\n-+\n-You may find this helpful after reverting a topic branch merge, as this option\n-recreates the topic branch with fresh commits so it can be remerged\n-successfully without needing to \"revert the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n-\n INCOMPATIBLE OPTIONS\n --------------------\n \n@@ -558,11 +548,6 @@ Other incompatible flag pairs:\n BEHAVIORAL INCONSISTENCIES\n --------------------------\n \n-  * --no-ff vs. --force-rebase\n-\n-    These options are actually identical, though their description\n-    leads people to believe they might not be.\n-\n  * empty commits:\n \n     am-based rebase will drop any \"empty\" commits, whether the\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350349","messageId":"20180617055856.22838-6-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[RFC PATCH v2 5/7] git-rebase.txt: document behavioral inconsistencies between modes","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-17T05:58:54Z","receivedAt":"2018-06-17T05:59:24Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"There are a variety of aspects that are common to all rebases regardless\nof which backend is in use; however, the behavior for these different\naspects varies in ways that could surprise users.  (In fact, it's not\nclear -- to me at least -- that these differences were even desirable or\nintentional.)  Document these differences.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 57 ++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex adccc15284..0dbfab06d0 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -555,6 +555,63 @@ Other incompatible flag pairs:\n  * --preserve-merges && --rebase-merges\n  * --rebase-merges && --strategy\n \n+BEHAVIORAL INCONSISTENCIES\n+--------------------------\n+\n+  * --no-ff vs. --force-rebase\n+\n+    These options are actually identical, though their description\n+    leads people to believe they might not be.\n+\n+ * empty commits:\n+\n+    am-based rebase will drop any \"empty\" commits, whether the\n+    commit started empty (had no changes relative to its parent to\n+    start with) or ended empty (all changes were already applied\n+    upstream in other commits).\n+\n+    merge-based rebase does the same.\n+\n+    interactive-based rebase will by default drop commits that\n+    started empty and halt if it hits a commit that ended up empty.\n+    The --keep-empty option exists for interactive rebases to allow\n+    it to keep commits that started empty.\n+\n+  * empty commit messages:\n+\n+    am-based rebase will silently apply commits with empty commit\n+    messages.\n+\n+    merge-based and interactive-based rebases will by default halt\n+    on any such commits.  The --allow-empty-message option exists to\n+    allow interactive-based rebases to apply such commits without\n+    halting.\n+\n+  * directory rename detection:\n+\n+    merge-based and interactive-based rebases work fine with\n+    directory rename detection.  am-based rebases sometimes do not.\n+\n+    git-am tries to avoid a full three way merge, instead calling\n+    git-apply.  That prevents us from detecting renames at all,\n+    which may defeat the directory rename detection.  There is a\n+    fallback, though; if the initial git-apply fails and the user\n+    has specified the -3 option, git-am will fall back to a three\n+    way merge.  However, git-am lacks the necessary information to\n+    do a \"real\" three way merge.  Instead, it has to use\n+    build_fake_ancestor() to get a merge base that is missing files\n+    whose rename may have been important to detect for directory\n+    rename detection to function.\n+\n+    Since am-based rebases work by first generating a bunch of\n+    patches (which no longer record what the original commits were\n+    and thus don't have the necessary info from which we can find a\n+    real merge-base), and then calling git-am, this implies that\n+    am-based rebases will not always successfully detect directory\n+    renames either.  merged-based rebases (rebase -m) and\n+    cherry-pick-based rebases (rebase -i) are not affected by this\n+    shortcoming.\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.rc2.1.g5453d3f70b.dirty\n\n"},{"id":"350358","messageId":"e8a6f54e-4361-dc66-c833-6047f8ea2058@talktalk.net","threadId":"48665","inReplyTo":"20180617055856.22838-8-newren@gmail.com","subject":"Re: [RFC PATCH v2 7/7] git-rebase: make --allow-empty-message the default","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-17T15:30:59Z","receivedAt":"2018-06-17T15:31:31Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 17/06/18 06:58, Elijah Newren wrote:\n> am-based rebases already apply commits with an empty commit message\n> without requiring the user to specify an extra flag.  Make merge-based and\n> interactive-based rebases behave the same.\n> \n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>   Documentation/git-rebase.txt  | 10 ----------\n>   git-rebase.sh                 |  2 +-\n>   t/t3404-rebase-interactive.sh |  7 ++++---\n>   t/t3405-rebase-malformed.sh   | 11 +++--------\n>   4 files changed, 8 insertions(+), 22 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 7a2ed9efdc..a5608f481f 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -562,16 +562,6 @@ BEHAVIORAL INCONSISTENCIES\n>       The --keep-empty option exists for interactive rebases to allow\n>       it to keep commits that started empty.\n>   \n> -  * empty commit messages:\n> -\n> -    am-based rebase will silently apply commits with empty commit\n> -    messages.\n> -\n> -    merge-based and interactive-based rebases will by default halt\n> -    on any such commits.  The --allow-empty-message option exists to\n> -    allow interactive-based rebases to apply such commits without\n> -    halting.\n> -\n>     * directory rename detection:\n>   \n>       merge-based and interactive-based rebases work fine with\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 5f891214fa..bf033da4e5 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -95,7 +95,7 @@ rebase_cousins=\n>   preserve_merges=\n>   autosquash=\n>   keep_empty=\n> -allow_empty_message=\n> +allow_empty_message=--allow-empty-message\n\nLooking at the option parsing in git-rebase.sh it appears that it does \nnot check for --no-allow-empty-message so there's no way to turn off the \ndefault for those modes that support it. I'm not sure what to think of \nthis change, I'm slightly uneasy with changing to default to be \ndifferent from cherry-pick, though one could argue rebasing is a \ndifferent operation and just keeping the existing messages even if they \nare empty is more appropriate and having all the rebase modes do the \ndefault to the same behaviour is definitely an improvement.\n\nBest Wishes\n\nPhillip\n\n>   signoff=\n>   test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n>   case \"$(git config --bool commit.gpgsign)\" in\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index c65826ddac..f84fa63b15 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n>   '\n>   \n>   test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n> +\ttest_when_finished \"git rebase --abort\" &&\n>   \told=$(git rev-parse HEAD) &&\n>   \ttest_tick &&\n>   \tset_fake_editor &&\n>   \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n>   \techo \"edited again\" > file7 &&\n>   \tgit add file7 &&\n> -\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n> -\ttest $old = $(git rev-parse HEAD) &&\n> -\tgit rebase --abort\n> +\techo all the things >>conflict &&\n> +\ttest_must_fail git rebase --continue &&\n> +\ttest $old = $(git rev-parse HEAD)\n>   '\n>   \n>   test_expect_success 'auto-amend only edited commits after \"edit\"' '\n> diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\n> index cb7c6de84a..da94dddc86 100755\n> --- a/t/t3405-rebase-malformed.sh\n> +++ b/t/t3405-rebase-malformed.sh\n> @@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n>   '\n>   \n>   test_expect_success 'rebase -m commit with empty message' '\n> -\ttest_must_fail git rebase -m master empty-message-merge &&\n> -\tgit rebase --abort &&\n> -\tgit rebase -m --allow-empty-message master empty-message-merge\n> +\tgit rebase -m master empty-message-merge\n>   '\n>   \n>   test_expect_success 'rebase -i commit with empty message' '\n>   \tgit checkout diff-in-message &&\n>   \tset_fake_editor &&\n> -\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> -\t\tgit rebase -i HEAD^ &&\n> -\tgit rebase --abort &&\n> -\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> -\t\tgit rebase -i --allow-empty-message HEAD^\n> +\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> +\t\tgit rebase -i HEAD^\n>   '\n>   \n>   test_done\n> \n\n"},{"id":"350359","messageId":"13ccb4d9-582b-d26b-f595-59cb0b7037ab@talktalk.net","threadId":"48665","inReplyTo":"20180617055856.22838-2-newren@gmail.com","subject":"Re: [RFC PATCH v2 1/7] git-rebase.txt: document incompatible options","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-17T15:38:27Z","receivedAt":"2018-06-17T15:38:33Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\nOn 17/06/18 06:58, Elijah Newren wrote:\n> git rebase has many options that only work with one of its three backends.\n> It also has a few other pairs of incompatible options.  Document these.\n> \n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>   Documentation/git-rebase.txt | 84 ++++++++++++++++++++++++++++++++----\n>   1 file changed, 76 insertions(+), 8 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index 0e20a66e73..adccc15284 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n>   --keep-empty::\n>   \tKeep the commits that do not change anything from its\n>   \tparents in the result.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --allow-empty-message::\n>   \tBy default, rebasing commits with an empty message will fail.\n>   \tThis option overrides that behavior, allowing commits with empty\n>   \tmessages to be rebased.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --skip::\n>   \tRestart the rebasing process by skipping the current patch.\n> @@ -271,6 +275,8 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n>   conflict happens, the side reported as 'ours' is the so-far rebased\n>   series, starting with <upstream>, and 'theirs' is the working branch.  In\n>   other words, the sides are swapped.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -s <strategy>::\n>   --strategy=<strategy>::\n> @@ -280,8 +286,10 @@ other words, the sides are swapped.\n>   +\n>   Because 'git rebase' replays each commit from the working branch\n>   on top of the <upstream> branch using the given strategy, using\n> -the 'ours' strategy simply discards all patches from the <branch>,\n> +the 'ours' strategy simply empties all patches from the <branch>,\n>   which makes little sense.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -X <strategy-option>::\n>   --strategy-option=<strategy-option>::\n> @@ -289,6 +297,8 @@ which makes little sense.\n>   \tThis implies `--merge` and, if no strategy has been\n>   \tspecified, `-s recursive`.  Note the reversal of 'ours' and\n>   \t'theirs' as noted above for the `-m` option.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -S[<keyid>]::\n>   --gpg-sign[=<keyid>]::\n> @@ -324,6 +334,8 @@ which makes little sense.\n>   \tand after each change.  When fewer lines of surrounding\n>   \tcontext exist they all must match.  By default no context is\n>   \tever ignored.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -f::\n>   --force-rebase::\n> @@ -355,19 +367,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n>   --whitespace=<option>::\n>   \tThese flag are passed to the 'git apply' program\n>   \t(see linkgit:git-apply[1]) that applies the patch.\n> -\tIncompatible with the --interactive option.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --committer-date-is-author-date::\n>   --ignore-date::\n>   \tThese flags are passed to 'git am' to easily change the dates\n>   \tof the rebased commits (see linkgit:git-am[1]).\n> -\tIncompatible with the --interactive option.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --signoff::\n>   \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n>   \tthat if `--interactive` is given then only commits marked to be\n> -\tpicked, edited or reworded will have the trailer added. Incompatible\n> -\twith the `--preserve-merges` option.\n> +\tpicked, edited or reworded will have the trailer added.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -i::\n>   --interactive::\n> @@ -378,6 +393,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n>   The commit list format can be changed by setting the configuration option\n>   rebase.instructionFormat.  A customized instruction format will automatically\n>   have the long commit hash prepended to the format.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -r::\n>   --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::\n> @@ -404,7 +421,7 @@ It is currently only possible to recreate the merge commits using the\n>   `recursive` merge strategy; Different merge strategies can be used only via\n>   explicit `exec git merge -s <strategy> [...]` commands.\n>   +\n> -See also REBASING MERGES below.\n> +See also REBASING MERGES and INCOMPATIBLE OPTIONS below.\n>   \n>   -p::\n>   --preserve-merges::\n> @@ -415,6 +432,8 @@ See also REBASING MERGES below.\n>   This uses the `--interactive` machinery internally, but combining it\n>   with the `--interactive` option explicitly is generally not a good\n>   idea unless you know what you are doing (see BUGS below).\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   -x <cmd>::\n>   --exec <cmd>::\n> @@ -437,6 +456,8 @@ squash/fixup series.\n>   +\n>   This uses the `--interactive` machinery internally, but it can be run\n>   without an explicit `--interactive`.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --root::\n>   \tRebase all commits reachable from <branch>, instead of\n> @@ -447,6 +468,8 @@ without an explicit `--interactive`.\n>   \tWhen used together with both --onto and --preserve-merges,\n>   \t'all' root commits will be rewritten to have <newbase> as parent\n>   \tinstead.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --autosquash::\n>   --no-autosquash::\n> @@ -461,11 +484,11 @@ without an explicit `--interactive`.\n>   \ttoo.  The recommended way to create fixup/squash commits is by using\n>   \tthe `--fixup`/`--squash` options of linkgit:git-commit[1].\n>   +\n> -This option is only valid when the `--interactive` option is used.\n> -+\n>   If the `--autosquash` option is enabled by default using the\n>   configuration variable `rebase.autoSquash`, this option can be\n>   used to override and disable this setting.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n>   \n>   --autostash::\n>   --no-autostash::\n> @@ -487,6 +510,51 @@ recreates the topic branch with fresh commits so it can be remerged\n>   successfully without needing to \"revert the reversion\" (see the\n>   link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n>   \n> +INCOMPATIBLE OPTIONS\n> +--------------------\n> +\n> +git-rebase has many flags that are incompatible with each other,\n> +predominantly due to the fact that it has three different underlying\n> +implementations:\n> +\n> + * one based on linkgit:git-am[1] (the default)\n> + * one based on linkgit:git-merge-recursive[1] (merge backend)\n> + * one based on linkgit:git-cherry-pick[1] (interactive backend)\n> +\n> +Flags only understood by the am backend:\n> +\n> + * --committer-date-is-author-date\n> + * --ignore-date\n> + * --whitespace\n> + * --ignore-whitespace\n> + * -C\n> +\n> +Flags understood by both merge and interactive backends:\n> +\n> + * --merge\n> + * --strategy\n> + * --strategy-option\n> + * --allow-empty-message\n> +\n> +Flags only understood by the interactive backend:\n> +\n> + * --[no-]autosquash\n> + * --rebase-merges\n> + * --preserve-merges\n> + * --interactive\n> + * --exec\n> + * --keep-empty\n> + * --autosquash\n> + * --edit-todo\n> + * --root + --onto\n> +\n> +Other incompatible flag pairs:\n> +\n> + * --preserve-merges && --interactive\n> + * --preserve-merges && --signoff\n> + * --preserve-merges && --rebase-merges\n> + * --rebase-merges && --strategy\n\nDoes --rebase-merges support --strategy-options?\n\n> +\n>   include::merge-strategies.txt[]\n>   \n>   NOTES\n> \nThis is a great step forward. In the long run it would be nice not to \nhave to mention the backends. Once git-rebase--merge.sh is gone, the \nsituation is simpler and it would be nice to reword this to say \nsomething like\n   The --committer-date-is-author-date, --ignore-date, --whitespace,\n   --ignore-whitespace and -C options are incompatible with the following\n   --exec ... Also note that --rebase-merges is incompatible with\n   --strategy; and --preserve-merges is incompatible with --interactive,\n   --signoff, --rebase-merges.\nrather than talking about am options etc.\n\nBest Wishes\n\nPhillip\n"},{"id":"350360","messageId":"fa4118c9-5ff9-0fa7-7df4-98a3c483f95d@talktalk.net","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"Re: [RFC PATCH v2 0/7] Document/fix/warn about rebase incompatibilities and inconsistences","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-17T15:41:32Z","receivedAt":"2018-06-17T15:41:37Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 17/06/18 06:58, Elijah Newren wrote:\n> git-rebase has lots of options that are mutually incompatible.  Even among\n> aspects of its behavior that is common to all rebase types, it has a number\n> of inconsistencies.  This series tries to document, fix, and/or warn users\n> about many of these.\n> \n> I have a much higher than average expectation that folks will object\n> to some of these patches.  I've tried to divide them up so that any parts\n> we decide to drop or redo can be more easily excised.\n> \n> No branch-diff; because it's a significant re-work; instead I'll comment\n> briefly on the individual patches...\n\nI found this series well structured and easy to follow. I've commented \non a couple of the patches, the others seemed fine to me. It's great to \nsee these inconsistencies being documented and some being eliminated.\n\nBest Wishes\n\nPhillip\n\n> \n> Elijah Newren (7):\n>    git-rebase.txt: document incompatible options\n> \n> Both Dscho (on a related patch series) and Phillip suggested changing the\n> documentation to avoid implementational details.  I instead made a separate\n> section with sets of incompatible options...but it still mentions the\n> different backends while doing so.  Does that seem alright?\n> \n>    git-rebase.sh: update help messages a bit\n> \n> Minor tweaks to `git rebase -h` output.\n> \n>    t3422: new testcases for checking when incompatible options passed\n> \n> The one unmodified patch from the first round.\n> \n>    git-rebase: error out when incompatible options passed\n> \n> Almost the same as the first round, except:\n>    * Documentation pulled into a separate patch (patch 1)\n>    * $() instead of ``\n> \n>    git-rebase.txt: document behavioral inconsistencies between modes\n> \n> Add another section to the documentation for aspects that ideally\n> should be common between all modes but are handled differently.\n> \n>    git-rebase.txt: address confusion between --no-ff vs --force-rebase\n> \n> This came up on the list not that long ago; fix the documentation.\n> \n>    git-rebase: make --allow-empty-message the default\n> \n> Address the easiest of the inconsistencies, assuming the am-based backend\n> has the correct default and the merge-based and interactive-based backends\n> are the ones that need to change.\n> \n>   Documentation/git-rebase.txt           | 154 ++++++++++++++++++++-----\n>   git-rebase.sh                          |  25 +++-\n>   t/t3404-rebase-interactive.sh          |   7 +-\n>   t/t3405-rebase-malformed.sh            |  11 +-\n>   t/t3422-rebase-incompatible-options.sh |  69 +++++++++++\n>   5 files changed, 224 insertions(+), 42 deletions(-)\n>   create mode 100755 t/t3422-rebase-incompatible-options.sh\n> \n\n"},{"id":"350362","messageId":"CAPig+cScoXgSrGQseX_u8SaXo1J-beb-fpZpF8V-rpwH5s-AUA@mail.gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-2-newren@gmail.com","subject":"Re: [RFC PATCH v2 1/7] git-rebase.txt: document incompatible options","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-06-17T17:15:57Z","receivedAt":"2018-06-17T17:16:12Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sun, Jun 17, 2018 at 1:59 AM Elijah Newren <newren@gmail.com> wrote:\n> git rebase has many options that only work with one of its three backends.\n> It also has a few other pairs of incompatible options.  Document these.\n>\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> @@ -487,6 +510,51 @@ recreates the topic branch with fresh commits so it can be remerged\n> +Flags only understood by the interactive backend:\n> + [...]\n> + * --edit-todo\n> + * --root + --onto\n\nWhat does \"+\" mean? Is it \"and\"?\n\n> +Other incompatible flag pairs:\n> +\n> + * --preserve-merges && --interactive\n> + * --preserve-merges && --signoff\n> + * --preserve-merges && --rebase-merges\n> + * --rebase-merges && --strategy\n\nIt's somewhat odd seeing \"programmer\" notation in end-user\ndocumentation. Perhaps replace \"&&\" with \"and\"?\n"},{"id":"350368","messageId":"nycvar.QRO.7.76.6.1806172337340.77@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"CABPp-BHa+sxuFBa3EmSyio28ytF_ORn950Keh1P=L-VxXtOwMw@mail.gmail.com","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-06-17T21:44:16Z","receivedAt":"2018-06-17T21:44:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Sat, 9 Jun 2018, Elijah Newren wrote:\n\n> On Sat, Jun 9, 2018 at 3:11 PM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n> > On Thu, 7 Jun 2018, Elijah Newren wrote:\n> >\n> >> am-based rebases suffer from an reduced ability to detect directory\n> >> renames upstream, which is fundamental to the fact that it throws\n> >> away information about the history: in particular, it dispenses with\n> >> the original commits involved by turning them into patches, and\n> >> without the knowledge of the original commits we cannot determine a\n> >> proper merge base.\n> >>\n> >> The am-based rebase will proceed by first trying git-apply, and, only\n> >> if it fails, will try to reconstruct a provisional merge base using\n> >> build_fake_ancestor().  This fake ancestor will ONLY contain the\n> >> files modified in the patch; without the full list of files in the\n> >> real merge base, renames of any missing files cannot be detected.\n> >> Directory rename detection works by looking at individual file\n> >> renames and deducing when a full directory has been renamed.\n> >>\n> >> Trying to modify build_fake_ancestor() to instead create a merge base\n> >> that includes common file information by looking for a commit that\n> >> contained all the same blobs as the pre-image of the patch would\n> >> require a very expensive search through history, may find the wrong\n> >> commit, and outside of rebase may not find any commit that matches.\n> >>\n> >> But we had all the relevant information to start.  So, instead of\n> >> attempting to fix am which just doesn't have the relevant\n> >> information, instead note its strength and weaknesses, and change the\n> >> default rebase machinery to interactive since it does not suffer from\n> >> the same problems.\n> >\n> > I'll let Eric comment on the grammar, and I'll comment on the idea\n> > behind this commit instead.\n> \n> Going to dump the hard job on Eric, eh?  ;-)\n\nJust trying to learn how to delegate.\n\n:0)\n\n> > IMHO `git rebase -i` is still too slow to be a true replacement for\n> > `git rebase --am` for the cases where it serves the user well. Maybe\n> > we should work on making `rebase -i` faster, first?\n> \n> That sounds fair.\n> \n> > I imagine, for example, that it might make *tons* of sense to avoid\n> > writing out the index and worktree files all the time. That was\n> > necessary in the shell script version because if the ridiculous\n> > limitations we subjected ourselves to, such as: no object-oriented\n> > state worth mentioning, only string-based processing, etc. But we\n> > could now start to do everything in memory (*maybe* write out the new\n> > blob/tree/commit objects immediately, but maybe not) until the time\n> > when we either have succeeded in the rebase, or when there was a\n> > problem and we have to exit with an error. And only then write the\n> > files and the index.\n> \n> Hmm...are you still planning on using cherry-pick (internally rather\n> than forking, of course)?\n\nThe sequencer side-steps the cherry-pick command by calling\nmerge_recursive() directly. But yes, this is what the interactive rebase\nwill always use.\n\n>  Because cherry-pick uses the merge-recursive machinery, and the\n>  merge-recursive machinery doesn't have a nice way of avoiding writing\n>  to the working tree or index.\n\nExactly. I think it could be taught to perform its magic in memory. I am\nnot saying that it is necessarily easy to teach merge-recursive.c this\ntrick, but it should be possible.\n\n> Fixing that is on my radar; see the first block of\n> https://public-inbox.org/git/CABPp-BG2fZHm3s-yrzxyGj3Eh+O7_LHLz5pgstHhG2drigSyRA@mail.gmail.com/\n\nGreat!\n\n> (reading up until \"At this point, I'd rather just fix the design flaw\n> rather than complicate the code further.\")\n> \n> However, also covered in my plans is a few things to speed up the\n> merge-recursive machinery, which should provide some other performance\n> benefits for interactive rebases.\n\nI am looking forward to see this materialize.\n\n> > In any case, I think that the rather noticeable change of the default\n> > would probably necessitate a deprecation phase.\n> \n> Why is it a \"rather noticable change of the default\"?\n\nI was really referring to speed. But I have to admit that I do not have\nany current numbers.\n\nAnother issue just hit me, though: rebase --am does not need to look at as\nmany Git objects as rebase --merge or rebase -i. Therefore, GVFS users\nwill still want to use --am wherever possible, to avoid \"hydrating\"\nmany objects during their rebase.\n\n> If we popped up the editor and asked the user to edit the list of\n> options, I'd agree, or if folks thought that it was significantly slower\n> by a big enough margin (though you already suggested waiting and making\n> sure we don't do that).  What else remains that qualifies?\n> \n> (Okay, the default behavior to just skip empty patches rather than halt\n> the rebase and ask the user to advise is different, but we could fix\n> that up too.  Is there anything else?)\n\nThat is indeed a change in behavior that is rather easy to address.\n\nAs to speed: that might be harder. But then, the performance might already\nbe good enough. I do not have numbers (nor the time to generate them) to\nback up my hunch that --am is substantially faster than --merge.\n\nCiao,\nDscho\n"},{"id":"350570","messageId":"CABPp-BEnJ4q9WGi4BgikpLJ9Aty5-3MR4VozjBk7ie4rGMc-ng@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1806172337340.77@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-20T16:27:54Z","receivedAt":"2018-06-20T16:27:59Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Sun, Jun 17, 2018 at 2:44 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n\n> I was really referring to speed. But I have to admit that I do not have\n> any current numbers.\n>\n> Another issue just hit me, though: rebase --am does not need to look at as\n> many Git objects as rebase --merge or rebase -i. Therefore, GVFS users\n> will still want to use --am wherever possible, to avoid \"hydrating\"\n> many objects during their rebase.\n\nWhat is it that makes rebase --am need fewer Git objects than rebase\n--merge or rebase -i?  I have one idea which isn't intrinsic to the\nalgorithm, so I'm curious if there's something else I'm unaware of.\n\nMy guess at what objects are needed by each type:\n\nAt a high level, rebase --am for each commit will need to compare the\ncommit to its parent to generate a diff (which thus involves walking\nover the objects in both the commit and its parent, though it should\nbe able to skip over subtrees that are equal), and then will need to\nlook at all the objects in the target commit on which it needs to\napply the patch (in order to properly fill the index for a starting\npoint, and used later when creating a new commit).  If the application\nof the diff fails, it falls back to a three-way merge, though the\nthree-way merge shouldn't need any additional objects.  So, to\nsummarize, rebase--am needs objects from the commit being rebased, its\nparent, and the target commit onto which it is applying, though it can\nshort circuit some objects when the commit and its parent have\nmatching subtree(s).\n\nrebase -i, if I understand correctly, does a three-way merge between\nthe commit, its parent, and the target commit.  Thus, we again walk\nover objects in those three commits; I think unpack_trees() does not\ntake advantage of matching trees to avoid descending into subtrees,\nbut if so that's an optimization that we may be able to implement\n(though it would require diving into unpack_trees() code, which is\nnever easy...).\n\n(Side notes: (1) rebase --merge is basically the same as rebase -i\nhere; it's path to reaching the recursive merge machinery is a bit\ndifferent but the resulting arguments are the same; (2) a real merge\nbetween branches would require more objects because it would have to\ndo some revision walking to find a merge base, and a real merge base\nis likely to differ more than just the parent commit.  But finding\nmerge bases isn't relevant to rebase -m or rebase -i)\n\nIs there something else I'm missing that fundamentally makes rebase -i\nneed more objects?\n\n> As to speed: that might be harder. But then, the performance might already\n> be good enough. I do not have numbers (nor the time to generate them) to\n> back up my hunch that --am is substantially faster than --merge.\n\nI too have a hunch that --am is faster than --merge, on big enough\nrepos or repos with enough renames.  I can partially back it up with\nan indirect number: at [1], it was reported that cherry-picks could be\nsped up by a factor of 20-30 on some repos with lots of renames.  I\nbelieve there are other performance improvements possible too, for the\n--merge or -i cases.\n\nI'm also curious now whether your comment on hydrating objects might\nuncover additional areas where performance improvements could be made\nfor non-am-based rebases of large-enough repos.\n\nElijah\n\n[1] https://public-inbox.org/git/CABPp-BH4LLzeJjE5cvwWQJ8xTj3m9oC-41Tu8BM8c7R0gQTjWw@mail.gmail.com/\n(see also Peter's last reply in that thread, and compare to his first\npost)\n"},{"id":"350573","messageId":"CABPp-BHrcUHX_zHxpojV5=sxJ1=NoDg9uhxv+NH5BsHsQYavPQ@mail.gmail.com","threadId":"48665","inReplyTo":"e8a6f54e-4361-dc66-c833-6047f8ea2058@talktalk.net","subject":"Re: [RFC PATCH v2 7/7] git-rebase: make --allow-empty-message the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-20T16:47:12Z","receivedAt":"2018-06-20T16:47:18Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Phillip,\n\nOn Sun, Jun 17, 2018 at 8:30 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n\n> Looking at the option parsing in git-rebase.sh it appears that it does not\n> check for --no-allow-empty-message so there's no way to turn off the default\n> for those modes that support it. I'm not sure what to think of this change,\n> I'm slightly uneasy with changing to default to be different from\n> cherry-pick, though one could argue rebasing is a different operation and\n> just keeping the existing messages even if they are empty is more\n> appropriate and having all the rebase modes do the default to the same\n> behaviour is definitely an improvement.\n>\n\nHere's my extended rationale for why to change the default for rebase\n-i/-m (and _maybe_ also for cherry-pick):\n\nFirst, commits with an empty commit message are fairly rare, so it's\nhard to gather that much data on; we're dealing with out-liers.  That\nalso means that folks who have touched the area in the past probably\nweren't dealing with full information either; they just tweaked what\nwas already there.\n\nIt makes sense that git-commit would default to not allowing empty\ncommit messages without a flag.  We'd like to warn against that kind\nof poor practice.  However, that implicitly means that commands which\nbuild on top of git-commit might copy that default even when it\ndoesn't make sense.  So it's not at all clear to me that cherry-pick\nor rebase -i/-m should have the same default.  They do, but that may\nhave been entirely accidental.  And when someone comes along and\nnotices the problematic default of stopping with empty commit\nmessages, they assume it was intended and add a flag to change it, as\nhappened for both commands.\n\nOn the other hand git-am was designed from the workflow of applying\nmany patches from the beginning, and has a different default.\nam-based rebases copy that default of silently applying commits with\nempty commit messages; it may not be clear that rebase should copy the\ndefault from am, but it does.  Yet, despite the fact that ignoring\nempty commit messages is the default backend for rebases, and thus is\nlikely used more than the other rebase backends, no one has ever\nsubmitted a patch to add a flag to rebase to get the opposite\nbehavior.  To me, this argues pretty strongly that not only is\nignoring empty messages the right default, that it's a waste of time\nto implement a flag (e.g. --no-allow-empty-message) providing the\nopposite behavior for rebases.\n\nIt is obvious that one of the two rebase backends have the wrong\ndefault, because they should have the same default as each other.  I\nam inclined to believe, based on the above logic, that am-based rebase\nhas the correct default.  I also suspect that cherry-pick has the\nwrong default, though it's not as cut-and-dry since it doesn't have\nmultiple backends with conflicting defaults.\n\n\nDoes that make sense?  Am I overlooking anything important?\n"},{"id":"350574","messageId":"CABPp-BFSgFyRrsVc+-gO04KvZGe+6siPJ0LwEtC7ZKQ-q5Gusg@mail.gmail.com","threadId":"48665","inReplyTo":"13ccb4d9-582b-d26b-f595-59cb0b7037ab@talktalk.net","subject":"Re: [RFC PATCH v2 1/7] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-20T17:09:07Z","receivedAt":"2018-06-20T17:09:11Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Sun, Jun 17, 2018 at 8:38 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n>> +Other incompatible flag pairs:\n>> +\n>> + * --preserve-merges && --interactive\n>> + * --preserve-merges && --signoff\n>> + * --preserve-merges && --rebase-merges\n>> + * --rebase-merges && --strategy\n>\n> Does --rebase-merges support --strategy-options?\n\nGood catch.  I hadn't yet tested --rebase-merges or --preserve-merges\nmyself, so I was just going off notes in the documentation or code for\nthose ones.  I created a simple case needing -Xignore-space-change to\nmerge cleanly, and found that any --strategy-option argument will be\nsilently ignored by --rebase-merges currently.  So, we should also\ndocument and warn the user that those options are currently\nincompatible.\n\n>> +\n>>   include::merge-strategies.txt[]\n>>     NOTES\n>>\n> This is a great step forward. In the long run it would be nice not to have\n> to mention the backends. Once git-rebase--merge.sh is gone, the situation is\n> simpler and it would be nice to reword this to say something like\n>   The --committer-date-is-author-date, --ignore-date, --whitespace,\n>   --ignore-whitespace and -C options are incompatible with the following\n>   --exec ... Also note that --rebase-merges is incompatible with\n>   --strategy; and --preserve-merges is incompatible with --interactive,\n>   --signoff, --rebase-merges.\n> rather than talking about am options etc.\n\nThat sounds like it would be simpler for the incompatible options, but\nwhat about discussing inconsistent behavior between different backends\n(empty commit handling, empty commit message handling, and directory\nrename detection)?  Do we first need to remove all those\ninconsistencies before rewording the documentation here, or is there a\nclever way to discuss those?\n"},{"id":"350575","messageId":"CABPp-BF0Qg8O3cQm51ptB6c7+CKUa+jND6zHdZsixOUMv+2ZxA@mail.gmail.com","threadId":"48665","inReplyTo":"CAPig+cScoXgSrGQseX_u8SaXo1J-beb-fpZpF8V-rpwH5s-AUA@mail.gmail.com","subject":"Re: [RFC PATCH v2 1/7] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-20T17:10:41Z","receivedAt":"2018-06-20T17:10:46Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Eric,\n\nOn Sun, Jun 17, 2018 at 10:15 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sun, Jun 17, 2018 at 1:59 AM Elijah Newren <newren@gmail.com> wrote:\n>> git rebase has many options that only work with one of its three backends.\n>> It also has a few other pairs of incompatible options.  Document these.\n>>\n>> Signed-off-by: Elijah Newren <newren@gmail.com>\n>> ---\n>> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n>> @@ -487,6 +510,51 @@ recreates the topic branch with fresh commits so it can be remerged\n>> +Flags only understood by the interactive backend:\n>> + [...]\n>> + * --edit-todo\n>> + * --root + --onto\n>\n> What does \"+\" mean? Is it \"and\"?\n\nYes, it means \"and\", though perhaps it'd be even clearer to write \"in\ncombination with\" or \"when used in combination with\"\n\n>> +Other incompatible flag pairs:\n>> +\n>> + * --preserve-merges && --interactive\n>> + * --preserve-merges && --signoff\n>> + * --preserve-merges && --rebase-merges\n>> + * --rebase-merges && --strategy\n>\n> It's somewhat odd seeing \"programmer\" notation in end-user\n> documentation. Perhaps replace \"&&\" with \"and\"?\n\nYes, good point.  I'll make that fix.\n"},{"id":"350623","messageId":"nycvar.QRO.7.76.6.1806211242440.11870@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"CABPp-BEnJ4q9WGi4BgikpLJ9Aty5-3MR4VozjBk7ie4rGMc-ng@mail.gmail.com","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-06-21T10:57:28Z","receivedAt":"2018-06-21T10:57:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Wed, 20 Jun 2018, Elijah Newren wrote:\n\n> On Sun, Jun 17, 2018 at 2:44 PM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n> \n> > I was really referring to speed. But I have to admit that I do not have\n> > any current numbers.\n> >\n> > Another issue just hit me, though: rebase --am does not need to look at as\n> > many Git objects as rebase --merge or rebase -i. Therefore, GVFS users\n> > will still want to use --am wherever possible, to avoid \"hydrating\"\n> > many objects during their rebase.\n> \n> What is it that makes rebase --am need fewer Git objects than rebase\n> --merge or rebase -i?\n\nMultiple things. The most obvious thing: --cherry-pick. When you call `git\nrebase --am`, it does not try to exclude the patches by looking at\n`rev-list --cherry-pick --right-only <upstream>..<head>`\n\nThis really bit us in GVFS Git because we have several thousand developers\nworking on the same code base, and you probably read the numbers elsewhere\nhow many commits are introduced while a developer goes on so much as a\nweek-long vacation.\n\nNext, rename detection.\n\nI think that bit us even harder because it tries to look at all the files\nthat have been changed in upstream in the meantime, which can be *a lot*.\nAnd if you know that moving files outside of your cozy little sparse\ncheckout is unlikely (or moving from the outside into your checkout), then\nall this hydration is pretty wasteful. That's why we had to switch off\nrename detection in GVFS Git.\n\n> My guess at what objects are needed by each type:\n> \n> At a high level, rebase --am for each commit will need to compare the\n> commit to its parent to generate a diff (which thus involves walking\n> over the objects in both the commit and its parent, though it should\n> be able to skip over subtrees that are equal), and then will need to\n> look at all the objects in the target commit on which it needs to\n> apply the patch (in order to properly fill the index for a starting\n> point, and used later when creating a new commit).\n\nNo, in --am mode, it does not even need to look at all the objects in the\ntarget commits. Only those objects that correspond to the files that are\ntouched by the diff.\n\nIn a massive code base, such as Windows', this makes a huge difference.\nEven comparing the number of files touched by the patches that are to be\nrebased to the number of files that were touched in upstream since you\nrebased last is ridiculous. And a three-way merge needs to consider that\nlatter set of files.\n\n> If the application of the diff fails, it falls back to a three-way\n> merge, though the three-way merge shouldn't need any additional objects.\n\nThe three-way merge needs to reconcile the diff between branch point and\nyour changes to the diff between branch point and upstream's changes. The\nlatter can be a lot bigger than the former, in which case --am's\ncomplexity (O(former)) is much nicer than --merge's (O(former u latter)).\n\n> So, to summarize, rebase--am needs objects from the commit being\n> rebased, its parent, and the target commit onto which it is applying,\n> though it can short circuit some objects when the commit and its parent\n> have matching subtree(s).\n> \n> rebase -i, if I understand correctly, does a three-way merge between\n> the commit, its parent, and the target commit.  Thus, we again walk\n> over objects in those three commits; I think unpack_trees() does not\n> take advantage of matching trees to avoid descending into subtrees,\n> but if so that's an optimization that we may be able to implement\n> (though it would require diving into unpack_trees() code, which is\n> never easy...).\n> \n> (Side notes: (1) rebase --merge is basically the same as rebase -i\n> here; it's path to reaching the recursive merge machinery is a bit\n> different but the resulting arguments are the same; (2) a real merge\n> between branches would require more objects because it would have to\n> do some revision walking to find a merge base, and a real merge base\n> is likely to differ more than just the parent commit.  But finding\n> merge bases isn't relevant to rebase -m or rebase -i)\n> \n> Is there something else I'm missing that fundamentally makes rebase -i\n> need more objects?\n> \n> > As to speed: that might be harder. But then, the performance might already\n> > be good enough. I do not have numbers (nor the time to generate them) to\n> > back up my hunch that --am is substantially faster than --merge.\n> \n> I too have a hunch that --am is faster than --merge, on big enough\n> repos or repos with enough renames.  I can partially back it up with\n> an indirect number: at [1], it was reported that cherry-picks could be\n> sped up by a factor of 20-30 on some repos with lots of renames.  I\n> believe there are other performance improvements possible too, for the\n> --merge or -i cases.\n> \n> I'm also curious now whether your comment on hydrating objects might\n> uncover additional areas where performance improvements could be made\n> for non-am-based rebases of large-enough repos.\n> \n> Elijah\n> \n> [1] https://public-inbox.org/git/CABPp-BH4LLzeJjE5cvwWQJ8xTj3m9oC-41Tu8BM8c7R0gQTjWw@mail.gmail.com/\n> (see also Peter's last reply in that thread, and compare to his first\n> post)\n\nI am too unfamiliar with the rename detection to understand the details,\nbut you are familiar with it, so I trust your judgement!\n\nCiao,\nDscho\n"},{"id":"350640","messageId":"20180621150023.23533-8-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[RFC PATCH v3 7/7] git-rebase: make --allow-empty-message the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:23Z","receivedAt":"2018-06-21T15:00:47Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"All rebase backends should behave the same with empty commit messages, but\ncurrently do not.  am-based rebases already apply commits with an empty\ncommit message without stopping or requiring the user to specify an extra\nflag.  Since am-based rebases are the default rebase type, and since it\nappears no one has ever requested a --no-allow-empty-message flag to\nchange this behavior, make --allow-empty-message the default so that\nmerge-based and interactive-based rebases will behave the same.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n\nSee also\nhttps://public-inbox.org/git/CABPp-BHrcUHX_zHxpojV5=sxJ1=NoDg9uhxv+NH5BsHsQYavPQ@mail.gmail.com/\nfor some discussion of this change.\n\n Documentation/git-rebase.txt  | 10 ----------\n git-rebase.sh                 |  2 +-\n t/t3404-rebase-interactive.sh |  7 ++++---\n t/t3405-rebase-malformed.sh   | 11 +++--------\n 4 files changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 1f422cd0a7..3addcf8218 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -563,16 +563,6 @@ BEHAVIORAL INCONSISTENCIES\n     The --keep-empty option exists for interactive rebases to allow\n     it to keep commits that started empty.\n \n-  * empty commit messages:\n-\n-    am-based rebase will silently apply commits with empty commit\n-    messages.\n-\n-    merge-based and interactive-based rebases will by default halt\n-    on any such commits.  The --allow-empty-message option exists to\n-    allow interactive-based rebases to apply such commits without\n-    halting.\n-\n   * directory rename detection:\n \n     merge-based and interactive-based rebases work fine with\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 590bdbb12a..a909a2cfb1 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -95,7 +95,7 @@ rebase_cousins=\n preserve_merges=\n autosquash=\n keep_empty=\n-allow_empty_message=\n+allow_empty_message=--allow-empty-message\n signoff=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n case \"$(git config --bool commit.gpgsign)\" in\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 352a52e59d..81ce9fe7f9 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n '\n \n test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n+\ttest_when_finished \"git rebase --abort\" &&\n \told=$(git rev-parse HEAD) &&\n \ttest_tick &&\n \tset_fake_editor &&\n \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n \techo \"edited again\" > file7 &&\n \tgit add file7 &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n-\ttest $old = $(git rev-parse HEAD) &&\n-\tgit rebase --abort\n+\techo all the things >>conflict &&\n+\ttest_must_fail git rebase --continue &&\n+\ttest $old = $(git rev-parse HEAD)\n '\n \n test_expect_success 'auto-amend only edited commits after \"edit\"' '\ndiff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\nindex cb7c6de84a..da94dddc86 100755\n--- a/t/t3405-rebase-malformed.sh\n+++ b/t/t3405-rebase-malformed.sh\n@@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n '\n \n test_expect_success 'rebase -m commit with empty message' '\n-\ttest_must_fail git rebase -m master empty-message-merge &&\n-\tgit rebase --abort &&\n-\tgit rebase -m --allow-empty-message master empty-message-merge\n+\tgit rebase -m master empty-message-merge\n '\n \n test_expect_success 'rebase -i commit with empty message' '\n \tgit checkout diff-in-message &&\n \tset_fake_editor &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i HEAD^ &&\n-\tgit rebase --abort &&\n-\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i --allow-empty-message HEAD^\n+\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n+\t\tgit rebase -i HEAD^\n '\n \n test_done\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350641","messageId":"20180621150023.23533-4-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 3/7] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:19Z","receivedAt":"2018-06-21T15:00:49Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase is split into three types: am, merge, and interactive.  Various\noptions imply different types, and which mode we are using determine which\nsub-script (git-rebase--$type) is executed to finish the work.  Not all\noptions work with all types, so add tests for combinations where we expect\nto receive an error rather than having options be silently ignored.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3422-rebase-incompatible-options.sh | 89 ++++++++++++++++++++++++++\n 1 file changed, 89 insertions(+)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nnew file mode 100755\nindex 0000000000..157374143f\n--- /dev/null\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -0,0 +1,89 @@\n+#!/bin/sh\n+\n+test_description='test if rebase detects and aborts on incompatible options'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_seq 2 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m orig &&\n+\n+\tgit branch A &&\n+\tgit branch B &&\n+\n+\tgit checkout A &&\n+\ttest_seq 1 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m A &&\n+\n+\tgit checkout B &&\n+\t# This is indented with HT SP HT.\n+\techo \"\t \tfoo();\" >>foo &&\n+\tgit add foo &&\n+\tgit commit -m B\n+'\n+\n+#\n+# Rebase has lots of useful options like --whitepsace=fix, which are\n+# actually all built in terms of flags to git-am.  Since neither\n+# --merge nor --interactive (nor any options that imply those two) use\n+# git-am, using them together will result in flags like --whitespace=fix\n+# being ignored.  Make sure rebase warns the user and aborts instead.\n+#\n+\n+test_run_rebase () {\n+\topt=$1\n+\tshift\n+\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --merge A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --interactive A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --exec 'true' A\n+\t\"\n+\n+}\n+\n+test_run_rebase --whitespace=fix\n+test_run_rebase --ignore-whitespace\n+test_run_rebase --committer-date-is-author-date\n+test_run_rebase -C4\n+\n+test_expect_success '--preserve-merges incompatible with --signoff' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --signoff A\n+'\n+\n+test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -s resolve A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n+'\n+\n+test_done\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350642","messageId":"20180621150023.23533-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 2/7] git-rebase.sh: update help messages a bit","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:18Z","receivedAt":"2018-06-21T15:00:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"signoff is not specific to the am-backend.  Also, re-order a few options\nto make like things (e.g. strategy and strategy-option) be near each\nother.\n---\n git-rebase.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..bf71b7fa20 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -20,23 +20,23 @@ onto=!             rebase onto given branch instead of upstream\n r,rebase-merges?   try to rebase merges instead of skipping them\n p,preserve-merges! try to recreate merges instead of ignoring them\n s,strategy=!       use the given merge strategy\n+X,strategy-option=! pass the argument through to the merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n+f,force-rebase!    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 x,exec=!           add exec lines after each commit of the editable list\n k,keep-empty\t   preserve empty commits during rebase\n allow-empty-message allow rebasing commits with empty messages\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 n,no-stat!         do not show diffstat of what changed upstream\n verify             allow pre-rebase hook to run\n rerere-autoupdate  allow rerere to update index with resolved conflicts\n root!              rebase all reachable commits up to the root(s)\n autosquash         move commits that begin with squash!/fixup! under -i\n+signoff            add a Signed-off-by: line to each commit\n committer-date-is-author-date! passed to 'git am'\n ignore-date!       passed to 'git am'\n-signoff            passed to 'git am'\n whitespace=!       passed to 'git apply'\n ignore-whitespace! passed to 'git apply'\n C=!                passed to 'git apply'\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350643","messageId":"20180621150023.23533-6-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 5/7] git-rebase.txt: document behavioral inconsistencies between modes","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:21Z","receivedAt":"2018-06-21T15:00:54Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"There are a variety of aspects that are common to all rebases regardless\nof which backend is in use; however, the behavior for these different\naspects varies in ways that could surprise users.  (In fact, it's not\nclear -- to me at least -- that these differences were even desirable or\nintentional.)  Document these differences.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 57 ++++++++++++++++++++++++++++++++++++\n 1 file changed, 57 insertions(+)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 7de6523931..340137e2cf 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -556,6 +556,63 @@ Other incompatible flag pairs:\n  * --rebase-merges and --strategy\n  * --rebase-merges and --strategy-option\n \n+BEHAVIORAL INCONSISTENCIES\n+--------------------------\n+\n+  * --no-ff vs. --force-rebase\n+\n+    These options are actually identical, though their description\n+    leads people to believe they might not be.\n+\n+ * empty commits:\n+\n+    am-based rebase will drop any \"empty\" commits, whether the\n+    commit started empty (had no changes relative to its parent to\n+    start with) or ended empty (all changes were already applied\n+    upstream in other commits).\n+\n+    merge-based rebase does the same.\n+\n+    interactive-based rebase will by default drop commits that\n+    started empty and halt if it hits a commit that ended up empty.\n+    The --keep-empty option exists for interactive rebases to allow\n+    it to keep commits that started empty.\n+\n+  * empty commit messages:\n+\n+    am-based rebase will silently apply commits with empty commit\n+    messages.\n+\n+    merge-based and interactive-based rebases will by default halt\n+    on any such commits.  The --allow-empty-message option exists to\n+    allow interactive-based rebases to apply such commits without\n+    halting.\n+\n+  * directory rename detection:\n+\n+    merge-based and interactive-based rebases work fine with\n+    directory rename detection.  am-based rebases sometimes do not.\n+\n+    git-am tries to avoid a full three way merge, instead calling\n+    git-apply.  That prevents us from detecting renames at all,\n+    which may defeat the directory rename detection.  There is a\n+    fallback, though; if the initial git-apply fails and the user\n+    has specified the -3 option, git-am will fall back to a three\n+    way merge.  However, git-am lacks the necessary information to\n+    do a \"real\" three way merge.  Instead, it has to use\n+    build_fake_ancestor() to get a merge base that is missing files\n+    whose rename may have been important to detect for directory\n+    rename detection to function.\n+\n+    Since am-based rebases work by first generating a bunch of\n+    patches (which no longer record what the original commits were\n+    and thus don't have the necessary info from which we can find a\n+    real merge-base), and then calling git-am, this implies that\n+    am-based rebases will not always successfully detect directory\n+    renames either.  merged-based rebases (rebase -m) and\n+    cherry-pick-based rebases (rebase -i) are not affected by this\n+    shortcoming.\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350644","messageId":"20180621150023.23533-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 1/7] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:17Z","receivedAt":"2018-06-21T15:00:59Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has many options that only work with one of its three backends.\nIt also has a few other pairs of incompatible options.  Document these.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 85 ++++++++++++++++++++++++++++++++----\n 1 file changed, 77 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0e20a66e73..7de6523931 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n \tThis option overrides that behavior, allowing commits with empty\n \tmessages to be rebased.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --skip::\n \tRestart the rebasing process by skipping the current patch.\n@@ -271,6 +275,8 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -280,8 +286,10 @@ other words, the sides are swapped.\n +\n Because 'git rebase' replays each commit from the working branch\n on top of the <upstream> branch using the given strategy, using\n-the 'ours' strategy simply discards all patches from the <branch>,\n+the 'ours' strategy simply empties all patches from the <branch>,\n which makes little sense.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -X <strategy-option>::\n --strategy-option=<strategy-option>::\n@@ -289,6 +297,8 @@ which makes little sense.\n \tThis implies `--merge` and, if no strategy has been\n \tspecified, `-s recursive`.  Note the reversal of 'ours' and\n \t'theirs' as noted above for the `-m` option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -S[<keyid>]::\n --gpg-sign[=<keyid>]::\n@@ -324,6 +334,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -f::\n --force-rebase::\n@@ -355,19 +367,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n \tthat if `--interactive` is given then only commits marked to be\n-\tpicked, edited or reworded will have the trailer added. Incompatible\n-\twith the `--preserve-merges` option.\n+\tpicked, edited or reworded will have the trailer added.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -i::\n --interactive::\n@@ -378,6 +393,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n The commit list format can be changed by setting the configuration option\n rebase.instructionFormat.  A customized instruction format will automatically\n have the long commit hash prepended to the format.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -r::\n --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::\n@@ -404,7 +421,7 @@ It is currently only possible to recreate the merge commits using the\n `recursive` merge strategy; Different merge strategies can be used only via\n explicit `exec git merge -s <strategy> [...]` commands.\n +\n-See also REBASING MERGES below.\n+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.\n \n -p::\n --preserve-merges::\n@@ -415,6 +432,8 @@ See also REBASING MERGES below.\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n idea unless you know what you are doing (see BUGS below).\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -x <cmd>::\n --exec <cmd>::\n@@ -437,6 +456,8 @@ squash/fixup series.\n +\n This uses the `--interactive` machinery internally, but it can be run\n without an explicit `--interactive`.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --root::\n \tRebase all commits reachable from <branch>, instead of\n@@ -447,6 +468,8 @@ without an explicit `--interactive`.\n \tWhen used together with both --onto and --preserve-merges,\n \t'all' root commits will be rewritten to have <newbase> as parent\n \tinstead.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n@@ -461,11 +484,11 @@ without an explicit `--interactive`.\n \ttoo.  The recommended way to create fixup/squash commits is by using\n \tthe `--fixup`/`--squash` options of linkgit:git-commit[1].\n +\n-This option is only valid when the `--interactive` option is used.\n-+\n If the `--autosquash` option is enabled by default using the\n configuration variable `rebase.autoSquash`, this option can be\n used to override and disable this setting.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autostash::\n --no-autostash::\n@@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n successfully without needing to \"revert the reversion\" (see the\n link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n \n+INCOMPATIBLE OPTIONS\n+--------------------\n+\n+git-rebase has many flags that are incompatible with each other,\n+predominantly due to the fact that it has three different underlying\n+implementations:\n+\n+ * one based on linkgit:git-am[1] (the default)\n+ * one based on linkgit:git-merge-recursive[1] (merge backend)\n+ * one based on linkgit:git-cherry-pick[1] (interactive backend)\n+\n+Flags only understood by the am backend:\n+\n+ * --committer-date-is-author-date\n+ * --ignore-date\n+ * --whitespace\n+ * --ignore-whitespace\n+ * -C\n+\n+Flags understood by both merge and interactive backends:\n+\n+ * --merge\n+ * --strategy\n+ * --strategy-option\n+ * --allow-empty-message\n+\n+Flags only understood by the interactive backend:\n+\n+ * --[no-]autosquash\n+ * --rebase-merges\n+ * --preserve-merges\n+ * --interactive\n+ * --exec\n+ * --keep-empty\n+ * --autosquash\n+ * --edit-todo\n+ * --root when used in combination with --onto\n+\n+Other incompatible flag pairs:\n+\n+ * --preserve-merges and --interactive\n+ * --preserve-merges and --signoff\n+ * --preserve-merges and --rebase-merges\n+ * --rebase-merges and --strategy\n+ * --rebase-merges and --strategy-option\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350645","messageId":"20180621150023.23533-5-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 4/7] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:20Z","receivedAt":"2018-06-21T15:01:01Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has three different types: am, merge, and interactive, all of\nwhich are implemented in terms of separate scripts.  am builds on git-am,\nmerge builds on git-merge-recursive, and interactive builds on\ngit-cherry-pick.  We make use of features in those lower-level commands in\nthe different rebase types, but those features don't exist in all of the\nlower level commands so we have a range of incompatibilities.  Previously,\nwe just accepted nearly any argument and silently ignored whichever ones\nweren't implemented for the type of rebase specified.  Change this so the\nincompatibilities are documented, included in the testsuite, and tested\nfor at runtime with an appropriate error message shown.\n\nSome exceptions I left out:\n\n  * --merge and --interactive are technically incompatible since they are\n    supposed to run different underlying scripts, but with a few small\n    changes, --interactive can do everything that --merge can.  In fact,\n    I'll shortly be sending another patch to remove git-rebase--merge and\n    reimplement it on top of git-rebase--interactive.\n\n  * One could argue that --interactive and --quiet are incompatible since\n    --interactive doesn't implement a --quiet mode (perhaps since\n    cherry-pick itself does not implement one).  However, the interactive\n    mode is more quiet than the other modes in general with progress\n    messages, so one could argue that it's already quiet.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh                          | 34 ++++++++++++++++++++++++++\n t/t3422-rebase-incompatible-options.sh | 16 ++++++------\n 2 files changed, 42 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex bf71b7fa20..590bdbb12a 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -503,6 +503,23 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n+if test -n \"$git_am_opt\"; then\n+\tincompatible_opts=$(echo \"$git_am_opt\" | sed -e 's/ -q//')\n+\tif test -n \"$interactive_rebase\"\n+\tthen\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$do_merge\"; then\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n if test -n \"$signoff\"\n then\n \ttest -n \"$preserve_merges\" &&\n@@ -511,6 +528,23 @@ then\n \tforce_rebase=t\n fi\n \n+if test -n \"$preserve_merges\"\n+then\n+\t# Note: incompatibility with --signoff handled in signoff block above\n+\t# Note: incompatibility with --interactive is just a strong warning;\n+\t#       git-rebase.txt caveats with \"unless you know what you are doing\"\n+\ttest -n \"$rebase_merges\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--preserve_merges' with '--rebase-merges'\")\"\n+fi\n+\n+if test -n \"$rebase_merges\"\n+then\n+\ttest -n \"$strategy_opts\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy-option'\")\"\n+\ttest -n \"$strategy\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy'\")\"\n+fi\n+\n if test -z \"$rebase_root\"\n then\n \tcase \"$#\" in\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 157374143f..415d5226bf 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -34,27 +34,27 @@ test_expect_success 'setup' '\n test_run_rebase () {\n \topt=$1\n \tshift\n-\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\ttest_expect_success \"$opt incompatible with --merge\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --merge A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\ttest_expect_success \"$opt incompatible with --interactive\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --interactive A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\ttest_expect_success \"$opt incompatible with --exec\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --exec 'true' A\n \t\"\n@@ -71,17 +71,17 @@ test_expect_success '--preserve-merges incompatible with --signoff' '\n \ttest_must_fail git rebase --preserve-merges --signoff A\n '\n \n-test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+test_expect_success '--preserve-merges incompatible with --rebase-merges' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --preserve-merges --rebase-merges A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy' '\n+test_expect_success '--rebase-merges incompatible with --strategy' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -s resolve A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+test_expect_success '--rebase-merges incompatible with --strategy-option' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n '\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350646","messageId":"20180621150023.23533-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180617055856.22838-1-newren@gmail.com","subject":"[PATCH v3 0/7] Document/fix/warn about rebase incompatibilities and inconsistencies","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:16Z","receivedAt":"2018-06-21T15:01:05Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase has lots of options that are mutually incompatible.  Even among\naspects of its behavior that is common to all rebase types, it has a number\nof inconsistencies.  This series tries to document, fix, and/or warn users\nabout many of these.\n\nI have left patch 7 in RFC state.  We probably need more opinions\nabout it, and whether cherry-pick should also be changed to match.\n\nChanges since v2 (full branch-diff below):\n  - Slight changes to documentation wording\n  - Add incompatibilitiy of --rebase-merges and --strategy-option\n  - Add tests and code for incompatibilities involving either\n    --preserve-merges or --rebase-merges\n  - Slightly more detail in the commit message for making -m and -i behave\n    the same with empty commit messages as am-based rebases.\n\nMany thanks to Phillip for reviewing the last series, and Eric who pointed\nout the wording improvements.\n\nElijah Newren (7):\n  git-rebase.txt: document incompatible options\n  git-rebase.sh: update help messages a bit\n  t3422: new testcases for checking when incompatible options passed\n  git-rebase: error out when incompatible options passed\n  git-rebase.txt: document behavioral inconsistencies between modes\n  git-rebase.txt: address confusion between --no-ff vs --force-rebase\n  git-rebase: make --allow-empty-message the default\n\n Documentation/git-rebase.txt           | 155 ++++++++++++++++++++-----\n git-rebase.sh                          |  42 ++++++-\n t/t3404-rebase-interactive.sh          |   7 +-\n t/t3405-rebase-malformed.sh            |  11 +-\n t/t3422-rebase-incompatible-options.sh |  89 ++++++++++++++\n 5 files changed, 262 insertions(+), 42 deletions(-)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\n 1: d184d5bd3f !  1: 4cdf9130cc git-rebase.txt: document incompatible options\n    @@ -191,14 +191,15 @@\n     + * --keep-empty\n     + * --autosquash\n     + * --edit-todo\n    -+ * --root + --onto\n    ++ * --root when used in combination with --onto\n     +\n     +Other incompatible flag pairs:\n     +\n    -+ * --preserve-merges && --interactive\n    -+ * --preserve-merges && --signoff\n    -+ * --preserve-merges && --rebase-merges\n    -+ * --rebase-merges && --strategy\n    ++ * --preserve-merges and --interactive\n    ++ * --preserve-merges and --signoff\n    ++ * --preserve-merges and --rebase-merges\n    ++ * --rebase-merges and --strategy\n    ++ * --rebase-merges and --strategy-option\n     +\n      include::merge-strategies.txt[]\n      \n 2: 788df9fa43 =  2: e336f76c5e git-rebase.sh: update help messages a bit\n 3: d3d124795a !  3: 4ab38d8a5f t3422: new testcases for checking when incompatible options passed\n    @@ -83,4 +83,24 @@\n     +test_run_rebase --committer-date-is-author-date\n     +test_run_rebase -C4\n     +\n    ++test_expect_success '--preserve-merges incompatible with --signoff' '\n    ++\tgit checkout B^0 &&\n    ++\ttest_must_fail git rebase --preserve-merges --signoff A\n    ++'\n    ++\n    ++test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n    ++\tgit checkout B^0 &&\n    ++\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n    ++'\n    ++\n    ++test_expect_failure '--rebase-merges incompatible with --strategy' '\n    ++\tgit checkout B^0 &&\n    ++\ttest_must_fail git rebase --rebase-merges -s resolve A\n    ++'\n    ++\n    ++test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n    ++\tgit checkout B^0 &&\n    ++\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n    ++'\n    ++\n     +test_done\n 4: 28d2dfd49a !  4: 5223954caf git-rebase: error out when incompatible options passed\n    @@ -56,6 +56,30 @@\n      if test -n \"$signoff\"\n      then\n      \ttest -n \"$preserve_merges\" &&\n    +@@\n    + \tforce_rebase=t\n    + fi\n    + \n    ++if test -n \"$preserve_merges\"\n    ++then\n    ++\t# Note: incompatibility with --signoff handled in signoff block above\n    ++\t# Note: incompatibility with --interactive is just a strong warning;\n    ++\t#       git-rebase.txt caveats with \"unless you know what you are doing\"\n    ++\ttest -n \"$rebase_merges\" &&\n    ++\t\tdie \"$(gettext \"error: cannot combine '--preserve_merges' with '--rebase-merges'\")\"\n    ++fi\n    ++\n    ++if test -n \"$rebase_merges\"\n    ++then\n    ++\ttest -n \"$strategy_opts\" &&\n    ++\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy-option'\")\"\n    ++\ttest -n \"$strategy\" &&\n    ++\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy'\")\"\n    ++fi\n    ++\n    + if test -z \"$rebase_root\"\n    + then\n    + \tcase \"$#\" in\n     \n     diff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\n     --- a/t/t3422-rebase-incompatible-options.sh\n    @@ -93,3 +117,24 @@\n      \t\tgit checkout B^0 &&\n      \t\ttest_must_fail git rebase $opt --exec 'true' A\n      \t\"\n    +@@\n    + \ttest_must_fail git rebase --preserve-merges --signoff A\n    + '\n    + \n    +-test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n    ++test_expect_success '--preserve-merges incompatible with --rebase-merges' '\n    + \tgit checkout B^0 &&\n    + \ttest_must_fail git rebase --preserve-merges --rebase-merges A\n    + '\n    + \n    +-test_expect_failure '--rebase-merges incompatible with --strategy' '\n    ++test_expect_success '--rebase-merges incompatible with --strategy' '\n    + \tgit checkout B^0 &&\n    + \ttest_must_fail git rebase --rebase-merges -s resolve A\n    + '\n    + \n    +-test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n    ++test_expect_success '--rebase-merges incompatible with --strategy-option' '\n    + \tgit checkout B^0 &&\n    + \ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n    + '\n 5: b2eec2cc5a !  5: 96f7ba98bc git-rebase.txt: document behavioral inconsistencies between modes\n    @@ -14,8 +14,8 @@\n     --- a/Documentation/git-rebase.txt\n     +++ b/Documentation/git-rebase.txt\n     @@\n    -  * --preserve-merges && --rebase-merges\n    -  * --rebase-merges && --strategy\n    +  * --rebase-merges and --strategy\n    +  * --rebase-merges and --strategy-option\n      \n     +BEHAVIORAL INCONSISTENCIES\n     +--------------------------\n 6: cea18d7e60 =  6: 7bb7b380ac git-rebase.txt: address confusion between --no-ff vs --force-rebase\n 7: ab8805c40a !  7: 3ed07548a6 git-rebase: make --allow-empty-message the default\n    @@ -2,9 +2,13 @@\n     \n         git-rebase: make --allow-empty-message the default\n     \n    -    am-based rebases already apply commits with an empty commit message\n    -    without requiring the user to specify an extra flag.  Make merge-based and\n    -    interactive-based rebases behave the same.\n    +    All rebase backends should behave the same with empty commit messages, but\n    +    currently do not.  am-based rebases already apply commits with an empty\n    +    commit message without stopping or requiring the user to specify an extra\n    +    flag.  Since am-based rebases are the default rebase type, and since it\n    +    appears no one has ever requested a --no-allow-empty-message flag to\n    +    change this behavior, make --allow-empty-message the default so that\n    +    merge-based and interactive-based rebases will behave the same.\n     \n         Signed-off-by: Elijah Newren <newren@gmail.com>\n     \n-- \n2.18.0.rc2.92.g133ed01dde\n"},{"id":"350647","messageId":"20180621150023.23533-7-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v3 6/7] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:00:22Z","receivedAt":"2018-06-21T15:01:09Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\nrebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\nworked for the am and merge backends, but wasn't a valid option for the\ninteractive backend.\n\nrebase was taught the --no-ff option for interactive rebases in commit\nb499549401cb (\"Teach rebase the --no-ff option.\", 2010-03-24), to do the\nexact same thing as --force-rebase does for non-interactive rebases.  This\ncommit explicitly documented the fact that --force-rebase was incompatible\nwith --interactive, though it made --no-ff a synonym for --force-rebase\nfor non-interactive rebases.  The choice of a new option was based on the\nfact that \"force rebase\" didn't sound like an appropriate term for the\ninteractive machinery.\n\nIn commit 6bb4e485cff8 (\"rebase: align variable names\", 2011-02-06), the\nseparate parsing of command line options in the different rebase scripts\nwas removed, and whether on accident or because the author noticed that\nthese options did the same thing, the options became synonyms and both\nwere accepted by all three rebase types.\n\nIn commit 2d26d533a012 (\"Documentation/git-rebase.txt: -f forces a rebase\nthat would otherwise be a no-op\", 2014-08-12), which reworded the\ndescription of the --force-rebase option, the (no-longer correct) sentence\nstating that --force-rebase was incompatible with --interactive was\nfinally removed.\n\nFinally, as explained at\nhttps://public-inbox.org/git/98279912-0f52-969d-44a6-22242039387f@xiplink.com\n\n    In the original discussion around this option [1], at one point I\n    proposed teaching rebase--interactive to respect --force-rebase\n    instead of adding a new option [2].  Ultimately --no-ff was chosen as\n    the better user interface design [3], because an interactive rebase\n    can't be \"forced\" to run.\n\nWe have accepted both --no-ff and --force-rebase as full synonyms for all\nthree rebase types for over seven years.  Documenting them differently\nand in ways that suggest they might not be quite synonyms simply leads to\nconfusion.  Adjust the documentation to match reality.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 35 ++++++++++-------------------------\n 1 file changed, 10 insertions(+), 25 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 340137e2cf..1f422cd0a7 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -337,16 +337,18 @@ See also INCOMPATIBLE OPTIONS below.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n--f::\n+--no-ff::\n --force-rebase::\n-\tForce a rebase even if the current branch is up to date and\n-\tthe command without `--force` would return without doing anything.\n+-f::\n+\tIndividually replay all rebased commits instead of fast-forwarding\n+\tover the unchanged ones.  This ensures that the entire history of\n+\tthe rebased branch is composed of new commits.\n +\n-You may find this (or --no-ff with an interactive rebase) helpful after\n-reverting a topic branch merge, as this option recreates the topic branch with\n-fresh commits so it can be remerged successfully without needing to \"revert\n-the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n+You may find this helpful after reverting a topic branch merge, as this option\n+recreates the topic branch with fresh commits so it can be remerged\n+successfully without needing to \"revert the reversion\" (see the\n+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for\n+details).\n \n --fork-point::\n --no-fork-point::\n@@ -498,18 +500,6 @@ See also INCOMPATIBLE OPTIONS below.\n \twith care: the final stash application after a successful\n \trebase might result in non-trivial conflicts.\n \n---no-ff::\n-\tWith --interactive, cherry-pick all rebased commits instead of\n-\tfast-forwarding over the unchanged ones.  This ensures that the\n-\tentire history of the rebased branch is composed of new commits.\n-+\n-Without --interactive, this is a synonym for --force-rebase.\n-+\n-You may find this helpful after reverting a topic branch merge, as this option\n-recreates the topic branch with fresh commits so it can be remerged\n-successfully without needing to \"revert the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n-\n INCOMPATIBLE OPTIONS\n --------------------\n \n@@ -559,11 +549,6 @@ Other incompatible flag pairs:\n BEHAVIORAL INCONSISTENCIES\n --------------------------\n \n-  * --no-ff vs. --force-rebase\n-\n-    These options are actually identical, though their description\n-    leads people to believe they might not be.\n-\n  * empty commits:\n \n     am-based rebase will drop any \"empty\" commits, whether the\n-- \n2.18.0.rc2.92.g133ed01dde\n\n"},{"id":"350650","messageId":"CABPp-BGh7yW69QwxQb13K0HM38NKmQif3A6C6UULEKYnkEJ5vA@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1806211242440.11870@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T15:36:35Z","receivedAt":"2018-06-21T15:36:40Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nThanks for all the food for thought.  This is awesome.\n\nOn Thu, Jun 21, 2018 at 3:57 AM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> On Wed, 20 Jun 2018, Elijah Newren wrote:\n>> On Sun, Jun 17, 2018 at 2:44 PM, Johannes Schindelin\n>> <Johannes.Schindelin@gmx.de> wrote:\n>>\n>> > I was really referring to speed. But I have to admit that I do not have\n>> > any current numbers.\n>> >\n>> > Another issue just hit me, though: rebase --am does not need to look at as\n>> > many Git objects as rebase --merge or rebase -i. Therefore, GVFS users\n>> > will still want to use --am wherever possible, to avoid \"hydrating\"\n>> > many objects during their rebase.\n>>\n>> What is it that makes rebase --am need fewer Git objects than rebase\n>> --merge or rebase -i?\n>\n> Multiple things. The most obvious thing: --cherry-pick. When you call `git\n> rebase --am`, it does not try to exclude the patches by looking at\n> `rev-list --cherry-pick --right-only <upstream>..<head>`\n>\n> This really bit us in GVFS Git because we have several thousand developers\n> working on the same code base, and you probably read the numbers elsewhere\n> how many commits are introduced while a developer goes on so much as a\n> week-long vacation.\n\nOoh, that's interesting.  Here's a crazy idea: I'm curious if this is\nessentially a workaround that we could expunge.  In particular,\nam-based rebases will drop empty commits (that is, either commits that\nare empty to start, or that after being applied are empty).  It never\ngrew a --no-allow-empty option either.  If rebase -i/-m were to behave\nthe same, for consistency sake, we could drop the `rev-list\n--cherry-pick ...` call.  Granted, that would result in a slight\ndifference in behavior (it could result in conflicts in some cases\ninstead of an automatically empty commit), but may well be worth it\nfor consistencies' sake between rebase backends.  As a side effect of\nmaking the backends consistent, it may also provide a nice performance\nboost for the GVFS case by removing the need to do the --cherry-pick\nthing.\n\n> Next, rename detection.\n>\n> I think that bit us even harder because it tries to look at all the files\n> that have been changed in upstream in the meantime, which can be *a lot*.\n> And if you know that moving files outside of your cozy little sparse\n> checkout is unlikely (or moving from the outside into your checkout), then\n> all this hydration is pretty wasteful. That's why we had to switch off\n> rename detection in GVFS Git.\n\nActually to be clear, for each side of the merge, rename detection\nonly needs to look at files that were not present in both the\nmerge-base and the branch.  Files which were modified but have the\nsame name are not involved (break detection is not active.).  But yes,\nI understand how you can still get an awful lot of files, which makes\nit worse when you then go and compare all of them in an O(N*M)\nfashion.\n\n>> My guess at what objects are needed by each type:\n>>\n>> At a high level, rebase --am for each commit will need to compare the\n>> commit to its parent to generate a diff (which thus involves walking\n>> over the objects in both the commit and its parent, though it should\n>> be able to skip over subtrees that are equal), and then will need to\n>> look at all the objects in the target commit on which it needs to\n>> apply the patch (in order to properly fill the index for a starting\n>> point, and used later when creating a new commit).\n>\n> No, in --am mode, it does not even need to look at all the objects in the\n> target commits. Only those objects that correspond to the files that are\n> touched by the diff.\n\nSorry, I mis-spoke.  Unless you've done something special with GVFS, I\nbelieve the --am mode would indeed need to read all the _tree_ objects\nin the target commits, but any _file_ object corresponding to a path\nnot modified by the other side need not be loaded since we can proceed\nsimply knowing its sha1sum.\n\n> In a massive code base, such as Windows', this makes a huge difference.\n> Even comparing the number of files touched by the patches that are to be\n> rebased to the number of files that were touched in upstream since you\n> rebased last is ridiculous. And a three-way merge needs to consider that\n> latter set of files.\n\nActually, the three-way merge isn't all that different.  For a path\nthat exists in both branches and the merge base, it first compares\nsha1sums (thus it does need to read all the tree objects), and then if\none side has not modified a certain path, it knows the merge result is\nthe sha1sum from the other side.  Thus, it won't need to read files\nthat were changed upstream so long as that path wasn't changed on your\nside.\n\nIn fact, --merge and --interactive have a slight performance advantage\nhere: if upstream didn't modify the path, then it doesn't need to read\nthe file from your side to do any diff or comparison.  It can just use\nwhatever sha1sum you have.  In contrast --am mode will need to read\nthe relevant file more than once.  Since it first creates a series of\npatches, it will have to read the file from your commit and its\nparent, create a diff, and then later apply that diff to the target\nversion, and since the target version matches the merge base it will\nend up just recovering the version of the file on your side that you\nstarted with anyway.  (Since that file is already local, though, this\nsmall performance advantage would currently be lost in the noise of\nthe other problems.)\n\n>> If the application of the diff fails, it falls back to a three-way\n>> merge, though the three-way merge shouldn't need any additional objects.\n>\n> The three-way merge needs to reconcile the diff between branch point and\n> your changes to the diff between branch point and upstream's changes. The\n> latter can be a lot bigger than the former, in which case --am's\n> complexity (O(former)) is much nicer than --merge's (O(former u latter)).\n\nYeah, renames mess up that whole \"a path that exists in both branches\nand the merge base\" requirement that I stipulated above, and widens\nthe scope considerably and affects performance rather markedly.  On\nthe positive side though, the more I read your description, the more I\nthink my rename performance work may give a speedup for the GVFS\nusecase far in excess of the factor of 30 I saw for my usecase.  It\nmay still not quite match --am mode's outright avoidance of rename\ndetection, but I still think it should be pretty impressive.  Time\nwill tell...\n\n\nElijah\n"},{"id":"350664","messageId":"xmqq4lhvudjt.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-2-newren@gmail.com","subject":"Re: [PATCH v3 1/7] git-rebase.txt: document incompatible options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T19:47:50Z","receivedAt":"2018-06-21T19:47:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> @@ -280,8 +286,10 @@ other words, the sides are swapped.\n>  +\n>  Because 'git rebase' replays each commit from the working branch\n>  on top of the <upstream> branch using the given strategy, using\n> -the 'ours' strategy simply discards all patches from the <branch>,\n> +the 'ours' strategy simply empties all patches from the <branch>,\n\nI think overall the direction this series takes, and especially what\nthis step does---clarify what the current code & design does first\nbefore attempting to improve the status quo, makes sense, but I had\ntrouble justifying this change.  Do you want to emphasize that the\noperation discards the changes but still leaves empty commits, and\n\"discards all patches\" imply there won't be any commits left on top\nof the \"onto\" point?\n\n>  which makes little sense.\n> ++\n> +See also INCOMPATIBLE OPTIONS below.\n\n> @@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n>  successfully without needing to \"revert the reversion\" (see the\n>  link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n>  \n> +INCOMPATIBLE OPTIONS\n> +--------------------\n> +\n> +git-rebase has many flags that are incompatible with each other,\n> +predominantly due to the fact that it has three different underlying\n> +implementations:\n> +\n> + * one based on linkgit:git-am[1] (the default)\n> + * one based on linkgit:git-merge-recursive[1] (merge backend)\n> + * one based on linkgit:git-cherry-pick[1] (interactive backend)\n> +\n> +Flags only understood by the am backend:\n> +\n> + * --committer-date-is-author-date\n> + * --ignore-date\n> + * --whitespace\n> + * --ignore-whitespace\n> + * -C\n> +\n> +Flags understood by both merge and interactive backends:\n> +\n> + * --merge\n> + * --strategy\n> + * --strategy-option\n> + * --allow-empty-message\n> +\n> +Flags only understood by the interactive backend:\n> +\n> + * --[no-]autosquash\n> + * --rebase-merges\n> + * --preserve-merges\n> + * --interactive\n> + * --exec\n> + * --keep-empty\n> + * --autosquash\n> + * --edit-todo\n> + * --root when used in combination with --onto\n> +\n> +Other incompatible flag pairs:\n> +\n> + * --preserve-merges and --interactive\n> + * --preserve-merges and --signoff\n> + * --preserve-merges and --rebase-merges\n> + * --rebase-merges and --strategy\n> + * --rebase-merges and --strategy-option\n> +\n>  include::merge-strategies.txt[]\n\nIt is a bit unclear what these lists want to say.  If --ignore-date\nis only understood by \"rebase\" and not \"rebase -i\", wouldn't that\nmake \"--interactive and --ignore-date\" an incompatible flag pair?\nOr do you mean the \"Other incompatible\" list to enumerate the ones\nthat are explicitly rejected, as opposed to getting silently\nignored?\n\nIn any case, I'll need to read through the remainder of the series\nto come to any conclusion, but given that -p is getting killed by\nits primary author, with help from others to split out its\nimplementation from the --interactive codepath, it might be a bad\ntime to do this series.  Thanks for working on this topic.\n\n"},{"id":"350666","messageId":"xmqqzhznsyi2.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-3-newren@gmail.com","subject":"Re: [PATCH v3 2/7] git-rebase.sh: update help messages a bit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T19:58:13Z","receivedAt":"2018-06-21T19:58:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> signoff is not specific to the am-backend.  Also, re-order a few options\n> to make like things (e.g. strategy and strategy-option) be near each\n> other.\n> ---\n>  git-rebase.sh | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n\nMissing sign-off, but otherwise looks good.\n\n>\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 40be59ecc4..bf71b7fa20 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -20,23 +20,23 @@ onto=!             rebase onto given branch instead of upstream\n>  r,rebase-merges?   try to rebase merges instead of skipping them\n>  p,preserve-merges! try to recreate merges instead of ignoring them\n>  s,strategy=!       use the given merge strategy\n> +X,strategy-option=! pass the argument through to the merge strategy\n>  no-ff!             cherry-pick all commits, even if unchanged\n> +f,force-rebase!    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>  x,exec=!           add exec lines after each commit of the editable list\n>  k,keep-empty\t   preserve empty commits during rebase\n>  allow-empty-message allow rebasing commits with empty messages\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>  n,no-stat!         do not show diffstat of what changed upstream\n>  verify             allow pre-rebase hook to run\n>  rerere-autoupdate  allow rerere to update index with resolved conflicts\n>  root!              rebase all reachable commits up to the root(s)\n>  autosquash         move commits that begin with squash!/fixup! under -i\n> +signoff            add a Signed-off-by: line to each commit\n>  committer-date-is-author-date! passed to 'git am'\n>  ignore-date!       passed to 'git am'\n> -signoff            passed to 'git am'\n>  whitespace=!       passed to 'git apply'\n>  ignore-whitespace! passed to 'git apply'\n>  C=!                passed to 'git apply'\n"},{"id":"350668","messageId":"xmqqvaabsy6y.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-4-newren@gmail.com","subject":"Re: [PATCH v3 3/7] t3422: new testcases for checking when incompatible options passed","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T20:04:53Z","receivedAt":"2018-06-21T20:04:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> +\tgit checkout B &&\n> +\t# This is indented with HT SP HT.\n> +\techo \"\t \tfoo();\" >>foo &&\n\nI often wonder, whenever I see a need for a comment like this, if\nsaying the same thing in code to make it visible is cleaner and less\nerror prone way to do so, i.e. e.g.\n\n\techo \"_ _foo();\" | tr \"_\" \"\\011\" >>foo &&\n\n> +# Rebase has lots of useful options like --whitepsace=fix, which are\n> +# actually all built in terms of flags to git-am.  Since neither\n> +# --merge nor --interactive (nor any options that imply those two) use\n> +# git-am, using them together will result in flags like --whitespace=fix\n> +# being ignored.  Make sure rebase warns the user and aborts instead.\n> +#\n> +\n> +test_run_rebase () {\n> +\topt=$1\n> +\tshift\n> +\ttest_expect_failure \"$opt incompatible with --merge\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --merge A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --strategy=ours A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --strategy=ours A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --interactive A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --exec\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --exec 'true' A\n> +\t\"\n> +\n> +}\n> +\n> +test_run_rebase --whitespace=fix\n> +test_run_rebase --ignore-whitespace\n> +test_run_rebase --committer-date-is-author-date\n> +test_run_rebase -C4\n\nI happen to be from old school and \"rebase\" primarily means\n\"format-patch piped to am\" in my mind, so from that point of view,\n\"test_run_rebase --OPT\" that says \"--OPT which is a valid option for\nthe primary operating mode of rebase does not work with the other\nexotic modes of the command\" is not all that bad, but I do not think\nthat worldview holds for many people in general.  Perhaps calling it\nsomething like \"test_rebase_am_only\" makes the intent clearer?\n\n> +test_expect_success '--preserve-merges incompatible with --signoff' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --preserve-merges --signoff A\n> +'\n> +\n> +test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n> +'\n> +\n> +test_expect_failure '--rebase-merges incompatible with --strategy' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --rebase-merges -s resolve A\n> +'\n> +\n> +test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n> +'\n> +\n> +test_done\n"},{"id":"350669","messageId":"xmqqr2kzsx1l.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-5-newren@gmail.com","subject":"Re: [PATCH v3 4/7] git-rebase: error out when incompatible options passed","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T20:29:42Z","receivedAt":"2018-06-21T20:29:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> +if test -n \"$git_am_opt\"; then\n> +\tincompatible_opts=$(echo \"$git_am_opt\" | sed -e 's/ -q//')\n\nThis is probably just a taste-thing, but I'd probably prefer to see\nthe \"sed\" filter out \"-q\" alone, and make an effort to leave future\nthings like \"-qx\" alone, e.g.\n\n    $(echo \" $git_am_opt \" | sed -e 's/ -q / /g' -e 's/^ \\(.*\\) $/\\1/')\n\nor something like that.\n\n> +\tif test -n \"$interactive_rebase\"\n> +\tthen\n> +\t\tif test -n \"$incompatible_opts\"\n> +\t\tthen\n> +\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n> +\t\tfi\n> +\tfi\n> +\tif test -n \"$do_merge\"; then\n> +\t\tif test -n \"$incompatible_opts\"\n> +\t\tthen\n> +\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n> +\t\tfi\n> +\tfi\n> +fi\n\nNot making --merge and --interactive incompatible as the proposed\nlog message said makes this hunk at manageable complexity, I guess\n;-)\n"},{"id":"350670","messageId":"CABPp-BGjCVAdUd0EDz3CNH=ymZYv1a29sER2zHHrVoOgJ38bBw@mail.gmail.com","threadId":"48665","inReplyTo":"xmqq4lhvudjt.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 1/7] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T20:33:41Z","receivedAt":"2018-06-21T20:33:47Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 21, 2018 at 12:47 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> @@ -280,8 +286,10 @@ other words, the sides are swapped.\n>>  +\n>>  Because 'git rebase' replays each commit from the working branch\n>>  on top of the <upstream> branch using the given strategy, using\n>> -the 'ours' strategy simply discards all patches from the <branch>,\n>> +the 'ours' strategy simply empties all patches from the <branch>,\n>\n> I think overall the direction this series takes, and especially what\n> this step does---clarify what the current code & design does first\n> before attempting to improve the status quo, makes sense, but I had\n> trouble justifying this change.  Do you want to emphasize that the\n> operation discards the changes but still leaves empty commits, and\n> \"discards all patches\" imply there won't be any commits left on top\n> of the \"onto\" point?\n\nYes, is there an alternative wording that you'd find more clear?\n\n(Also, I'd like to push to make rebase -i/-m behave the same as\nam-based rebase with empty commits, meaning they are just discarded by\ndefault rather than halted at.  But I haven't gotten to that point...)\n\n>> @@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n>>  successfully without needing to \"revert the reversion\" (see the\n>>  link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n>>\n>> +INCOMPATIBLE OPTIONS\n>> +--------------------\n>> +\n>> +git-rebase has many flags that are incompatible with each other,\n>> +predominantly due to the fact that it has three different underlying\n>> +implementations:\n>> +\n>> + * one based on linkgit:git-am[1] (the default)\n>> + * one based on linkgit:git-merge-recursive[1] (merge backend)\n>> + * one based on linkgit:git-cherry-pick[1] (interactive backend)\n>> +\n>> +Flags only understood by the am backend:\n>> +\n>> + * --committer-date-is-author-date\n>> + * --ignore-date\n>> + * --whitespace\n>> + * --ignore-whitespace\n>> + * -C\n>> +\n>> +Flags understood by both merge and interactive backends:\n>> +\n>> + * --merge\n>> + * --strategy\n>> + * --strategy-option\n>> + * --allow-empty-message\n>> +\n>> +Flags only understood by the interactive backend:\n>> +\n>> + * --[no-]autosquash\n>> + * --rebase-merges\n>> + * --preserve-merges\n>> + * --interactive\n>> + * --exec\n>> + * --keep-empty\n>> + * --autosquash\n>> + * --edit-todo\n>> + * --root when used in combination with --onto\n>> +\n>> +Other incompatible flag pairs:\n>> +\n>> + * --preserve-merges and --interactive\n>> + * --preserve-merges and --signoff\n>> + * --preserve-merges and --rebase-merges\n>> + * --rebase-merges and --strategy\n>> + * --rebase-merges and --strategy-option\n>> +\n>>  include::merge-strategies.txt[]\n>\n> It is a bit unclear what these lists want to say.  If --ignore-date\n> is only understood by \"rebase\" and not \"rebase -i\", wouldn't that\n> make \"--interactive and --ignore-date\" an incompatible flag pair?\n> Or do you mean the \"Other incompatible\" list to enumerate the ones\n> that are explicitly rejected, as opposed to getting silently\n> ignored?\n\nYes, --interactive and --ignore-date are an incompatible flag pair but\nI didn't want to list all 65 of those pairs explicitly.  Anything that\nonly works by being passed to git-am is incompatible with anything\nthat implies the --merge or --interactive backends.\n\nThe list becomes simpler once we nuke git-rebase--merge.sh,\nimplementing it atop git-rebase--interactive.sh (which comes in a\nseparate series that depends on this one).\n\n> In any case, I'll need to read through the remainder of the series\n> to come to any conclusion, but given that -p is getting killed by\n> its primary author, with help from others to split out its\n> implementation from the --interactive codepath, it might be a bad\n> time to do this series.  Thanks for working on this topic.\n\nThis series doesn't conflict with ag/rebase-p at all; it merges\ncleanly with next and pu.  The follow-on work to nuke\ngit-rebase--merge.sh, however, does conflict so I'm waiting on\n(re-)sending it.\n"},{"id":"350671","messageId":"CABPp-BEgdK1e_rtk4u=9Anc2OBVtehTnC6Ow=HWhA9Q5sT6SBw@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqzhznsyi2.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 2/7] git-rebase.sh: update help messages a bit","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T20:34:15Z","receivedAt":"2018-06-21T20:34:19Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 21, 2018 at 12:58 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> signoff is not specific to the am-backend.  Also, re-order a few options\n>> to make like things (e.g. strategy and strategy-option) be near each\n>> other.\n>> ---\n>>  git-rebase.sh | 6 +++---\n>>  1 file changed, 3 insertions(+), 3 deletions(-)\n>\n> Missing sign-off, but otherwise looks good.\n\nOops.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n"},{"id":"350672","messageId":"CABPp-BFtuv0REjFQZ9g9sOWKMumg1KDQk8nG+TD4JGdwF-VedQ@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqvaabsy6y.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 3/7] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T20:37:58Z","receivedAt":"2018-06-21T20:38:03Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 21, 2018 at 1:04 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> +     git checkout B &&\n>> +     # This is indented with HT SP HT.\n>> +     echo \"          foo();\" >>foo &&\n>\n> I often wonder, whenever I see a need for a comment like this, if\n> saying the same thing in code to make it visible is cleaner and less\n> error prone way to do so, i.e. e.g.\n>\n>         echo \"_ _foo();\" | tr \"_\" \"\\011\" >>foo &&\n\nI can make that change.  Should I make the same change to\nt4015-diff-whitespace.sh, where I copied that comment and line of code\nfrom?  (In a different topic submission, of course.)\n\n>> +# Rebase has lots of useful options like --whitepsace=fix, which are\n>> +# actually all built in terms of flags to git-am.  Since neither\n>> +# --merge nor --interactive (nor any options that imply those two) use\n>> +# git-am, using them together will result in flags like --whitespace=fix\n>> +# being ignored.  Make sure rebase warns the user and aborts instead.\n>> +#\n>> +\n>> +test_run_rebase () {\n>> +     opt=$1\n>> +     shift\n>> +     test_expect_failure \"$opt incompatible with --merge\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --merge A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --strategy=ours\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --strategy=ours A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --strategy=ours A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --interactive\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --interactive A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --exec\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --exec 'true' A\n>> +     \"\n>> +\n>> +}\n>> +\n>> +test_run_rebase --whitespace=fix\n>> +test_run_rebase --ignore-whitespace\n>> +test_run_rebase --committer-date-is-author-date\n>> +test_run_rebase -C4\n>\n> I happen to be from old school and \"rebase\" primarily means\n> \"format-patch piped to am\" in my mind, so from that point of view,\n> \"test_run_rebase --OPT\" that says \"--OPT which is a valid option for\n> the primary operating mode of rebase does not work with the other\n> exotic modes of the command\" is not all that bad, but I do not think\n> that worldview holds for many people in general.  Perhaps calling it\n> something like \"test_rebase_am_only\" makes the intent clearer?\n\nWell, if that's what rebase means in your mind, then I'm sure you'll\nhave fun commenting on my follow-on series.  :-)\n\nAnyway, sure, I'm happy to change the function name.\n"},{"id":"350673","messageId":"CABPp-BEbVhG_=DzfhNd+rA1mOyN0QLKNYOXRVx7Arj_LjjwLXg@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqr2kzsx1l.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 4/7] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T20:41:30Z","receivedAt":"2018-06-21T20:41:34Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 21, 2018 at 1:29 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> +if test -n \"$git_am_opt\"; then\n>> +     incompatible_opts=$(echo \"$git_am_opt\" | sed -e 's/ -q//')\n>\n> This is probably just a taste-thing, but I'd probably prefer to see\n> the \"sed\" filter out \"-q\" alone, and make an effort to leave future\n> things like \"-qx\" alone, e.g.\n>\n>     $(echo \" $git_am_opt \" | sed -e 's/ -q / /g' -e 's/^ \\(.*\\) $/\\1/')\n>\n> or something like that.\n\nMakes sense.\n\n>> +     if test -n \"$interactive_rebase\"\n>> +     then\n>> +             if test -n \"$incompatible_opts\"\n>> +             then\n>> +                     die \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n>> +             fi\n>> +     fi\n>> +     if test -n \"$do_merge\"; then\n>> +             if test -n \"$incompatible_opts\"\n>> +             then\n>> +                     die \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n>> +             fi\n>> +     fi\n>> +fi\n>\n> Not making --merge and --interactive incompatible as the proposed\n> log message said makes this hunk at manageable complexity, I guess\n> ;-)\n\nRight, and since --interactive essentially handles --merge just fine\nand I'm planning to soon simplify anyway[1], at least once ag/rebase-p\nmerges to master, I didn't want to make it any more complex.\n\n[1] https://public-inbox.org/git/20180607171344.23331-3-newren@gmail.com/\n"},{"id":"350674","messageId":"xmqqfu1fswdh.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-6-newren@gmail.com","subject":"Re: [PATCH v3 5/7] git-rebase.txt: document behavioral inconsistencies between modes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T20:44:10Z","receivedAt":"2018-06-21T20:44:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> +BEHAVIORAL INCONSISTENCIES\n> +--------------------------\n> +\n> +  * --no-ff vs. --force-rebase\n\nDo we want to `--quote` these?\n\n> +    These options are actually identical, though their description\n> +    leads people to believe they might not be.\n\nPerhaps the same bandwidth can be spent on improving their\ndescription, instead of adding this paragraph?\n\n> + * empty commits:\n> +\n> +    am-based rebase will drop any \"empty\" commits, whether the\n> +    commit started empty (had no changes relative to its parent to\n> +    start with) or ended empty (all changes were already applied\n> +    upstream in other commits).\n> +\n> +    merge-based rebase does the same.\n> +\n> +    interactive-based rebase will by default drop commits that\n> +    started empty and halt if it hits a commit that ended up empty.\n\nI think the description is accurate.\n\nWRT a change that ends up being empty (as opposed to a change that\nis empty from the beginning), I'd think that the current behaviour\nis desireable one.  \"am\" based rebase is solely to transplant an\nexisting history and want to stop much less than \"interactive\" one\nwhose purpose is to polish a series before making it publishable,\nand asking for confirmation (\"this has become empty--do you want to\ndrop it?\") is more appropriate from the workflow point of view; so\nit may deserve s/inconsistencies/differences/.\n\n> +    The --keep-empty option exists for interactive rebases to allow\n> +    it to keep commits that started empty.\n\nOn the other hand, lack of --keep-empty on the \"am\" side is probably\na bug that wants to be fixed.\n\n> +  * empty commit messages:\n> +\n> +    am-based rebase will silently apply commits with empty commit\n> +    messages.\n> +\n> +    merge-based and interactive-based rebases will by default halt\n> +    on any such commits.  The --allow-empty-message option exists to\n> +    allow interactive-based rebases to apply such commits without\n> +    halting.\n\nDitto for desirable difference coming from workflow point of view.\n\n> +  * directory rename detection:\n> +\n> +    merge-based and interactive-based rebases work fine with\n> +    directory rename detection.  am-based rebases sometimes do not.\n\nI quite do not get what the big deal is with \"directory rename\"; it\nis merely a degree of magic heuristics employed while detecting file\nrenames.  It is natural to expect that the less information you make\navailable to the machinery, the less amount of heuristics gets\nexercised to make \"magic\" happen.  Is the internal implementation\ndetail described below (omitted) all that interesting to general\nreaders of \"git rebase --help\", I wonder?  I would understand it if\nthis were under Documentation/technical/, though.\n"},{"id":"350675","messageId":"xmqqbmc3swaa.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180621150023.23533-7-newren@gmail.com","subject":"Re: [PATCH v3 6/7] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-21T20:46:05Z","receivedAt":"2018-06-21T20:46:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\n> rebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\n> worked for the am and merge backends, but wasn't a valid option for the\n> interactive backend.\n> ...\n>  INCOMPATIBLE OPTIONS\n>  --------------------\n>  \n> @@ -559,11 +549,6 @@ Other incompatible flag pairs:\n>  BEHAVIORAL INCONSISTENCIES\n>  --------------------------\n>  \n> -  * --no-ff vs. --force-rebase\n> -\n> -    These options are actually identical, though their description\n> -    leads people to believe they might not be.\n\nAh, I should have held off my review of 5/7 before reading this one.\nPerhaps we want to do this before the step 5/7 to reduce the churn?\n\n\n\n"},{"id":"350680","messageId":"CAPig+cSVJk_mf8UeOoXysMZfP5c-MFBqa3H-w+Wns6_oZ8u5Ug@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqvaabsy6y.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 3/7] t3422: new testcases for checking when incompatible options passed","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-06-21T21:18:13Z","receivedAt":"2018-06-21T21:18:28Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jun 21, 2018 at 4:05 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n> > +     # This is indented with HT SP HT.\n> > +     echo \"          foo();\" >>foo &&\n>\n> I often wonder, whenever I see a need for a comment like this, if\n> saying the same thing in code to make it visible is cleaner and less\n> error prone way to do so, i.e. e.g.\n>\n>         echo \"_ _foo();\" | tr \"_\" \"\\011\" >>foo &&\n\nOr use q_to_tab() from test-lib-functions.h:\n\n    echo \"q qfoo();\" | q_to_tab\n"},{"id":"350681","messageId":"CABPp-BH0c-wgjjj7Rzy-KRzKDMc8PLK5GqrGrnCUjzpux4VGLg@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqbmc3swaa.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 6/7] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T21:22:29Z","receivedAt":"2018-06-21T21:22:34Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Thu, Jun 21, 2018 at 1:46 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\n>> rebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\n>> worked for the am and merge backends, but wasn't a valid option for the\n>> interactive backend.\n>> ...\n>>  INCOMPATIBLE OPTIONS\n>>  --------------------\n>>\n>> @@ -559,11 +549,6 @@ Other incompatible flag pairs:\n>>  BEHAVIORAL INCONSISTENCIES\n>>  --------------------------\n>>\n>> -  * --no-ff vs. --force-rebase\n>> -\n>> -    These options are actually identical, though their description\n>> -    leads people to believe they might not be.\n>\n> Ah, I should have held off my review of 5/7 before reading this one.\n> Perhaps we want to do this before the step 5/7 to reduce the churn?\n\nSure, I can switch the order around.\n"},{"id":"350682","messageId":"CABPp-BH5GYed+BBMadY869qGVpP7DDcD3HQtJSed_RPDVFJ-vA@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqfu1fswdh.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 5/7] git-rebase.txt: document behavioral inconsistencies between modes","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-21T21:25:58Z","receivedAt":"2018-06-21T21:26:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Junio,\n\nOn Thu, Jun 21, 2018 at 1:44 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> +BEHAVIORAL INCONSISTENCIES\n>> +--------------------------\n>> +\n>> +  * --no-ff vs. --force-rebase\n>\n> Do we want to `--quote` these?\n\nAh, good point.\n\n>> + * empty commits:\n>> +\n>> +    am-based rebase will drop any \"empty\" commits, whether the\n>> +    commit started empty (had no changes relative to its parent to\n>> +    start with) or ended empty (all changes were already applied\n>> +    upstream in other commits).\n>> +\n>> +    merge-based rebase does the same.\n>> +\n>> +    interactive-based rebase will by default drop commits that\n>> +    started empty and halt if it hits a commit that ended up empty.\n>\n> I think the description is accurate.\n>\n> WRT a change that ends up being empty (as opposed to a change that\n> is empty from the beginning), I'd think that the current behaviour\n> is desireable one.  \"am\" based rebase is solely to transplant an\n> existing history and want to stop much less than \"interactive\" one\n> whose purpose is to polish a series before making it publishable,\n> and asking for confirmation (\"this has become empty--do you want to\n> drop it?\") is more appropriate from the workflow point of view; so\n> it may deserve s/inconsistencies/differences/.\n\nAre you arguing the default for an explicit interactive rebase, or\nalso an implied one?\n\nI would argue that implied interactive rebases also solely have the\npurpose of \"transplanting an existing history\", as you say.  Thus, if\nthe user passes --rebase-merges (or --strategy or --strategy-options\nafter git-rebase--merge becomes part of git-rebase--interactive), then\nthe default should be the same as for am-based rebase, i.e. just\nsilently drop the empty commits.\n\n>> +    The --keep-empty option exists for interactive rebases to allow\n>> +    it to keep commits that started empty.\n>\n> On the other hand, lack of --keep-empty on the \"am\" side is probably\n> a bug that wants to be fixed.\n\nI personally don't like --keep-empty; it's too granular.  I'd prefer a\n  --empty={drop,halt,keep}\nflag, and have it apply to both patches that were empty when the\nrebase started as well as patches that became empty after application\non the new base.  I think that'd be useful for both am-based and\ninteractive-based rebases.\n\nThen we could also make an explicit --interactive flag imply\n--empty=halt, if so desired, and otherwise make --empty=drop the\ndefault.\n\nI'm interested in implementing that, if other folks think it's not crazy.\n\nThoughts?\n\n>> +  * empty commit messages:\n>> +\n>> +    am-based rebase will silently apply commits with empty commit\n>> +    messages.\n>> +\n>> +    merge-based and interactive-based rebases will by default halt\n>> +    on any such commits.  The --allow-empty-message option exists to\n>> +    allow interactive-based rebases to apply such commits without\n>> +    halting.\n>\n> Ditto for desirable difference coming from workflow point of view.\n\nI can see the argument for having a difference for rebases if the\ninteractive rebase was explicit, though I disagree with the argument.\nSee https://public-inbox.org/git/CABPp-BHrcUHX_zHxpojV5=sxJ1=NoDg9uhxv+NH5BsHsQYavPQ@mail.gmail.com/\nfor my views on this.\n\nHowever, I'm curious again -- is your argument only for\ninteractive_rebase=explicit or also for interactive_rebase=implied?\n\n>> +  * directory rename detection:\n>> +\n>> +    merge-based and interactive-based rebases work fine with\n>> +    directory rename detection.  am-based rebases sometimes do not.\n>\n> I quite do not get what the big deal is with \"directory rename\"; it\n> is merely a degree of magic heuristics employed while detecting file\n> renames.  It is natural to expect that the less information you make\n> available to the machinery, the less amount of heuristics gets\n> exercised to make \"magic\" happen.  Is the internal implementation\n> detail described below (omitted) all that interesting to general\n> readers of \"git rebase --help\", I wonder?  I would understand it if\n> this were under Documentation/technical/, though.\n\nYou are right that the last two paragraphs are probably much too\ntechnical and belong elsewhere; I can move them.  However, I am not\nsure if you were requesting just those paragraphs be moved, or if you\nwanted the whole \"directory rename detection\" section removed from the\nmanpage.  Could you clarify?  Also, if the latter...How would users\nknow how much \"information is made available to the underlying\nmachinery\", as you put it?  Or, at a higher level, what is the right\nway to communicate to them how they can obtain a behavior they might\nwant (directory rename detection), if it's not mentioned somewhere in\nthe manpage?  Is there an alternate place to put this in the document?\n\n\nThanks,\nElijah\n"},{"id":"350715","messageId":"20180622083254.7311-1-szeder.dev@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-2-newren@gmail.com","subject":"Re: [PATCH v3 1/7] git-rebase.txt: document incompatible options","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-06-22T08:32:54Z","receivedAt":"2018-06-22T08:33:13Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"\n> @@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n>  successfully without needing to \"revert the reversion\" (see the\n>  link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n>  \n> +INCOMPATIBLE OPTIONS\n> +--------------------\n> +\n> +git-rebase has many flags that are incompatible with each other,\n> +predominantly due to the fact that it has three different underlying\n> +implementations:\n> +\n> + * one based on linkgit:git-am[1] (the default)\n> + * one based on linkgit:git-merge-recursive[1] (merge backend)\n\nReferencing a non-existing man page via the 'linkgit' macro causes\n'make check-docs' to complain:\n\n      LINT lint-docs\n  ./git-rebase.txt:511: no such source: git-merge-recursive[1]\n\n"},{"id":"350836","messageId":"20180625161300.26060-4-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 3/9] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:54Z","receivedAt":"2018-06-25T16:13:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase is split into three types: am, merge, and interactive.  Various\noptions imply different types, and which mode we are using determine which\nsub-script (git-rebase--$type) is executed to finish the work.  Not all\noptions work with all types, so add tests for combinations where we expect\nto receive an error rather than having options be silently ignored.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3422-rebase-incompatible-options.sh | 88 ++++++++++++++++++++++++++\n 1 file changed, 88 insertions(+)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nnew file mode 100755\nindex 0000000000..2687a85254\n--- /dev/null\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -0,0 +1,88 @@\n+#!/bin/sh\n+\n+test_description='test if rebase detects and aborts on incompatible options'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_seq 2 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m orig &&\n+\n+\tgit branch A &&\n+\tgit branch B &&\n+\n+\tgit checkout A &&\n+\ttest_seq 1 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m A &&\n+\n+\tgit checkout B &&\n+\techo \"q qfoo();\" | q_to_tab >>foo &&\n+\tgit add foo &&\n+\tgit commit -m B\n+'\n+\n+#\n+# Rebase has lots of useful options like --whitepsace=fix, which are\n+# actually all built in terms of flags to git-am.  Since neither\n+# --merge nor --interactive (nor any options that imply those two) use\n+# git-am, using them together will result in flags like --whitespace=fix\n+# being ignored.  Make sure rebase warns the user and aborts instead.\n+#\n+\n+test_rebase_am_only () {\n+\topt=$1\n+\tshift\n+\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --merge A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --interactive A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --exec 'true' A\n+\t\"\n+\n+}\n+\n+test_rebase_am_only --whitespace=fix\n+test_rebase_am_only --ignore-whitespace\n+test_rebase_am_only --committer-date-is-author-date\n+test_rebase_am_only -C4\n+\n+test_expect_success '--preserve-merges incompatible with --signoff' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --signoff A\n+'\n+\n+test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -s resolve A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n+'\n+\n+test_done\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350837","messageId":"20180625161300.26060-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 2/9] git-rebase.sh: update help messages a bit","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:53Z","receivedAt":"2018-06-25T16:13:29Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"signoff is not specific to the am-backend.  Also, re-order a few options\nto make like things (e.g. strategy and strategy-option) be near each\nother.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..bf71b7fa20 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -20,23 +20,23 @@ onto=!             rebase onto given branch instead of upstream\n r,rebase-merges?   try to rebase merges instead of skipping them\n p,preserve-merges! try to recreate merges instead of ignoring them\n s,strategy=!       use the given merge strategy\n+X,strategy-option=! pass the argument through to the merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n+f,force-rebase!    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 x,exec=!           add exec lines after each commit of the editable list\n k,keep-empty\t   preserve empty commits during rebase\n allow-empty-message allow rebasing commits with empty messages\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 n,no-stat!         do not show diffstat of what changed upstream\n verify             allow pre-rebase hook to run\n rerere-autoupdate  allow rerere to update index with resolved conflicts\n root!              rebase all reachable commits up to the root(s)\n autosquash         move commits that begin with squash!/fixup! under -i\n+signoff            add a Signed-off-by: line to each commit\n committer-date-is-author-date! passed to 'git am'\n ignore-date!       passed to 'git am'\n-signoff            passed to 'git am'\n whitespace=!       passed to 'git apply'\n ignore-whitespace! passed to 'git apply'\n C=!                passed to 'git apply'\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350838","messageId":"20180625161300.26060-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180621150023.23533-1-newren@gmail.com","subject":"[PATCH v4 0/9] Document/fix/warn about rebase incompatibilities and inconsistencies","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:51Z","receivedAt":"2018-06-25T16:13:33Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase has lots of options that are mutually incompatible.  Even among\naspects of its behavior that is common to all rebase types, it has a number\nof inconsistencies.  This series tries to document, fix, and/or warn users\nabout many of these.\n\nChanges since v3 (range-diff included at the end):\n  * Fix many small issues mentioned by Junio and SZEDER, including a fix\n    suggested by Eric.\n  * Add a new patch (#6) which introduces technical documentation on directory\n    rename detection, so that...\n  * The more technical portion of the docs from patch 7 (used to be patch 5\n    in v3) can be moved from git-rebase.txt to the new\n    technical/directory-rename-detection.txt, as suggested by Junio.\n  * Also adds a new patch (#8) which adds testcases to demonstrate what the\n    new technical doc discusses.\n\nItems of particular note for reviewers:\n  * I have left patch 9 (used to be patch 7) in RFC state, but\n    expanded the commit message with an in-depth usability rationale\n    for the change.\n  * It sounded like Junio was slightly unclear about the intent of the\n    wording in Patch 1.  Not sure if my answer (in email) was sufficient or\n    if there are changes I should make to the patch.\n  * On Patch 5 of v3 (which is now patch 7 of v4), Junio suggested a course\n    of action to take with --keep-empty.  I counter-proposed with a\n    --empty={drop,halt,keep} idea.  Is just deferring this issue to a later\n    series okay, or are there changes I should make to the current series to\n    handle this?  (If so, what changes should those be?)\n\nElijah Newren (9):\n  git-rebase.txt: document incompatible options\n  git-rebase.sh: update help messages a bit\n  t3422: new testcases for checking when incompatible options passed\n  git-rebase: error out when incompatible options passed\n  git-rebase.txt: address confusion between --no-ff vs --force-rebase\n  directory-rename-detection.txt: technical docs on abilities and\n    limitations\n  git-rebase.txt: document behavioral differences between modes\n  t3401: add directory rename testcases for rebase and am\n  git-rebase: make --allow-empty-message the default\n\n Documentation/git-rebase.txt                  | 135 ++++++++++++++----\n .../technical/directory-rename-detection.txt  | 115 +++++++++++++++\n git-rebase.sh                                 |  43 +++++-\n t/t3401-rebase-and-am-rename.sh               | 105 ++++++++++++++\n t/t3404-rebase-interactive.sh                 |   7 +-\n t/t3405-rebase-malformed.sh                   |  11 +-\n t/t3422-rebase-incompatible-options.sh        |  88 ++++++++++++\n 7 files changed, 462 insertions(+), 42 deletions(-)\n create mode 100644 Documentation/technical/directory-rename-detection.txt\n create mode 100755 t/t3401-rebase-and-am-rename.sh\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\n 1: 4cdf9130cc !  1: 3f454ebc5e git-rebase.txt: document incompatible options\n    @@ -163,7 +163,7 @@\n     +implementations:\n     +\n     + * one based on linkgit:git-am[1] (the default)\n    -+ * one based on linkgit:git-merge-recursive[1] (merge backend)\n    ++ * one based on git-merge-recursive (merge backend)\n     + * one based on linkgit:git-cherry-pick[1] (interactive backend)\n     +\n     +Flags only understood by the am backend:\n 2: e336f76c5e !  2: 31a5a071a6 git-rebase.sh: update help messages a bit\n    @@ -6,6 +6,8 @@\n         to make like things (e.g. strategy and strategy-option) be near each\n         other.\n     \n    +    Signed-off-by: Elijah Newren <newren@gmail.com>\n    +\n     diff --git a/git-rebase.sh b/git-rebase.sh\n     --- a/git-rebase.sh\n     +++ b/git-rebase.sh\n 3: 4ab38d8a5f !  3: 5a2b5eec79 t3422: new testcases for checking when incompatible options passed\n    @@ -34,8 +34,7 @@\n     +\tgit commit -m A &&\n     +\n     +\tgit checkout B &&\n    -+\t# This is indented with HT SP HT.\n    -+\techo \"\t \tfoo();\" >>foo &&\n    ++\techo \"q qfoo();\" | q_to_tab >>foo &&\n     +\tgit add foo &&\n     +\tgit commit -m B\n     +'\n    @@ -48,7 +47,7 @@\n     +# being ignored.  Make sure rebase warns the user and aborts instead.\n     +#\n     +\n    -+test_run_rebase () {\n    ++test_rebase_am_only () {\n     +\topt=$1\n     +\tshift\n     +\ttest_expect_failure \"$opt incompatible with --merge\" \"\n    @@ -78,10 +77,10 @@\n     +\n     +}\n     +\n    -+test_run_rebase --whitespace=fix\n    -+test_run_rebase --ignore-whitespace\n    -+test_run_rebase --committer-date-is-author-date\n    -+test_run_rebase -C4\n    ++test_rebase_am_only --whitespace=fix\n    ++test_rebase_am_only --ignore-whitespace\n    ++test_rebase_am_only --committer-date-is-author-date\n    ++test_rebase_am_only -C4\n     +\n     +test_expect_success '--preserve-merges incompatible with --signoff' '\n     +\tgit checkout B^0 &&\n 4: 5223954caf !  4: 1e1c83724a git-rebase: error out when incompatible options passed\n    @@ -37,7 +37,8 @@\n      fi\n      \n     +if test -n \"$git_am_opt\"; then\n    -+\tincompatible_opts=$(echo \"$git_am_opt\" | sed -e 's/ -q//')\n    ++\tincompatible_opts=$(echo \" $git_am_opt \" | \\\n    ++\t\t\t    sed -e 's/ -q / /g' -e 's/^ \\(.*\\) $/\\1/')\n     +\tif test -n \"$interactive_rebase\"\n     +\tthen\n     +\t\tif test -n \"$incompatible_opts\"\n    @@ -85,7 +86,7 @@\n     --- a/t/t3422-rebase-incompatible-options.sh\n     +++ b/t/t3422-rebase-incompatible-options.sh\n     @@\n    - test_run_rebase () {\n    + test_rebase_am_only () {\n      \topt=$1\n      \tshift\n     -\ttest_expect_failure \"$opt incompatible with --merge\" \"\n 5: 96f7ba98bc < --: ---------- git-rebase.txt: document behavioral inconsistencies between modes\n 6: 7bb7b380ac !  5: 51023269d3 git-rebase.txt: address confusion between --no-ff vs --force-rebase\n    @@ -93,15 +93,3 @@\n      INCOMPATIBLE OPTIONS\n      --------------------\n      \n    -@@\n    - BEHAVIORAL INCONSISTENCIES\n    - --------------------------\n    - \n    --  * --no-ff vs. --force-rebase\n    --\n    --    These options are actually identical, though their description\n    --    leads people to believe they might not be.\n    --\n    -  * empty commits:\n    - \n    -     am-based rebase will drop any \"empty\" commits, whether the\n--: ---------- >  6: f017d45dd9 directory-rename-detection.txt: technical docs on abilities and limitations\n--: ---------- >  7: 0a359df404 git-rebase.txt: document behavioral differences between modes\n--: ---------- >  8: beaadceaef t3401: add directory rename testcases for rebase and am\n 7: 3ed07548a6 !  9: 431b2c36d5 git-rebase: make --allow-empty-message the default\n    @@ -2,13 +2,85 @@\n     \n         git-rebase: make --allow-empty-message the default\n     \n    -    All rebase backends should behave the same with empty commit messages, but\n    -    currently do not.  am-based rebases already apply commits with an empty\n    -    commit message without stopping or requiring the user to specify an extra\n    -    flag.  Since am-based rebases are the default rebase type, and since it\n    -    appears no one has ever requested a --no-allow-empty-message flag to\n    -    change this behavior, make --allow-empty-message the default so that\n    -    merge-based and interactive-based rebases will behave the same.\n    +    rebase backends currently behave differently with empty commit messages,\n    +    largely as a side-effect of the different underlying commands on which\n    +    they are based.  am-based rebases apply commits with an empty commit\n    +    message without stopping or requiring the user to specify an extra flag.\n    +    (It is interesting to note that am-based rebases are the default rebase\n    +    type, and no one has ever requested a --no-allow-empty-message flag to\n    +    change this behavior.)  merge-based and interactive-based rebases (which\n    +    are ultimately based on git-commit), will currently halt on any such\n    +    commits and require the user to manually specify what to do with the\n    +    commit and continue.\n    +\n    +    One possible rationale for the difference in behavior is that the purpose\n    +    of an \"am\" based rebase is solely to transplant an existing history, while\n    +    an \"interactive\" rebase is one whose purpose is to polish a series before\n    +    making it publishable.  Thus, stopping and asking for confirmation for a\n    +    possible problem is more appropriate in the latter case.  However, there\n    +    are two problems with this rationale:\n    +\n    +      1) merge-based rebases are also non-interactive and there are multiple\n    +         types of rebases that use the interactive machinery but are not\n    +         explicitly interactive (e.g. when either --rebase-merges or\n    +         --keep-empty are specified without --interactive).  These rebases are\n    +         also used solely to transplant an existing history, and thus also\n    +         should default to --allow-empty-message.\n    +\n    +      2) this rationale only says that the user is more accepting of stopping\n    +         in the case of an explicitly interactive rebase, not that stopping\n    +         for this particular reason actually makes sense.  Exploring whether\n    +         it makes sense, requires backing up and analyzing the underlying\n    +         commands...\n    +\n    +    If git-commit did not error out on empty commits by default, accidental\n    +    creation of commits with empty messages would be a very common occurrence\n    +    (this check has caught me many times).  Further, nearly all such empty\n    +    commit messages would be considered an accidental error (as evidenced by a\n    +    huge amount of documentation across version control systems and in various\n    +    blog posts explaining how important commit messages are).  A simple check\n    +    for what would otherwise be a common error thus made a lot of sense, and\n    +    git-commit gained an --allow-empty-message flag for special case\n    +    overrides.  This has made commits with empty messages very rare.\n    +\n    +    There are two sources for commits with empty messages for rebase (and\n    +    cherry-pick): (a) commits created in git where the user previously\n    +    specified --allow-empty-message to git-commit, and (b) commits imported\n    +    into git from other version control systems.  In case (a), the user has\n    +    already explicitly specified that there is something special about this\n    +    commit that makes them not want to specify a commit message; forcing them\n    +    to re-specify with every cherry-pick or rebase seems more likely to be\n    +    infuriating than helpful.  In case (b), the commit is highly unlikely to\n    +    have been authored by the person who has imported the history and is doing\n    +    the rebase or cherry-pick, and thus the user is unlikely to be the\n    +    appropriate person to write a commit message for it.  Stopping and\n    +    expecting the user to modify the commit before proceeding thus seems\n    +    counter-productive.\n    +\n    +    Further, note that while empty commit messages was a common error case for\n    +    git-commit to deal with, it is a rare case for rebase (or cherry-pick).\n    +    The fact that it is rare raises the question of why it would be worth\n    +    checking and stopping on this particular condition and not others.  For\n    +    example, why doesn't an interactive rebase automatically stop if the\n    +    commit message's first line is 2000 columns long, or is missing a blank\n    +    line after the first line, or has every line indented with five spaces, or\n    +    any number of other myriad problems?\n    +\n    +    Finally, note that if a user doing an interactive rebase does have the\n    +    necessary knowledge to add a message for any such commit and wants to do\n    +    so, it is rather simple for them to change the appropriate line from\n    +    'pick' to 'reword'.  The fact that the subject is empty in the todo list\n    +    that the user edits should even serve as a way to notify them.\n    +\n    +    As far as I can tell, the fact that merge-based and interactive-based\n    +    rebases stop on commits with empty commit messages is solely a by-product\n    +    of having been based on git-commit.  It went without notice for a long\n    +    time precisely because such cases are rare.  The rareness of this\n    +    situation made it difficult to reason about, so when folks did eventually\n    +    notice this behavior, they assumed it was there for a good reason and just\n    +    added an --allow-empty-message flag.  In my opinion, stopping on such\n    +    messages not desirable in any of these cases, even the (explicitly)\n    +    interactive case.\n     \n         Signed-off-by: Elijah Newren <newren@gmail.com>\n     \n    @@ -16,7 +88,7 @@\n     --- a/Documentation/git-rebase.txt\n     +++ b/Documentation/git-rebase.txt\n     @@\n    -     The --keep-empty option exists for interactive rebases to allow\n    +     The `--keep-empty` option exists for interactive rebases to allow\n          it to keep commits that started empty.\n      \n     -  * empty commit messages:\n    @@ -25,7 +97,7 @@\n     -    messages.\n     -\n     -    merge-based and interactive-based rebases will by default halt\n    --    on any such commits.  The --allow-empty-message option exists to\n    +-    on any such commits.  The `--allow-empty-message` option exists to\n     -    allow interactive-based rebases to apply such commits without\n     -    halting.\n     -\n\n-- \n2.18.0.9.g678597d97e\n"},{"id":"350839","messageId":"20180625161300.26060-6-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 5/9] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:56Z","receivedAt":"2018-06-25T16:14:45Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\nrebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\nworked for the am and merge backends, but wasn't a valid option for the\ninteractive backend.\n\nrebase was taught the --no-ff option for interactive rebases in commit\nb499549401cb (\"Teach rebase the --no-ff option.\", 2010-03-24), to do the\nexact same thing as --force-rebase does for non-interactive rebases.  This\ncommit explicitly documented the fact that --force-rebase was incompatible\nwith --interactive, though it made --no-ff a synonym for --force-rebase\nfor non-interactive rebases.  The choice of a new option was based on the\nfact that \"force rebase\" didn't sound like an appropriate term for the\ninteractive machinery.\n\nIn commit 6bb4e485cff8 (\"rebase: align variable names\", 2011-02-06), the\nseparate parsing of command line options in the different rebase scripts\nwas removed, and whether on accident or because the author noticed that\nthese options did the same thing, the options became synonyms and both\nwere accepted by all three rebase types.\n\nIn commit 2d26d533a012 (\"Documentation/git-rebase.txt: -f forces a rebase\nthat would otherwise be a no-op\", 2014-08-12), which reworded the\ndescription of the --force-rebase option, the (no-longer correct) sentence\nstating that --force-rebase was incompatible with --interactive was\nfinally removed.\n\nFinally, as explained at\nhttps://public-inbox.org/git/98279912-0f52-969d-44a6-22242039387f@xiplink.com\n\n    In the original discussion around this option [1], at one point I\n    proposed teaching rebase--interactive to respect --force-rebase\n    instead of adding a new option [2].  Ultimately --no-ff was chosen as\n    the better user interface design [3], because an interactive rebase\n    can't be \"forced\" to run.\n\nWe have accepted both --no-ff and --force-rebase as full synonyms for all\nthree rebase types for over seven years.  Documenting them differently\nand in ways that suggest they might not be quite synonyms simply leads to\nconfusion.  Adjust the documentation to match reality.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 30 ++++++++++--------------------\n 1 file changed, 10 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex b2d95e3fb9..2f47495a4d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -337,16 +337,18 @@ See also INCOMPATIBLE OPTIONS below.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n--f::\n+--no-ff::\n --force-rebase::\n-\tForce a rebase even if the current branch is up to date and\n-\tthe command without `--force` would return without doing anything.\n+-f::\n+\tIndividually replay all rebased commits instead of fast-forwarding\n+\tover the unchanged ones.  This ensures that the entire history of\n+\tthe rebased branch is composed of new commits.\n +\n-You may find this (or --no-ff with an interactive rebase) helpful after\n-reverting a topic branch merge, as this option recreates the topic branch with\n-fresh commits so it can be remerged successfully without needing to \"revert\n-the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n+You may find this helpful after reverting a topic branch merge, as this option\n+recreates the topic branch with fresh commits so it can be remerged\n+successfully without needing to \"revert the reversion\" (see the\n+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for\n+details).\n \n --fork-point::\n --no-fork-point::\n@@ -498,18 +500,6 @@ See also INCOMPATIBLE OPTIONS below.\n \twith care: the final stash application after a successful\n \trebase might result in non-trivial conflicts.\n \n---no-ff::\n-\tWith --interactive, cherry-pick all rebased commits instead of\n-\tfast-forwarding over the unchanged ones.  This ensures that the\n-\tentire history of the rebased branch is composed of new commits.\n-+\n-Without --interactive, this is a synonym for --force-rebase.\n-+\n-You may find this helpful after reverting a topic branch merge, as this option\n-recreates the topic branch with fresh commits so it can be remerged\n-successfully without needing to \"revert the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n-\n INCOMPATIBLE OPTIONS\n --------------------\n \n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350840","messageId":"20180625161300.26060-10-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[RFC PATCH v4 9/9] git-rebase: make --allow-empty-message the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:13:00Z","receivedAt":"2018-06-25T16:14:47Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase backends currently behave differently with empty commit messages,\nlargely as a side-effect of the different underlying commands on which\nthey are based.  am-based rebases apply commits with an empty commit\nmessage without stopping or requiring the user to specify an extra flag.\n(It is interesting to note that am-based rebases are the default rebase\ntype, and no one has ever requested a --no-allow-empty-message flag to\nchange this behavior.)  merge-based and interactive-based rebases (which\nare ultimately based on git-commit), will currently halt on any such\ncommits and require the user to manually specify what to do with the\ncommit and continue.\n\nOne possible rationale for the difference in behavior is that the purpose\nof an \"am\" based rebase is solely to transplant an existing history, while\nan \"interactive\" rebase is one whose purpose is to polish a series before\nmaking it publishable.  Thus, stopping and asking for confirmation for a\npossible problem is more appropriate in the latter case.  However, there\nare two problems with this rationale:\n\n  1) merge-based rebases are also non-interactive and there are multiple\n     types of rebases that use the interactive machinery but are not\n     explicitly interactive (e.g. when either --rebase-merges or\n     --keep-empty are specified without --interactive).  These rebases are\n     also used solely to transplant an existing history, and thus also\n     should default to --allow-empty-message.\n\n  2) this rationale only says that the user is more accepting of stopping\n     in the case of an explicitly interactive rebase, not that stopping\n     for this particular reason actually makes sense.  Exploring whether\n     it makes sense, requires backing up and analyzing the underlying\n     commands...\n\nIf git-commit did not error out on empty commits by default, accidental\ncreation of commits with empty messages would be a very common occurrence\n(this check has caught me many times).  Further, nearly all such empty\ncommit messages would be considered an accidental error (as evidenced by a\nhuge amount of documentation across version control systems and in various\nblog posts explaining how important commit messages are).  A simple check\nfor what would otherwise be a common error thus made a lot of sense, and\ngit-commit gained an --allow-empty-message flag for special case\noverrides.  This has made commits with empty messages very rare.\n\nThere are two sources for commits with empty messages for rebase (and\ncherry-pick): (a) commits created in git where the user previously\nspecified --allow-empty-message to git-commit, and (b) commits imported\ninto git from other version control systems.  In case (a), the user has\nalready explicitly specified that there is something special about this\ncommit that makes them not want to specify a commit message; forcing them\nto re-specify with every cherry-pick or rebase seems more likely to be\ninfuriating than helpful.  In case (b), the commit is highly unlikely to\nhave been authored by the person who has imported the history and is doing\nthe rebase or cherry-pick, and thus the user is unlikely to be the\nappropriate person to write a commit message for it.  Stopping and\nexpecting the user to modify the commit before proceeding thus seems\ncounter-productive.\n\nFurther, note that while empty commit messages was a common error case for\ngit-commit to deal with, it is a rare case for rebase (or cherry-pick).\nThe fact that it is rare raises the question of why it would be worth\nchecking and stopping on this particular condition and not others.  For\nexample, why doesn't an interactive rebase automatically stop if the\ncommit message's first line is 2000 columns long, or is missing a blank\nline after the first line, or has every line indented with five spaces, or\nany number of other myriad problems?\n\nFinally, note that if a user doing an interactive rebase does have the\nnecessary knowledge to add a message for any such commit and wants to do\nso, it is rather simple for them to change the appropriate line from\n'pick' to 'reword'.  The fact that the subject is empty in the todo list\nthat the user edits should even serve as a way to notify them.\n\nAs far as I can tell, the fact that merge-based and interactive-based\nrebases stop on commits with empty commit messages is solely a by-product\nof having been based on git-commit.  It went without notice for a long\ntime precisely because such cases are rare.  The rareness of this\nsituation made it difficult to reason about, so when folks did eventually\nnotice this behavior, they assumed it was there for a good reason and just\nadded an --allow-empty-message flag.  In my opinion, stopping on such\nmessages not desirable in any of these cases, even the (explicitly)\ninteractive case.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n\nMy commit messsage seems like one of those things that someone else will\ninstantly see how to shrink to less than a quarter of its size while still\nretaining all essential reasoning.  I can't seem to find the simple way to\nstate it, though.\n\n Documentation/git-rebase.txt  | 10 ----------\n git-rebase.sh                 |  2 +-\n t/t3404-rebase-interactive.sh |  7 ++++---\n t/t3405-rebase-malformed.sh   | 11 +++--------\n 4 files changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a67df4caba..9e136ee16e 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -563,16 +563,6 @@ BEHAVIORAL DIFFERENCES\n     The `--keep-empty` option exists for interactive rebases to allow\n     it to keep commits that started empty.\n \n-  * empty commit messages:\n-\n-    am-based rebase will silently apply commits with empty commit\n-    messages.\n-\n-    merge-based and interactive-based rebases will by default halt\n-    on any such commits.  The `--allow-empty-message` option exists to\n-    allow interactive-based rebases to apply such commits without\n-    halting.\n-\n   * directory rename detection:\n \n     merge-based and interactive-based rebases work fine with\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 18ac8226c4..031dbd2ec8 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -95,7 +95,7 @@ rebase_cousins=\n preserve_merges=\n autosquash=\n keep_empty=\n-allow_empty_message=\n+allow_empty_message=--allow-empty-message\n signoff=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n case \"$(git config --bool commit.gpgsign)\" in\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 352a52e59d..81ce9fe7f9 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n '\n \n test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n+\ttest_when_finished \"git rebase --abort\" &&\n \told=$(git rev-parse HEAD) &&\n \ttest_tick &&\n \tset_fake_editor &&\n \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n \techo \"edited again\" > file7 &&\n \tgit add file7 &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n-\ttest $old = $(git rev-parse HEAD) &&\n-\tgit rebase --abort\n+\techo all the things >>conflict &&\n+\ttest_must_fail git rebase --continue &&\n+\ttest $old = $(git rev-parse HEAD)\n '\n \n test_expect_success 'auto-amend only edited commits after \"edit\"' '\ndiff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\nindex cb7c6de84a..da94dddc86 100755\n--- a/t/t3405-rebase-malformed.sh\n+++ b/t/t3405-rebase-malformed.sh\n@@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n '\n \n test_expect_success 'rebase -m commit with empty message' '\n-\ttest_must_fail git rebase -m master empty-message-merge &&\n-\tgit rebase --abort &&\n-\tgit rebase -m --allow-empty-message master empty-message-merge\n+\tgit rebase -m master empty-message-merge\n '\n \n test_expect_success 'rebase -i commit with empty message' '\n \tgit checkout diff-in-message &&\n \tset_fake_editor &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i HEAD^ &&\n-\tgit rebase --abort &&\n-\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i --allow-empty-message HEAD^\n+\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n+\t\tgit rebase -i HEAD^\n '\n \n test_done\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350841","messageId":"20180625161300.26060-9-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 8/9] t3401: add directory rename testcases for rebase and am","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:59Z","receivedAt":"2018-06-25T16:14:49Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Add a simple directory rename testcase, in conjunction with each of the\ntypes of rebases:\n  git-rebase--interactive\n  git-rebase--am\n  git-rebase--merge\nand also use the same testcase for\n  git am --3way\n\nThis demonstrates a difference in behavior between the different rebase\nbackends in regards to directory rename detection.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3401-rebase-and-am-rename.sh | 105 ++++++++++++++++++++++++++++++++\n 1 file changed, 105 insertions(+)\n create mode 100755 t/t3401-rebase-and-am-rename.sh\n\ndiff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh\nnew file mode 100755\nindex 0000000000..8f832957fc\n--- /dev/null\n+++ b/t/t3401-rebase-and-am-rename.sh\n@@ -0,0 +1,105 @@\n+#!/bin/sh\n+\n+test_description='git rebase + directory rename tests'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'setup testcase' '\n+\ttest_create_repo dir-rename &&\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tmkdir x &&\n+\t\ttest_seq  1 10 >x/a &&\n+\t\ttest_seq 11 20 >x/b &&\n+\t\ttest_seq 21 30 >x/c &&\n+\t\ttest_write_lines a b c d e f g h i >l &&\n+\t\tgit add x l &&\n+\t\tgit commit -m \"Initial\" &&\n+\n+\t\tgit branch O &&\n+\t\tgit branch A &&\n+\t\tgit branch B &&\n+\n+\t\tgit checkout A &&\n+\t\tgit mv x y &&\n+\t\tgit mv l letters &&\n+\t\tgit commit -m \"Rename x to y, l to letters\" &&\n+\n+\t\tgit checkout B &&\n+\t\techo j >>l &&\n+\t\ttest_seq 31 40 >x/d &&\n+\t\tgit add l x/d &&\n+\t\tgit commit -m \"Modify l, add x/d\"\n+\t)\n+'\n+\n+test_expect_success 'rebase --interactive: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tset_fake_editor &&\n+\t\tFAKE_LINES=\"1\" git rebase --interactive A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'rebase (am): directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_success 'rebase --merge: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase --merge A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'am: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout A^0 &&\n+\n+\t\tgit format-patch -1 B &&\n+\n+\t\tgit am --3way 0001*.patch &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_done\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350842","messageId":"20180625161300.26060-8-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 7/9] git-rebase.txt: document behavioral differences between modes","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:58Z","receivedAt":"2018-06-25T16:14:55Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"There are a variety of aspects that are common to all rebases regardless\nof which backend is in use; however, the behavior for these different\naspects varies in ways that could surprise users.  (In fact, it's not\nclear -- to me at least -- that these differences were even desirable or\nintentional.)  Document these differences.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt                  | 32 +++++++++++++++++++\n .../technical/directory-rename-detection.txt  | 23 +++++++++++++\n 2 files changed, 55 insertions(+)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 2f47495a4d..a67df4caba 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -546,6 +546,38 @@ Other incompatible flag pairs:\n  * --rebase-merges and --strategy\n  * --rebase-merges and --strategy-option\n \n+BEHAVIORAL DIFFERENCES\n+-----------------------\n+\n+ * empty commits:\n+\n+    am-based rebase will drop any \"empty\" commits, whether the\n+    commit started empty (had no changes relative to its parent to\n+    start with) or ended empty (all changes were already applied\n+    upstream in other commits).\n+\n+    merge-based rebase does the same.\n+\n+    interactive-based rebase will by default drop commits that\n+    started empty and halt if it hits a commit that ended up empty.\n+    The `--keep-empty` option exists for interactive rebases to allow\n+    it to keep commits that started empty.\n+\n+  * empty commit messages:\n+\n+    am-based rebase will silently apply commits with empty commit\n+    messages.\n+\n+    merge-based and interactive-based rebases will by default halt\n+    on any such commits.  The `--allow-empty-message` option exists to\n+    allow interactive-based rebases to apply such commits without\n+    halting.\n+\n+  * directory rename detection:\n+\n+    merge-based and interactive-based rebases work fine with\n+    directory rename detection.  am-based rebases sometimes do not.\n+\n include::merge-strategies.txt[]\n \n NOTES\ndiff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt\nindex 6e22920a39..1c0086e287 100644\n--- a/Documentation/technical/directory-rename-detection.txt\n+++ b/Documentation/technical/directory-rename-detection.txt\n@@ -90,3 +90,26 @@ directory rename detection support in:\n     simply not implemented.  Further, to implement this, directory rename\n     detection logic would need to move from merge-recursive to\n     diffcore-rename.\n+\n+  * am\n+\n+    git-am tries to avoid a full three way merge, instead calling\n+    git-apply.  That prevents us from detecting renames at all, which may\n+    defeat the directory rename detection.  There is a fallback, though; if\n+    the initial git-apply fails and the user has specified the -3 option,\n+    git-am will fall back to a three way merge.  However, git-am lacks the\n+    necessary information to do a \"real\" three way merge.  Instead, it has\n+    to use build_fake_ancestor() to get a merge base that is missing files\n+    whose rename may have been important to detect for directory rename\n+    detection to function.\n+\n+  * rebase\n+\n+    Since am-based rebases work by first generating a bunch of patches\n+    (which no longer record what the original commits were and thus don't\n+    have the necessary info from which we can find a real merge-base), and\n+    then calling git-am, this implies that am-based rebases will not always\n+    successfully detect directory renames either (see the 'am' section\n+    above).  merged-based rebases (rebase -m) and cherry-pick-based rebases\n+    (rebase -i) are not affected by this shortcoming, and fully support\n+    directory rename detection.\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350843","messageId":"20180625161300.26060-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 1/9] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:52Z","receivedAt":"2018-06-25T16:14:57Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has many options that only work with one of its three backends.\nIt also has a few other pairs of incompatible options.  Document these.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 85 ++++++++++++++++++++++++++++++++----\n 1 file changed, 77 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0e20a66e73..b2d95e3fb9 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n \tThis option overrides that behavior, allowing commits with empty\n \tmessages to be rebased.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --skip::\n \tRestart the rebasing process by skipping the current patch.\n@@ -271,6 +275,8 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -280,8 +286,10 @@ other words, the sides are swapped.\n +\n Because 'git rebase' replays each commit from the working branch\n on top of the <upstream> branch using the given strategy, using\n-the 'ours' strategy simply discards all patches from the <branch>,\n+the 'ours' strategy simply empties all patches from the <branch>,\n which makes little sense.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -X <strategy-option>::\n --strategy-option=<strategy-option>::\n@@ -289,6 +297,8 @@ which makes little sense.\n \tThis implies `--merge` and, if no strategy has been\n \tspecified, `-s recursive`.  Note the reversal of 'ours' and\n \t'theirs' as noted above for the `-m` option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -S[<keyid>]::\n --gpg-sign[=<keyid>]::\n@@ -324,6 +334,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -f::\n --force-rebase::\n@@ -355,19 +367,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n \tthat if `--interactive` is given then only commits marked to be\n-\tpicked, edited or reworded will have the trailer added. Incompatible\n-\twith the `--preserve-merges` option.\n+\tpicked, edited or reworded will have the trailer added.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -i::\n --interactive::\n@@ -378,6 +393,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n The commit list format can be changed by setting the configuration option\n rebase.instructionFormat.  A customized instruction format will automatically\n have the long commit hash prepended to the format.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -r::\n --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::\n@@ -404,7 +421,7 @@ It is currently only possible to recreate the merge commits using the\n `recursive` merge strategy; Different merge strategies can be used only via\n explicit `exec git merge -s <strategy> [...]` commands.\n +\n-See also REBASING MERGES below.\n+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.\n \n -p::\n --preserve-merges::\n@@ -415,6 +432,8 @@ See also REBASING MERGES below.\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n idea unless you know what you are doing (see BUGS below).\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -x <cmd>::\n --exec <cmd>::\n@@ -437,6 +456,8 @@ squash/fixup series.\n +\n This uses the `--interactive` machinery internally, but it can be run\n without an explicit `--interactive`.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --root::\n \tRebase all commits reachable from <branch>, instead of\n@@ -447,6 +468,8 @@ without an explicit `--interactive`.\n \tWhen used together with both --onto and --preserve-merges,\n \t'all' root commits will be rewritten to have <newbase> as parent\n \tinstead.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n@@ -461,11 +484,11 @@ without an explicit `--interactive`.\n \ttoo.  The recommended way to create fixup/squash commits is by using\n \tthe `--fixup`/`--squash` options of linkgit:git-commit[1].\n +\n-This option is only valid when the `--interactive` option is used.\n-+\n If the `--autosquash` option is enabled by default using the\n configuration variable `rebase.autoSquash`, this option can be\n used to override and disable this setting.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autostash::\n --no-autostash::\n@@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n successfully without needing to \"revert the reversion\" (see the\n link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n \n+INCOMPATIBLE OPTIONS\n+--------------------\n+\n+git-rebase has many flags that are incompatible with each other,\n+predominantly due to the fact that it has three different underlying\n+implementations:\n+\n+ * one based on linkgit:git-am[1] (the default)\n+ * one based on git-merge-recursive (merge backend)\n+ * one based on linkgit:git-cherry-pick[1] (interactive backend)\n+\n+Flags only understood by the am backend:\n+\n+ * --committer-date-is-author-date\n+ * --ignore-date\n+ * --whitespace\n+ * --ignore-whitespace\n+ * -C\n+\n+Flags understood by both merge and interactive backends:\n+\n+ * --merge\n+ * --strategy\n+ * --strategy-option\n+ * --allow-empty-message\n+\n+Flags only understood by the interactive backend:\n+\n+ * --[no-]autosquash\n+ * --rebase-merges\n+ * --preserve-merges\n+ * --interactive\n+ * --exec\n+ * --keep-empty\n+ * --autosquash\n+ * --edit-todo\n+ * --root when used in combination with --onto\n+\n+Other incompatible flag pairs:\n+\n+ * --preserve-merges and --interactive\n+ * --preserve-merges and --signoff\n+ * --preserve-merges and --rebase-merges\n+ * --rebase-merges and --strategy\n+ * --rebase-merges and --strategy-option\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350844","messageId":"20180625161300.26060-7-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 6/9] directory-rename-detection.txt: technical docs on abilities and limitations","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:57Z","receivedAt":"2018-06-25T16:15:00Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Signed-off-by: Elijah Newren <newren@gmail.com>\n---\n .../technical/directory-rename-detection.txt  | 92 +++++++++++++++++++\n 1 file changed, 92 insertions(+)\n create mode 100644 Documentation/technical/directory-rename-detection.txt\n\ndiff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt\nnew file mode 100644\nindex 0000000000..6e22920a39\n--- /dev/null\n+++ b/Documentation/technical/directory-rename-detection.txt\n@@ -0,0 +1,92 @@\n+Directory rename detection\n+==========================\n+\n+Rename detection logic in diffcore-rename that checks for renames of\n+individual files is aggregated and analyzed in merge-recursive for cases\n+where combinations of renames indicate that a full directory has been\n+renamed.\n+\n+Scope of abilities\n+------------------\n+\n+It is perhaps easiest to start with an example:\n+\n+  * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is\n+    likely that x/d added in the meantime would also want to move to z/d by\n+    taking the hint that the entire directory 'x' moved to 'z'.\n+\n+More interesting possibilities exist, though, such as:\n+\n+  * one side of history renames x -> z, and the other renames some file to\n+    x/e, causing the need for the merge to do a transitive rename.\n+\n+  * one side of history renames x -> z, but also renames all files within\n+    x.  For example, x/a -> z/alpha, x/b -> z/bravo, etc.\n+\n+  * both 'x' and 'y' being merged into a single directory 'z', with a\n+    directory rename being detected for both x->z and y->z.\n+\n+  * not all files in a directory being renamed to the same location;\n+    i.e. perhaps most the files in 'x' are now found under 'z', but a few\n+    are found under 'w'.\n+\n+  * a directory being renamed, which also contained a subdirectory that was\n+    renamed to some entirely different location.  (And perhaps the inner\n+    directory itself contained inner directories that were renamed to yet\n+    other locations).\n+\n+  * combinations of the above; see t/t6043-merge-rename-directories.sh for\n+    various interesting cases.\n+\n+Limitations -- applicability of directory renames\n+-------------------------------------------------\n+\n+In order to prevent edge and corner cases resulting in either conflicts\n+that cannot be represented in the index or which might be too complex for\n+users to try to understand and resolve, a couple basic rules limit when\n+directory rename detection applies:\n+\n+  1) If a given directory still exists on both sides of a merge, we do\n+     not consider it to have been renamed.\n+\n+  2) If a subset of to-be-renamed files have a file or directory in the\n+     way (or would be in the way of each other), \"turn off\" the directory\n+     rename for those specific sub-paths and report the conflict to the\n+     user.\n+\n+  3) If the other side of history did a directory rename to a path that\n+     your side of history renamed away, then ignore that particular\n+     rename from the other side of history for any implicit directory\n+     renames (but warn the user).\n+\n+Limitations -- detailed rules and testcases\n+-------------------------------------------\n+\n+t/t6043-merge-rename-directories.sh contains extensive tests and commentary\n+which generate and explore the rules listed above.  It also lists a few\n+additional rules:\n+\n+  a) If renames split a directory into two or more others, the directory\n+     with the most renames, \"wins\".\n+\n+  b) Avoid directory-rename-detection for a path, if that path is the\n+     source of a rename on either side of a merge.\n+\n+  c) Only apply implicit directory renames to directories if the other side\n+     of history is the one doing the renaming.\n+\n+Limitations -- support in different commands\n+--------------------------------------------\n+\n+Directory rename detection is supported by 'merge' and 'cherry-pick'.\n+Other git commands which users might be surprised to see limited or no\n+directory rename detection support in:\n+\n+  * diff\n+\n+    Folks have requested in the past that `git diff` detect directory\n+    renames and somehow simplify its output.  It is not clear whether this\n+    would be desirable or how the output should be simplified, so this was\n+    simply not implemented.  Further, to implement this, directory rename\n+    detection logic would need to move from merge-recursive to\n+    diffcore-rename.\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350845","messageId":"20180625161300.26060-5-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v4 4/9] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:12:55Z","receivedAt":"2018-06-25T16:15:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has three different types: am, merge, and interactive, all of\nwhich are implemented in terms of separate scripts.  am builds on git-am,\nmerge builds on git-merge-recursive, and interactive builds on\ngit-cherry-pick.  We make use of features in those lower-level commands in\nthe different rebase types, but those features don't exist in all of the\nlower level commands so we have a range of incompatibilities.  Previously,\nwe just accepted nearly any argument and silently ignored whichever ones\nweren't implemented for the type of rebase specified.  Change this so the\nincompatibilities are documented, included in the testsuite, and tested\nfor at runtime with an appropriate error message shown.\n\nSome exceptions I left out:\n\n  * --merge and --interactive are technically incompatible since they are\n    supposed to run different underlying scripts, but with a few small\n    changes, --interactive can do everything that --merge can.  In fact,\n    I'll shortly be sending another patch to remove git-rebase--merge and\n    reimplement it on top of git-rebase--interactive.\n\n  * One could argue that --interactive and --quiet are incompatible since\n    --interactive doesn't implement a --quiet mode (perhaps since\n    cherry-pick itself does not implement one).  However, the interactive\n    mode is more quiet than the other modes in general with progress\n    messages, so one could argue that it's already quiet.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh                          | 35 ++++++++++++++++++++++++++\n t/t3422-rebase-incompatible-options.sh | 16 ++++++------\n 2 files changed, 43 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex bf71b7fa20..18ac8226c4 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -503,6 +503,24 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n+if test -n \"$git_am_opt\"; then\n+\tincompatible_opts=$(echo \" $git_am_opt \" | \\\n+\t\t\t    sed -e 's/ -q / /g' -e 's/^ \\(.*\\) $/\\1/')\n+\tif test -n \"$interactive_rebase\"\n+\tthen\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$do_merge\"; then\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n if test -n \"$signoff\"\n then\n \ttest -n \"$preserve_merges\" &&\n@@ -511,6 +529,23 @@ then\n \tforce_rebase=t\n fi\n \n+if test -n \"$preserve_merges\"\n+then\n+\t# Note: incompatibility with --signoff handled in signoff block above\n+\t# Note: incompatibility with --interactive is just a strong warning;\n+\t#       git-rebase.txt caveats with \"unless you know what you are doing\"\n+\ttest -n \"$rebase_merges\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--preserve_merges' with '--rebase-merges'\")\"\n+fi\n+\n+if test -n \"$rebase_merges\"\n+then\n+\ttest -n \"$strategy_opts\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy-option'\")\"\n+\ttest -n \"$strategy\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy'\")\"\n+fi\n+\n if test -z \"$rebase_root\"\n then\n \tcase \"$#\" in\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex 2687a85254..fc0ce150d1 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -33,27 +33,27 @@ test_expect_success 'setup' '\n test_rebase_am_only () {\n \topt=$1\n \tshift\n-\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\ttest_expect_success \"$opt incompatible with --merge\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --merge A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\ttest_expect_success \"$opt incompatible with --interactive\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --interactive A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\ttest_expect_success \"$opt incompatible with --exec\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --exec 'true' A\n \t\"\n@@ -70,17 +70,17 @@ test_expect_success '--preserve-merges incompatible with --signoff' '\n \ttest_must_fail git rebase --preserve-merges --signoff A\n '\n \n-test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+test_expect_success '--preserve-merges incompatible with --rebase-merges' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --preserve-merges --rebase-merges A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy' '\n+test_expect_success '--rebase-merges incompatible with --strategy' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -s resolve A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+test_expect_success '--rebase-merges incompatible with --strategy-option' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n '\n-- \n2.18.0.9.g678597d97e\n\n"},{"id":"350846","messageId":"CABPp-BGwBcj4pA5tOhBqJiVZanoZeBdmRa7v7C74=nctrNoZ8g@mail.gmail.com","threadId":"48665","inReplyTo":"20180607050454.19438-1-newren@gmail.com","subject":"Re: [PATCH] t3401: add directory rename testcases for rebase and am","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-25T16:17:02Z","receivedAt":"2018-06-25T16:17:07Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 6, 2018 at 10:04 PM, Elijah Newren <newren@gmail.com> wrote:\n> Add a simple directory rename testcase, in conjunction with each of the\n> types of rebases:\n>   git-rebase--interactive\n>   git-rebase--am\n>   git-rebase--merge\n> and also use the same testcase for\n>   git am --3way\n>\n> This demonstrates an inconsistency between the different rebase backends\n> and which can detect the directory rename.\n\nDue to changes in the en/rebase-consistency series, I'm no longer\nkeeping this patch as a separate submission but have pulled it into v4\nof that series[1].\n\n\n[1] https://public-inbox.org/git/20180625161300.26060-9-newren@gmail.com/\n"},{"id":"350990","messageId":"xmqqk1qll8f7.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180625161300.26060-4-newren@gmail.com","subject":"Re: [PATCH v4 3/9] t3422: new testcases for checking when incompatible options passed","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-26T18:17:00Z","receivedAt":"2018-06-26T18:17:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> +# Rebase has lots of useful options like --whitepsace=fix, which are\n> +# actually all built in terms of flags to git-am.  Since neither\n> +# --merge nor --interactive (nor any options that imply those two) use\n> +# git-am, using them together will result in flags like --whitespace=fix\n> +# being ignored.  Make sure rebase warns the user and aborts instead.\n> +#\n> +\n> +test_rebase_am_only () {\n> +\topt=$1\n> +\tshift\n> +\ttest_expect_failure \"$opt incompatible with --merge\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --merge A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --strategy=ours A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --strategy=ours A\n\nThis line is broken and it is carried over to later patches.  It\nneeds to be -Xours (or --strategy-option=ours, if we really want ot\nbe verbose).\n\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --interactive A\n> +\t\"\n> +\n> +\ttest_expect_failure \"$opt incompatible with --exec\" \"\n> +\t\tgit checkout B^0 &&\n> +\t\ttest_must_fail git rebase $opt --exec 'true' A\n> +\t\"\n> +\n> +}\n\n> +\n> +test_rebase_am_only --whitespace=fix\n> +test_rebase_am_only --ignore-whitespace\n> +test_rebase_am_only --committer-date-is-author-date\n> +test_rebase_am_only -C4\n\nI was hesitant to hardcode what I perceive as limitations of non-am\nrebase implementations with a test like this, but once somebody\nfixes \"rebase -i\" for example to be capable of --whitespace=fix for\nexample, then we can just drop one line from the above four (and\nwrite other tests for \"rebase -i --whitespace=fix\").  The\ntest_rebase_am_only is to help us make sure what is (still) not\nsupported by non-am rebases gets diagnosed as an error.\n\nSo my worry is totally unfounded, which is good.\n\n> +test_expect_success '--preserve-merges incompatible with --signoff' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --preserve-merges --signoff A\n> +'\n> +\n> +test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n> +'\n> +\n> +test_expect_failure '--rebase-merges incompatible with --strategy' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --rebase-merges -s resolve A\n> +'\n> +\n> +test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n> +\tgit checkout B^0 &&\n> +\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n> +'\n> +\n> +test_done\n"},{"id":"351064","messageId":"CABPp-BGOqC1YbeYunL_hb=oyDufHKJsC9JvSRapoa7C-Y9Bqyg@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqk1qll8f7.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 3/9] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T06:50:40Z","receivedAt":"2018-06-27T06:50:44Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, Jun 26, 2018 at 11:17 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Elijah Newren <newren@gmail.com> writes:\n>\n>> +# Rebase has lots of useful options like --whitepsace=fix, which are\n>> +# actually all built in terms of flags to git-am.  Since neither\n>> +# --merge nor --interactive (nor any options that imply those two) use\n>> +# git-am, using them together will result in flags like --whitespace=fix\n>> +# being ignored.  Make sure rebase warns the user and aborts instead.\n>> +#\n>> +\n>> +test_rebase_am_only () {\n>> +     opt=$1\n>> +     shift\n>> +     test_expect_failure \"$opt incompatible with --merge\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --merge A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --strategy=ours\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --strategy=ours A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --strategy=ours A\n>\n> This line is broken and it is carried over to later patches.  It\n> needs to be -Xours (or --strategy-option=ours, if we really want ot\n> be verbose).\n\nIndeed; I'll fix that up and resubmit.  Thanks for catching it.\n\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --interactive\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --interactive A\n>> +     \"\n>> +\n>> +     test_expect_failure \"$opt incompatible with --exec\" \"\n>> +             git checkout B^0 &&\n>> +             test_must_fail git rebase $opt --exec 'true' A\n>> +     \"\n>> +\n>> +}\n>\n>> +\n>> +test_rebase_am_only --whitespace=fix\n>> +test_rebase_am_only --ignore-whitespace\n>> +test_rebase_am_only --committer-date-is-author-date\n>> +test_rebase_am_only -C4\n>\n> I was hesitant to hardcode what I perceive as limitations of non-am\n> rebase implementations with a test like this, but once somebody\n> fixes \"rebase -i\" for example to be capable of --whitespace=fix for\n> example, then we can just drop one line from the above four (and\n> write other tests for \"rebase -i --whitespace=fix\").  The\n> test_rebase_am_only is to help us make sure what is (still) not\n> supported by non-am rebases gets diagnosed as an error.\n\nYes, and I was thinking in particular that we could start by teaching\nrebase -i to understand --ignore-space-change/--ignore-whitespace by\njust transliterating it into -Xignore-space-change.  That is, after\nhttps://public-inbox.org/git/20180607050845.19779-2-newren@gmail.com/\nis picked up and eventually merged down.  Speaking of which, I need to\nresubmit that.\n\n> So my worry is totally unfounded, which is good.\n"},{"id":"351065","messageId":"20180627072319.31356-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 2/9] git-rebase.sh: update help messages a bit","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:12Z","receivedAt":"2018-06-27T07:23:42Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"signoff is not specific to the am-backend.  Also, re-order a few options\nto make like things (e.g. strategy and strategy-option) be near each\nother.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 40be59ecc4..bf71b7fa20 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -20,23 +20,23 @@ onto=!             rebase onto given branch instead of upstream\n r,rebase-merges?   try to rebase merges instead of skipping them\n p,preserve-merges! try to recreate merges instead of ignoring them\n s,strategy=!       use the given merge strategy\n+X,strategy-option=! pass the argument through to the merge strategy\n no-ff!             cherry-pick all commits, even if unchanged\n+f,force-rebase!    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 x,exec=!           add exec lines after each commit of the editable list\n k,keep-empty\t   preserve empty commits during rebase\n allow-empty-message allow rebasing commits with empty messages\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 n,no-stat!         do not show diffstat of what changed upstream\n verify             allow pre-rebase hook to run\n rerere-autoupdate  allow rerere to update index with resolved conflicts\n root!              rebase all reachable commits up to the root(s)\n autosquash         move commits that begin with squash!/fixup! under -i\n+signoff            add a Signed-off-by: line to each commit\n committer-date-is-author-date! passed to 'git am'\n ignore-date!       passed to 'git am'\n-signoff            passed to 'git am'\n whitespace=!       passed to 'git apply'\n ignore-whitespace! passed to 'git apply'\n C=!                passed to 'git apply'\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351066","messageId":"20180627072319.31356-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 1/9] git-rebase.txt: document incompatible options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:11Z","receivedAt":"2018-06-27T07:23:45Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has many options that only work with one of its three backends.\nIt also has a few other pairs of incompatible options.  Document these.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 85 ++++++++++++++++++++++++++++++++----\n 1 file changed, 77 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 0e20a66e73..b2d95e3fb9 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -243,11 +243,15 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --allow-empty-message::\n \tBy default, rebasing commits with an empty message will fail.\n \tThis option overrides that behavior, allowing commits with empty\n \tmessages to be rebased.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --skip::\n \tRestart the rebasing process by skipping the current patch.\n@@ -271,6 +275,8 @@ branch on top of the <upstream> branch.  Because of this, when a merge\n conflict happens, the side reported as 'ours' is the so-far rebased\n series, starting with <upstream>, and 'theirs' is the working branch.  In\n other words, the sides are swapped.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -s <strategy>::\n --strategy=<strategy>::\n@@ -280,8 +286,10 @@ other words, the sides are swapped.\n +\n Because 'git rebase' replays each commit from the working branch\n on top of the <upstream> branch using the given strategy, using\n-the 'ours' strategy simply discards all patches from the <branch>,\n+the 'ours' strategy simply empties all patches from the <branch>,\n which makes little sense.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -X <strategy-option>::\n --strategy-option=<strategy-option>::\n@@ -289,6 +297,8 @@ which makes little sense.\n \tThis implies `--merge` and, if no strategy has been\n \tspecified, `-s recursive`.  Note the reversal of 'ours' and\n \t'theirs' as noted above for the `-m` option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -S[<keyid>]::\n --gpg-sign[=<keyid>]::\n@@ -324,6 +334,8 @@ which makes little sense.\n \tand after each change.  When fewer lines of surrounding\n \tcontext exist they all must match.  By default no context is\n \tever ignored.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -f::\n --force-rebase::\n@@ -355,19 +367,22 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n --whitespace=<option>::\n \tThese flag are passed to the 'git apply' program\n \t(see linkgit:git-apply[1]) that applies the patch.\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --committer-date-is-author-date::\n --ignore-date::\n \tThese flags are passed to 'git am' to easily change the dates\n \tof the rebased commits (see linkgit:git-am[1]).\n-\tIncompatible with the --interactive option.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --signoff::\n \tAdd a Signed-off-by: trailer to all the rebased commits. Note\n \tthat if `--interactive` is given then only commits marked to be\n-\tpicked, edited or reworded will have the trailer added. Incompatible\n-\twith the `--preserve-merges` option.\n+\tpicked, edited or reworded will have the trailer added.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -i::\n --interactive::\n@@ -378,6 +393,8 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n The commit list format can be changed by setting the configuration option\n rebase.instructionFormat.  A customized instruction format will automatically\n have the long commit hash prepended to the format.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -r::\n --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::\n@@ -404,7 +421,7 @@ It is currently only possible to recreate the merge commits using the\n `recursive` merge strategy; Different merge strategies can be used only via\n explicit `exec git merge -s <strategy> [...]` commands.\n +\n-See also REBASING MERGES below.\n+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.\n \n -p::\n --preserve-merges::\n@@ -415,6 +432,8 @@ See also REBASING MERGES below.\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n idea unless you know what you are doing (see BUGS below).\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n -x <cmd>::\n --exec <cmd>::\n@@ -437,6 +456,8 @@ squash/fixup series.\n +\n This uses the `--interactive` machinery internally, but it can be run\n without an explicit `--interactive`.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --root::\n \tRebase all commits reachable from <branch>, instead of\n@@ -447,6 +468,8 @@ without an explicit `--interactive`.\n \tWhen used together with both --onto and --preserve-merges,\n \t'all' root commits will be rewritten to have <newbase> as parent\n \tinstead.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autosquash::\n --no-autosquash::\n@@ -461,11 +484,11 @@ without an explicit `--interactive`.\n \ttoo.  The recommended way to create fixup/squash commits is by using\n \tthe `--fixup`/`--squash` options of linkgit:git-commit[1].\n +\n-This option is only valid when the `--interactive` option is used.\n-+\n If the `--autosquash` option is enabled by default using the\n configuration variable `rebase.autoSquash`, this option can be\n used to override and disable this setting.\n++\n+See also INCOMPATIBLE OPTIONS below.\n \n --autostash::\n --no-autostash::\n@@ -487,6 +510,52 @@ recreates the topic branch with fresh commits so it can be remerged\n successfully without needing to \"revert the reversion\" (see the\n link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n \n+INCOMPATIBLE OPTIONS\n+--------------------\n+\n+git-rebase has many flags that are incompatible with each other,\n+predominantly due to the fact that it has three different underlying\n+implementations:\n+\n+ * one based on linkgit:git-am[1] (the default)\n+ * one based on git-merge-recursive (merge backend)\n+ * one based on linkgit:git-cherry-pick[1] (interactive backend)\n+\n+Flags only understood by the am backend:\n+\n+ * --committer-date-is-author-date\n+ * --ignore-date\n+ * --whitespace\n+ * --ignore-whitespace\n+ * -C\n+\n+Flags understood by both merge and interactive backends:\n+\n+ * --merge\n+ * --strategy\n+ * --strategy-option\n+ * --allow-empty-message\n+\n+Flags only understood by the interactive backend:\n+\n+ * --[no-]autosquash\n+ * --rebase-merges\n+ * --preserve-merges\n+ * --interactive\n+ * --exec\n+ * --keep-empty\n+ * --autosquash\n+ * --edit-todo\n+ * --root when used in combination with --onto\n+\n+Other incompatible flag pairs:\n+\n+ * --preserve-merges and --interactive\n+ * --preserve-merges and --signoff\n+ * --preserve-merges and --rebase-merges\n+ * --rebase-merges and --strategy\n+ * --rebase-merges and --strategy-option\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351067","messageId":"20180627072319.31356-8-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 7/9] git-rebase.txt: document behavioral differences between modes","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:17Z","receivedAt":"2018-06-27T07:23:48Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"There are a variety of aspects that are common to all rebases regardless\nof which backend is in use; however, the behavior for these different\naspects varies in ways that could surprise users.  (In fact, it's not\nclear -- to me at least -- that these differences were even desirable or\nintentional.)  Document these differences.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt                  | 32 +++++++++++++++++++\n .../technical/directory-rename-detection.txt  | 23 +++++++++++++\n 2 files changed, 55 insertions(+)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 2f47495a4d..a67df4caba 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -546,6 +546,38 @@ Other incompatible flag pairs:\n  * --rebase-merges and --strategy\n  * --rebase-merges and --strategy-option\n \n+BEHAVIORAL DIFFERENCES\n+-----------------------\n+\n+ * empty commits:\n+\n+    am-based rebase will drop any \"empty\" commits, whether the\n+    commit started empty (had no changes relative to its parent to\n+    start with) or ended empty (all changes were already applied\n+    upstream in other commits).\n+\n+    merge-based rebase does the same.\n+\n+    interactive-based rebase will by default drop commits that\n+    started empty and halt if it hits a commit that ended up empty.\n+    The `--keep-empty` option exists for interactive rebases to allow\n+    it to keep commits that started empty.\n+\n+  * empty commit messages:\n+\n+    am-based rebase will silently apply commits with empty commit\n+    messages.\n+\n+    merge-based and interactive-based rebases will by default halt\n+    on any such commits.  The `--allow-empty-message` option exists to\n+    allow interactive-based rebases to apply such commits without\n+    halting.\n+\n+  * directory rename detection:\n+\n+    merge-based and interactive-based rebases work fine with\n+    directory rename detection.  am-based rebases sometimes do not.\n+\n include::merge-strategies.txt[]\n \n NOTES\ndiff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt\nindex 6e22920a39..1c0086e287 100644\n--- a/Documentation/technical/directory-rename-detection.txt\n+++ b/Documentation/technical/directory-rename-detection.txt\n@@ -90,3 +90,26 @@ directory rename detection support in:\n     simply not implemented.  Further, to implement this, directory rename\n     detection logic would need to move from merge-recursive to\n     diffcore-rename.\n+\n+  * am\n+\n+    git-am tries to avoid a full three way merge, instead calling\n+    git-apply.  That prevents us from detecting renames at all, which may\n+    defeat the directory rename detection.  There is a fallback, though; if\n+    the initial git-apply fails and the user has specified the -3 option,\n+    git-am will fall back to a three way merge.  However, git-am lacks the\n+    necessary information to do a \"real\" three way merge.  Instead, it has\n+    to use build_fake_ancestor() to get a merge base that is missing files\n+    whose rename may have been important to detect for directory rename\n+    detection to function.\n+\n+  * rebase\n+\n+    Since am-based rebases work by first generating a bunch of patches\n+    (which no longer record what the original commits were and thus don't\n+    have the necessary info from which we can find a real merge-base), and\n+    then calling git-am, this implies that am-based rebases will not always\n+    successfully detect directory renames either (see the 'am' section\n+    above).  merged-based rebases (rebase -m) and cherry-pick-based rebases\n+    (rebase -i) are not affected by this shortcoming, and fully support\n+    directory rename detection.\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351068","messageId":"20180627072319.31356-10-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[RFC PATCH v5 9/9] git-rebase: make --allow-empty-message the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:19Z","receivedAt":"2018-06-27T07:23:50Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase backends currently behave differently with empty commit messages,\nlargely as a side-effect of the different underlying commands on which\nthey are based.  am-based rebases apply commits with an empty commit\nmessage without stopping or requiring the user to specify an extra flag.\n(It is interesting to note that am-based rebases are the default rebase\ntype, and no one has ever requested a --no-allow-empty-message flag to\nchange this behavior.)  merge-based and interactive-based rebases (which\nare ultimately based on git-commit), will currently halt on any such\ncommits and require the user to manually specify what to do with the\ncommit and continue.\n\nOne possible rationale for the difference in behavior is that the purpose\nof an \"am\" based rebase is solely to transplant an existing history, while\nan \"interactive\" rebase is one whose purpose is to polish a series before\nmaking it publishable.  Thus, stopping and asking for confirmation for a\npossible problem is more appropriate in the latter case.  However, there\nare two problems with this rationale:\n\n  1) merge-based rebases are also non-interactive and there are multiple\n     types of rebases that use the interactive machinery but are not\n     explicitly interactive (e.g. when either --rebase-merges or\n     --keep-empty are specified without --interactive).  These rebases are\n     also used solely to transplant an existing history, and thus also\n     should default to --allow-empty-message.\n\n  2) this rationale only says that the user is more accepting of stopping\n     in the case of an explicitly interactive rebase, not that stopping\n     for this particular reason actually makes sense.  Exploring whether\n     it makes sense, requires backing up and analyzing the underlying\n     commands...\n\nIf git-commit did not error out on empty commits by default, accidental\ncreation of commits with empty messages would be a very common occurrence\n(this check has caught me many times).  Further, nearly all such empty\ncommit messages would be considered an accidental error (as evidenced by a\nhuge amount of documentation across version control systems and in various\nblog posts explaining how important commit messages are).  A simple check\nfor what would otherwise be a common error thus made a lot of sense, and\ngit-commit gained an --allow-empty-message flag for special case\noverrides.  This has made commits with empty messages very rare.\n\nThere are two sources for commits with empty messages for rebase (and\ncherry-pick): (a) commits created in git where the user previously\nspecified --allow-empty-message to git-commit, and (b) commits imported\ninto git from other version control systems.  In case (a), the user has\nalready explicitly specified that there is something special about this\ncommit that makes them not want to specify a commit message; forcing them\nto re-specify with every cherry-pick or rebase seems more likely to be\ninfuriating than helpful.  In case (b), the commit is highly unlikely to\nhave been authored by the person who has imported the history and is doing\nthe rebase or cherry-pick, and thus the user is unlikely to be the\nappropriate person to write a commit message for it.  Stopping and\nexpecting the user to modify the commit before proceeding thus seems\ncounter-productive.\n\nFurther, note that while empty commit messages was a common error case for\ngit-commit to deal with, it is a rare case for rebase (or cherry-pick).\nThe fact that it is rare raises the question of why it would be worth\nchecking and stopping on this particular condition and not others.  For\nexample, why doesn't an interactive rebase automatically stop if the\ncommit message's first line is 2000 columns long, or is missing a blank\nline after the first line, or has every line indented with five spaces, or\nany number of other myriad problems?\n\nFinally, note that if a user doing an interactive rebase does have the\nnecessary knowledge to add a message for any such commit and wants to do\nso, it is rather simple for them to change the appropriate line from\n'pick' to 'reword'.  The fact that the subject is empty in the todo list\nthat the user edits should even serve as a way to notify them.\n\nAs far as I can tell, the fact that merge-based and interactive-based\nrebases stop on commits with empty commit messages is solely a by-product\nof having been based on git-commit.  It went without notice for a long\ntime precisely because such cases are rare.  The rareness of this\nsituation made it difficult to reason about, so when folks did eventually\nnotice this behavior, they assumed it was there for a good reason and just\nadded an --allow-empty-message flag.  In my opinion, stopping on such\nmessages not desirable in any of these cases, even the (explicitly)\ninteractive case.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n\nMy commit messsage seems like one of those things that someone else will\ninstantly see how to shrink to less than a quarter of its size while still\nretaining all essential reasoning.  I can't seem to find the simple way to\nstate it, though.\n\n Documentation/git-rebase.txt  | 10 ----------\n git-rebase.sh                 |  2 +-\n t/t3404-rebase-interactive.sh |  7 ++++---\n t/t3405-rebase-malformed.sh   | 11 +++--------\n 4 files changed, 8 insertions(+), 22 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex a67df4caba..9e136ee16e 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -563,16 +563,6 @@ BEHAVIORAL DIFFERENCES\n     The `--keep-empty` option exists for interactive rebases to allow\n     it to keep commits that started empty.\n \n-  * empty commit messages:\n-\n-    am-based rebase will silently apply commits with empty commit\n-    messages.\n-\n-    merge-based and interactive-based rebases will by default halt\n-    on any such commits.  The `--allow-empty-message` option exists to\n-    allow interactive-based rebases to apply such commits without\n-    halting.\n-\n   * directory rename detection:\n \n     merge-based and interactive-based rebases work fine with\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 18ac8226c4..031dbd2ec8 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -95,7 +95,7 @@ rebase_cousins=\n preserve_merges=\n autosquash=\n keep_empty=\n-allow_empty_message=\n+allow_empty_message=--allow-empty-message\n signoff=\n test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n case \"$(git config --bool commit.gpgsign)\" in\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 352a52e59d..81ce9fe7f9 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n '\n \n test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n+\ttest_when_finished \"git rebase --abort\" &&\n \told=$(git rev-parse HEAD) &&\n \ttest_tick &&\n \tset_fake_editor &&\n \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n \techo \"edited again\" > file7 &&\n \tgit add file7 &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n-\ttest $old = $(git rev-parse HEAD) &&\n-\tgit rebase --abort\n+\techo all the things >>conflict &&\n+\ttest_must_fail git rebase --continue &&\n+\ttest $old = $(git rev-parse HEAD)\n '\n \n test_expect_success 'auto-amend only edited commits after \"edit\"' '\ndiff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\nindex cb7c6de84a..da94dddc86 100755\n--- a/t/t3405-rebase-malformed.sh\n+++ b/t/t3405-rebase-malformed.sh\n@@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n '\n \n test_expect_success 'rebase -m commit with empty message' '\n-\ttest_must_fail git rebase -m master empty-message-merge &&\n-\tgit rebase --abort &&\n-\tgit rebase -m --allow-empty-message master empty-message-merge\n+\tgit rebase -m master empty-message-merge\n '\n \n test_expect_success 'rebase -i commit with empty message' '\n \tgit checkout diff-in-message &&\n \tset_fake_editor &&\n-\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i HEAD^ &&\n-\tgit rebase --abort &&\n-\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n-\t\tgit rebase -i --allow-empty-message HEAD^\n+\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n+\t\tgit rebase -i HEAD^\n '\n \n test_done\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351069","messageId":"20180627072319.31356-7-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 6/9] directory-rename-detection.txt: technical docs on abilities and limitations","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:16Z","receivedAt":"2018-06-27T07:23:56Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Signed-off-by: Elijah Newren <newren@gmail.com>\n---\n .../technical/directory-rename-detection.txt  | 92 +++++++++++++++++++\n 1 file changed, 92 insertions(+)\n create mode 100644 Documentation/technical/directory-rename-detection.txt\n\ndiff --git a/Documentation/technical/directory-rename-detection.txt b/Documentation/technical/directory-rename-detection.txt\nnew file mode 100644\nindex 0000000000..6e22920a39\n--- /dev/null\n+++ b/Documentation/technical/directory-rename-detection.txt\n@@ -0,0 +1,92 @@\n+Directory rename detection\n+==========================\n+\n+Rename detection logic in diffcore-rename that checks for renames of\n+individual files is aggregated and analyzed in merge-recursive for cases\n+where combinations of renames indicate that a full directory has been\n+renamed.\n+\n+Scope of abilities\n+------------------\n+\n+It is perhaps easiest to start with an example:\n+\n+  * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is\n+    likely that x/d added in the meantime would also want to move to z/d by\n+    taking the hint that the entire directory 'x' moved to 'z'.\n+\n+More interesting possibilities exist, though, such as:\n+\n+  * one side of history renames x -> z, and the other renames some file to\n+    x/e, causing the need for the merge to do a transitive rename.\n+\n+  * one side of history renames x -> z, but also renames all files within\n+    x.  For example, x/a -> z/alpha, x/b -> z/bravo, etc.\n+\n+  * both 'x' and 'y' being merged into a single directory 'z', with a\n+    directory rename being detected for both x->z and y->z.\n+\n+  * not all files in a directory being renamed to the same location;\n+    i.e. perhaps most the files in 'x' are now found under 'z', but a few\n+    are found under 'w'.\n+\n+  * a directory being renamed, which also contained a subdirectory that was\n+    renamed to some entirely different location.  (And perhaps the inner\n+    directory itself contained inner directories that were renamed to yet\n+    other locations).\n+\n+  * combinations of the above; see t/t6043-merge-rename-directories.sh for\n+    various interesting cases.\n+\n+Limitations -- applicability of directory renames\n+-------------------------------------------------\n+\n+In order to prevent edge and corner cases resulting in either conflicts\n+that cannot be represented in the index or which might be too complex for\n+users to try to understand and resolve, a couple basic rules limit when\n+directory rename detection applies:\n+\n+  1) If a given directory still exists on both sides of a merge, we do\n+     not consider it to have been renamed.\n+\n+  2) If a subset of to-be-renamed files have a file or directory in the\n+     way (or would be in the way of each other), \"turn off\" the directory\n+     rename for those specific sub-paths and report the conflict to the\n+     user.\n+\n+  3) If the other side of history did a directory rename to a path that\n+     your side of history renamed away, then ignore that particular\n+     rename from the other side of history for any implicit directory\n+     renames (but warn the user).\n+\n+Limitations -- detailed rules and testcases\n+-------------------------------------------\n+\n+t/t6043-merge-rename-directories.sh contains extensive tests and commentary\n+which generate and explore the rules listed above.  It also lists a few\n+additional rules:\n+\n+  a) If renames split a directory into two or more others, the directory\n+     with the most renames, \"wins\".\n+\n+  b) Avoid directory-rename-detection for a path, if that path is the\n+     source of a rename on either side of a merge.\n+\n+  c) Only apply implicit directory renames to directories if the other side\n+     of history is the one doing the renaming.\n+\n+Limitations -- support in different commands\n+--------------------------------------------\n+\n+Directory rename detection is supported by 'merge' and 'cherry-pick'.\n+Other git commands which users might be surprised to see limited or no\n+directory rename detection support in:\n+\n+  * diff\n+\n+    Folks have requested in the past that `git diff` detect directory\n+    renames and somehow simplify its output.  It is not clear whether this\n+    would be desirable or how the output should be simplified, so this was\n+    simply not implemented.  Further, to implement this, directory rename\n+    detection logic would need to move from merge-recursive to\n+    diffcore-rename.\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351070","messageId":"20180627072319.31356-9-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 8/9] t3401: add directory rename testcases for rebase and am","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:18Z","receivedAt":"2018-06-27T07:23:59Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Add a simple directory rename testcase, in conjunction with each of the\ntypes of rebases:\n  git-rebase--interactive\n  git-rebase--am\n  git-rebase--merge\nand also use the same testcase for\n  git am --3way\n\nThis demonstrates a difference in behavior between the different rebase\nbackends in regards to directory rename detection.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3401-rebase-and-am-rename.sh | 105 ++++++++++++++++++++++++++++++++\n 1 file changed, 105 insertions(+)\n create mode 100755 t/t3401-rebase-and-am-rename.sh\n\ndiff --git a/t/t3401-rebase-and-am-rename.sh b/t/t3401-rebase-and-am-rename.sh\nnew file mode 100755\nindex 0000000000..8f832957fc\n--- /dev/null\n+++ b/t/t3401-rebase-and-am-rename.sh\n@@ -0,0 +1,105 @@\n+#!/bin/sh\n+\n+test_description='git rebase + directory rename tests'\n+\n+. ./test-lib.sh\n+. \"$TEST_DIRECTORY\"/lib-rebase.sh\n+\n+test_expect_success 'setup testcase' '\n+\ttest_create_repo dir-rename &&\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tmkdir x &&\n+\t\ttest_seq  1 10 >x/a &&\n+\t\ttest_seq 11 20 >x/b &&\n+\t\ttest_seq 21 30 >x/c &&\n+\t\ttest_write_lines a b c d e f g h i >l &&\n+\t\tgit add x l &&\n+\t\tgit commit -m \"Initial\" &&\n+\n+\t\tgit branch O &&\n+\t\tgit branch A &&\n+\t\tgit branch B &&\n+\n+\t\tgit checkout A &&\n+\t\tgit mv x y &&\n+\t\tgit mv l letters &&\n+\t\tgit commit -m \"Rename x to y, l to letters\" &&\n+\n+\t\tgit checkout B &&\n+\t\techo j >>l &&\n+\t\ttest_seq 31 40 >x/d &&\n+\t\tgit add l x/d &&\n+\t\tgit commit -m \"Modify l, add x/d\"\n+\t)\n+'\n+\n+test_expect_success 'rebase --interactive: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tset_fake_editor &&\n+\t\tFAKE_LINES=\"1\" git rebase --interactive A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'rebase (am): directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_success 'rebase --merge: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout B^0 &&\n+\n+\t\tgit rebase --merge A &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_expect_failure 'am: directory rename detected' '\n+\t(\n+\t\tcd dir-rename &&\n+\n+\t\tgit checkout A^0 &&\n+\n+\t\tgit format-patch -1 B &&\n+\n+\t\tgit am --3way 0001*.patch &&\n+\n+\t\tgit ls-files -s >out &&\n+\t\ttest_line_count = 5 out &&\n+\n+\t\ttest_path_is_file y/d &&\n+\t\ttest_path_is_missing x/d\n+\t)\n+'\n+\n+test_done\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351071","messageId":"20180627072319.31356-5-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 4/9] git-rebase: error out when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:14Z","receivedAt":"2018-06-27T07:24:01Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase has three different types: am, merge, and interactive, all of\nwhich are implemented in terms of separate scripts.  am builds on git-am,\nmerge builds on git-merge-recursive, and interactive builds on\ngit-cherry-pick.  We make use of features in those lower-level commands in\nthe different rebase types, but those features don't exist in all of the\nlower level commands so we have a range of incompatibilities.  Previously,\nwe just accepted nearly any argument and silently ignored whichever ones\nweren't implemented for the type of rebase specified.  Change this so the\nincompatibilities are documented, included in the testsuite, and tested\nfor at runtime with an appropriate error message shown.\n\nSome exceptions I left out:\n\n  * --merge and --interactive are technically incompatible since they are\n    supposed to run different underlying scripts, but with a few small\n    changes, --interactive can do everything that --merge can.  In fact,\n    I'll shortly be sending another patch to remove git-rebase--merge and\n    reimplement it on top of git-rebase--interactive.\n\n  * One could argue that --interactive and --quiet are incompatible since\n    --interactive doesn't implement a --quiet mode (perhaps since\n    cherry-pick itself does not implement one).  However, the interactive\n    mode is more quiet than the other modes in general with progress\n    messages, so one could argue that it's already quiet.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh                          | 35 ++++++++++++++++++++++++++\n t/t3422-rebase-incompatible-options.sh | 16 ++++++------\n 2 files changed, 43 insertions(+), 8 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex bf71b7fa20..18ac8226c4 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -503,6 +503,24 @@ then\n \tgit_format_patch_opt=\"$git_format_patch_opt --progress\"\n fi\n \n+if test -n \"$git_am_opt\"; then\n+\tincompatible_opts=$(echo \" $git_am_opt \" | \\\n+\t\t\t    sed -e 's/ -q / /g' -e 's/^ \\(.*\\) $/\\1/')\n+\tif test -n \"$interactive_rebase\"\n+\tthen\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+\tif test -n \"$do_merge\"; then\n+\t\tif test -n \"$incompatible_opts\"\n+\t\tthen\n+\t\t\tdie \"$(gettext \"error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)\")\"\n+\t\tfi\n+\tfi\n+fi\n+\n if test -n \"$signoff\"\n then\n \ttest -n \"$preserve_merges\" &&\n@@ -511,6 +529,23 @@ then\n \tforce_rebase=t\n fi\n \n+if test -n \"$preserve_merges\"\n+then\n+\t# Note: incompatibility with --signoff handled in signoff block above\n+\t# Note: incompatibility with --interactive is just a strong warning;\n+\t#       git-rebase.txt caveats with \"unless you know what you are doing\"\n+\ttest -n \"$rebase_merges\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--preserve_merges' with '--rebase-merges'\")\"\n+fi\n+\n+if test -n \"$rebase_merges\"\n+then\n+\ttest -n \"$strategy_opts\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy-option'\")\"\n+\ttest -n \"$strategy\" &&\n+\t\tdie \"$(gettext \"error: cannot combine '--rebase_merges' with '--strategy'\")\"\n+fi\n+\n if test -z \"$rebase_root\"\n then\n \tcase \"$#\" in\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nindex b007a15eba..bb78a6ec86 100755\n--- a/t/t3422-rebase-incompatible-options.sh\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -33,27 +33,27 @@ test_expect_success 'setup' '\n test_rebase_am_only () {\n \topt=$1\n \tshift\n-\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\ttest_expect_success \"$opt incompatible with --merge\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --merge A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --strategy-option=ours A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\ttest_expect_success \"$opt incompatible with --interactive\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --interactive A\n \t\"\n \n-\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\ttest_expect_success \"$opt incompatible with --exec\" \"\n \t\tgit checkout B^0 &&\n \t\ttest_must_fail git rebase $opt --exec 'true' A\n \t\"\n@@ -70,17 +70,17 @@ test_expect_success '--preserve-merges incompatible with --signoff' '\n \ttest_must_fail git rebase --preserve-merges --signoff A\n '\n \n-test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+test_expect_success '--preserve-merges incompatible with --rebase-merges' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --preserve-merges --rebase-merges A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy' '\n+test_expect_success '--rebase-merges incompatible with --strategy' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -s resolve A\n '\n \n-test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+test_expect_success '--rebase-merges incompatible with --strategy-option' '\n \tgit checkout B^0 &&\n \ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n '\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351072","messageId":"20180627072319.31356-6-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 5/9] git-rebase.txt: address confusion between --no-ff vs --force-rebase","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:15Z","receivedAt":"2018-06-27T07:24:03Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"rebase was taught the --force-rebase option in commit b2f82e05de (\"Teach\nrebase to rebase even if upstream is up to date\", 2009-02-13).  This flag\nworked for the am and merge backends, but wasn't a valid option for the\ninteractive backend.\n\nrebase was taught the --no-ff option for interactive rebases in commit\nb499549401cb (\"Teach rebase the --no-ff option.\", 2010-03-24), to do the\nexact same thing as --force-rebase does for non-interactive rebases.  This\ncommit explicitly documented the fact that --force-rebase was incompatible\nwith --interactive, though it made --no-ff a synonym for --force-rebase\nfor non-interactive rebases.  The choice of a new option was based on the\nfact that \"force rebase\" didn't sound like an appropriate term for the\ninteractive machinery.\n\nIn commit 6bb4e485cff8 (\"rebase: align variable names\", 2011-02-06), the\nseparate parsing of command line options in the different rebase scripts\nwas removed, and whether on accident or because the author noticed that\nthese options did the same thing, the options became synonyms and both\nwere accepted by all three rebase types.\n\nIn commit 2d26d533a012 (\"Documentation/git-rebase.txt: -f forces a rebase\nthat would otherwise be a no-op\", 2014-08-12), which reworded the\ndescription of the --force-rebase option, the (no-longer correct) sentence\nstating that --force-rebase was incompatible with --interactive was\nfinally removed.\n\nFinally, as explained at\nhttps://public-inbox.org/git/98279912-0f52-969d-44a6-22242039387f@xiplink.com\n\n    In the original discussion around this option [1], at one point I\n    proposed teaching rebase--interactive to respect --force-rebase\n    instead of adding a new option [2].  Ultimately --no-ff was chosen as\n    the better user interface design [3], because an interactive rebase\n    can't be \"forced\" to run.\n\nWe have accepted both --no-ff and --force-rebase as full synonyms for all\nthree rebase types for over seven years.  Documenting them differently\nand in ways that suggest they might not be quite synonyms simply leads to\nconfusion.  Adjust the documentation to match reality.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n Documentation/git-rebase.txt | 30 ++++++++++--------------------\n 1 file changed, 10 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex b2d95e3fb9..2f47495a4d 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -337,16 +337,18 @@ See also INCOMPATIBLE OPTIONS below.\n +\n See also INCOMPATIBLE OPTIONS below.\n \n--f::\n+--no-ff::\n --force-rebase::\n-\tForce a rebase even if the current branch is up to date and\n-\tthe command without `--force` would return without doing anything.\n+-f::\n+\tIndividually replay all rebased commits instead of fast-forwarding\n+\tover the unchanged ones.  This ensures that the entire history of\n+\tthe rebased branch is composed of new commits.\n +\n-You may find this (or --no-ff with an interactive rebase) helpful after\n-reverting a topic branch merge, as this option recreates the topic branch with\n-fresh commits so it can be remerged successfully without needing to \"revert\n-the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n+You may find this helpful after reverting a topic branch merge, as this option\n+recreates the topic branch with fresh commits so it can be remerged\n+successfully without needing to \"revert the reversion\" (see the\n+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for\n+details).\n \n --fork-point::\n --no-fork-point::\n@@ -498,18 +500,6 @@ See also INCOMPATIBLE OPTIONS below.\n \twith care: the final stash application after a successful\n \trebase might result in non-trivial conflicts.\n \n---no-ff::\n-\tWith --interactive, cherry-pick all rebased commits instead of\n-\tfast-forwarding over the unchanged ones.  This ensures that the\n-\tentire history of the rebased branch is composed of new commits.\n-+\n-Without --interactive, this is a synonym for --force-rebase.\n-+\n-You may find this helpful after reverting a topic branch merge, as this option\n-recreates the topic branch with fresh commits so it can be remerged\n-successfully without needing to \"revert the reversion\" (see the\n-link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).\n-\n INCOMPATIBLE OPTIONS\n --------------------\n \n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351073","messageId":"20180627072319.31356-4-newren@gmail.com","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"[PATCH v5 3/9] t3422: new testcases for checking when incompatible options passed","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:13Z","receivedAt":"2018-06-27T07:24:10Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git rebase is split into three types: am, merge, and interactive.  Various\noptions imply different types, and which mode we are using determine which\nsub-script (git-rebase--$type) is executed to finish the work.  Not all\noptions work with all types, so add tests for combinations where we expect\nto receive an error rather than having options be silently ignored.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3422-rebase-incompatible-options.sh | 88 ++++++++++++++++++++++++++\n 1 file changed, 88 insertions(+)\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\ndiff --git a/t/t3422-rebase-incompatible-options.sh b/t/t3422-rebase-incompatible-options.sh\nnew file mode 100755\nindex 0000000000..b007a15eba\n--- /dev/null\n+++ b/t/t3422-rebase-incompatible-options.sh\n@@ -0,0 +1,88 @@\n+#!/bin/sh\n+\n+test_description='test if rebase detects and aborts on incompatible options'\n+. ./test-lib.sh\n+\n+test_expect_success 'setup' '\n+\ttest_seq 2 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m orig &&\n+\n+\tgit branch A &&\n+\tgit branch B &&\n+\n+\tgit checkout A &&\n+\ttest_seq 1 9 >foo &&\n+\tgit add foo &&\n+\tgit commit -m A &&\n+\n+\tgit checkout B &&\n+\techo \"q qfoo();\" | q_to_tab >>foo &&\n+\tgit add foo &&\n+\tgit commit -m B\n+'\n+\n+#\n+# Rebase has lots of useful options like --whitepsace=fix, which are\n+# actually all built in terms of flags to git-am.  Since neither\n+# --merge nor --interactive (nor any options that imply those two) use\n+# git-am, using them together will result in flags like --whitespace=fix\n+# being ignored.  Make sure rebase warns the user and aborts instead.\n+#\n+\n+test_rebase_am_only () {\n+\topt=$1\n+\tshift\n+\ttest_expect_failure \"$opt incompatible with --merge\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --merge A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --strategy-option=ours A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --interactive A\n+\t\"\n+\n+\ttest_expect_failure \"$opt incompatible with --exec\" \"\n+\t\tgit checkout B^0 &&\n+\t\ttest_must_fail git rebase $opt --exec 'true' A\n+\t\"\n+\n+}\n+\n+test_rebase_am_only --whitespace=fix\n+test_rebase_am_only --ignore-whitespace\n+test_rebase_am_only --committer-date-is-author-date\n+test_rebase_am_only -C4\n+\n+test_expect_success '--preserve-merges incompatible with --signoff' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --signoff A\n+'\n+\n+test_expect_failure '--preserve-merges incompatible with --rebase-merges' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --preserve-merges --rebase-merges A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -s resolve A\n+'\n+\n+test_expect_failure '--rebase-merges incompatible with --strategy-option' '\n+\tgit checkout B^0 &&\n+\ttest_must_fail git rebase --rebase-merges -Xignore-space-change A\n+'\n+\n+test_done\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351074","messageId":"20180627072319.31356-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180625161300.26060-1-newren@gmail.com","subject":"[PATCH v5 0/9] Document/fix/warn about rebase incompatibilities and inconsistencies","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:23:10Z","receivedAt":"2018-06-27T07:24:14Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase has lots of options that are mutually incompatible.  Even among\naspects of its behavior that is common to all rebase types, it has a number\nof inconsistencies.  This series tries to document, fix, and/or warn users\nabout many of these.\n\nChanges since v4 (short branch-diff at the end):\n  - Fixed --strategy vs. --strategy-option (in patch 3, carries over to\n    context region in later commit)\n\nv4 didn't get a lot of feedback (though it was picked up by Junio), so I'll\nrepeat the areas that would be of most note for reviewers since v3:\n\n  * I have left patch 9 in RFC state; since v3 it has an expanded the\n    commit message with an in-depth usability rationale for the\n    change.\n  * It sounded like Junio was slightly unclear about the intent of the\n    wording in Patch 1.  Not sure if my answer (in email) was sufficient or\n    if there are wording improvements others might suggest.\n  * I'm assuming the --keep-empty and/or --empty={drop,halt,keep} (see\n    comments on patch 5 of v3) can be resolved in a later series.\n\nElijah Newren (9):\n  git-rebase.txt: document incompatible options\n  git-rebase.sh: update help messages a bit\n  t3422: new testcases for checking when incompatible options passed\n  git-rebase: error out when incompatible options passed\n  git-rebase.txt: address confusion between --no-ff vs --force-rebase\n  directory-rename-detection.txt: technical docs on abilities and\n    limitations\n  git-rebase.txt: document behavioral differences between modes\n  t3401: add directory rename testcases for rebase and am\n  git-rebase: make --allow-empty-message the default\n\n Documentation/git-rebase.txt                  | 135 ++++++++++++++----\n .../technical/directory-rename-detection.txt  | 115 +++++++++++++++\n git-rebase.sh                                 |  43 +++++-\n t/t3401-rebase-and-am-rename.sh               | 105 ++++++++++++++\n t/t3404-rebase-interactive.sh                 |   7 +-\n t/t3405-rebase-malformed.sh                   |  11 +-\n t/t3422-rebase-incompatible-options.sh        |  88 ++++++++++++\n 7 files changed, 462 insertions(+), 42 deletions(-)\n create mode 100644 Documentation/technical/directory-rename-detection.txt\n create mode 100755 t/t3401-rebase-and-am-rename.sh\n create mode 100755 t/t3422-rebase-incompatible-options.sh\n\n 1: 3f454ebc5e =  1: 3f454ebc5e git-rebase.txt: document incompatible options\n 2: 31a5a071a6 =  2: 31a5a071a6 git-rebase.sh: update help messages a bit\n 3: 5a2b5eec79 !  3: bc3a5a3f95 t3422: new testcases for checking when incompatible options passed\n    @@ -62,7 +62,7 @@\n     +\n     +\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n     +\t\tgit checkout B^0 &&\n    -+\t\ttest_must_fail git rebase $opt --strategy=ours A\n    ++\t\ttest_must_fail git rebase $opt --strategy-option=ours A\n     +\t\"\n     +\n     +\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n 4: 1e1c83724a !  4: ca3b8327f7 git-rebase: error out when incompatible options passed\n    @@ -104,7 +104,7 @@\n     -\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n     +\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n      \t\tgit checkout B^0 &&\n    - \t\ttest_must_fail git rebase $opt --strategy=ours A\n    + \t\ttest_must_fail git rebase $opt --strategy-option=ours A\n      \t\"\n      \n     -\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n 5: 51023269d3 =  5: 6ac359359e git-rebase.txt: address confusion between --no-ff vs --force-rebase\n 6: f017d45dd9 =  6: e5c5db9110 directory-rename-detection.txt: technical docs on abilities and limitations\n 7: 0a359df404 =  7: e330437305 git-rebase.txt: document behavioral differences between modes\n 8: beaadceaef =  8: f704f7eee8 t3401: add directory rename testcases for rebase and am\n 9: 431b2c36d5 =  9: 436f597487 git-rebase: make --allow-empty-message the default\n\n-- \n2.18.0.9.g431b2c36d5\n"},{"id":"351075","messageId":"20180627073623.31725-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180627073623.31725-1-newren@gmail.com","subject":"[PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:36:22Z","receivedAt":"2018-06-27T07:36:38Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"We are not passing the same args to merge strategies when we are doing an\n--interactive rebase as we do with a --merge rebase.  The merge strategy\nshould not need to be aware of which type of rebase is in effect.  Add a\ntestcase which checks for the appropriate args.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3418-rebase-continue.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 03bf1b8a3b..872022106f 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n+test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+\trm -fr .git/rebase-* &&\n+\tgit reset --hard commit-new-file-F2-on-topic-branch &&\n+\ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n+\ttest_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n+\tmkdir test-bin &&\n+\tcat >test-bin/git-merge-funny <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$@\" >>funny.args\n+\tcase \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n+\tcase \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n+\tcase \"\\$4\" in --) ;; *) exit 2 ;; esac\n+\tshift 2 &&\n+\t>funny.was.run &&\n+\texec git merge-recursive \"\\$@\"\n+\tEOF\n+\tchmod +x test-bin/git-merge-funny &&\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n+\t) &&\n+\ttest -f funny.was.run &&\n+\trm funny.was.run &&\n+\techo \"Resolved\" >F2 &&\n+\tgit add F2 &&\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\tgit rebase --continue\n+\t) &&\n+\ttest -f funny.was.run\n+'\n+\n test_expect_success 'rebase passes merge strategy options correctly' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F3-on-topic-branch &&\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351076","messageId":"20180627073623.31725-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180627073623.31725-1-newren@gmail.com","subject":"[PATCH v2 2/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:36:23Z","receivedAt":"2018-06-27T07:36:41Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase.sh wrote strategy options to .git/rebase/merge/strategy_opts\nin the following format:\n  '--ours'  '--renormalize'\nNote the double spaces.\n\ngit-rebase--interactive uses sequencer.c to parse that file, and\nsequencer.c used split_cmdline() to get the individual strategy options.\nAfter splitting, sequencer.c prefixed each \"option\" with a double dash,\nso, concatenating all its options would result in:\n  -- --ours -- --renormalize\n\nSo, when it ended up calling try_merge_strategy(), that in turn would run\n  git merge-$strategy -- --ours -- --renormalize $merge_base -- $head $remote\n\ninstead of the expected/desired\n  git merge-$strategy --ours --renormalize $merge_base -- $head $remote\n\nRemove the extra spaces so that when it goes through split_cmdline() we end\nup with the desired command line.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh              | 2 +-\n sequencer.c                | 7 ++++++-\n t/t3418-rebase-continue.sh | 2 +-\n 3 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 19bdebb480..f3b10c7f62 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -328,7 +328,7 @@ do\n \t\tdo_merge=t\n \t\t;;\n \t--strategy-option=*)\n-\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n+\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n \t\tdo_merge=t\n \t\ttest -z \"$strategy\" && strategy=recursive\n \t\t;;\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51e..ef9237c814 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2206,6 +2206,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n {\n \tint i;\n+\tchar *strategy_opts_string;\n \n \tstrbuf_reset(buf);\n \tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n@@ -2214,7 +2215,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n \t\treturn;\n \n-\topts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);\n+\tstrategy_opts_string = buf->buf;\n+\tif (*strategy_opts_string == ' ')\n+\t\tstrategy_opts_string++;\n+\topts->xopts_nr = split_cmdline(strategy_opts_string,\n+\t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n \t\tconst char *arg = opts->xopts[i];\n \ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 872022106f..7ca6cbc415 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,7 +74,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n-test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+test_expect_success 'rebase -i --continue handles merge strategy and options' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F2-on-topic-branch &&\n \ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351077","messageId":"20180627073623.31725-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180607050845.19779-1-newren@gmail.com","subject":"[PATCH v2 0/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:36:21Z","receivedAt":"2018-06-27T07:36:44Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"The interactive machinery for git rebase can accept special merge\nstrategies or strategy options, but has a bug in its handling of\nstrategy options.  This short series patches that.\n\nChanges since v1:\n  - Small change to the second commit message\n  - Addition of a cover letter.  :-)\n\nElijah Newren (2):\n  t3418: add testcase showing problems with rebase -i and strategy\n    options\n  Fix use of strategy options with interactive rebases\n\n git-rebase.sh              |  2 +-\n sequencer.c                |  7 ++++++-\n t/t3418-rebase-continue.sh | 32 ++++++++++++++++++++++++++++++++\n 3 files changed, 39 insertions(+), 2 deletions(-)\n\n 1: 68cad084cf =  1: 43b9ac5a63 t3418: add testcase showing problems with rebase -i and strategy options\n 2: 8eda0e7c1e !  2: d345eb96d5 Fix use of strategy options with interactive rebases\n    @@ -2,9 +2,10 @@\n     \n         Fix use of strategy options with interactive rebases\n     \n    -    git-rebase.sh wrote stuff like\n    +    git-rebase.sh wrote strategy options to .git/rebase/merge/strategy_opts\n    +    in the following format:\n           '--ours'  '--renormalize'\n    -    to .git/rebase-merge/strategy_opts.  Note the double spaces.\n    +    Note the double spaces.\n     \n         git-rebase--interactive uses sequencer.c to parse that file, and\n         sequencer.c used split_cmdline() to get the individual strategy options.\n    @@ -15,10 +16,11 @@\n         So, when it ended up calling try_merge_strategy(), that in turn would run\n           git merge-$strategy -- --ours -- --renormalize $merge_base -- $head $remote\n     \n    -    instead of the expected\n    +    instead of the expected/desired\n           git merge-$strategy --ours --renormalize $merge_base -- $head $remote\n     \n    -    Remove the extra spaces so that split_cmdline() will work as expected.\n    +    Remove the extra spaces so that when it goes through split_cmdline() we end\n    +    up with the desired command line.\n     \n         Signed-off-by: Elijah Newren <newren@gmail.com>\n     \n-- \n2.18.0.9.g431b2c36d5\n"},{"id":"351078","messageId":"CAPig+cTwwuqPgF2NtGRgpcdjFqJK22+FFDV2c-20oQXFLEPaWQ@mail.gmail.com","threadId":"48665","inReplyTo":"20180627073623.31725-2-newren@gmail.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-06-27T07:45:37Z","receivedAt":"2018-06-27T07:45:51Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jun 27, 2018 at 3:36 AM Elijah Newren <newren@gmail.com> wrote:\n> We are not passing the same args to merge strategies when we are doing an\n> --interactive rebase as we do with a --merge rebase.  The merge strategy\n> should not need to be aware of which type of rebase is in effect.  Add a\n> testcase which checks for the appropriate args.\n>\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n> diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n> @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n> +test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n> +       rm -fr .git/rebase-* &&\n> +       git reset --hard commit-new-file-F2-on-topic-branch &&\n> +       test_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n> +       test_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n> +       mkdir test-bin &&\n> +       cat >test-bin/git-merge-funny <<-EOF &&\n> +       #!$SHELL_PATH\n> +       echo \"\\$@\" >>funny.args\n> +       case \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n> +       case \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n> +       case \"\\$4\" in --) ;; *) exit 2 ;; esac\n> +       shift 2 &&\n> +       >funny.was.run &&\n> +       exec git merge-recursive \"\\$@\"\n> +       EOF\n> +       chmod +x test-bin/git-merge-funny &&\n> +       (\n> +               PATH=./test-bin:$PATH\n\nBroken &&-chain (in subshell).\n\n> +               test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n> +       ) &&\n> +       test -f funny.was.run &&\n> +       rm funny.was.run &&\n> +       echo \"Resolved\" >F2 &&\n> +       git add F2 &&\n> +       (\n> +               PATH=./test-bin:$PATH\n\nDitto.\n\n> +               git rebase --continue\n> +       ) &&\n> +       test -f funny.was.run\n> +'\n"},{"id":"351079","messageId":"20180627074600.32149-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180607050615.19598-1-newren@gmail.com","subject":"[PATCH v2] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:46:00Z","receivedAt":"2018-06-27T07:46:11Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Signed-off-by: Elijah Newren <newren@gmail.com>\n---\n\nChanges since v1:\n  - Fixed up commit message (move below comment to below diffstat as\n    originally intended)\n\nLong term I just want to make git-rebase--merge go away, so this patch\nwill eventually be obsoleted.  But since I'm waiting for multiple\ntopics to merge down before re-submitting that series, and since that\nseries has some open questions as well, I figure it's worth\n(re-)submitting this simple fix in the mean time.\n\n git-rebase--merge.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--merge.sh b/git-rebase--merge.sh\nindex cf4c042214..aa2f2f0872 100644\n--- a/git-rebase--merge.sh\n+++ b/git-rebase--merge.sh\n@@ -71,7 +71,7 @@ call_merge () {\n \ttest -z \"$strategy\" && strategy=recursive\n \t# If cmt doesn't have a parent, don't include it as a base\n \tbase=$(git rev-parse --verify --quiet $cmt^)\n-\teval 'git-merge-$strategy' $strategy_opts $base ' -- \"$hd\" \"$cmt\"'\n+\teval 'git merge-$strategy' $strategy_opts $base ' -- \"$hd\" \"$cmt\"'\n \trv=$?\n \tcase \"$rv\" in\n \t0)\n@@ -88,7 +88,7 @@ call_merge () {\n \t\t;;\n \t*)\n \t\tdie \"Unknown exit code ($rv) from command:\" \\\n-\t\t\t\"git-merge-$strategy $cmt^ -- HEAD $cmt\"\n+\t\t\t\"git merge-$strategy $cmt^ -- HEAD $cmt\"\n \t\t;;\n \tesac\n }\n-- \n2.18.0.9.g431b2c36d5\n"},{"id":"351080","messageId":"CABPp-BFkjF5z6axqW-v=zPq9U9sOQGpUKK+WvLknkkGzX-F4rA@mail.gmail.com","threadId":"48665","inReplyTo":"CAPig+cTwwuqPgF2NtGRgpcdjFqJK22+FFDV2c-20oQXFLEPaWQ@mail.gmail.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T07:49:22Z","receivedAt":"2018-06-27T07:49:26Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 27, 2018 at 12:45 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Wed, Jun 27, 2018 at 3:36 AM Elijah Newren <newren@gmail.com> wrote:\n>> We are not passing the same args to merge strategies when we are doing an\n>> --interactive rebase as we do with a --merge rebase.  The merge strategy\n>> should not need to be aware of which type of rebase is in effect.  Add a\n>> testcase which checks for the appropriate args.\n>>\n>> Signed-off-by: Elijah Newren <newren@gmail.com>\n>> ---\n>> diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n>> @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n>> +test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n>> +       rm -fr .git/rebase-* &&\n>> +       git reset --hard commit-new-file-F2-on-topic-branch &&\n>> +       test_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n>> +       test_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n>> +       mkdir test-bin &&\n>> +       cat >test-bin/git-merge-funny <<-EOF &&\n>> +       #!$SHELL_PATH\n>> +       echo \"\\$@\" >>funny.args\n>> +       case \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n>> +       case \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n>> +       case \"\\$4\" in --) ;; *) exit 2 ;; esac\n>> +       shift 2 &&\n>> +       >funny.was.run &&\n>> +       exec git merge-recursive \"\\$@\"\n>> +       EOF\n>> +       chmod +x test-bin/git-merge-funny &&\n>> +       (\n>> +               PATH=./test-bin:$PATH\n>\n> Broken &&-chain (in subshell).\n>\n>> +               test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n>> +       ) &&\n>> +       test -f funny.was.run &&\n>> +       rm funny.was.run &&\n>> +       echo \"Resolved\" >F2 &&\n>> +       git add F2 &&\n>> +       (\n>> +               PATH=./test-bin:$PATH\n>\n> Ditto.\n>\n\nI'm just trying to prove how important your other patch series is.  ;-)\n\nDoh, sorry for the mistake.  Again.  I'll fix it up.\n"},{"id":"351114","messageId":"20180627154804.3743-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180627073623.31725-1-newren@gmail.com","subject":"[PATCH v3 0/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T15:48:02Z","receivedAt":"2018-06-27T15:48:28Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"The interactive machinery for git rebase can accept special merge\nstrategies or strategy options, but has a bug in its handling of\nstrategy options.  This short series patches that.\n\nChanges since v2:\n  - Fix broken &&-chaining (Thanks to Eric for spotting)\n\nElijah Newren (2):\n  t3418: add testcase showing problems with rebase -i and strategy\n    options\n  Fix use of strategy options with interactive rebases\n\n git-rebase.sh              |  2 +-\n sequencer.c                |  7 ++++++-\n t/t3418-rebase-continue.sh | 32 ++++++++++++++++++++++++++++++++\n 3 files changed, 39 insertions(+), 2 deletions(-)\n\n 1: 43b9ac5a63 !  1: f8a5df9ef1 t3418: add testcase showing problems with rebase -i and strategy options\n    @@ -34,7 +34,7 @@\n     +\tEOF\n     +\tchmod +x test-bin/git-merge-funny &&\n     +\t(\n    -+\t\tPATH=./test-bin:$PATH\n    ++\t\tPATH=./test-bin:$PATH &&\n     +\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n     +\t) &&\n     +\ttest -f funny.was.run &&\n    @@ -42,7 +42,7 @@\n     +\techo \"Resolved\" >F2 &&\n     +\tgit add F2 &&\n     +\t(\n    -+\t\tPATH=./test-bin:$PATH\n    ++\t\tPATH=./test-bin:$PATH &&\n     +\t\tgit rebase --continue\n     +\t) &&\n     +\ttest -f funny.was.run\n 2: d345eb96d5 =  2: b7e4971e66 Fix use of strategy options with interactive rebases\n\n-- \n2.18.0.9.g431b2c36d5\n"},{"id":"351115","messageId":"20180627154804.3743-3-newren@gmail.com","threadId":"48665","inReplyTo":"20180627154804.3743-1-newren@gmail.com","subject":"[PATCH v3 2/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T15:48:04Z","receivedAt":"2018-06-27T15:48:30Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"git-rebase.sh wrote strategy options to .git/rebase/merge/strategy_opts\nin the following format:\n  '--ours'  '--renormalize'\nNote the double spaces.\n\ngit-rebase--interactive uses sequencer.c to parse that file, and\nsequencer.c used split_cmdline() to get the individual strategy options.\nAfter splitting, sequencer.c prefixed each \"option\" with a double dash,\nso, concatenating all its options would result in:\n  -- --ours -- --renormalize\n\nSo, when it ended up calling try_merge_strategy(), that in turn would run\n  git merge-$strategy -- --ours -- --renormalize $merge_base -- $head $remote\n\ninstead of the expected/desired\n  git merge-$strategy --ours --renormalize $merge_base -- $head $remote\n\nRemove the extra spaces so that when it goes through split_cmdline() we end\nup with the desired command line.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh              | 2 +-\n sequencer.c                | 7 ++++++-\n t/t3418-rebase-continue.sh | 2 +-\n 3 files changed, 8 insertions(+), 3 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 19bdebb480..f3b10c7f62 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -328,7 +328,7 @@ do\n \t\tdo_merge=t\n \t\t;;\n \t--strategy-option=*)\n-\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n+\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n \t\tdo_merge=t\n \t\ttest -z \"$strategy\" && strategy=recursive\n \t\t;;\ndiff --git a/sequencer.c b/sequencer.c\nindex 5354d4d51e..ef9237c814 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2206,6 +2206,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n {\n \tint i;\n+\tchar *strategy_opts_string;\n \n \tstrbuf_reset(buf);\n \tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n@@ -2214,7 +2215,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n \t\treturn;\n \n-\topts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);\n+\tstrategy_opts_string = buf->buf;\n+\tif (*strategy_opts_string == ' ')\n+\t\tstrategy_opts_string++;\n+\topts->xopts_nr = split_cmdline(strategy_opts_string,\n+\t\t\t\t       (const char ***)&opts->xopts);\n \tfor (i = 0; i < opts->xopts_nr; i++) {\n \t\tconst char *arg = opts->xopts[i];\n \ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 11546d6e14..c145dbac38 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,7 +74,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n-test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+test_expect_success 'rebase -i --continue handles merge strategy and options' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F2-on-topic-branch &&\n \ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351116","messageId":"20180627154804.3743-2-newren@gmail.com","threadId":"48665","inReplyTo":"20180627154804.3743-1-newren@gmail.com","subject":"[PATCH v3 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T15:48:03Z","receivedAt":"2018-06-27T15:48:32Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"We are not passing the same args to merge strategies when we are doing an\n--interactive rebase as we do with a --merge rebase.  The merge strategy\nshould not need to be aware of which type of rebase is in effect.  Add a\ntestcase which checks for the appropriate args.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n t/t3418-rebase-continue.sh | 32 ++++++++++++++++++++++++++++++++\n 1 file changed, 32 insertions(+)\n\ndiff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\nindex 03bf1b8a3b..11546d6e14 100755\n--- a/t/t3418-rebase-continue.sh\n+++ b/t/t3418-rebase-continue.sh\n@@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n \ttest -f funny.was.run\n '\n \n+test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n+\trm -fr .git/rebase-* &&\n+\tgit reset --hard commit-new-file-F2-on-topic-branch &&\n+\ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n+\ttest_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n+\tmkdir test-bin &&\n+\tcat >test-bin/git-merge-funny <<-EOF &&\n+\t#!$SHELL_PATH\n+\techo \"\\$@\" >>funny.args\n+\tcase \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n+\tcase \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n+\tcase \"\\$4\" in --) ;; *) exit 2 ;; esac\n+\tshift 2 &&\n+\t>funny.was.run &&\n+\texec git merge-recursive \"\\$@\"\n+\tEOF\n+\tchmod +x test-bin/git-merge-funny &&\n+\t(\n+\t\tPATH=./test-bin:$PATH &&\n+\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n+\t) &&\n+\ttest -f funny.was.run &&\n+\trm funny.was.run &&\n+\techo \"Resolved\" >F2 &&\n+\tgit add F2 &&\n+\t(\n+\t\tPATH=./test-bin:$PATH &&\n+\t\tgit rebase --continue\n+\t) &&\n+\ttest -f funny.was.run\n+'\n+\n test_expect_success 'rebase passes merge strategy options correctly' '\n \trm -fr .git/rebase-* &&\n \tgit reset --hard commit-new-file-F3-on-topic-branch &&\n-- \n2.18.0.9.g431b2c36d5\n\n"},{"id":"351121","messageId":"xmqqh8logofg.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"CABPp-BFkjF5z6axqW-v=zPq9U9sOQGpUKK+WvLknkkGzX-F4rA@mail.gmail.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-27T16:54:43Z","receivedAt":"2018-06-27T16:54:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n>>> +       chmod +x test-bin/git-merge-funny &&\n>>> +       (\n>>> +               PATH=./test-bin:$PATH\n>>\n>> Broken &&-chain (in subshell).\n>>\n>>> +               test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n>>> +       ) &&\n>>> +       test -f funny.was.run &&\n>>> +       rm funny.was.run &&\n>>> +       echo \"Resolved\" >F2 &&\n>>> +       git add F2 &&\n>>> +       (\n>>> +               PATH=./test-bin:$PATH\n>>\n>> Ditto.\n>>\n>\n> I'm just trying to prove how important your other patch series is.  ;-)\n\nActually, this shows why the other patch series, especially its last\nstep, is problematic a bit.  The above assignments are followed by a\nsingle command, i.e.\n\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n+\t) &&\n\n+\t(\n+\t\tPATH=./test-bin:$PATH\n+\t\tgit rebase --continue\n+\t) &&\n\nand it would be reasonable to assume that these variable assignments\nwould not fail.  IOW, there is no BUG in breaking &&-chain at these\ntwo places.  It is merely that the automated mechanism introduced by\nstep 29/29 of that other series does not understand that (which is\nexpected).  It is not wrong to have && at the end of the assignment,\nthough.\n\nHaving said that, it would be simpler for at least the latter to\nwrite it using a single-shot environment assignment, perhaps?  I.e.\n\n\tPATH=./test-bin:$PATH git rebase --continue &&\n\nwithout running in a subshell?\n"},{"id":"351124","messageId":"CABPp-BEYbC0C+bczQuNTcC_jxVM59czh7HTpqi9dv09fvCjMrA@mail.gmail.com","threadId":"48665","inReplyTo":"xmqqh8logofg.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-06-27T17:27:56Z","receivedAt":"2018-06-27T17:28:00Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, Jun 27, 2018 at 9:54 AM, Junio C Hamano <gitster@pobox.com> wrote:\n\n> +       (\n> +               PATH=./test-bin:$PATH\n> +               test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n> +       ) &&\n>\n> +       (\n> +               PATH=./test-bin:$PATH\n> +               git rebase --continue\n> +       ) &&\n>\n> and it would be reasonable to assume that these variable assignments\n> would not fail.  IOW, there is no BUG in breaking &&-chain at these\n> two places.  It is merely that the automated mechanism introduced by\n> step 29/29 of that other series does not understand that (which is\n> expected).  It is not wrong to have && at the end of the assignment,\n> though.\n>\n> Having said that, it would be simpler for at least the latter to\n> write it using a single-shot environment assignment, perhaps?  I.e.\n>\n>         PATH=./test-bin:$PATH git rebase --continue &&\n>\n> without running in a subshell?\n\nSeems reasonable.  Since these tests were essentially copies of other\ntests within the same file, just for rebase -i instead of -m, should I\nalso add another patch to the series fixing up the rebase -m testcase\nto also replace the subshell with a single-shot environment\nassignment?\n"},{"id":"351139","messageId":"eb66b6da-a306-3f65-abf3-9b845fba32cd@kdbg.org","threadId":"48665","inReplyTo":"CABPp-BEYbC0C+bczQuNTcC_jxVM59czh7HTpqi9dv09fvCjMrA@mail.gmail.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2018-06-27T18:17:41Z","receivedAt":"2018-06-27T18:17:47Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 27.06.2018 um 19:27 schrieb Elijah Newren:\n> On Wed, Jun 27, 2018 at 9:54 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Having said that, it would be simpler for at least the latter to\n>> write it using a single-shot environment assignment, perhaps?  I.e.\n>>\n>>          PATH=./test-bin:$PATH git rebase --continue &&\n>>\n>> without running in a subshell?\n> \n> Seems reasonable.  Since these tests were essentially copies of other\n> tests within the same file, just for rebase -i instead of -m, should I\n> also add another patch to the series fixing up the rebase -m testcase\n> to also replace the subshell with a single-shot environment\n> assignment?\n\nPitfalls ahead!\n\n\tPATH=... git rebase ...\n\nis OK, but\n\n\tPATH=... test_must_fail git rebase ...\n\nis not; the latter requires the subshell, otherwise the modified PATH \nvariable survives the command because test_must_fail is a shell \nfunction. Yes, it's silly, but that's how it is.\n\n-- Hannes\n"},{"id":"351142","messageId":"CAPig+cRckrRSp6Wg7vWXuOWUTW8rChFpVM9Px06u+Kb_p1-8-w@mail.gmail.com","threadId":"48665","inReplyTo":"eb66b6da-a306-3f65-abf3-9b845fba32cd@kdbg.org","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-06-27T18:24:29Z","receivedAt":"2018-06-27T18:24:44Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Wed, Jun 27, 2018 at 2:17 PM Johannes Sixt <j6t@kdbg.org> wrote:\n> Pitfalls ahead!\n>\n>         PATH=... git rebase ...\n>\n> is OK, but\n>\n>         PATH=... test_must_fail git rebase ...\n>\n> is not; the latter requires the subshell, otherwise the modified PATH\n> variable survives the command because test_must_fail is a shell\n> function. Yes, it's silly, but that's how it is.\n\nAs an alternative to the subshell, some test use 'env':\n\n    test_must_fail env PATH=... git rebase ...\n"},{"id":"351144","messageId":"20180627182805.28375-1-szeder.dev@gmail.com","threadId":"48665","inReplyTo":"20180627154804.3743-2-newren@gmail.com","subject":"Re: [PATCH v3 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-06-27T18:28:05Z","receivedAt":"2018-06-27T18:28:18Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n> index 03bf1b8a3b..11546d6e14 100755\n> --- a/t/t3418-rebase-continue.sh\n> +++ b/t/t3418-rebase-continue.sh\n> @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n>  \ttest -f funny.was.run\n>  '\n>  \n> +test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n> +\trm -fr .git/rebase-* &&\n> +\tgit reset --hard commit-new-file-F2-on-topic-branch &&\n> +\ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n> +\ttest_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n> +\tmkdir test-bin &&\n> +\tcat >test-bin/git-merge-funny <<-EOF &&\n> +\t#!$SHELL_PATH\n> +\techo \"\\$@\" >>funny.args\n> +\tcase \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n> +\tcase \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n> +\tcase \"\\$4\" in --) ;; *) exit 2 ;; esac\n> +\tshift 2 &&\n> +\t>funny.was.run &&\n> +\texec git merge-recursive \"\\$@\"\n> +\tEOF\n> +\tchmod +x test-bin/git-merge-funny &&\n\nYou could use the 'write_script' helper function here.\n\n> +\t(\n> +\t\tPATH=./test-bin:$PATH &&\n> +\t\ttest_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n> +\t) &&\n> +\ttest -f funny.was.run &&\n> +\trm funny.was.run &&\n> +\techo \"Resolved\" >F2 &&\n> +\tgit add F2 &&\n> +\t(\n> +\t\tPATH=./test-bin:$PATH &&\n> +\t\tgit rebase --continue\n> +\t) &&\n> +\ttest -f funny.was.run\n> +'\n> +\n>  test_expect_success 'rebase passes merge strategy options correctly' '\n>  \trm -fr .git/rebase-* &&\n>  \tgit reset --hard commit-new-file-F3-on-topic-branch &&\n> -- \n> 2.18.0.9.g431b2c36d5\n> \n> \n"},{"id":"351146","messageId":"20180627183445.28625-1-szeder.dev@gmail.com","threadId":"48665","inReplyTo":"eb66b6da-a306-3f65-abf3-9b845fba32cd@kdbg.org","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-06-27T18:34:45Z","receivedAt":"2018-06-27T18:35:07Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> Am 27.06.2018 um 19:27 schrieb Elijah Newren:\n> > On Wed, Jun 27, 2018 at 9:54 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> >> Having said that, it would be simpler for at least the latter to\n> >> write it using a single-shot environment assignment, perhaps?  I.e.\n> >>\n> >>          PATH=./test-bin:$PATH git rebase --continue &&\n> >>\n> >> without running in a subshell?\n> > \n> > Seems reasonable.  Since these tests were essentially copies of other\n> > tests within the same file, just for rebase -i instead of -m, should I\n> > also add another patch to the series fixing up the rebase -m testcase\n> > to also replace the subshell with a single-shot environment\n> > assignment?\n> \n> Pitfalls ahead!\n> \n> \tPATH=... git rebase ...\n> \n> is OK, but\n> \n> \tPATH=... test_must_fail git rebase ...\n> \n> is not; the latter requires the subshell, otherwise the modified PATH \n> variable survives the command because test_must_fail is a shell \n> function. Yes, it's silly, but that's how it is.\n\nWe have the 'test_env' helper function for this case:\n\n  test_env PATH=./test-bin:$PATH test_must_fail git rebase --opts\n\n"},{"id":"351155","messageId":"xmqqr2ksdojh.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"eb66b6da-a306-3f65-abf3-9b845fba32cd@kdbg.org","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-27T19:20:34Z","receivedAt":"2018-06-27T19:20:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n> Pitfalls ahead!\n\nThanks.  I said \"at least the latter\" for this exact reason ;-).\n\n> \tPATH=... git rebase ...\n>\n> is OK, but\n>\n> \tPATH=... test_must_fail git rebase ...\n>\n> is not; the latter requires the subshell, otherwise the modified PATH\n> variable survives the command because test_must_fail is a shell\n> function. Yes, it's silly, but that's how it is.\n\nOr you could do\n\n\ttest_must_fail env VAR=VAL git rebase ...\n\nwhich I am not particularly fond of, but seems to be used quite\noften.\n"},{"id":"351156","messageId":"xmqqmuvgdods.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"CABPp-BEYbC0C+bczQuNTcC_jxVM59czh7HTpqi9dv09fvCjMrA@mail.gmail.com","subject":"Re: [PATCH v2 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-06-27T19:23:59Z","receivedAt":"2018-06-27T19:24:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> Seems reasonable.  Since these tests were essentially copies of other\n> tests within the same file, just for rebase -i instead of -m, should I\n> also add another patch to the series fixing up the rebase -m testcase\n> to also replace the subshell with a single-shot environment\n> assignment?\n\nI personally would think it would be best to leave that to a later\nday, and take your v3 that properly &&-chains these two assignments.\n\nIt may be a good clean-up, but is an overkill if done as a\npreparatory clean-up in the context of these two small fixes.\n\n"},{"id":"351333","messageId":"0ec512fd-eaff-21c6-17c0-31c02cd1c7a3@talktalk.net","threadId":"48665","inReplyTo":"20180627072319.31356-1-newren@gmail.com","subject":"Re: [PATCH v5 0/9] Document/fix/warn about rebase incompatibilities and inconsistencies","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-06-29T13:20:00Z","receivedAt":"2018-06-29T13:20:09Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Elijah\n\nOn 27/06/18 08:23, Elijah Newren wrote:\n> git-rebase has lots of options that are mutually incompatible.  Even among\n> aspects of its behavior that is common to all rebase types, it has a number\n> of inconsistencies.  This series tries to document, fix, and/or warn users\n> about many of these.\n> \n> Changes since v4 (short branch-diff at the end):\n>   - Fixed --strategy vs. --strategy-option (in patch 3, carries over to\n>     context region in later commit)\n> \n> v4 didn't get a lot of feedback (though it was picked up by Junio), so I'll\n> repeat the areas that would be of most note for reviewers since v3:\n> \n>   * I have left patch 9 in RFC state; since v3 it has an expanded the\n>     commit message with an in-depth usability rationale for the\n>     change.\n>   * It sounded like Junio was slightly unclear about the intent of the\n>     wording in Patch 1.  Not sure if my answer (in email) was sufficient or\n>     if there are wording improvements others might suggest.\n>   * I'm assuming the --keep-empty and/or --empty={drop,halt,keep} (see\n>     comments on patch 5 of v3) can be resolved in a later series.\n\nI'm sorry I've not got round to looking at the last couple of versions.\nUnfortunately I'm about to go off-line for a couple of weeks so I just\nwanted to let you know I wasn't ignoring you!. If they haven't been\nmerged when I get back on-line I'll have a look then\n\nBest Wishes\n\nPhillip\n\n> Elijah Newren (9):\n>   git-rebase.txt: document incompatible options\n>   git-rebase.sh: update help messages a bit\n>   t3422: new testcases for checking when incompatible options passed\n>   git-rebase: error out when incompatible options passed\n>   git-rebase.txt: address confusion between --no-ff vs --force-rebase\n>   directory-rename-detection.txt: technical docs on abilities and\n>     limitations\n>   git-rebase.txt: document behavioral differences between modes\n>   t3401: add directory rename testcases for rebase and am\n>   git-rebase: make --allow-empty-message the default\n> \n>  Documentation/git-rebase.txt                  | 135 ++++++++++++++----\n>  .../technical/directory-rename-detection.txt  | 115 +++++++++++++++\n>  git-rebase.sh                                 |  43 +++++-\n>  t/t3401-rebase-and-am-rename.sh               | 105 ++++++++++++++\n>  t/t3404-rebase-interactive.sh                 |   7 +-\n>  t/t3405-rebase-malformed.sh                   |  11 +-\n>  t/t3422-rebase-incompatible-options.sh        |  88 ++++++++++++\n>  7 files changed, 462 insertions(+), 42 deletions(-)\n>  create mode 100644 Documentation/technical/directory-rename-detection.txt\n>  create mode 100755 t/t3401-rebase-and-am-rename.sh\n>  create mode 100755 t/t3422-rebase-incompatible-options.sh\n> \n>  1: 3f454ebc5e =  1: 3f454ebc5e git-rebase.txt: document incompatible options\n>  2: 31a5a071a6 =  2: 31a5a071a6 git-rebase.sh: update help messages a bit\n>  3: 5a2b5eec79 !  3: bc3a5a3f95 t3422: new testcases for checking when incompatible options passed\n>     @@ -62,7 +62,7 @@\n>      +\n>      +\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n>      +\t\tgit checkout B^0 &&\n>     -+\t\ttest_must_fail git rebase $opt --strategy=ours A\n>     ++\t\ttest_must_fail git rebase $opt --strategy-option=ours A\n>      +\t\"\n>      +\n>      +\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n>  4: 1e1c83724a !  4: ca3b8327f7 git-rebase: error out when incompatible options passed\n>     @@ -104,7 +104,7 @@\n>      -\ttest_expect_failure \"$opt incompatible with --strategy-option=ours\" \"\n>      +\ttest_expect_success \"$opt incompatible with --strategy-option=ours\" \"\n>       \t\tgit checkout B^0 &&\n>     - \t\ttest_must_fail git rebase $opt --strategy=ours A\n>     + \t\ttest_must_fail git rebase $opt --strategy-option=ours A\n>       \t\"\n>       \n>      -\ttest_expect_failure \"$opt incompatible with --interactive\" \"\n>  5: 51023269d3 =  5: 6ac359359e git-rebase.txt: address confusion between --no-ff vs --force-rebase\n>  6: f017d45dd9 =  6: e5c5db9110 directory-rename-detection.txt: technical docs on abilities and limitations\n>  7: 0a359df404 =  7: e330437305 git-rebase.txt: document behavioral differences between modes\n>  8: beaadceaef =  8: f704f7eee8 t3401: add directory rename testcases for rebase and am\n>  9: 431b2c36d5 =  9: 436f597487 git-rebase: make --allow-empty-message the default\n> \n\n"},{"id":"352228","messageId":"CAM0VKj=rGHm3V_z4S6NNP2-fjyfrgrLz-bWrZ8t0gcVD-gTq_w@mail.gmail.com","threadId":"48665","inReplyTo":"20180627182805.28375-1-szeder.dev@gmail.com","subject":"Re: [PATCH v3 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-07-11T10:56:44Z","receivedAt":"2018-07-11T10:56:59Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Wed, Jun 27, 2018 at 8:28 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>\n> > diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n> > index 03bf1b8a3b..11546d6e14 100755\n> > --- a/t/t3418-rebase-continue.sh\n> > +++ b/t/t3418-rebase-continue.sh\n> > @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n> >       test -f funny.was.run\n> >  '\n> >\n> > +test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n> > +     rm -fr .git/rebase-* &&\n> > +     git reset --hard commit-new-file-F2-on-topic-branch &&\n> > +     test_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n> > +     test_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n> > +     mkdir test-bin &&\n> > +     cat >test-bin/git-merge-funny <<-EOF &&\n> > +     #!$SHELL_PATH\n> > +     echo \"\\$@\" >>funny.args\n> > +     case \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n> > +     case \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n> > +     case \"\\$4\" in --) ;; *) exit 2 ;; esac\n> > +     shift 2 &&\n> > +     >funny.was.run &&\n> > +     exec git merge-recursive \"\\$@\"\n> > +     EOF\n> > +     chmod +x test-bin/git-merge-funny &&\n>\n> You could use the 'write_script' helper function here.\n>\n> > +     (\n> > +             PATH=./test-bin:$PATH &&\n> > +             test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n> > +     ) &&\n> > +     test -f funny.was.run &&\n\nAnd please use 'test_path_is_file' here ...\n\n> > +     rm funny.was.run &&\n> > +     echo \"Resolved\" >F2 &&\n> > +     git add F2 &&\n> > +     (\n> > +             PATH=./test-bin:$PATH &&\n> > +             git rebase --continue\n> > +     ) &&\n> > +     test -f funny.was.run\n\n... and here.\n\n> > +'\n> > +\n> >  test_expect_success 'rebase passes merge strategy options correctly' '\n> >       rm -fr .git/rebase-* &&\n> >       git reset --hard commit-new-file-F3-on-topic-branch &&\n> > --\n> > 2.18.0.9.g431b2c36d5\n> >\n> >\n"},{"id":"352289","messageId":"CABPp-BF_HDW-ie1ZaTrnniWuE7FxThiukk0xJ7P5rfUiwXBGug@mail.gmail.com","threadId":"48665","inReplyTo":"CAM0VKj=rGHm3V_z4S6NNP2-fjyfrgrLz-bWrZ8t0gcVD-gTq_w@mail.gmail.com","subject":"Re: [PATCH v3 1/2] t3418: add testcase showing problems with rebase -i and strategy options","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-07-11T19:12:30Z","receivedAt":"2018-07-11T19:12:32Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"HI SZEDER,\n\nOn Wed, Jul 11, 2018 at 3:56 AM, SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> On Wed, Jun 27, 2018 at 8:28 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n>>\n>> > diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n>> > index 03bf1b8a3b..11546d6e14 100755\n>> > --- a/t/t3418-rebase-continue.sh\n>> > +++ b/t/t3418-rebase-continue.sh\n>> > @@ -74,6 +74,38 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n>> >       test -f funny.was.run\n>> >  '\n>> >\n>> > +test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n>> > +     rm -fr .git/rebase-* &&\n>> > +     git reset --hard commit-new-file-F2-on-topic-branch &&\n>> > +     test_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n>> > +     test_when_finished \"rm -fr test-bin funny.was.run funny.args\" &&\n>> > +     mkdir test-bin &&\n>> > +     cat >test-bin/git-merge-funny <<-EOF &&\n>> > +     #!$SHELL_PATH\n>> > +     echo \"\\$@\" >>funny.args\n>> > +     case \"\\$1\" in --opt) ;; *) exit 2 ;; esac\n>> > +     case \"\\$2\" in --foo) ;; *) exit 2 ;; esac\n>> > +     case \"\\$4\" in --) ;; *) exit 2 ;; esac\n>> > +     shift 2 &&\n>> > +     >funny.was.run &&\n>> > +     exec git merge-recursive \"\\$@\"\n>> > +     EOF\n>> > +     chmod +x test-bin/git-merge-funny &&\n>>\n>> You could use the 'write_script' helper function here.\n>>\n>> > +     (\n>> > +             PATH=./test-bin:$PATH &&\n>> > +             test_must_fail git rebase -i -s funny -Xopt -Xfoo master topic\n>> > +     ) &&\n>> > +     test -f funny.was.run &&\n>\n> And please use 'test_path_is_file' here ...\n>\n>> > +     rm funny.was.run &&\n>> > +     echo \"Resolved\" >F2 &&\n>> > +     git add F2 &&\n>> > +     (\n>> > +             PATH=./test-bin:$PATH &&\n>> > +             git rebase --continue\n>> > +     ) &&\n>> > +     test -f funny.was.run\n>\n> ... and here.\n>\n\nThanks for looking over things.  This particular test was a copy of\nanother from the same file, just for rebase -i instead of rebase -m.\nI think it'd be nice to keep the two tests looking similar and either\nfix up the rebase -m case with a preparatory patch added to this\nseries, or wait for this series to merge and let a future series clean\nup both testcases.  For other suggested fixups to the same test, Junio\nsuggested just taking the latter approach[1], so I'm assuming that's\nhow I should handle these as well.\n\n[1] https://public-inbox.org/git/xmqqmuvgdods.fsf@gitster-ct.c.googlers.com/\n"},{"id":"352351","messageId":"nycvar.QRO.7.76.6.1807121740270.75@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"20180627154804.3743-3-newren@gmail.com","subject":"Re: [PATCH v3 2/2] Fix use of strategy options with interactive rebases","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-12T15:41:42Z","receivedAt":"2018-07-12T15:42:10Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Wed, 27 Jun 2018, Elijah Newren wrote:\n\n> git-rebase.sh wrote strategy options to .git/rebase/merge/strategy_opts\n> in the following format:\n>   '--ours'  '--renormalize'\n> Note the double spaces.\n> \n> git-rebase--interactive uses sequencer.c to parse that file, and\n> sequencer.c used split_cmdline() to get the individual strategy options.\n> After splitting, sequencer.c prefixed each \"option\" with a double dash,\n> so, concatenating all its options would result in:\n>   -- --ours -- --renormalize\n> \n> So, when it ended up calling try_merge_strategy(), that in turn would run\n>   git merge-$strategy -- --ours -- --renormalize $merge_base -- $head $remote\n> \n> instead of the expected/desired\n>   git merge-$strategy --ours --renormalize $merge_base -- $head $remote\n> \n> Remove the extra spaces so that when it goes through split_cmdline() we end\n> up with the desired command line.\n> \n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n>  git-rebase.sh              | 2 +-\n>  sequencer.c                | 7 ++++++-\n>  t/t3418-rebase-continue.sh | 2 +-\n>  3 files changed, 8 insertions(+), 3 deletions(-)\n> \n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 19bdebb480..f3b10c7f62 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -328,7 +328,7 @@ do\n>  \t\tdo_merge=t\n>  \t\t;;\n>  \t--strategy-option=*)\n> -\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n> +\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n\nDidn't you mean to use \"s/^ *//\" instead?\n\n>  \t\tdo_merge=t\n>  \t\ttest -z \"$strategy\" && strategy=recursive\n>  \t\t;;\n> diff --git a/sequencer.c b/sequencer.c\n> index 5354d4d51e..ef9237c814 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -2206,6 +2206,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>  static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n>  {\n>  \tint i;\n> +\tchar *strategy_opts_string;\n>  \n>  \tstrbuf_reset(buf);\n>  \tif (!read_oneliner(buf, rebase_path_strategy(), 0))\n> @@ -2214,7 +2215,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n>  \tif (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n>  \t\treturn;\n>  \n> -\topts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);\n> +\tstrategy_opts_string = buf->buf;\n> +\tif (*strategy_opts_string == ' ')\n\nI think that this would ideally even be a `while` instead of an `if`.\n\n> +\t\tstrategy_opts_string++;\n> +\topts->xopts_nr = split_cmdline(strategy_opts_string,\n> +\t\t\t\t       (const char ***)&opts->xopts);\n>  \tfor (i = 0; i < opts->xopts_nr; i++) {\n>  \t\tconst char *arg = opts->xopts[i];\n>  \n> diff --git a/t/t3418-rebase-continue.sh b/t/t3418-rebase-continue.sh\n> index 11546d6e14..c145dbac38 100755\n> --- a/t/t3418-rebase-continue.sh\n> +++ b/t/t3418-rebase-continue.sh\n> @@ -74,7 +74,7 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '\n>  \ttest -f funny.was.run\n>  '\n>  \n> -test_expect_failure 'rebase -i --continue handles merge strategy and options' '\n> +test_expect_success 'rebase -i --continue handles merge strategy and options' '\n>  \trm -fr .git/rebase-* &&\n>  \tgit reset --hard commit-new-file-F2-on-topic-branch &&\n>  \ttest_commit \"commit-new-file-F3-on-topic-branch-for-dash-i\" F3 32 &&\n\nThanks!\nDscho\n"},{"id":"352354","messageId":"nycvar.QRO.7.76.6.1807121743040.75@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"20180627074600.32149-1-newren@gmail.com","subject":"Re: [PATCH v2] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-12T15:49:16Z","receivedAt":"2018-07-12T15:49:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Wed, 27 Jun 2018, Elijah Newren wrote:\n\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n> \n> Changes since v1:\n>   - Fixed up commit message (move below comment to below diffstat as\n>     originally intended)\n> \n> Long term I just want to make git-rebase--merge go away, so this patch\n> will eventually be obsoleted.  But since I'm waiting for multiple\n> topics to merge down before re-submitting that series, and since that\n> series has some open questions as well, I figure it's worth\n> (re-)submitting this simple fix in the mean time.\n\nI carry essentially the same patch in Git for Windows for a while now\n(more than a year, to be a little preciser):\n\nhttps://github.com/git-for-windows/git/commit/42c6f1c943a\n\n(but it seems that I either missed one when I wrote that commit, or I\nmissed when it was introduced)\n\nThere are more dashed forms in Git's code base, still, see e.g.\n\nhttps://github.com/git-for-windows/git/commit/4b3fc41b117\nhttps://github.com/git-for-windows/git/commit/c47a29c373c\n\nI would *love* to see those go away.\n\nFWIW I had originally also \"undashed\" the use of `git-receive-pack`, but\nthat breaks things, as the dashed form was unfortunately baked into the\nprotocol (which is of course a design mistake even if Linus still denies\nit).\n\nIt would go a long way to help with platforms and packaging methods where\nhardlinks are simply inconvenient. Because we could then finally get rid\nof (almost) all those hardlinked builtins.\n\nCiao,\nDscho\n"},{"id":"352469","messageId":"20180713155110.21627-1-newren@gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1807121740270.75@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v3 2/2] Fix use of strategy options with interactive rebases","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-07-13T15:51:10Z","receivedAt":"2018-07-13T15:51:26Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Thu, Jul 12, 2018 at 8:41 AM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> Hi Elijah,\n>\n> On Wed, 27 Jun 2018, Elijah Newren wrote:\n>\n...\n>> diff --git a/git-rebase.sh b/git-rebase.sh\n>> index 19bdebb480..f3b10c7f62 100755\n>> --- a/git-rebase.sh\n>> +++ b/git-rebase.sh\n>> @@ -328,7 +328,7 @@ do\n>>               do_merge=t\n>>               ;;\n>>       --strategy-option=*)\n>> -             strategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\")\"\n>> +             strategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n>\n> Didn't you mean to use \"s/^ *//\" instead?\n>\n>>               do_merge=t\n>>               test -z \"$strategy\" && strategy=recursive\n>>               ;;\n>> diff --git a/sequencer.c b/sequencer.c\n>> index 5354d4d51e..ef9237c814 100644\n>> --- a/sequencer.c\n>> +++ b/sequencer.c\n>> @@ -2206,6 +2206,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)\n>>  static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n>>  {\n>>       int i;\n>> +     char *strategy_opts_string;\n>>\n>>       strbuf_reset(buf);\n>>       if (!read_oneliner(buf, rebase_path_strategy(), 0))\n>> @@ -2214,7 +2215,11 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n>>       if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))\n>>               return;\n>>\n>> -     opts->xopts_nr = split_cmdline(buf->buf, (const char ***)&opts->xopts);\n>> +     strategy_opts_string = buf->buf;\n>> +     if (*strategy_opts_string == ' ')\n>\n> I think that this would ideally even be a `while` instead of an `if`.\n\nThanks for taking a look; both sound like good suggestions.  Since the\npatch in question has already reached next, here's a patch on top of\nen/rebase-i-microfixes to make these two changes:\n\n-- 8< --\nSubject: [PATCH] Whitespace handling improvements with interactive rebase\n strategy options\n\nIn commit 0060041df (\"Fix use of strategy options with interactive\nrebases\", 2018-06-27), extra whitespace was removed from a generated\nstring to fix up parsing.  Instead of assuming one extra space, though, we\ncan just remove all leading whitespace and make the code slightly more\nrobust.\n\nSuggested-by: Johanness Schindelin <Johannes.Schindelin@gmx.de>\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\n git-rebase.sh | 2 +-\n sequencer.c   | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex f3b10c7f62..e572980bbc 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -328,7 +328,7 @@ do\n \t\tdo_merge=t\n \t\t;;\n \t--strategy-option=*)\n-\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e s/^.//)\"\n+\t\tstrategy_opts=\"$strategy_opts $(git rev-parse --sq-quote \"--${1#--strategy-option=}\" | sed -e \"s/ *//\")\"\n \t\tdo_merge=t\n \t\ttest -z \"$strategy\" && strategy=recursive\n \t\t;;\ndiff --git a/sequencer.c b/sequencer.c\nindex ef9237c814..3f780f8f50 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -2216,7 +2216,7 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)\n \t\treturn;\n \n \tstrategy_opts_string = buf->buf;\n-\tif (*strategy_opts_string == ' ')\n+\twhile (*strategy_opts_string == ' ')\n \t\tstrategy_opts_string++;\n \topts->xopts_nr = split_cmdline(strategy_opts_string,\n \t\t\t\t       (const char ***)&opts->xopts);\n-- \n2.18.0.645.g72fe132ec2\n\n"},{"id":"352471","messageId":"CABPp-BHrjqHVpV3bwR+aa5Q4yvARMyna10TrXPXBuKpDQ0r_tQ@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1807121743040.75@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v2] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-07-13T16:13:16Z","receivedAt":"2018-07-13T16:13:20Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Thu, Jul 12, 2018 at 8:49 AM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> Hi Elijah,\n>\n> On Wed, 27 Jun 2018, Elijah Newren wrote:\n>\n>> Signed-off-by: Elijah Newren <newren@gmail.com>\n>> ---\n>>\n>> Changes since v1:\n>>   - Fixed up commit message (move below comment to below diffstat as\n>>     originally intended)\n>>\n>> Long term I just want to make git-rebase--merge go away, so this patch\n>> will eventually be obsoleted.  But since I'm waiting for multiple\n>> topics to merge down before re-submitting that series, and since that\n>> series has some open questions as well, I figure it's worth\n>> (re-)submitting this simple fix in the mean time.\n>\n> I carry essentially the same patch in Git for Windows for a while now\n> (more than a year, to be a little preciser):\n>\n> https://github.com/git-for-windows/git/commit/42c6f1c943a\n>\n> (but it seems that I either missed one when I wrote that commit, or I\n> missed when it was introduced)\n\nSo...I helped you get your work upstream without knowing it?  :-)\n\n> There are more dashed forms in Git's code base, still, see e.g.\n>\n> https://github.com/git-for-windows/git/commit/4b3fc41b117\n> https://github.com/git-for-windows/git/commit/c47a29c373c\n>\n> I would *love* to see those go away.\n\nAre there blockers or more known work needed to get these ready for\nsubmission, or is it more a case of you just haven't had time to\nsubmit upstream?\n\n> FWIW I had originally also \"undashed\" the use of `git-receive-pack`, but\n> that breaks things, as the dashed form was unfortunately baked into the\n> protocol (which is of course a design mistake even if Linus still denies\n> it).\n>\n> It would go a long way to help with platforms and packaging methods where\n> hardlinks are simply inconvenient. Because we could then finally get rid\n> of (almost) all those hardlinked builtins.\n\nI thought they were symlinked rather than hardlinked, but yeah I've\nalways found them slightly annoying.\n"},{"id":"352575","messageId":"nycvar.QRO.7.76.6.1807150018060.75@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"CABPp-BHrjqHVpV3bwR+aa5Q4yvARMyna10TrXPXBuKpDQ0r_tQ@mail.gmail.com","subject":"Re: [PATCH v2] git-rebase--merge: modernize \"git-$cmd\" to \"git $cmd\"","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-07-14T22:20:41Z","receivedAt":"2018-07-14T22:20:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Fri, 13 Jul 2018, Elijah Newren wrote:\n\n> On Thu, Jul 12, 2018 at 8:49 AM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n> >\n> > On Wed, 27 Jun 2018, Elijah Newren wrote:\n> >\n> >> Signed-off-by: Elijah Newren <newren@gmail.com>\n> >> ---\n> >>\n> >> Changes since v1:\n> >>   - Fixed up commit message (move below comment to below diffstat as\n> >>     originally intended)\n> >>\n> >> Long term I just want to make git-rebase--merge go away, so this patch\n> >> will eventually be obsoleted.  But since I'm waiting for multiple\n> >> topics to merge down before re-submitting that series, and since that\n> >> series has some open questions as well, I figure it's worth\n> >> (re-)submitting this simple fix in the mean time.\n> >\n> > I carry essentially the same patch in Git for Windows for a while now\n> > (more than a year, to be a little preciser):\n> >\n> > https://github.com/git-for-windows/git/commit/42c6f1c943a\n> >\n> > (but it seems that I either missed one when I wrote that commit, or I\n> > missed when it was introduced)\n> \n> So...I helped you get your work upstream without knowing it?  :-)\n\nYes. Thank you.\n\n> > There are more dashed forms in Git's code base, still, see e.g.\n> >\n> > https://github.com/git-for-windows/git/commit/4b3fc41b117\n> > https://github.com/git-for-windows/git/commit/c47a29c373c\n> >\n> > I would *love* to see those go away.\n> \n> Are there blockers or more known work needed to get these ready for\n> submission, or is it more a case of you just haven't had time to\n> submit upstream?\n\nTime is the main problem.\n\nI also meant to accompany those patches with a commit (that I did not\nmanage to write yet) that optoinally skips hard-linking the builtins\n(except `git-receive-pack`, of course).\n\n> > FWIW I had originally also \"undashed\" the use of `git-receive-pack`, but\n> > that breaks things, as the dashed form was unfortunately baked into the\n> > protocol (which is of course a design mistake even if Linus still denies\n> > it).\n> >\n> > It would go a long way to help with platforms and packaging methods where\n> > hardlinks are simply inconvenient. Because we could then finally get rid\n> > of (almost) all those hardlinked builtins.\n> \n> I thought they were symlinked rather than hardlinked, but yeah I've\n> always found them slightly annoying.\n\nThey are hardlinked, with a newly-introduced option to symlink instead\nthat Ævar came up with IIRC.\n\nSymlinks, of course, are just as impossible to handle portably in .zip\nfiles as hardlinks.\n\nCiao,\nDscho"},{"id":"357943","messageId":"20180912024241.GA27036@localhost","threadId":"48665","inReplyTo":"20180627072319.31356-10-newren@gmail.com","subject":"2.19.0 regression: leaving editor with empty commit message doesn't stop rebase [was: Re: [RFC PATCH v5 9/9] git-rebase: make --allow-empty-message the default]","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-09-12T02:42:41Z","receivedAt":"2018-09-12T02:42:55Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"\nLately I noticed that occasionally I ended up with an empty commit\nmessage after an interactive rebase.  However, since I didn't do\nanything that I haven't already done countless times before, I thought\nthat one of my local patches touching the area where 'git commit'\ncalls launch_editor() got messed up.  Unfortunately, it turned out\nthat my patch is fine, and those empty commit messages are the\nconsequence of a regression in v2.19.0, which bisects down to this\npatch.\n\nTo reproduce the issue, just start an interactive rebase, choose a\ncommit to reword, save, delete all the commit message, save, and BAM!\nthere is the commit with the empty message.\n\n\nOn Wed, Jun 27, 2018 at 12:23:19AM -0700, Elijah Newren wrote:\n> rebase backends currently behave differently with empty commit messages,\n> largely as a side-effect of the different underlying commands on which\n> they are based.  am-based rebases apply commits with an empty commit\n> message without stopping or requiring the user to specify an extra flag.\n> (It is interesting to note that am-based rebases are the default rebase\n> type, and no one has ever requested a --no-allow-empty-message flag to\n> change this behavior.)  merge-based and interactive-based rebases (which\n> are ultimately based on git-commit), will currently halt on any such\n> commits and require the user to manually specify what to do with the\n> commit and continue.\n> \n> One possible rationale for the difference in behavior is that the purpose\n> of an \"am\" based rebase is solely to transplant an existing history, while\n> an \"interactive\" rebase is one whose purpose is to polish a series before\n> making it publishable.  Thus, stopping and asking for confirmation for a\n> possible problem is more appropriate in the latter case.  However, there\n> are two problems with this rationale:\n> \n>   1) merge-based rebases are also non-interactive and there are multiple\n>      types of rebases that use the interactive machinery but are not\n>      explicitly interactive (e.g. when either --rebase-merges or\n>      --keep-empty are specified without --interactive).  These rebases are\n>      also used solely to transplant an existing history, and thus also\n>      should default to --allow-empty-message.\n> \n>   2) this rationale only says that the user is more accepting of stopping\n>      in the case of an explicitly interactive rebase, not that stopping\n>      for this particular reason actually makes sense.  Exploring whether\n>      it makes sense, requires backing up and analyzing the underlying\n>      commands...\n> \n> If git-commit did not error out on empty commits by default, accidental\n> creation of commits with empty messages would be a very common occurrence\n> (this check has caught me many times).  Further, nearly all such empty\n> commit messages would be considered an accidental error (as evidenced by a\n> huge amount of documentation across version control systems and in various\n> blog posts explaining how important commit messages are).  A simple check\n> for what would otherwise be a common error thus made a lot of sense, and\n> git-commit gained an --allow-empty-message flag for special case\n> overrides.  This has made commits with empty messages very rare.\n> \n> There are two sources for commits with empty messages for rebase (and\n> cherry-pick): (a) commits created in git where the user previously\n> specified --allow-empty-message to git-commit, and (b) commits imported\n> into git from other version control systems.  In case (a), the user has\n> already explicitly specified that there is something special about this\n> commit that makes them not want to specify a commit message; forcing them\n> to re-specify with every cherry-pick or rebase seems more likely to be\n> infuriating than helpful.  In case (b), the commit is highly unlikely to\n> have been authored by the person who has imported the history and is doing\n> the rebase or cherry-pick, and thus the user is unlikely to be the\n> appropriate person to write a commit message for it.  Stopping and\n> expecting the user to modify the commit before proceeding thus seems\n> counter-productive.\n\nI agree that this is an issue that should be addressed, and also agree\nthat it's reasonable to accept an empty commit message, if the\noriginal commit already had an empty commit message.  (Though perhaps\nnot completely silently, but with a warning?  Dunno.)\n\nHowever, this should only be the case for existing commit messages\nthat are taken verbatim, but never in the case when the user is asked\nfor a commit message.\n\n> Further, note that while empty commit messages was a common error case for\n> git-commit to deal with, it is a rare case for rebase (or cherry-pick).\n> The fact that it is rare raises the question of why it would be worth\n> checking and stopping on this particular condition and not others.  For\n> example, why doesn't an interactive rebase automatically stop if the\n> commit message's first line is 2000 columns long, or is missing a blank\n> line after the first line, or has every line indented with five spaces, or\n> any number of other myriad problems?\n\nBecause leaving the editor with an empty commit message is and has\nalways been the established way for aborting 'git commit' and thus\nstopping whatever operation it was part of.\n\nAnd because the instructions in the commit message template, which is\nshown for 'reword' and 'squash', too, still say so:\n\n  # Please enter the commit message for your changes. Lines starting\n  # with '#' will be ignored, and an empty message aborts the commit.\n\n> Finally, note that if a user doing an interactive rebase does have the\n> necessary knowledge to add a message for any such commit and wants to do\n> so, it is rather simple for them to change the appropriate line from\n> 'pick' to 'reword'.  The fact that the subject is empty in the todo list\n> that the user edits should even serve as a way to notify them.\n> \n> As far as I can tell, the fact that merge-based and interactive-based\n> rebases stop on commits with empty commit messages is solely a by-product\n> of having been based on git-commit.  It went without notice for a long\n> time precisely because such cases are rare.  The rareness of this\n> situation made it difficult to reason about, so when folks did eventually\n> notice this behavior, they assumed it was there for a good reason and just\n> added an --allow-empty-message flag.  In my opinion, stopping on such\n> messages not desirable in any of these cases, even the (explicitly)\n> interactive case.\n\nIt is desired, and for a very good reason.\n\nLet's suppose you start an interactive rebase, choose a commit to\nsquash, save the instruction sheet, rebase fires up your editor, and\nthen you notice that you mistakenly chose the wrong commit to squash.\nWhat do you do, how do you abort?\n\nBefore this patch you could clear the commit message, exit the editor,\nand then rebase would say \"Aborting commit due to empty commit\nmessage.\", and you get to run 'git rebase --abort', and start over.\n\nBut with this patch?  I don't know...  Just saving the commit message\nas is would let rebase continue and create a bunch of unnecessary\nobjects, and then you would have to use the reflog to return to the\npre-rebase state.\n\n\n> Signed-off-by: Elijah Newren <newren@gmail.com>\n> ---\n> \n> My commit messsage seems like one of those things that someone else will\n> instantly see how to shrink to less than a quarter of its size while still\n> retaining all essential reasoning.  I can't seem to find the simple way to\n> state it, though.\n> \n>  Documentation/git-rebase.txt  | 10 ----------\n>  git-rebase.sh                 |  2 +-\n>  t/t3404-rebase-interactive.sh |  7 ++++---\n>  t/t3405-rebase-malformed.sh   | 11 +++--------\n>  4 files changed, 8 insertions(+), 22 deletions(-)\n> \n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index a67df4caba..9e136ee16e 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -563,16 +563,6 @@ BEHAVIORAL DIFFERENCES\n>      The `--keep-empty` option exists for interactive rebases to allow\n>      it to keep commits that started empty.\n>  \n> -  * empty commit messages:\n> -\n> -    am-based rebase will silently apply commits with empty commit\n> -    messages.\n> -\n> -    merge-based and interactive-based rebases will by default halt\n> -    on any such commits.  The `--allow-empty-message` option exists to\n> -    allow interactive-based rebases to apply such commits without\n> -    halting.\n> -\n>    * directory rename detection:\n>  \n>      merge-based and interactive-based rebases work fine with\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 18ac8226c4..031dbd2ec8 100755\n> --- a/git-rebase.sh\n> +++ b/git-rebase.sh\n> @@ -95,7 +95,7 @@ rebase_cousins=\n>  preserve_merges=\n>  autosquash=\n>  keep_empty=\n> -allow_empty_message=\n> +allow_empty_message=--allow-empty-message\n>  signoff=\n>  test \"$(git config --bool rebase.autosquash)\" = \"true\" && autosquash=t\n>  case \"$(git config --bool commit.gpgsign)\" in\n> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\n> index 352a52e59d..81ce9fe7f9 100755\n> --- a/t/t3404-rebase-interactive.sh\n> +++ b/t/t3404-rebase-interactive.sh\n> @@ -553,15 +553,16 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n>  '\n>  \n>  test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n> +\ttest_when_finished \"git rebase --abort\" &&\n>  \told=$(git rev-parse HEAD) &&\n>  \ttest_tick &&\n>  \tset_fake_editor &&\n>  \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n>  \techo \"edited again\" > file7 &&\n>  \tgit add file7 &&\n> -\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n> -\ttest $old = $(git rev-parse HEAD) &&\n> -\tgit rebase --abort\n> +\techo all the things >>conflict &&\n> +\ttest_must_fail git rebase --continue &&\n> +\ttest $old = $(git rev-parse HEAD)\n>  '\n>  \n>  test_expect_success 'auto-amend only edited commits after \"edit\"' '\n> diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\n> index cb7c6de84a..da94dddc86 100755\n> --- a/t/t3405-rebase-malformed.sh\n> +++ b/t/t3405-rebase-malformed.sh\n> @@ -77,19 +77,14 @@ test_expect_success 'rebase commit with diff in message' '\n>  '\n>  \n>  test_expect_success 'rebase -m commit with empty message' '\n> -\ttest_must_fail git rebase -m master empty-message-merge &&\n> -\tgit rebase --abort &&\n> -\tgit rebase -m --allow-empty-message master empty-message-merge\n> +\tgit rebase -m master empty-message-merge\n>  '\n>  \n>  test_expect_success 'rebase -i commit with empty message' '\n>  \tgit checkout diff-in-message &&\n>  \tset_fake_editor &&\n> -\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> -\t\tgit rebase -i HEAD^ &&\n> -\tgit rebase --abort &&\n> -\tFAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> -\t\tgit rebase -i --allow-empty-message HEAD^\n> +\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n> +\t\tgit rebase -i HEAD^\n>  '\n>  \n>  test_done\n> -- \n> 2.18.0.9.g431b2c36d5\n> \n"},{"id":"357951","messageId":"CABPp-BEe=NCXhaCcbNQv6vxcuD2oWMvMfMMPv5+RVKfqarc0hA@mail.gmail.com","threadId":"48665","inReplyTo":"20180912024241.GA27036@localhost","subject":"Re: 2.19.0 regression: leaving editor with empty commit message doesn't stop rebase [was: Re: [RFC PATCH v5 9/9] git-rebase: make --allow-empty-message the default]","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-09-12T06:21:07Z","receivedAt":"2018-09-12T06:21:21Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi,\n\nOn Tue, Sep 11, 2018 at 7:42 PM SZEDER Gábor <szeder.dev@gmail.com> wrote:\n> Lately I noticed that occasionally I ended up with an empty commit\n> message after an interactive rebase...those empty commit messages are the\n> consequence of a regression in v2.19.0, which bisects down to this\n> patch.\n>\n> To reproduce the issue, just start an interactive rebase, choose a\n> commit to reword, save, delete all the commit message, save, and BAM!\n> there is the commit with the empty message.\n>\n>\n> On Wed, Jun 27, 2018 at 12:23:19AM -0700, Elijah Newren wrote:\n> > rebase backends currently behave differently with empty commit messages,\n> > largely as a side-effect of the different underlying commands on which\n> > they are based.  am-based rebases apply commits with an empty commit\n...\n> I agree that this is an issue that should be addressed, and also agree\n> that it's reasonable to accept an empty commit message, if the\n> original commit already had an empty commit message.  (Though perhaps\n> not completely silently, but with a warning?  Dunno.)\n>\n> However, this should only be the case for existing commit messages\n> that are taken verbatim, but never in the case when the user is asked\n> for a commit message.\n...\n>   # Please enter the commit message for your changes. Lines starting\n>   # with '#' will be ignored, and an empty message aborts the commit.\n...\n> Let's suppose you start an interactive rebase, choose a commit to\n> squash, save the instruction sheet, rebase fires up your editor, and\n> then you notice that you mistakenly chose the wrong commit to squash.\n> What do you do, how do you abort?\n\nAll sound like reasonable arguments to me to differentiate between\ncommit messages that started empty (which I admit was what I had in\nmind) vs. ones where we asked for user input and it came out empty.\n\nAre you cooking up a patch?  I might be able to find a little time to\ndig into this tomorrow if no one else is working on it already by\nthen.  It'll probably conflict a bunch with all the\nrewrite-rebase-in-C topics in flight in pu.  :-(\n"},{"id":"358008","messageId":"20180912211848.26949-1-newren@gmail.com","threadId":"48665","inReplyTo":"20180912024241.GA27036@localhost","subject":"[PATCH] sequencer: fix --allow-empty-message behavior, make it smarter","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2018-09-12T21:18:48Z","receivedAt":"2018-09-12T21:19:04Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"In commit b00bf1c9a8dd (\"git-rebase: make --allow-empty-message the\ndefault\", 2018-06-27), several arguments were given for transplanting\nempty commits without halting and asking the user for confirmation on\neach commit.  These arguments were incomplete because the logic clearly\nassumed the only cases under consideration were transplanting of commits\nwith empty messages (see the comment about \"There are two sources for\ncommits with empty messages).  It didn't discuss or even consider\nrewords, squashes, etc. where the user is explicitly asked for a new\ncommit message and provides an empty one.  (My bad, I totally should\nhave thought about that at the time, but just didn't.)\n\nRewords and squashes are significantly different, though, as described\nby SZEDER:\n\n    Let's suppose you start an interactive rebase, choose a commit to\n    squash, save the instruction sheet, rebase fires up your editor, and\n    then you notice that you mistakenly chose the wrong commit to\n    squash.  What do you do, how do you abort?\n\n    Before [that commit] you could clear the commit message, exit the\n    editor, and then rebase would say \"Aborting commit due to empty\n    commit message.\", and you get to run 'git rebase --abort', and start\n    over.\n\n    But [since that commit, ...] saving the commit message as is would\n    let rebase continue and create a bunch of unnecessary objects, and\n    then you would have to use the reflog to return to the pre-rebase\n    state.\n\nAlso, he states:\n\n    The instructions in the commit message template, which is shown for\n    'reword' and 'squash', too, still say...\n\n    # Please enter the commit message for your changes. Lines starting\n    # with '#' will be ignored, and an empty message aborts the commit.\n\nThese are sound arguments that when editing commit messages during a\nsequencer operation, that if the commit message is empty then the\noperation should halt and ask the user to correct.  The arguments in\ncommit b00bf1c9a8dd (referenced above) still apply when transplanting\npreviously created commits with empty commit messages, so the sequencer\nshould not halt for those.\n\nFurthermore, all rationale so far applies equally for cherry-pick as for\nrebase.  Therefore, make the code default to --allow-empty-message when\ntransplanting an existing commit, and to default to halting when the\nuser is asked to edit a commit message and provides an empty one -- for\nboth rebase and cherry-pick.\n\nSigned-off-by: Elijah Newren <newren@gmail.com>\n---\nThis patch cleanly applies to both 2.19.0 and pu.  There are some related\ncode cleanups that I'd like to make, but doing that cleanup conflicts with\nthe various rewrite-rebase-in-C topics sitting in pu; since those are\nfairly lengthy, I really don't want to cause problems there, but I think\nSZEDER really wants this 2.19.0 regression fix before 2.20.0 and thus\nbefore those other topics.\n\n\n sequencer.c                   |  4 ++--\n t/t3404-rebase-interactive.sh |  7 +++----\n t/t3405-rebase-malformed.sh   |  2 +-\n t/t3505-cherry-pick-empty.sh  | 18 ++++++++----------\n 4 files changed, 14 insertions(+), 17 deletions(-)\n\ndiff --git a/sequencer.c b/sequencer.c\nindex dc2c58d464..638ee151f2 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -899,7 +899,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n \tif ((flags & ALLOW_EMPTY))\n \t\targv_array_push(&cmd.args, \"--allow-empty\");\n \n-\tif (opts->allow_empty_message)\n+\tif (!(flags & EDIT_MSG))\n \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n \n \tif (cmd.err == -1) {\n@@ -1313,7 +1313,7 @@ static int try_to_commit(struct strbuf *msg, const char *author,\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n \t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n-\tif (!opts->allow_empty_message && message_is_empty(msg, cleanup)) {\n+\tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n \t}\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 86bba5ed7c..ff89b6341a 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -569,16 +569,15 @@ test_expect_success '--continue tries to commit, even for \"edit\"' '\n '\n \n test_expect_success 'aborted --continue does not squash commits after \"edit\"' '\n-\ttest_when_finished \"git rebase --abort\" &&\n \told=$(git rev-parse HEAD) &&\n \ttest_tick &&\n \tset_fake_editor &&\n \tFAKE_LINES=\"edit 1\" git rebase -i HEAD^ &&\n \techo \"edited again\" > file7 &&\n \tgit add file7 &&\n-\techo all the things >>conflict &&\n-\ttest_must_fail git rebase --continue &&\n-\ttest $old = $(git rev-parse HEAD)\n+\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" git rebase --continue &&\n+\ttest $old = $(git rev-parse HEAD) &&\n+\tgit rebase --abort\n '\n \n test_expect_success 'auto-amend only edited commits after \"edit\"' '\ndiff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh\nindex da94dddc86..860e63e444 100755\n--- a/t/t3405-rebase-malformed.sh\n+++ b/t/t3405-rebase-malformed.sh\n@@ -83,7 +83,7 @@ test_expect_success 'rebase -m commit with empty message' '\n test_expect_success 'rebase -i commit with empty message' '\n \tgit checkout diff-in-message &&\n \tset_fake_editor &&\n-\tenv FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n+\ttest_must_fail env FAKE_COMMIT_MESSAGE=\" \" FAKE_LINES=\"reword 1\" \\\n \t\tgit rebase -i HEAD^\n '\n \ndiff --git a/t/t3505-cherry-pick-empty.sh b/t/t3505-cherry-pick-empty.sh\nindex fbdc47cfbd..5f911bb529 100755\n--- a/t/t3505-cherry-pick-empty.sh\n+++ b/t/t3505-cherry-pick-empty.sh\n@@ -11,17 +11,14 @@ test_expect_success setup '\n \ttest_tick &&\n \tgit commit -m \"first\" &&\n \n-\tgit checkout -b empty-branch &&\n-\ttest_tick &&\n-\tgit commit --allow-empty -m \"empty\" &&\n-\n+\tgit checkout -b empty-message-branch &&\n \techo third >> file1 &&\n \tgit add file1 &&\n \ttest_tick &&\n \tgit commit --allow-empty-message -m \"\" &&\n \n \tgit checkout master &&\n-\tgit checkout -b empty-branch2 &&\n+\tgit checkout -b empty-change-branch &&\n \ttest_tick &&\n \tgit commit --allow-empty -m \"empty\"\n \n@@ -29,7 +26,7 @@ test_expect_success setup '\n \n test_expect_success 'cherry-pick an empty commit' '\n \tgit checkout master &&\n-\ttest_expect_code 1 git cherry-pick empty-branch^\n+\ttest_expect_code 1 git cherry-pick empty-change-branch\n '\n \n test_expect_success 'index lockfile was removed' '\n@@ -37,8 +34,9 @@ test_expect_success 'index lockfile was removed' '\n '\n \n test_expect_success 'cherry-pick a commit with an empty message' '\n+\ttest_when_finished \"git reset --hard empty-message-branch~1\" &&\n \tgit checkout master &&\n-\ttest_expect_code 1 git cherry-pick empty-branch\n+\tgit cherry-pick empty-message-branch\n '\n \n test_expect_success 'index lockfile was removed' '\n@@ -47,7 +45,7 @@ test_expect_success 'index lockfile was removed' '\n \n test_expect_success 'cherry-pick a commit with an empty message with --allow-empty-message' '\n \tgit checkout -f master &&\n-\tgit cherry-pick --allow-empty-message empty-branch\n+\tgit cherry-pick --allow-empty-message empty-message-branch\n '\n \n test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n@@ -55,12 +53,12 @@ test_expect_success 'cherry pick an empty non-ff commit without --allow-empty' '\n \techo fourth >>file2 &&\n \tgit add file2 &&\n \tgit commit -m \"fourth\" &&\n-\ttest_must_fail git cherry-pick empty-branch2\n+\ttest_must_fail git cherry-pick empty-change-branch\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+\tgit cherry-pick --allow-empty empty-change-branch\n '\n \n test_expect_success 'cherry pick with --keep-redundant-commits' '\n-- \n2.19.0.612.g68a16e0245\n\n"},{"id":"358089","messageId":"xmqqefdxf8nk.fsf@gitster-ct.c.googlers.com","threadId":"48665","inReplyTo":"20180912211848.26949-1-newren@gmail.com","subject":"Re: [PATCH] sequencer: fix --allow-empty-message behavior, make it smarter","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-13T20:24:15Z","receivedAt":"2018-09-13T20:24:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Elijah Newren <newren@gmail.com> writes:\n\n> This patch cleanly applies to both 2.19.0 and pu.  There are some related\n> code cleanups that I'd like to make, but doing that cleanup conflicts with\n> the various rewrite-rebase-in-C topics sitting in pu; since those are\n> fairly lengthy, I really don't want to cause problems there, but I think\n> SZEDER really wants this 2.19.0 regression fix before 2.20.0 and thus\n> before those other topics.\n\nOh absolutely.  Materials for 2.19.x maintenance track can and\nshould jump over other topics for 2.20 and later.  Thanks for being\nconsiderate.\n\n> @@ -899,7 +899,7 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,\n>  \tif ((flags & ALLOW_EMPTY))\n>  \t\targv_array_push(&cmd.args, \"--allow-empty\");\n>  \n> -\tif (opts->allow_empty_message)\n> +\tif (!(flags & EDIT_MSG))\n>  \t\targv_array_push(&cmd.args, \"--allow-empty-message\");\n\nHmph.  I briefly wondered if an alternative logic would be better:\n\n\tIf and only the original commit being rewritten is empty,\n\tthen we allow the result to be empty.\n\nBut looking at EDIT_MSG would be more explicit and probably is a\nbetter idea.  That would allow you to abort a reword of a commit\nwhose message is empty.\n\nThe reason why I thought about the alt logic is because I am worried\nabout a use case where\n\n\t$ GIT_EDITOR=: git rebase|cherry-pick ...\n\nis used to say \"I do not want you to go interactive, when the only\ninteraction needed from me is to edit the message---I am perfectly\nhappy with the messages of commits being replayed or ones you come\nup with as the default\".  Because \"--allow-empty-message\" tends to\nmake things _less_ interactive, the worry is unfounded.\n\n"},{"id":"367242","messageId":"nycvar.QRO.7.76.6.1901211635080.41@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"CABPp-BGh7yW69QwxQb13K0HM38NKmQif3A6C6UULEKYnkEJ5vA@mail.gmail.com","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-01-21T15:55:44Z","receivedAt":"2019-01-21T15:56:08Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nwhile looking for the patches I promised to review much earlier, I\nrealized that I never answered to this, even older mail. Sorry about that.\n\n[On a positive note: it only has been, what, exactly 7 months since you\nsent it. My record is, I believe, somewhat around 5 years before I\nresponded to a mail.]\n\nOn Thu, 21 Jun 2018, Elijah Newren wrote:\n\n> Thanks for all the food for thought.  This is awesome.\n\n:-)\n\n> On Thu, Jun 21, 2018 at 3:57 AM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n> > On Wed, 20 Jun 2018, Elijah Newren wrote:\n> >> On Sun, Jun 17, 2018 at 2:44 PM, Johannes Schindelin\n> >> <Johannes.Schindelin@gmx.de> wrote:\n> >>\n> >> > I was really referring to speed. But I have to admit that I do not have\n> >> > any current numbers.\n> >> >\n> >> > Another issue just hit me, though: rebase --am does not need to look at as\n> >> > many Git objects as rebase --merge or rebase -i. Therefore, GVFS users\n> >> > will still want to use --am wherever possible, to avoid \"hydrating\"\n> >> > many objects during their rebase.\n> >>\n> >> What is it that makes rebase --am need fewer Git objects than rebase\n> >> --merge or rebase -i?\n> >\n> > Multiple things. The most obvious thing: --cherry-pick. When you call `git\n> > rebase --am`, it does not try to exclude the patches by looking at\n> > `rev-list --cherry-pick --right-only <upstream>..<head>`\n> >\n> > This really bit us in GVFS Git because we have several thousand developers\n> > working on the same code base, and you probably read the numbers elsewhere\n> > how many commits are introduced while a developer goes on so much as a\n> > week-long vacation.\n> \n> Ooh, that's interesting.  Here's a crazy idea: I'm curious if this is\n> essentially a workaround that we could expunge.\n\nThat is indeed a very, very compelling idea.\n\n> In particular, am-based rebases will drop empty commits (that is, either\n> commits that are empty to start, or that after being applied are empty).\n> It never grew a --no-allow-empty option either.  If rebase -i/-m were to\n> behave the same, for consistency sake, we could drop the `rev-list\n> --cherry-pick ...` call.  Granted, that would result in a slight\n> difference in behavior (it could result in conflicts in some cases\n> instead of an automatically empty commit), but may well be worth it for\n> consistencies' sake between rebase backends.  As a side effect of making\n> the backends consistent, it may also provide a nice performance boost\n> for the GVFS case by removing the need to do the --cherry-pick thing.\n\nI very much like the consistency thing. I am slightly worried about the\nramifications, though.\n\nFor example, when I did not use GitGitGadget yet to submit patches, I used\none of my machines to keep a record of still-in-flight branches, and to\nverify whether a branch had been merged, I simply used `git rebase -i\nupstream/master`. If that showed a `noop`, I was sure that it was merged.\n\nWhile I no longer have *this* particular use case, I take it as an\nindication that Git users out there are probably using the interactive\nrebase in similar manners.\n\nSo we would *in the least* have to keep this as an option, and we would\nhave to work with a deprecation notice for a couple of major versions\nbefore we flip the default.\n\nHaving said that, I really like the performance implication of switching\nthe default to skip the --cherry-pick, *in particular* with an eye toward\nVFS for Git (TAFKA GVFS).\n\n> > Next, rename detection.\n> >\n> > I think that bit us even harder because it tries to look at all the files\n> > that have been changed in upstream in the meantime, which can be *a lot*.\n> > And if you know that moving files outside of your cozy little sparse\n> > checkout is unlikely (or moving from the outside into your checkout), then\n> > all this hydration is pretty wasteful. That's why we had to switch off\n> > rename detection in GVFS Git.\n> \n> Actually to be clear, for each side of the merge, rename detection\n> only needs to look at files that were not present in both the\n> merge-base and the branch.  Files which were modified but have the\n> same name are not involved (break detection is not active.).  But yes,\n> I understand how you can still get an awful lot of files, which makes\n> it worse when you then go and compare all of them in an O(N*M)\n> fashion.\n\nYes.\n\nIt is made worse by the fact that Git never sprouted an option to tell it\nabout *known* renames, even if that would make tons of sense. I mean, it\nis nice that Git tries to detect renames. Really nice. In some cases it\nfails, though, and in other cases it just takes a lot of time, so it would\nbe a real boon if there was a way to skip Git's rename detection. It'd be\nsimilar in spirit to way you can side-step Git's binary file detection, by\nusing .gitattributes. (Obviously, the rename thing would need to use a\ndifferent facility than .gitattributes.)\n\n> >> My guess at what objects are needed by each type:\n> >>\n> >> At a high level, rebase --am for each commit will need to compare the\n> >> commit to its parent to generate a diff (which thus involves walking\n> >> over the objects in both the commit and its parent, though it should\n> >> be able to skip over subtrees that are equal), and then will need to\n> >> look at all the objects in the target commit on which it needs to\n> >> apply the patch (in order to properly fill the index for a starting\n> >> point, and used later when creating a new commit).\n> >\n> > No, in --am mode, it does not even need to look at all the objects in the\n> > target commits. Only those objects that correspond to the files that are\n> > touched by the diff.\n> \n> Sorry, I mis-spoke.  Unless you've done something special with GVFS, I\n> believe the --am mode would indeed need to read all the _tree_ objects\n> in the target commits, but any _file_ object corresponding to a path\n> not modified by the other side need not be loaded since we can proceed\n> simply knowing its sha1sum.\n\nThat *might* be good enough with the \"largest repository on the planet\".\nEmprically, we determined pretty early on that it is not the commits and\ntrees that make the initial clone unbearably large. It's the blobs.\n\n> > In a massive code base, such as Windows', this makes a huge difference.\n> > Even comparing the number of files touched by the patches that are to be\n> > rebased to the number of files that were touched in upstream since you\n> > rebased last is ridiculous. And a three-way merge needs to consider that\n> > latter set of files.\n> \n> Actually, the three-way merge isn't all that different.  For a path\n> that exists in both branches and the merge base, it first compares\n> sha1sums (thus it does need to read all the tree objects), and then if\n> one side has not modified a certain path, it knows the merge result is\n> the sha1sum from the other side.  Thus, it won't need to read files\n> that were changed upstream so long as that path wasn't changed on your\n> side.\n\nTrue.\n\n> In fact, --merge and --interactive have a slight performance advantage\n> here: if upstream didn't modify the path, then it doesn't need to read\n> the file from your side to do any diff or comparison.  It can just use\n> whatever sha1sum you have.  In contrast --am mode will need to read\n> the relevant file more than once.  Since it first creates a series of\n> patches, it will have to read the file from your commit and its\n> parent, create a diff, and then later apply that diff to the target\n> version, and since the target version matches the merge base it will\n> end up just recovering the version of the file on your side that you\n> started with anyway.  (Since that file is already local, though, this\n> small performance advantage would currently be lost in the noise of\n> the other problems.)\n\nI had not thought of that. You're right, with largish patch series,\ninteractive rebase might actually be faster than --am based rebase. I have\nnot even tested this, I guess I really should first look at numbers before\nI speak further :0)\n\n> >> If the application of the diff fails, it falls back to a three-way\n> >> merge, though the three-way merge shouldn't need any additional objects.\n> >\n> > The three-way merge needs to reconcile the diff between branch point and\n> > your changes to the diff between branch point and upstream's changes. The\n> > latter can be a lot bigger than the former, in which case --am's\n> > complexity (O(former)) is much nicer than --merge's (O(former u latter)).\n> \n> Yeah, renames mess up that whole \"a path that exists in both branches\n> and the merge base\" requirement that I stipulated above, and widens\n> the scope considerably and affects performance rather markedly.  On\n> the positive side though, the more I read your description, the more I\n> think my rename performance work may give a speedup for the GVFS\n> usecase far in excess of the factor of 30 I saw for my usecase.  It\n> may still not quite match --am mode's outright avoidance of rename\n> detection, but I still think it should be pretty impressive.  Time\n> will tell...\n\nI am very hopeful.\n\nAnd I also think that one fallout of your work on that front could be to\nteach Git a way to skip/overrule rename detection. After all, it is not\n*all* that common that files are renamed. Take Git's commit history, for\nexample. Apart from the huge builtin/ move (for which rename detection\nwill fail after many iterations after that move), there were only sporadic\nrenames (such as sha1_file.c -> sha1-file.c). In \"real\" repositories,\nrefactorings are also rather rare, for the same reason: they simply cause\na lot of trouble with a lot of concurrent development going on. If we had\nsuch a facility (say, via notes) to tell Git: look, don't even bother to\ntry to detect renames, at least in *commit range*, just use this here data\nbase that I prepared for you, we would not only be able to speed up\noperations such as rebase, we also would have an easy way to solve the\nproblem where the rename detection simply fails after sustained\ndevelopment because both sides diverged *so much* that Git cannot detect\nany similarity.\n\nAnother thought that occurred to me: in the context of GitGitGadget, where\nI cannot rely on the `amlog` notes (because there are too many\ninaccuracies in that information), I was looking for another way to\nidentify commits in `pu` that corresponds to the original commits (i.e.\nthe commits by the authors themselves, in GitGitGadget's PRs). Sadly, I\nlack the time to work on this with any seriousness, I can only spend a\ncouple hours here and there on it, but I *think* that there might be a\nchance to use something like MinHash and/or Locally Sensitive Hashes to\nnot only determine near-identical commits, but also correspondences\nbetween commits and mails on the Git mailing list containing patches. And\nthe very same technology should also be able to speed up rename detection,\nmuch more robustly (and with a much better time complexity) than what we\nhave now. Did you look in that direction already?\n\nCiao,\nDscho\n"},{"id":"367251","messageId":"CABPp-BEQ2e06zFEgOYp2iA9tvD9gdV-zOtyD3sOnmxCHd=PrSw@mail.gmail.com","threadId":"48665","inReplyTo":"nycvar.QRO.7.76.6.1901211635080.41@tvgsbejvaqbjf.bet","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2019-01-21T19:02:27Z","receivedAt":"2019-01-21T19:02:47Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi Dscho,\n\nOn Mon, Jan 21, 2019 at 7:56 AM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> Hi Elijah,\n>\n> while looking for the patches I promised to review much earlier, I\n> realized that I never answered to this, even older mail. Sorry about that.\n>\n> [On a positive note: it only has been, what, exactly 7 months since you\n> sent it. My record is, I believe, somewhat around 5 years before I\n> responded to a mail.]\n\nNo worries; I figured it was mostly an exchange of ideas, not a\nhammering down of implementation details, and as such, it was\nproductive with or without further responses.  In fact, I had somewhat\nforgotten about this email.\n\n> On Thu, 21 Jun 2018, Elijah Newren wrote:\n>\n> > Thanks for all the food for thought.  This is awesome.\n>\n> :-)\n>\n> > On Thu, Jun 21, 2018 at 3:57 AM, Johannes Schindelin\n> > <Johannes.Schindelin@gmx.de> wrote:\n> > > On Wed, 20 Jun 2018, Elijah Newren wrote:\n> > >> On Sun, Jun 17, 2018 at 2:44 PM, Johannes Schindelin\n> > >> <Johannes.Schindelin@gmx.de> wrote:\n> > >>\n....\n> > >> What is it that makes rebase --am need fewer Git objects than rebase\n> > >> --merge or rebase -i?\n> > >\n> > > Multiple things. The most obvious thing: --cherry-pick. When you call `git\n....\n> > Ooh, that's interesting.  Here's a crazy idea: I'm curious if this is\n> > essentially a workaround that we could expunge.\n>\n> That is indeed a very, very compelling idea.\n>\n> > In particular, am-based rebases will drop empty commits (that is, either\n> > commits that are empty to start, or that after being applied are empty).\n> > It never grew a --no-allow-empty option either.  If rebase -i/-m were to\n> > behave the same, for consistency sake, we could drop the `rev-list\n> > --cherry-pick ...` call.  Granted, that would result in a slight\n> > difference in behavior (it could result in conflicts in some cases\n> > instead of an automatically empty commit), but may well be worth it for\n> > consistencies' sake between rebase backends.  As a side effect of making\n> > the backends consistent, it may also provide a nice performance boost\n> > for the GVFS case by removing the need to do the --cherry-pick thing.\n>\n> I very much like the consistency thing. I am slightly worried about the\n> ramifications, though.\n>\n> For example, when I did not use GitGitGadget yet to submit patches, I used\n> one of my machines to keep a record of still-in-flight branches, and to\n> verify whether a branch had been merged, I simply used `git rebase -i\n> upstream/master`. If that showed a `noop`, I was sure that it was merged.\n>\n> While I no longer have *this* particular use case, I take it as an\n> indication that Git users out there are probably using the interactive\n> rebase in similar manners.\n>\n> So we would *in the least* have to keep this as an option, and we would\n> have to work with a deprecation notice for a couple of major versions\n> before we flip the default.\n>\n> Having said that, I really like the performance implication of switching\n> the default to skip the --cherry-pick, *in particular* with an eye toward\n> VFS for Git (TAFKA GVFS).\n\nHandling of empty commits seems to be a bit of a mess in rebase.  --am\njust drops them, with no option to do otherwise.  --interactive will\nby default drop them if the commit is known apriori to be a clean\ncherry-pick, but if the commit is just a subset of something else\nupstream then it will instead halt with no option to just drop those\n(instead requiring a 'git rebase --skip' for each one after it halts).\ninteractive rebase has a --keep option to make it not drop the apriori\nclean cherry-picks, but will still halt on them anyway much as it does\nfor commits which were just a subset of upstream changes.  To me, it\nwould make more sense to have a keep option which doesn't halt\n(perhaps acting like a combination of --keep and cherry-pick's\n--keep-redundant-commits).  I've been thinking about adding a more\ngeneral\n   --empty={drop,halt,keep}\noption to all types of rebase.  However, I'm curious if we should also\ndifferentiate between starts-empty and becomes-empty.  I know of a lot\nof repos which use empty commits for version-related and\npublish-related weirdness; perhaps commits which start empty should be\nkept, even if commits which become empty during rebase (due to the\nsame changes having already been made upstream) should be removed.\n\nIt's still just an idea floating around in my head.\n\nAnyway, thanks for the extra usecase and backward compatibility\ncontext.  Before worrying about adding extra options and deprecation\nperiods, though, perhaps we could start by by omitting the\n--cherry-pick for implicitly_interactive rebases, like --merge?  (In\nparticular, I'm thinking that when we switch the default rebase to be\n--merge instead of --am[1], we avoid breaking things.)\n\n[1] https://public-inbox.org/git/xmqqh8jeh1id.fsf@gitster-ct.c.googlers.com/\n\n> > > Next, rename detection.\n> > >\n> > > I think that bit us even harder because it tries to look at all the files\n> > > that have been changed in upstream in the meantime, which can be *a lot*.\n> > > And if you know that moving files outside of your cozy little sparse\n> > > checkout is unlikely (or moving from the outside into your checkout), then\n> > > all this hydration is pretty wasteful. That's why we had to switch off\n> > > rename detection in GVFS Git.\n> >\n> > Actually to be clear, for each side of the merge, rename detection\n> > only needs to look at files that were not present in both the\n> > merge-base and the branch.  Files which were modified but have the\n> > same name are not involved (break detection is not active.).  But yes,\n> > I understand how you can still get an awful lot of files, which makes\n> > it worse when you then go and compare all of them in an O(N*M)\n> > fashion.\n>\n> Yes.\n>\n> It is made worse by the fact that Git never sprouted an option to tell it\n> about *known* renames, even if that would make tons of sense. I mean, it\n> is nice that Git tries to detect renames. Really nice. In some cases it\n> fails, though, and in other cases it just takes a lot of time, so it would\n> be a real boon if there was a way to skip Git's rename detection. It'd be\n> similar in spirit to way you can side-step Git's binary file detection, by\n> using .gitattributes. (Obviously, the rename thing would need to use a\n> different facility than .gitattributes.)\n\nHmm, I'll have to keep that in the back of my mind.  First I want to\nremove all unnecessary time that rename detection takes, which can\noften be huge.  But additional performance improvements ideas after\nthat are something I want to keep a note of.\n\n> > >> My guess at what objects are needed by each type:\n> > >>\n> > >> At a high level, rebase --am for each commit will need to compare the\n> > >> commit to its parent to generate a diff (which thus involves walking\n> > >> over the objects in both the commit and its parent, though it should\n> > >> be able to skip over subtrees that are equal), and then will need to\n> > >> look at all the objects in the target commit on which it needs to\n> > >> apply the patch (in order to properly fill the index for a starting\n> > >> point, and used later when creating a new commit).\n> > >\n> > > No, in --am mode, it does not even need to look at all the objects in the\n> > > target commits. Only those objects that correspond to the files that are\n> > > touched by the diff.\n> >\n> > Sorry, I mis-spoke.  Unless you've done something special with GVFS, I\n> > believe the --am mode would indeed need to read all the _tree_ objects\n> > in the target commits, but any _file_ object corresponding to a path\n> > not modified by the other side need not be loaded since we can proceed\n> > simply knowing its sha1sum.\n>\n> That *might* be good enough with the \"largest repository on the planet\".\n> Emprically, we determined pretty early on that it is not the commits and\n> trees that make the initial clone unbearably large. It's the blobs.\n>\n> > > In a massive code base, such as Windows', this makes a huge difference.\n> > > Even comparing the number of files touched by the patches that are to be\n> > > rebased to the number of files that were touched in upstream since you\n> > > rebased last is ridiculous. And a three-way merge needs to consider that\n> > > latter set of files.\n> >\n> > Actually, the three-way merge isn't all that different.  For a path\n> > that exists in both branches and the merge base, it first compares\n> > sha1sums (thus it does need to read all the tree objects), and then if\n> > one side has not modified a certain path, it knows the merge result is\n> > the sha1sum from the other side.  Thus, it won't need to read files\n> > that were changed upstream so long as that path wasn't changed on your\n> > side.\n>\n> True.\n>\n> > In fact, --merge and --interactive have a slight performance advantage\n> > here: if upstream didn't modify the path, then it doesn't need to read\n> > the file from your side to do any diff or comparison.  It can just use\n> > whatever sha1sum you have.  In contrast --am mode will need to read\n> > the relevant file more than once.  Since it first creates a series of\n> > patches, it will have to read the file from your commit and its\n> > parent, create a diff, and then later apply that diff to the target\n> > version, and since the target version matches the merge base it will\n> > end up just recovering the version of the file on your side that you\n> > started with anyway.  (Since that file is already local, though, this\n> > small performance advantage would currently be lost in the noise of\n> > the other problems.)\n>\n> I had not thought of that. You're right, with largish patch series,\n> interactive rebase might actually be faster than --am based rebase. I have\n> not even tested this, I guess I really should first look at numbers before\n> I speak further :0)\n\nI think merge-recursive has some performance problems that are likely\nto mask this otherwise inherent advantage that interactive rebase\nshould enjoy over am-style rebase.  But once those are fixed...\n\n> > >> If the application of the diff fails, it falls back to a three-way\n> > >> merge, though the three-way merge shouldn't need any additional objects.\n> > >\n> > > The three-way merge needs to reconcile the diff between branch point and\n> > > your changes to the diff between branch point and upstream's changes. The\n> > > latter can be a lot bigger than the former, in which case --am's\n> > > complexity (O(former)) is much nicer than --merge's (O(former u latter)).\n> >\n> > Yeah, renames mess up that whole \"a path that exists in both branches\n> > and the merge base\" requirement that I stipulated above, and widens\n> > the scope considerably and affects performance rather markedly.  On\n> > the positive side though, the more I read your description, the more I\n> > think my rename performance work may give a speedup for the GVFS\n> > usecase far in excess of the factor of 30 I saw for my usecase.  It\n> > may still not quite match --am mode's outright avoidance of rename\n> > detection, but I still think it should be pretty impressive.  Time\n> > will tell...\n>\n> I am very hopeful.\n>\n> And I also think that one fallout of your work on that front could be to\n> teach Git a way to skip/overrule rename detection. After all, it is not\n> *all* that common that files are renamed. Take Git's commit history, for\n> example. Apart from the huge builtin/ move (for which rename detection\n> will fail after many iterations after that move), there were only sporadic\n> renames (such as sha1_file.c -> sha1-file.c). In \"real\" repositories,\n> refactorings are also rather rare, for the same reason: they simply cause\n> a lot of trouble with a lot of concurrent development going on. If we had\n> such a facility (say, via notes) to tell Git: look, don't even bother to\n> try to detect renames, at least in *commit range*, just use this here data\n> base that I prepared for you, we would not only be able to speed up\n> operations such as rebase, we also would have an easy way to solve the\n> problem where the rename detection simply fails after sustained\n> development because both sides diverged *so much* that Git cannot detect\n> any similarity.\n>\n> Another thought that occurred to me: in the context of GitGitGadget, where\n> I cannot rely on the `amlog` notes (because there are too many\n> inaccuracies in that information), I was looking for another way to\n> identify commits in `pu` that corresponds to the original commits (i.e.\n> the commits by the authors themselves, in GitGitGadget's PRs). Sadly, I\n> lack the time to work on this with any seriousness, I can only spend a\n> couple hours here and there on it, but I *think* that there might be a\n> chance to use something like MinHash and/or Locally Sensitive Hashes to\n> not only determine near-identical commits, but also correspondences\n> between commits and mails on the Git mailing list containing patches. And\n> the very same technology should also be able to speed up rename detection,\n> much more robustly (and with a much better time complexity) than what we\n> have now. Did you look in that direction already?\n\nI've looked at a few different things for speeding up rename\ndetection, but I've been away from merge-recursive while I've been\nworking on git repo-filter (or filter-repo or whatever I/we end up\ncalling it).  I'm hoping to get repo-filter into shape to share with\neveryone before or at Git Merge, and then get back to merge\nimprovements.\n\nI am not familiar with MinHash and Locally Sensitive Hashes, but I'll\nadd them to the list of things to look into.  Thanks for the idea.\n"},{"id":"367322","messageId":"nycvar.QRO.7.76.6.1901221633290.41@tvgsbejvaqbjf.bet","threadId":"48665","inReplyTo":"CABPp-BEQ2e06zFEgOYp2iA9tvD9gdV-zOtyD3sOnmxCHd=PrSw@mail.gmail.com","subject":"Re: [RFC PATCH 3/3] git-rebase.sh: make git-rebase--interactive the default","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-01-22T15:37:02Z","receivedAt":"2019-01-22T15:37:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Elijah,\n\nOn Mon, 21 Jan 2019, Elijah Newren wrote:\n\n> Before worrying about adding extra options and deprecation periods,\n> though, perhaps we could start by by omitting the --cherry-pick for\n> implicitly_interactive rebases, like --merge?  (In particular, I'm\n> thinking that when we switch the default rebase to be --merge instead of\n> --am[1], we avoid breaking things.)\n\nThere are more implicitly interactive rebase modes, though, such as\n`--exec` and `--rebase-merges`. I would like to keep `--cherry-pick` for\nthem by default, at least I think I would.\n\n> I am not familiar with MinHash and Locally Sensitive Hashes, but I'll\n> add them to the list of things to look into.  Thanks for the idea.\n\nOf course! Please let me know if you get to this idea, or if you find\nsomething even better. I'd like to collaborate with you on this, as I\nreally need to find a better way to identify upstream commits in\nGitGitGadget.\n\nThanks,\nDscho\n"}]}