{"thread":{"id":"38916","subject":"[PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","startedAt":"2015-03-26T13:04:07Z","lastAt":"2015-04-02T09:53:35Z","messageCount":19,"participants":["Sebastian Schuberth","Junio C Hamano","Sergey Organov","Johannes Sixt"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"258545","messageId":"CAHGBnuO5Y=ejJLxktk0GsnXx8h2LwPW1i7TqDePhfZ_zLR_X9A@mail.gmail.com","threadId":"38916","inReplyTo":null,"subject":"[PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-03-26T13:04:07Z","receivedAt":"2015-03-26T13:04:07Z","isPatch":true,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"Ignoring a merge sounds like ignoring the changes a merge commit\nintroduces altogether, as if the merge commit was skipped or dropped from\nhistory. But that is not what happens if this options is not specified.\nInstead, what happens is that the separate commits a merge commit\nintroduces are replayed in order, and only any possible merge conflict\nresolutions are ignored. Get this straight in the docs.\n\nAlso, do not say that merge commits are *tried* to be recreated. They are\nrecreated, but possibly with conflicts, which in turn are likely to be\ndifferent from any original conflicts. Still recreating a merge commit does\nnot just silently fail in any case, which is how \"try to recreate\" might\nsound.\n\nSigned-off-by: Sebastian Schuberth <sschuberth@gmail.com>\n---\n Documentation/git-rebase.txt | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex d728030..3a6d139 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -362,7 +362,7 @@ default is `--no-fork-point`, otherwise the\ndefault is `--fork-point`.\n\n -p::\n --preserve-merges::\n-    Instead of ignoring merges, try to recreate them.\n+    Recreate merge commits instead of replaying commits a merge\ncommit introduces.\n +\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n-- \n1.9.5.msysgit.1\n"},{"id":"258560","messageId":"xmqqd23vzkon.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"CAHGBnuO5Y=ejJLxktk0GsnXx8h2LwPW1i7TqDePhfZ_zLR_X9A@mail.gmail.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-26T18:18:48Z","receivedAt":"2015-03-26T18:18:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sebastian Schuberth <sschuberth@gmail.com> writes:\n\n> Also, do not say that merge commits are *tried* to be recreated.\n\nGood point.  \"We will try but it might fail\" is better left unsaid\nas that is true almost everywhere.\n\n\n> Signed-off-by: Sebastian Schuberth <sschuberth@gmail.com>\n> ---\n>  Documentation/git-rebase.txt | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index d728030..3a6d139 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -362,7 +362,7 @@ default is `--no-fork-point`, otherwise the\n> default is `--fork-point`.\n>\n>  -p::\n>  --preserve-merges::\n> -    Instead of ignoring merges, try to recreate them.\n> +    Recreate merge commits instead of replaying commits a merge\n> commit introduces.\n\nHmm, is this line-wrapped?\n\nAlthough I fully agree that the new text is better than the original,\nI think the new text fails to point out one major aspect by not\nmentioning \"linear\" or \"flatten\" anywhere.  The point of \"git rebase\"\nwithout \"-p\" is not just to replay but to flatten\n\n\tInstead of flattening the history by replaying each\n\tnon-merge commit to be rebased, preserve the shape of the\n\trebased history by recreating merge commits as well.\n\nor something along that line, perhaps?\n\nThis reminds me a related tangent discussion we had long time ago (I\nthought j6t was involved hence a new Cc:, but my apologies to j6t if\nI am misremembering), about what exactly is \"recreate merges instead\nof replaying commits\".\n\nI think the current preserve-merges considers everything between\n<upstream> and <branch> as \"commits to be rebased\", and recreate\nmerges across these rebased tips of branches that are merged.  There\nhowever were repeated wishes (or wishful misunderstandings ;-) that\nthere were a mode to rebuild the trunk, considering only the commits\non the first-parent chain as \"commits to be rebased\", recreating the\nhistory by replaying the merge commits (whose first parent might be\nrewritten during the rebase, but the tips of side branches these\nmerges bring into the history are kept intact).\n\nSurely there is no such mode right now, but I am fairly sure that I\nwouldn't have any objection against a patch to implement such a\nfeature (perhaps \"--first-parent --preserve-merges\"?), and with or\nwithout such a feature in the system, I would be happier if we made\nsure that the description we are discussing to update makes it clear\nthat the current behaviour is \"everything between <upstream> and\n<branch>\", and cannot be misread as \"do not touch side branches\ninstead of dropping merged commits\".\n\n>  +\n>  This uses the `--interactive` machinery internally, but combining it\n>  with the `--interactive` option explicitly is generally not a good\n"},{"id":"258565","messageId":"55146BF5.7040008@gmail.com","threadId":"38916","inReplyTo":"xmqqd23vzkon.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-03-26T20:28:37Z","receivedAt":"2015-03-26T20:28:37Z","isPatch":true,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"On 26.03.2015 19:18, Junio C Hamano wrote:\n\n>> Also, do not say that merge commits are *tried* to be recreated.\n>\n> Good point.  \"We will try but it might fail\" is better left unsaid\n> as that is true almost everywhere.\n\nExactly.\n\n>>   -p::\n>>   --preserve-merges::\n>> -    Instead of ignoring merges, try to recreate them.\n>> +    Recreate merge commits instead of replaying commits a merge\n>> commit introduces.\n>\n> Hmm, is this line-wrapped?\n\nProbably, I had to send this via GMail.\n\n> Although I fully agree that the new text is better than the original,\n> I think the new text fails to point out one major aspect by not\n> mentioning \"linear\" or \"flatten\" anywhere.  The point of \"git rebase\"\n> without \"-p\" is not just to replay but to flatten\n>\n> \tInstead of flattening the history by replaying each\n> \tnon-merge commit to be rebased, preserve the shape of the\n> \trebased history by recreating merge commits as well.\n>\n> or something along that line, perhaps?\n\nHm, I'm not sure about the \"as well\" here. Non-merge commits basically \nare just picked, not recreated in the same sense as merge commits. I'll \ncome up with another proposal.\n\n> I think the current preserve-merges considers everything between\n> <upstream> and <branch> as \"commits to be rebased\", and recreate\n> merges across these rebased tips of branches that are merged.  There\n> however were repeated wishes (or wishful misunderstandings ;-) that\n> there were a mode to rebuild the trunk, considering only the commits\n> on the first-parent chain as \"commits to be rebased\", recreating the\n> history by replaying the merge commits (whose first parent might be\n> rewritten during the rebase, but the tips of side branches these\n> merges bring into the history are kept intact).\n\nI guess I'm a victim of that wishful misunderstanding then, as I indeed \nthough that's exactly what the current -p is doing. Well, modulo the \nspecial case where the second parent is the tip of a branch whose \nfork-point with the trunk is part of the rebase, see \"Example 1\" at [1].\n\nIn other word, you're saying that the current preserve-merges does not \nkeep the tips of side branches intact. If that's so, what is is doing \nwith the tips of the side branches?\n\n> without such a feature in the system, I would be happier if we made\n> sure that the description we are discussing to update makes it clear\n> that the current behaviour is \"everything between <upstream> and\n> <branch>\", and cannot be misread as \"do not touch side branches\n> instead of dropping merged commits\".\n\nAgreed. As soon as I understand the difference between the two :-)\n\n[1] http://stackoverflow.com/a/15915431/1127485\n\n-- \nSebastian Schuberth\n"},{"id":"258568","messageId":"xmqqoanfxyv2.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"55146BF5.7040008@gmail.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-26T20:55:29Z","receivedAt":"2015-03-26T20:55:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sebastian Schuberth <sschuberth@gmail.com> writes:\n\n>> \tInstead of flattening the history by replaying each\n>> \tnon-merge commit to be rebased, preserve the shape of the\n>> \trebased history by recreating merge commits as well.\n>>\n>> or something along that line, perhaps?\n>\n> Hm, I'm not sure about the \"as well\" here. Non-merge commits basically\n> are just picked, not recreated in the same sense as merge\n> commits. I'll come up with another proposal.\n\nOK.  I do not see qualitative difference between picking a non-merge\nand picking a merge; they are both being replayed and it is not like\nthe machiery is trying to preserve an evil merge.  Having said that,\nI do not have a strong feeling either way between keeping and\ndropping that \"as well\".  I threw it in there only to contrast the\npreserve mode (where merges are also picked) with the normal mode\n(where merges are not picked).\n"},{"id":"258571","messageId":"871tkblapv.fsf@javad.com","threadId":"38916","inReplyTo":"xmqqd23vzkon.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-03-26T21:17:48Z","receivedAt":"2015-03-26T21:17:48Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n[...]\n\n> I think the current preserve-merges considers everything between\n> <upstream> and <branch> as \"commits to be rebased\", and recreate\n> merges across these rebased tips of branches that are merged.\n>\n> There however were repeated wishes (or wishful misunderstandings ;-)\n> that there were a mode to rebuild the trunk, considering only the\n> commits on the first-parent chain as \"commits to be rebased\",\n> recreating the history by replaying the merge commits (whose first\n> parent might be rewritten during the rebase, but the tips of side\n> branches these merges bring into the history are kept intact).\n>\n> Surely there is no such mode right now,\n\nIsn't it what Johannes Sixt <j6t@kdbg.org> mentions here?:\n\n[QUOTE]\nIf you want a version of --preserve-merges that does what *you* need,\nconsider this commit:\n\n  git://repo.or.cz/git/mingw/j6t.git rebase-p-first-parent\n\nUse it like this:\n\n  git rebase -i -p --first-parent ...\n\nBeware, its implementation is incomplete: if the rebase is interrupted,\nthen 'git rebase --continue' behaves as if --first-parent were not given.\n[/QUOTE].\n\nref: http://permalink.gmane.org/gmane.comp.version-control.git/263584\n\nIf so, then I'd say such mode almost exists.\n\n> but I am fairly sure that I wouldn't have any objection against a\n> patch to implement such a feature (perhaps \"--first-parent\n> --preserve-merges\"?),\n\nIt'd be very welcome feature here, preferably along with a way to pass\nit to 'git pull --rebase', including a way to configure it to be the\ndefault. \n\n> and with or without such a feature in the system, I would be happier\n> if we made sure that the description we are discussing to update makes\n> it clear that the current behaviour is \"everything between <upstream>\n> and <branch>\", and cannot be misread as \"do not touch side branches\n> instead of dropping merged commits\".\n\nI'd also suggest to somehow warn in the manual that current modes of\noperation silently drop changes to merge commits that were made to\nnon-conflicting paths (either during conflict resolution or otherwise.)\n\n-- Sergey.\n"},{"id":"258572","messageId":"55147D27.1060204@kdbg.org","threadId":"38916","inReplyTo":"871tkblapv.fsf@javad.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Johannes Sixt","fromEmail":"j6t@kdbg.org","sentAt":"2015-03-26T21:41:59Z","receivedAt":"2015-03-26T21:41:59Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Am 26.03.2015 um 22:17 schrieb Sergey Organov:\n> Junio C Hamano <gitster@pobox.com> writes:\n>> There however were repeated wishes (or wishful misunderstandings ;-)\n>> that there were a mode to rebuild the trunk, considering only the\n>> commits on the first-parent chain as \"commits to be rebased\",\n>> recreating the history by replaying the merge commits (whose first\n>> parent might be rewritten during the rebase, but the tips of side\n>> branches these merges bring into the history are kept intact).\n>>\n>> Surely there is no such mode right now,\n>\n> Isn't it what Johannes Sixt <j6t@kdbg.org> mentions here?:\n>\n> [QUOTE]\n> If you want a version of --preserve-merges that does what *you* need,\n> consider this commit:\n>\n>    git://repo.or.cz/git/mingw/j6t.git rebase-p-first-parent\n>\n> Use it like this:\n>\n>    git rebase -i -p --first-parent ...\n>\n> Beware, its implementation is incomplete: if the rebase is interrupted,\n> then 'git rebase --continue' behaves as if --first-parent were not given.\n> [/QUOTE].\n>\n> ref: http://permalink.gmane.org/gmane.comp.version-control.git/263584\n>\n> If so, then I'd say such mode almost exists.\n\nThe patch was discussed here:\nhttp://thread.gmane.org/gmane.comp.version-control.git/198125\n\nThe reason that this has not progressed any further is this response in \nthe thread:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/198125/focus=198483\n\nwhere you basically say that a --first-parent mode is good, but it \nshould be separate from --preserve-merges. I haven't made up my mind, \nyet, how to proceed from there.\n\nIf somebody wants to pick up the baton, I'll happily pass it on.\n\n-- Hannes\n"},{"id":"258668","messageId":"5519178A.6080408@gmail.com","threadId":"38916","inReplyTo":"xmqqd23vzkon.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-03-30T09:29:46Z","receivedAt":"2015-03-30T09:29:46Z","isPatch":true,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"On 3/26/2015 19:18, Junio C Hamano wrote:\n\n> Although I fully agree that the new text is better than the original,\n> I think the new text fails to point out one major aspect by not\n> mentioning \"linear\" or \"flatten\" anywhere.  The point of \"git rebase\"\n> without \"-p\" is not just to replay but to flatten\n\nI think it's a bit odd to say that \"-p\" does not flatten if the whole current rebase docs do not use the terms flattening / linearize at all. If we say that that \"-p\" does not flatten, we should say that a \"standard\" rebase wihtout \"-p\" does. I plan to send a patch for that later.\n\n\n> \tInstead of flattening the history by replaying each\n> \tnon-merge commit to be rebased, preserve the shape of the\n> \trebased history by recreating merge commits as well.\n\nPersonally, I like \"positive logic\" better here, i.e. start with saying what the option does, not what it does not do.\n\nSo how about:\n\n[PATCH] docs: Clarify what git-rebase's \"-p\" / \"--preserve-merges\" does\n\nIgnoring a merge sounds like ignoring the changes a merge commit\nintroduces altogether, as if the merge commit was skipped or dropped from\nhistory. But that is not what happens if \"-p\" is not specified.\n\nInstead, what happens is that the individual commits a merge commit\nintroduces are replayed in order, and only any possible merge conflict\nresolutions or manual amendments to the merge commit are ignored. Get this\nstraight in the docs.\n\nAlso, do not say that merge commits are *tried* to be recreated. As that is\ntrue almost everywhere it is better left unsaid.\n\nSigned-off-by: Sebastian Schuberth <sschuberth@gmail.com>\n---\n Documentation/git-rebase.txt | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex d728030..47984e8 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -362,7 +362,9 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n \n -p::\n --preserve-merges::\n-\tInstead of ignoring merges, try to recreate them.\n+\tRecreate merge commits instead of flattening the history by replaying\n+\tcommits a merge commit introduces. Merge conflict resolutions or manual\n+\tamendments to merge commits are not preserved.\n +\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n-- \n1.9.5.msysgit.1\n"},{"id":"258676","messageId":"xmqqfv8mxuuv.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"5519178A.6080408@gmail.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-30T17:23:20Z","receivedAt":"2015-03-30T17:23:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sebastian Schuberth <sschuberth@gmail.com> writes:\n\n> So how about:\n>\n> [PATCH] docs: Clarify what git-rebase's \"-p\" / \"--preserve-merges\" does\n>\n> Ignoring a merge sounds like ignoring the changes a merge commit\n> introduces altogether, as if the merge commit was skipped or dropped from\n> history. But that is not what happens if \"-p\" is not specified.\n\nEvery time I read the above (which is essentially the same from your\nfirst edition I think) I find the \"ignoring the changes a merge\ncommit introduces altogether\" and \"as if the merge commit was\nskipped\" somehow contradicting with each other.  If the latter were\n\"as if the side branch that was merged was skipped or dropped\", I do\nnot see the room for such a misinterpretation.\n\nThat is, at least to me,\n\n         D---E---F\n        /         \\\n    ---A---B---C---G---H\n\nthe former, i.e. \"the changes the merge G introdues\", is \"diff C G\",\nwhile \"merge commit was skipped\" would mean a history like this:\n\n    ---A---B---C---D'--E'--F'--H'\n\nAnd I think with \"as if the side branch that was merged was\ndropped\", this misinterpretation will become impossible.  It can\nonly mean this history:\n\n    ---A---B---C---.---H'\n\n> Instead, what happens is that the individual commits a merge commit\n> introduces are replayed in order, and only any possible merge conflict\n> resolutions or manual amendments to the merge commit are ignored. Get this\n> straight in the docs.\n>\n> Also, do not say that merge commits are *tried* to be recreated. As that is\n> true almost everywhere it is better left unsaid.\n>\n> Signed-off-by: Sebastian Schuberth <sschuberth@gmail.com>\n> ---\n>  Documentation/git-rebase.txt | 4 +++-\n>  1 file changed, 3 insertions(+), 1 deletion(-)\n>\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index d728030..47984e8 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -362,7 +362,9 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n>  \n>  -p::\n>  --preserve-merges::\n> -\tInstead of ignoring merges, try to recreate them.\n> +\tRecreate merge commits instead of flattening the history by replaying\n> +\tcommits a merge commit introduces. Merge conflict resolutions or manual\n> +\tamendments to merge commits are not preserved.\n\nThe patch text itself reads fine.\n\n>  +\n>  This uses the `--interactive` machinery internally, but combining it\n>  with the `--interactive` option explicitly is generally not a good\n"},{"id":"258687","messageId":"CAHGBnuP0mRYWyJiLvWHuqsVxMRPPtvu-QuWmcD8xXeVOXhwSDA@mail.gmail.com","threadId":"38916","inReplyTo":"xmqqfv8mxuuv.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-03-30T19:42:15Z","receivedAt":"2015-03-30T19:42:15Z","isPatch":true,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"On Mon, Mar 30, 2015 at 7:23 PM, Junio C Hamano <gitster@pobox.com> wrote:\n\n>> Ignoring a merge sounds like ignoring the changes a merge commit\n>> introduces altogether, as if the merge commit was skipped or dropped from\n>> history. But that is not what happens if \"-p\" is not specified.\n>\n> Every time I read the above (which is essentially the same from your\n> first edition I think) I find the \"ignoring the changes a merge\n> commit introduces altogether\" and \"as if the merge commit was\n> skipped\" somehow contradicting with each other.  If the latter were\n> \"as if the side branch that was merged was skipped or dropped\", I do\n> not see the room for such a misinterpretation.\n>\n> That is, at least to me,\n>\n>          D---E---F\n>         /         \\\n>     ---A---B---C---G---H\n>\n> the former, i.e. \"the changes the merge G introdues\", is \"diff C G\",\n\nTo me, too. In other words, this is the combined diff of all commits\nreachable from all parents of the merge (other than the first parent).\nIn your example, that would be the combined diff of D, E and F, which\nequals \"git diff C G\".\n\nHowever, I'm used to thinking that a non-conflicting merge itself has\nno diff, but introduces commits that have diffs. This way of seeing it\nprobably comes from my intensive use of gitk which does not display a\ndiff when selecting a merge commit unless it has conflicts resolved.\n\n> while \"merge commit was skipped\" would mean a history like this:\n>\n>     ---A---B---C---D'--E'--F'--H'\n>\n\nThis is where your interpretation differs. If a merge commit was\nskipped, it is non-existent. If it is non-existent, it also has no\nparents. If it has no parents, there are no commits that D, E, F could\nbe replayed on to of C. Thus for me, skipping merge commit G in your\nexample would result in:\n\n    ---A---B---C---H'\n\n> And I think with \"as if the side branch that was merged was\n> dropped\", this misinterpretation will become impossible.  It can\n> only mean this history:\n>\n>     ---A---B---C---.---H'\n\nI think we need to generalize the wording a bit for merges with more\nthan two parents. How about making the the first paragraph of the\ncommit message simply read:\n\nIgnoring a merge sounds like dropping the merge commit and all side\nbranches it merges from history. But that is not what happens if \"-p\" is\nnot specified.\n\n-- \nSebastian Schuberth\n"},{"id":"258689","messageId":"xmqqtwx2w937.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"CAHGBnuP0mRYWyJiLvWHuqsVxMRPPtvu-QuWmcD8xXeVOXhwSDA@mail.gmail.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-30T19:58:52Z","receivedAt":"2015-03-30T19:58:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sebastian Schuberth <sschuberth@gmail.com> writes:\n\n>> That is, at least to me,\n>>\n>>          D---E---F\n>>         /         \\\n>>     ---A---B---C---G---H\n>>\n>> the former, i.e. \"the changes the merge G introdues\", is \"diff C G\",\n>\n> To me, too. In other words, this is the combined diff of all commits\n> reachable from all parents of the merge (other than the first parent).\n> In your example, that would be the combined diff of D, E and F, which\n> equals \"git diff C G\".\n>\n>> while \"merge commit was skipped\" would mean a history like this:\n>>\n>>     ---A---B---C---D'--E'--F'--H'\n>>\n>\n> This is where your interpretation differs.\n\nI know.  If I am rebasing this whole graph on top of somewhere while\nignoring merge G:\n\n>>          D---E---F\n>>         /         \\\n>>     ---A---B---C---G---H\n\nI'll expect changes made by A, B, C, D, E, F and H appear as\ndifferent commits in the result.  That is what \"ignore G\" means to\nme.\n\nBut it is pointless for you to say \"Your attempt to misunderstand\nthe current and proposed text is flawed\".  People are flawed and I\nam merely pointing out that what you wrote can be read by people\nother than you in a way you did not mean to.\n\nAnd my response was an attempt to offer a suggestion to make it\nharder to be misread by anybody.\n\n> Ignoring a merge sounds like dropping the merge commit and all side\n> branches it merges from history.\n\n... Yes to _some_ people (including you, but not me).  And that is\nwhy we are trying to improve the text in the documentation, no?\n"},{"id":"258690","messageId":"xmqqoanaw7xm.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"xmqqtwx2w937.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-30T20:23:49Z","receivedAt":"2015-03-30T20:23:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n>> Ignoring a merge sounds like dropping the merge commit and all side\n>> branches it merges from history.\n>\n> ... Yes to _some_ people (including you, but not me).  And that is\n> why we are trying to improve the text in the documentation, no?\n\nLet's try this again as I do not think there is no need to argue in\nthe end.\n\nWe agree that this is a good patch:\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex d728030..47984e8 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -362,7 +362,9 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n \n -p::\n --preserve-merges::\n-\tInstead of ignoring merges, try to recreate them.\n+\tRecreate merge commits instead of flattening the history by replaying\n+\tcommits a merge commit introduces. Merge conflict resolutions or manual\n+\tamendments to merge commits are not preserved.\n +\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n\nThe primary reason is \"ignoring merges\" can be read in two ways.\n\n - Some people, including the ones who wrote the original text (and\n   also those who haven't complained to the original text since 2008\n   because their reading of the phrase was the same as those who\n   wrote it), read it as \"We will normally replay what appears in\n   the output from 'git log --no-merges', losing what was merged\n   where into what.  This option instead keeps the shape of the\n   history by considering where the merge commits sit in the\n   original history\".\n\n - It can however be read in a different way, namely, \"We will\n   replay what appears in 'git log --first-parent --no-merges'\n   output, ignoring all the side branches\".  Some other people,\n   including you, find that inconsistent with what is actually\n   implemented as a normal rebase.\n\nAnd we agree the updated text is a good change, because it does not\nsay \"ignore merge\" anywhere to invite such a confusion.\n\nI am only reacting to your description to justify that change, which\nwas:\n\n> Ignoring a merge sounds like ignoring the changes a merge commit\n> introduces altogether, as if the merge commit was skipped or dropped from\n> history. But that is not what happens if \"-p\" is not specified.\n\nAnd we agree that the first part of the sentence, up to\n\"... altogether\", is good.\n\nI am saying \"as if\" part is reintroducing the confusion.\n\n    as if the merge commit was skipped or dropped from history.\n\nTo those who did not interpret the existing \"ignoring merges\", which\nmeant to be read as \"replay the output of 'log --no-merges'\nsequencially\", the above exactly says \"replay the output of 'log\n--no-merges'\".  That is the reason why they were happy with the\ncurrent text, without seeing how it can be read differently.\n\nTo them (including me), the justfication is saying \"... sounds like\nX, as if Y, but it is wrong\" using Y that is completely opposite of\nX, even they would agree that X is a wrong interpretation caused by\na non-optimal phrasing.\n\nThat is why I suggested to avoid \"merge commit was skipped or\ndropped\" in the description and instead say \"as if the side branch\nthat was merged was skipped or dropped\".\n\nThe following may be agreeable to both camps of people, those who\nread \"ignoring merge\" to mean \"log --no-merges\" and those who read\nit to mean \"log --first-parent --no-merges\", I would think.\n\n-- >8 --\nFrom: Sebastian Schuberth <sschuberth@gmail.com>\nDate: Mon, 30 Mar 2015 11:29:46 +0200\nSubject docs: clarify what git-rebase's \"-p\" / \"--preserve-merges\" does\n\nIgnoring a merge can be read as ignoring the changes a merge commit\nintroduces altogether, as if the entire side branch the merge commit\nmerged was removed from the history.  But that is not what happens\nif \"-p\" is not specified.  What happens is that the individual\ncommits a merge commit introduces are replayed in order, and only\nany possible merge conflict resolutions or manual amendments to the\nmerge commit are ignored.\n\nGet this straight in the docs.\n\nAlso, do not say that merge commits are *tried* to be recreated. As that is\ntrue almost everywhere it is better left unsaid.\n\nSigned-off-by: Sebastian Schuberth <sschuberth@gmail.com>\n---\n Documentation/git-rebase.txt | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex d728030..47984e8 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -362,7 +362,9 @@ default is `--no-fork-point`, otherwise the default is `--fork-point`.\n \n -p::\n --preserve-merges::\n-\tInstead of ignoring merges, try to recreate them.\n+\tRecreate merge commits instead of flattening the history by replaying\n+\tcommits a merge commit introduces. Merge conflict resolutions or manual\n+\tamendments to merge commits are not preserved.\n +\n This uses the `--interactive` machinery internally, but combining it\n with the `--interactive` option explicitly is generally not a good\n"},{"id":"258694","messageId":"5519BB7F.4040603@gmail.com","threadId":"38916","inReplyTo":"xmqqoanaw7xm.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sebastian Schuberth","fromEmail":"sschuberth@gmail.com","sentAt":"2015-03-30T21:09:19Z","receivedAt":"2015-03-30T21:09:19Z","isPatch":true,"sender":{"key":"sschuberth@gmail.com","avatar":"https://avatars.githubusercontent.com/u/349154?v=4"},"body":"On 30.03.2015 22:23, Junio C Hamano wrote:\n\n> Ignoring a merge can be read as ignoring the changes a merge commit\n> introduces altogether, as if the entire side branch the merge commit\n> merged was removed from the history.  But that is not what happens\n\nSounds good to me. Thanks.\n\n-- \nSebastian Schuberth\n"},{"id":"258735","messageId":"87lhidlebw.fsf@javad.com","threadId":"38916","inReplyTo":"55147D27.1060204@kdbg.org","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-03-31T09:13:23Z","receivedAt":"2015-03-31T09:13:23Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Johannes Sixt <j6t@kdbg.org> writes:\n\n>> Junio C Hamano <gitster@pobox.com> writes:\n\n[...]\n\n> The patch was discussed here:\n> http://thread.gmane.org/gmane.comp.version-control.git/198125\n>\n> The reason that this has not progressed any further is this response\n> in the thread:\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/198125/focus=198483\n>\n> where you basically say that a --first-parent mode is good, but it\n> should be separate from --preserve-merges. I haven't made up my mind,\n> yet, how to proceed from there.\n\nAs far as I can see, there are 2 separate issues:\n\n1. How to calculate the set of commits to rebase.\n\n2. How to rebase merge commits.\n\nCan we leave (1) for a while at its current state and focus on (2)?\nJohannes's patch contains a fix for that: use cherry-pick to recreate\nmerge commits instead of trying to re-merge. Could this change be\naccepted alone, as a known fix for current buggy behavior of loosing\nuser changes in merge commits?\n\n-- Sergey.\n"},{"id":"258746","messageId":"xmqqh9t1rv0r.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"87lhidlebw.fsf@javad.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-31T16:28:36Z","receivedAt":"2015-03-31T16:28:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> 1. How to calculate the set of commits to rebase.\n>\n> 2. How to rebase merge commits.\n>\n> Can we leave (1) for a while at its current state and focus on (2)?\n\nPerhaps.  You would have to be careful though, so let me think aloud\na bit...\n\nSuppose you started from an upstream history whose tip was B, and\nyou worked on merging some changes X an Y you made earlier on a side\nbranch.\n\n         X---Y\n        /     \\\n   O---A---B---Z---\n\nIn the meantime, the upstream history has advance and now it looks\nlike this:\n\n   O---A---B---C---D\n\nYou want to forward-port the change done by X, Y on the side branch\nand its merge Z on top of D, right?\n\nIn other words, you want to have this:\n\n         X-----------Y\n        /             \\\n   O---A---B---C---D---Z'\n\nIn this case, replaying the difference going from B to Z on top of D\nmay be better than redoing a merge between Y and D, in that the\nformer will carry evil merges and resolution of conflict forward.\n\nI wonder if it will be the right way to get a correct result to\napply the difference to go from B to Z on top of an old commit when\nyou are side-porting.\n\nImagine you want to backport the same X-Y history by redoing the\nmerge Z on top of another child of O (i.e. A's sibling).  That is,\nyou start from this:\n\n\n         X---Y\n        /     \\\n   O---A---B---Z---\n    \\\n     M---N\n\nand would want to create this:\n    \n    \n   O           X'--Y'\n    \\         /     \\    \n     M---N---A'--B'--Z'--\n\nAs long as everything down to the merge-base of the parents of the\noriginal merge (in this example, merge-base across Y and B that are\nZ's parents, which is A) is being transplanted, \"apply the\ndifference going from B to Z, on top of B', to obtain Z'\" should\nwork, I would think.\n"},{"id":"258748","messageId":"87iodhqetq.fsf@javad.com","threadId":"38916","inReplyTo":"xmqqh9t1rv0r.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-03-31T17:03:45Z","receivedAt":"2015-03-31T17:03:45Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> 1. How to calculate the set of commits to rebase.\n>>\n>> 2. How to rebase merge commits.\n>>\n>> Can we leave (1) for a while at its current state and focus on (2)?\n>\n> Perhaps.  You would have to be careful though, so let me think aloud\n> a bit...\n\nYeah, care should be taken indeed, and it's not trivial to foresee all\npossible troubles from changing to cherry-picking of merge commits.\nHowever, in general it looks like it's better to get some conflict to\ndeal with from cherry-picking than to miss essential changes silently as\nit sometimes happens now.\n\nI also wonder if git remembers in merge commits what merge strategy was\nused? If not, then it's yet another argument in favor of cherry-picking.\n\n-- Sergey.\n"},{"id":"258749","messageId":"xmqq8uedrtdb.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"xmqqh9t1rv0r.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-03-31T17:04:16Z","receivedAt":"2015-03-31T17:04:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I wonder if it will be the right way to get a correct result to\n> apply the difference to go from B to Z on top of an old commit when\n> you are side-porting.\n>\n> Imagine you want to backport the same X-Y history by redoing the\n> merge Z on top of another child of O (i.e. A's sibling).  That is,\n> you start from this:\n>\n>\n>          X---Y\n>         /     \\\n>    O---A---B---Z---\n>     \\\n>      M---N\n>\n> and would want to create this:\n>     \n>     \n>    O           X'--Y'\n>     \\         /     \\    \n>      M---N---A'--B'--Z'--\n>\n> As long as everything down to the merge-base of the parents of the\n> original merge (in this example, merge-base across Y and B that are\n> Z's parents, which is A) is being transplanted, \"apply the\n> difference going from B to Z, on top of B', to obtain Z'\" should\n> work, I would think.\n\nAnd just after I send the message because I needed to catch a bus, I\nnotice that there is a problem.\n\nActually, \"replay diff going from B to Z instead of merging\" must be\ndone very carefully.  Imagine when Y in the original history were a\ncherry-pick of M.  What you would be creating would look more like\nthis instead:\n     \n    O           X'--.\n     \\         /     \\    \n      M---N---A'--B'--Z'--\n\nbecause Y' becomes a no-op, as the transplanted history already has\nM applied.  But the original \"diff going from B to Z\" has the effect\nof M already in there.  You would end up adding the same hunk twice\nwithout noticing.  You somehow need to come up with a way to deal\nwith this.\n\nIf you did a real merge between X' and B' to recreate Z', you would\nnot have such a problem.\n\nOne way to be careful when recreating Z' out of Z might be:\n\n    - Retry a merge between the original B and Y, with conflict\n      markers intact;\n\n    - Compare the result with what is recorded in Z.  The\n      differences are textual conflict resolution and evil merge\n      changes;\n\n    - Now try a merge between B' and Y', with conflict markers\n      intact;\n\n    - Apply the difference you obtained in the second step to the\n      result of the third step.\n\nwhich is essentially the same as what rerere does.\n"},{"id":"258819","messageId":"87vbhgks0v.fsf@javad.com","threadId":"38916","inReplyTo":"xmqq8uedrtdb.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sergey Organov","fromEmail":"s.organov@javad.com","sentAt":"2015-04-01T11:27:28Z","receivedAt":"2015-04-01T11:27:28Z","isPatch":true,"sender":{"key":"s.organov@javad.com","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> I wonder if it will be the right way to get a correct result to\n>> apply the difference to go from B to Z on top of an old commit when\n>> you are side-porting.\n>>\n>> Imagine you want to backport the same X-Y history by redoing the\n>> merge Z on top of another child of O (i.e. A's sibling).  That is,\n>> you start from this:\n>>\n>>\n>>          X---Y\n>>         /     \\\n>>    O---A---B---Z---\n>>     \\\n>>      M---N\n>>\n>> and would want to create this:\n>>     \n>>     \n>>    O           X'--Y'\n>>     \\         /     \\    \n>>      M---N---A'--B'--Z'--\n>>\n>> As long as everything down to the merge-base of the parents of the\n>> original merge (in this example, merge-base across Y and B that are\n>> Z's parents, which is A) is being transplanted, \"apply the\n>> difference going from B to Z, on top of B', to obtain Z'\" should\n>> work, I would think.\n>\n> And just after I send the message because I needed to catch a bus, I\n> notice that there is a problem.\n>\n> Actually, \"replay diff going from B to Z instead of merging\" must be\n> done very carefully.  Imagine when Y in the original history were a\n> cherry-pick of M.  What you would be creating would look more like\n> this instead:\n>      \n>     O           X'--.\n>      \\         /     \\    \n>       M---N---A'--B'--Z'--\n>\n> because Y' becomes a no-op, as the transplanted history already has\n> M applied.  But the original \"diff going from B to Z\" has the effect\n> of M already in there.  You would end up adding the same hunk twice\n> without noticing. You somehow need to come up with a way to deal\n> with this.\n\nNope. It seems like cherry-pick takes care of that:\n\n[SCRIPT]\ngit init t; cd t; git config rerere.enabled false\n\ncat > a <<EOF\nLine01\nLine02\nLine03\nLine04\nLine05\nLine06\nLine07\nLine08\nLine09\nEOF\n\ngit add a\ngit commit -aqm \"A\"\n\ngit checkout -b two-chunks\nsed -i -e 's/Line04/Line04_1/' a\nsed -i -e 's/Line08/Line08_1/' a\ngit commit -aqm \"A_04_08_1\"\n\ngit checkout master\nsed -i -e 's/Line04/Line04_1/' a\ngit commit -aqm \"A_04_1\"\n\ngit cherry-pick two-chunks\n\ngit log --oneline\ncat a\n[/SCRIPT]\n\nWhat do I miss?\n\n-- Sergey.\n"},{"id":"258829","messageId":"xmqqpp7nn5l3.fsf@gitster.dls.corp.google.com","threadId":"38916","inReplyTo":"87vbhgks0v.fsf@javad.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-04-01T17:03:52Z","receivedAt":"2015-04-01T17:03:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <s.organov@javad.com> writes:\n\n> Nope. It seems like cherry-pick takes care of that:\n> ...\n> What do I miss?\n\nThe fact that cherry-pick did not flag it as a potential conflict\nsituation where a manual verification is required (the cherry-pick\nprocess can be fooled by textual similarity and either add the same\nthing twice or fail to add one thing that is needed).\n"},{"id":"258850","messageId":"87619ezwio.fsf@javad.com","threadId":"38916","inReplyTo":"xmqqpp7nn5l3.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH] docs: Clarify what git-rebase's \"--preserve-merges\" does","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2015-04-02T09:53:35Z","receivedAt":"2015-04-02T09:53:35Z","isPatch":true,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Sergey Organov <s.organov@javad.com> writes:\n>\n>> Nope. It seems like cherry-pick takes care of that:\n>> ...\n>> What do I miss?\n>\n> The fact that cherry-pick did not flag it as a potential conflict\n> situation where a manual verification is required\n> (the cherry-pick process can be fooled by textual similarity and\n> either add the same thing twice or fail to add one thing that is\n> needed).\n\nWell, it was not required in the simple case I tested, and cherry-pick\ndid the right thing. I suspect it will do the right thing (flag a\nconflict) where manual verification is required. A test-case\ndemonstrating the problem you have in mind, maybe?\n\nAnyway, how is it different to cherry-pick merge commit compared to any\nother commit? I mean, provided we cherry-pick other commits, we already\naccepted all the possible negative consequences of cherry-picking. How\ncherry-picking merge commits make this worse?\n\nI.e., do you think we have a show-stopper, or just that there are ways\nto handle merge commits event better than simple \"cherry-pick -m1\"? The\nlatter is probably true, but simple cherry-pick still looks much better\nthan what we have now, no?\n\n-- Sergey.\n"}]}