{"thread":{"id":"47864","subject":"[RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","startedAt":"2018-02-16T13:08:50Z","lastAt":"2018-04-02T06:07:10Z","messageCount":173,"participants":["Sergey Organov","Jacob Keller","Igor Djordjevic","Johannes Schindelin","Junio C Hamano","Phillip Wood"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"339535","messageId":"87y3jtqdyg.fsf@javad.com","threadId":"47864","inReplyTo":null,"subject":"[RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-16T13:08:39Z","receivedAt":"2018-02-16T13:08:50Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi,\n\nBy accepting the challenges raised in recent discussion of advanced\nsupport for history rebasing and editing in Git, I hopefully figured out\na clean and elegant method of rebasing merges that I think is \"The Right\nWay (TM)\" to perform this so far troublesome operation. [\"(TM)\" here has\nsecond meaning: a \"Trivial Merge (TM)\", see below.]\n\nLet me begin by outlining the method in git terms, and special thanks\nhere must go to \"Johannes Sixt\" <j6t@kdbg.org> for his original bright\nidea to use \"cherry-pick -m1\" to rebase merge commits.\n\nEnd of preface -- here we go.\n\nGiven 2 original branches, b1 and b2, and a merge commit M that joins\nthem, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose\nalso that B1' and B2' happen to be the tip commits on b1' and b2',\nrespectively.\n\nTo produce merge commit M' that joins b1' and b2', the following\noperations will suffice:\n\n1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2').\n2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1').\n3. Merge --no-ff new b2' to current new b1', to produce UM'.\n4. Get rid of U1' and U2' by re-writing parent references of UM' from\n   U1' and U2' to  B1' and B2', respectively, to produce M'.\n5. Mission complete.\n\nLet's now see why and how the method actually works.\n\nFirs off, let me introduce you to my new friend, the Trivial Merge, or\n(TM) for short. By definition, (TM) is a merge that introduces\nabsolutely no differences to the sides of the merge. (I also like to\nsometimes call him \"Angel Merge\", both as the most beautiful of all\nmerges, and as direct antithesis to \"evil merge\".)\n\nOne very nice thing about (TM) is that to safely rebase it, it suffices\nto merge its (rebased) parents. It is safe in this case, as (TM) itself\ndoesn't posses any content changes, and thus none could be missed by\nreplacing it with another merge commit.\n\nI bet most of us have never seen (TM) in practice though, so let's see\nhow (TM) can help us handle general case of some random merge. What I'm\ngoing to do is to create a virtual (TM) and see how it goes from there.\n\nLet's start with this history:\n\n  M\n / \\\nB1  B2\n\nAnd let's transform it to the following one, contextually equivalent to\nthe original, by introducing 2 simple utility commits U1 and U2, and a\nnew utility merge commit UM:\n\n  UM\n /  \\\nU1   U2\n|    |\nB1   B2\n\nHere content of any of the created UM, U1, and U2 is the same, and is\nexact copy of original content of M. I.e., provided [A] denotes\n\"content of commit A\", we have:\n\n[UM] = [U1] = [U2] = [M]\n\nStress again how these changes to the history preserve the exact content\nof the original merge ([UM] = [M]), and how U1 an U2 represent content\nchanges due to merge on either side[*], and how neither preceding nor\nsubsequent commits content would be affected by the change of\nrepresentation.\n\nNow observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be\nexactly our new friend -- the \"Trivial Merge (TM)\" his true self,\nintroducing zero changes to content.\n\nNext we rebase our new representation of the history and we get:\n\n  UM'\n /  \\\nU1'  U2'\n|    |\nB1'  B2'\n\nHere UM' is bare merge of U1' and U2', in exact accordance with the\nmethod of rebasing a (TM) we've already discussed above, and U1' and U2'\nare rebased versions of U1 and U2, obtained by usual rebasing methods\nfor non-merge commits.\n\n(Note, however, that at this point UM' is not necessarily a (TM)\nanymore, so in real implementation it may make sense to check if UM' is\nnot a (TM) and stop for possible user amendment.)\n\nFinally, to get to our required merge commit M', we get the content of\nUM' and record two actual parents of the merge:\n\n  M'\n / \\\nB1' B2'\n\nWhere [M'] = [UM'].\n\nThat's it. Mission complete.\n\nI expect the method to have the following nice features:\n\n- it carefully preserves user changes by rebasing the merge commit\nitself, in a way that is semantically similar to rebasing simple\n(non-merge) commits, yet it allows changes made to branches during\nhistory editing to propagate over corresponding merge commit that joins\nthe branches, even automatically when the changes don't conflict, as\nexpected.\n\n- it has provision for detection of even slightest chances of ending up\nwith surprising merge (just check if UM' is still (TM)), so that\nimplementation could stop for user inspection and amendment when\nappropriate, yet it is capable of handling trivial cases smoothly and\nautomatically.\n\n- it never falls back to simple invocation of merge operation on rebased\noriginal branches themselves, thus avoiding the problem of lack of\nknowledge of how the merge at hand has been performed in the first\nplace. It doesn't prevent implementation from letting user to manually\nperform whatever merge she wishes when suspect result is automatically\ndetected though.\n\n- it extends trivially to octopus merges.\n\n- it appears shiny to the point that it will likely be able to handle\neven darkest evil merges nicely, no special treatment required.\n\nFootnote:\n\n[*] We may as well consider the (UM,U1,U2) trio to be semantically split\nrepresentation of git merge commit, where U1 and U2 represent content\nchanges to the sides, and UM represents pure history joint. Or, the\nother way around, we may consider git merge commit to be optimized\nrepresentation of this trio. I think this split representation could\nhelp to simplify reasoning about git merges in general.\n\n-- Sergey\n"},{"id":"339592","messageId":"CA+P7+xrgmSHv-coOdUAmBm31Sd0DzYdoez=tVO8drew9q7DExw@mail.gmail.com","threadId":"47864","inReplyTo":"87y3jtqdyg.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-02-18T04:16:34Z","receivedAt":"2018-02-18T04:18:25Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Fri, Feb 16, 2018 at 5:08 AM, Sergey Organov <sorganov@gmail.com> wrote:\n> Hi,\n>\n> By accepting the challenges raised in recent discussion of advanced\n> support for history rebasing and editing in Git, I hopefully figured out\n> a clean and elegant method of rebasing merges that I think is \"The Right\n> Way (TM)\" to perform this so far troublesome operation. [\"(TM)\" here has\n> second meaning: a \"Trivial Merge (TM)\", see below.]\n>\n> Let me begin by outlining the method in git terms, and special thanks\n> here must go to \"Johannes Sixt\" <j6t@kdbg.org> for his original bright\n> idea to use \"cherry-pick -m1\" to rebase merge commits.\n>\n> End of preface -- here we go.\n>\n\nI hope to take a more detailed look at this, also possibly with some\nattempts at re-creating the process by hand to see it in practice.\n\n> Given 2 original branches, b1 and b2, and a merge commit M that joins\n> them, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose\n> also that B1' and B2' happen to be the tip commits on b1' and b2',\n> respectively.\n>\n> To produce merge commit M' that joins b1' and b2', the following\n> operations will suffice:\n>\n> 1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2').\n> 2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1').\n> 3. Merge --no-ff new b2' to current new b1', to produce UM'.\n> 4. Get rid of U1' and U2' by re-writing parent references of UM' from\n>    U1' and U2' to  B1' and B2', respectively, to produce M'.\n> 5. Mission complete.\n>\n\nSeems pretty straight forward, go to each branch and cherry-pick the\nmerge respective to its relative parent, and then finally re-merge\neverything, and consume the intermittent commits.\n\n> Let's now see why and how the method actually works.\n>\n> Firs off, let me introduce you to my new friend, the Trivial Merge, or\n> (TM) for short. By definition, (TM) is a merge that introduces\n> absolutely no differences to the sides of the merge. (I also like to\n> sometimes call him \"Angel Merge\", both as the most beautiful of all\n> merges, and as direct antithesis to \"evil merge\".)\n>\n> One very nice thing about (TM) is that to safely rebase it, it suffices\n> to merge its (rebased) parents. It is safe in this case, as (TM) itself\n> doesn't posses any content changes, and thus none could be missed by\n> replacing it with another merge commit.\n>\n> I bet most of us have never seen (TM) in practice though, so let's see\n> how (TM) can help us handle general case of some random merge. What I'm\n> going to do is to create a virtual (TM) and see how it goes from there.\n>\n> Let's start with this history:\n>\n>   M\n>  / \\\n> B1  B2\n>\n> And let's transform it to the following one, contextually equivalent to\n> the original, by introducing 2 simple utility commits U1 and U2, and a\n> new utility merge commit UM:\n>\n>   UM\n>  /  \\\n> U1   U2\n> |    |\n> B1   B2\n>\n> Here content of any of the created UM, U1, and U2 is the same, and is\n> exact copy of original content of M. I.e., provided [A] denotes\n> \"content of commit A\", we have:\n>\n> [UM] = [U1] = [U2] = [M]\n>\n> Stress again how these changes to the history preserve the exact content\n> of the original merge ([UM] = [M]), and how U1 an U2 represent content\n> changes due to merge on either side[*], and how neither preceding nor\n> subsequent commits content would be affected by the change of\n> representation.\n>\n> Now observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be\n> exactly our new friend -- the \"Trivial Merge (TM)\" his true self,\n> introducing zero changes to content.\n>\n> Next we rebase our new representation of the history and we get:\n>\n>   UM'\n>  /  \\\n> U1'  U2'\n> |    |\n> B1'  B2'\n>\n> Here UM' is bare merge of U1' and U2', in exact accordance with the\n> method of rebasing a (TM) we've already discussed above, and U1' and U2'\n> are rebased versions of U1 and U2, obtained by usual rebasing methods\n> for non-merge commits.\n>\n> (Note, however, that at this point UM' is not necessarily a (TM)\n> anymore, so in real implementation it may make sense to check if UM' is\n> not a (TM) and stop for possible user amendment.)\n>\n\nThis might be a bit tricky for a user to understand what the process\nis, especially if they don't understand how it's creating special U1'\nand U2' commits. However, it *is* the cleanest method I've either seen\nor thought of for presenting the conflict to the user.\n\n> Finally, to get to our required merge commit M', we get the content of\n> UM' and record two actual parents of the merge:\n>\n>   M'\n>  / \\\n> B1' B2'\n>\n> Where [M'] = [UM'].\n>\n> That's it. Mission complete.\n>\n> I expect the method to have the following nice features:\n>\n> - it carefully preserves user changes by rebasing the merge commit\n> itself, in a way that is semantically similar to rebasing simple\n> (non-merge) commits, yet it allows changes made to branches during\n> history editing to propagate over corresponding merge commit that joins\n> the branches, even automatically when the changes don't conflict, as\n> expected.\n>\n\nRight.\n\n> - it has provision for detection of even slightest chances of ending up\n> with surprising merge (just check if UM' is still (TM)), so that\n> implementation could stop for user inspection and amendment when\n> appropriate, yet it is capable of handling trivial cases smoothly and\n> automatically.\n\nNice!\n\n>\n> - it never falls back to simple invocation of merge operation on rebased\n> original branches themselves, thus avoiding the problem of lack of\n> knowledge of how the merge at hand has been performed in the first\n> place. It doesn't prevent implementation from letting user to manually\n> perform whatever merge she wishes when suspect result is automatically\n> detected though.\n>\n\nRight, since we're re-creating the intermittent commits U1' and U2'\nfirst based on the original merge, that's how we manage to maintain\nthe result of the merge. I like it.\n\n> - it extends trivially to octopus merges.\n>\n> - it appears shiny to the point that it will likely be able to handle\n> even darkest evil merges nicely, no special treatment required.\n>\n\nYep, and I like that it has a pretty reasonable way of presenting\nconflicts for resolution. It may be a bit tricky to explain the use of\nthe intermittent commits U1' and U2' though.\n\n> Footnote:\n>\n> [*] We may as well consider the (UM,U1,U2) trio to be semantically split\n> representation of git merge commit, where U1 and U2 represent content\n> changes to the sides, and UM represents pure history joint. Or, the\n> other way around, we may consider git merge commit to be optimized\n> representation of this trio. I think this split representation could\n> help to simplify reasoning about git merges in general.\n\nYes, I think this concept is pretty useful. I think it could be useful\nas a way of showing how the merge worked.\n\nThanks,\nJake\n\n>\n> -- Sergey\n"},{"id":"339598","messageId":"87a7w5r1ip.fsf@javad.com","threadId":"47864","inReplyTo":"CA+P7+xrgmSHv-coOdUAmBm31Sd0DzYdoez=tVO8drew9q7DExw@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-19T05:28:46Z","receivedAt":"2018-02-19T05:28:54Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Jake,\n\nJacob Keller <jacob.keller@gmail.com> writes:\n> On Fri, Feb 16, 2018 at 5:08 AM, Sergey Organov <sorganov@gmail.com> wrote:\n>> Hi,\n>>\n>> By accepting the challenges raised in recent discussion of advanced\n>> support for history rebasing and editing in Git, I hopefully figured out\n>> a clean and elegant method of rebasing merges that I think is \"The Right\n>> Way (TM)\" to perform this so far troublesome operation. [\"(TM)\" here has\n>> second meaning: a \"Trivial Merge (TM)\", see below.]\n>>\n>> Let me begin by outlining the method in git terms, and special thanks\n>> here must go to \"Johannes Sixt\" <j6t@kdbg.org> for his original bright\n>> idea to use \"cherry-pick -m1\" to rebase merge commits.\n>>\n>> End of preface -- here we go.\n>>\n>\n> I hope to take a more detailed look at this, also possibly with some\n> attempts at re-creating the process by hand to see it in practice.\n\nThank you for your interest and for the review, and yes, some testing is\nwhat the idea desperately needs. Unfortunately I don't have much time\nfor it right now, nor am I fluent enough in git internals to actually\nmake even a raw prototype really soon, sorry. Anybody who is interested\nis very welcome to volunteer!\n\n[...]\n>\n> This might be a bit tricky for a user to understand what the process\n> is, especially if they don't understand how it's creating special U1'\n> and U2' commits. However, it *is* the cleanest method I've either seen\n> or thought of for presenting the conflict to the user.\n>\n[...]\n>> - it appears shiny to the point that it will likely be able to handle\n>> even darkest evil merges nicely, no special treatment required.\n>>\n>\n> Yep, and I like that it has a pretty reasonable way of presenting\n> conflicts for resolution. It may be a bit tricky to explain the use of\n> the intermittent commits U1' and U2' though.\n\nYeah, I see how all this sends somewhat unique challenges to the\nimplementation to get user interaction in case of conflicts right, even\nthough all the basic concepts are old buddies and should be familiar to\nthe user.\n\nThat said, the recursive merge strategy comes to mind, where creating\nvirtual merge base may itself cause conflicts, so something similar\nenough is likely to already exist.\n\n-- Sergey\n"},{"id":"339688","messageId":"bbe64321-4d3a-d3fe-8bb9-58b600fabf35@gmail.com","threadId":"47864","inReplyTo":"87y3jtqdyg.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-19T23:44:52Z","receivedAt":"2018-02-19T23:45:02Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 16/02/2018 14:08, Sergey Organov wrote:\n> \n> By accepting the challenges raised in recent discussion of advanced\n> support for history rebasing and editing in Git, I hopefully figured out\n> a clean and elegant method of rebasing merges that I think is \"The Right\n> Way (TM)\" to perform this so far troublesome operation. [\"(TM)\" here has\n> second meaning: a \"Trivial Merge (TM)\", see below.]\n> \n> Let me begin by outlining the method in git terms, and special thanks\n> here must go to \"Johannes Sixt\" <j6t@kdbg.org> for his original bright\n> idea to use \"cherry-pick -m1\" to rebase merge commits.\n> \n> End of preface -- here we go.\n> \n> Given 2 original branches, b1 and b2, and a merge commit M that joins\n> them, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose\n> also that B1' and B2' happen to be the tip commits on b1' and b2',\n> respectively.\n> \n> To produce merge commit M' that joins b1' and b2', the following\n> operations will suffice:\n> \n> 1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2').\n> 2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1').\n> 3. Merge --no-ff new b2' to current new b1', to produce UM'.\n> 4. Get rid of U1' and U2' by re-writing parent references of UM' from\n>    U1' and U2' to  B1' and B2', respectively, to produce M'.\n> 5. Mission complete.\n> \n> Let's now see why and how the method actually works.\n> \n> Firs off, let me introduce you to my new friend, the Trivial Merge, or\n> (TM) for short. By definition, (TM) is a merge that introduces\n> absolutely no differences to the sides of the merge. (I also like to\n> sometimes call him \"Angel Merge\", both as the most beautiful of all\n> merges, and as direct antithesis to \"evil merge\".)\n> \n> One very nice thing about (TM) is that to safely rebase it, it suffices\n> to merge its (rebased) parents. It is safe in this case, as (TM) itself\n> doesn't posses any content changes, and thus none could be missed by\n> replacing it with another merge commit.\n> \n> I bet most of us have never seen (TM) in practice though, so let's see\n> how (TM) can help us handle general case of some random merge. What I'm\n> going to do is to create a virtual (TM) and see how it goes from there.\n> \n> Let's start with this history:\n> \n>   M\n>  / \\\n> B1  B2\n> \n> And let's transform it to the following one, contextually equivalent to\n> the original, by introducing 2 simple utility commits U1 and U2, and a\n> new utility merge commit UM:\n> \n>   UM\n>  /  \\\n> U1   U2\n> |    |\n> B1   B2\n> \n> Here content of any of the created UM, U1, and U2 is the same, and is\n> exact copy of original content of M. I.e., provided [A] denotes\n> \"content of commit A\", we have:\n> \n> [UM] = [U1] = [U2] = [M]\n> \n> Stress again how these changes to the history preserve the exact content\n> of the original merge ([UM] = [M]), and how U1 an U2 represent content\n> changes due to merge on either side[*], and how neither preceding nor\n> subsequent commits content would be affected by the change of\n> representation.\n> \n> Now observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be\n> exactly our new friend -- the \"Trivial Merge (TM)\" his true self,\n> introducing zero changes to content.\n> \n> Next we rebase our new representation of the history and we get:\n> \n>   UM'\n>  /  \\\n> U1'  U2'\n> |    |\n> B1'  B2'\n> \n> Here UM' is bare merge of U1' and U2', in exact accordance with the\n> method of rebasing a (TM) we've already discussed above, and U1' and U2'\n> are rebased versions of U1 and U2, obtained by usual rebasing methods\n> for non-merge commits.\n> \n> (Note, however, that at this point UM' is not necessarily a (TM)\n> anymore, so in real implementation it may make sense to check if UM' is\n> not a (TM) and stop for possible user amendment.)\n> \n> Finally, to get to our required merge commit M', we get the content of\n> UM' and record two actual parents of the merge:\n> \n>   M'\n>  / \\\n> B1' B2'\n> \n> Where [M'] = [UM'].\n> \n> That's it. Mission complete.\n> \n> I expect the method to have the following nice features:\n> \n> - it carefully preserves user changes by rebasing the merge commit\n> itself, in a way that is semantically similar to rebasing simple\n> (non-merge) commits, yet it allows changes made to branches during\n> history editing to propagate over corresponding merge commit that joins\n> the branches, even automatically when the changes don't conflict, as\n> expected.\n> \n> - it has provision for detection of even slightest chances of ending up\n> with surprising merge (just check if UM' is still (TM)), so that\n> implementation could stop for user inspection and amendment when\n> appropriate, yet it is capable of handling trivial cases smoothly and\n> automatically.\n> \n> - it never falls back to simple invocation of merge operation on rebased\n> original branches themselves, thus avoiding the problem of lack of\n> knowledge of how the merge at hand has been performed in the first\n> place. It doesn't prevent implementation from letting user to manually\n> perform whatever merge she wishes when suspect result is automatically\n> detected though.\n> \n> - it extends trivially to octopus merges.\n> \n> - it appears shiny to the point that it will likely be able to handle\n> even darkest evil merges nicely, no special treatment required.\n> \n> Footnote:\n> \n> [*] We may as well consider the (UM,U1,U2) trio to be semantically split\n> representation of git merge commit, where U1 and U2 represent content\n> changes to the sides, and UM represents pure history joint. Or, the\n> other way around, we may consider git merge commit to be optimized\n> representation of this trio. I think this split representation could\n> help to simplify reasoning about git merges in general.\n\nI`m far from a Git expert, but merely a bit advanced user, so please \ntake my opinion with a grain of salt.\n\nThat said, I`m really interested in this topic, which seems to (try \nto) address the only \"bad feeling\" I had with rebasing merges - being \nafraid of silently losing amendments by actually trying to \"replay\" \nthe merge (where additional and possibly important context is \nmissing), instead of really \"rebasing\" it (somehow).\n\nEven though this behavior is known and documented, it still left some \nto be desired.\n\nMight be I`m missing something, but so far I like how described \napproach just \"feels right\" (to me, for now), being really simple, \nyet robust :)\n\nAs my humble contribution to the cause and discussion itself, I`m \nproviding possibly naive, yet simple demonstration script[1], and \nclearly showing where current `git rebase --preserve-merges` is \nlacking (in my opinion, even though being expected and documented), \nand how your proposal seems to improve the situation here.\n\nThanks for your thoughts, and hoping to see this going somewhere :)\n\nRegards, Buga\n\n[1] Demonstration script:\n--- 8< ---\n#!/bin/sh\n\n# rm -rf ./.git\n# rm -f ./test.txt\n\ngit init\n\ntouch ./test.txt\ngit add -- test.txt\n\nfor i in {1..20}\ndo\n\techo A$i >>test.txt\n\tgit commit -am \"A$i\"\ndone\n\ngit checkout -b b1\nsed -i '6iB1' test.txt\ngit commit -am \"B1\"\n\ngit checkout -b b2 HEAD^\nsed -i '16iB2' test.txt\ngit commit -am \"B2\"\n\ngit checkout -b merge b1\ngit merge --no-commit b2\nsed -i '12iX' test.txt # amend merge commit\ngit commit -am \"M\"\ngit tag original-merge\n\ngit checkout master\nfor i in {1..5}\ndo\n\tj=`expr \"$i\" + 20`\n\tsed -i \"${i}iA${j}\" test.txt\n\tgit commit -am \"A$j\"\ndone\n\n# (1) current merge rebasing logic,\n# not preserving merge commit manual amendment, as documented\ngit rebase --preserve-merges master merge\ngit tag preserve-merges\n\n# (2) simple/naive demonstration of proposed merge rebasing logic\n# using described \"Trivial Merge\" (TM, or \"Angel Merge\"),\n# preserving merge commit manual amendment :)\ngit checkout b1\ngit rebase master\ngit cherry-pick -m1 original-merge\n\ngit checkout b2\ngit rebase master\ngit cherry-pick -m2 original-merge\n\ngit branch -f merge b1\ngit checkout merge\ngit merge b2 --no-commit\ngit commit -a --reuse-message original-merge\ngit tag angel-merge\n\ngit reset --hard b1^\ngit read-tree --reset angel-merge\ngit update-ref refs/heads/merge \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse b1^)\" -p \"$(git rev-parse b2^)\")\"\ngit tag -f angel-merge\ngit branch -f b1 b1^\ngit branch -f b2 b2^\n\n# show resulting graph\necho\ngit log --all --decorate --oneline --graph\n\n# comparison between original merge and rebased merge (1),\n# showing merge commit amendment \"X\" being silently lost during rebase\necho\necho 'diff original-merge..preserve-merges:'\ngit diff original-merge..preserve-merges\n\n# comparison between original merge and rebased merge (2),\n# showing merge commit amendment \"X\" being preserved during rebase\n# (not shown in diff)\necho\necho 'diff original-merge..angel-merge:'\ngit diff original-merge..angel-merge\n\n# direct comparison between two merge rebasing approaches,\n# merge commit amendment difference showing up\necho\necho 'diff preserve-merges angel-merge:'\ngit diff preserve-merges angel-merge\n"},{"id":"339705","messageId":"87woz7ltmp.fsf@javad.com","threadId":"47864","inReplyTo":"bbe64321-4d3a-d3fe-8bb9-58b600fabf35@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-20T12:42:38Z","receivedAt":"2018-02-20T12:42:46Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n\n[...]\n\n>\n> Even though this behavior is known and documented, it still left some \n> to be desired.\n>\n> Might be I`m missing something, but so far I like how described \n> approach just \"feels right\" (to me, for now), being really simple, \n> yet robust :)\n>\n> As my humble contribution to the cause and discussion itself, I`m \n> providing possibly naive, yet simple demonstration script[1], and \n> clearly showing where current `git rebase --preserve-merges` is \n> lacking (in my opinion, even though being expected and documented), \n> and how your proposal seems to improve the situation here.\n\nThanks for the test-case, -- it's nice to see this thingy working!\n\n>\n> Thanks for your thoughts, and hoping to see this going somewhere :)\n\nSo do I. Even if nobody volunteers to adopt it, I hope I'll be able to\nimplement something myself, not very soon though.\n\n-- Sergey\n"},{"id":"340353","messageId":"nycvar.QRO.7.76.6.1802270051470.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"bbe64321-4d3a-d3fe-8bb9-58b600fabf35@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-02-27T00:07:01Z","receivedAt":"2018-02-27T00:07:14Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Tue, 20 Feb 2018, Igor Djordjevic wrote:\n\n> I`m really interested in this topic, which seems to (try to) address the\n> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n> losing amendments by actually trying to \"replay\" the merge (where\n> additional and possibly important context is missing), instead of really\n> \"rebasing\" it (somehow).\n\nIf those amendments are what you are worried about, why not address them\nspecifically?\n\nIn other words, rather than performing the equivalent of\n\n\tgit show <merge>^! | git apply\n\n(which would of course completely ignore if the rewritten <merge>^2\ndropped a patch, amended a patch, or even added a new patch), what you\nreally want is to figure out what changes the user made when merging, and\nwhat merge strategy was used to begin with.\n\nTo see what I mean, look at the output of `git show 0fd90daba8`: it shows\nhow conflicts were resolved. By necessity, this is more complicated than a\nsimple diff: it is *not* as simple as taking a diff between two revisions\nand applying that diff to a third revision. There were (at least) three\nrevisions involved in the original merge commit, and recreating that merge\ncommit faithfully means to represent the essence of the merge commit\nfaithfully enough to be able to replay it on a new set of at least three\nrevisions.  That can be simplified to two-way diffs only in very, very\nspecial circumstances, and in all other cases this simplification will\nsimply fall on its nose.\n\nIf the proposed solution was to extend `git apply` to process combined\ndiffs, I would agree that we're on to something. That is not the proposed\nsolution, though.\n\nIn short: while I am sympathetic to the desire to keep things simple,\nthe idea to somehow side-step replaying the original merge seems to be\n*prone* to be flawed. Any system that cannot accommodate\ndropped/changed/added commits on either side of a merge is likely to be\ntoo limited to be useful.\n\nCiao,\nJohannes\n"},{"id":"340373","messageId":"87tvu36n5v.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802270051470.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-27T05:01:48Z","receivedAt":"2018-02-27T05:01:57Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Buga,\n>\n> On Tue, 20 Feb 2018, Igor Djordjevic wrote:\n>\n>> I`m really interested in this topic, which seems to (try to) address the\n>> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n>> losing amendments by actually trying to \"replay\" the merge (where\n>> additional and possibly important context is missing), instead of really\n>> \"rebasing\" it (somehow).\n\n[...]\n\n> In short: while I am sympathetic to the desire to keep things simple,\n> the idea to somehow side-step replaying the original merge seems to be\n> *prone* to be flawed.\n\nThe proposed (TM) solution does replay the original merge.\n\n> Any system that cannot accommodate dropped/changed/added commits on\n> either side of a merge is likely to be too limited to be useful.\n\nI believe the proposed (TM) solution handles all that nicely. It does\naccommodate dropped/changed/added commits on either side of a merge,\nsymmetrically, and never silently drops user modifications.\n\nIf you think (TM) is flawed, please give us a test-case.\n\n-- Sergey\n"},{"id":"340376","messageId":"CA+P7+xq8UUcLWomUi=PS_hTKfJd3dMAxMmhioDS1bixwcmKAqw@mail.gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802270051470.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-02-27T05:30:01Z","receivedAt":"2018-02-27T05:30:27Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Mon, Feb 26, 2018 at 4:07 PM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> Hi Buga,\n>\n> On Tue, 20 Feb 2018, Igor Djordjevic wrote:\n>\n>> I`m really interested in this topic, which seems to (try to) address the\n>> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n>> losing amendments by actually trying to \"replay\" the merge (where\n>> additional and possibly important context is missing), instead of really\n>> \"rebasing\" it (somehow).\n>\n> If those amendments are what you are worried about, why not address them\n> specifically?\n>\n> In other words, rather than performing the equivalent of\n>\n>         git show <merge>^! | git apply\n>\n> (which would of course completely ignore if the rewritten <merge>^2\n> dropped a patch, amended a patch, or even added a new patch), what you\n> really want is to figure out what changes the user made when merging, and\n> what merge strategy was used to begin with.\n>\n> To see what I mean, look at the output of `git show 0fd90daba8`: it shows\n> how conflicts were resolved. By necessity, this is more complicated than a\n> simple diff: it is *not* as simple as taking a diff between two revisions\n> and applying that diff to a third revision. There were (at least) three\n> revisions involved in the original merge commit, and recreating that merge\n> commit faithfully means to represent the essence of the merge commit\n> faithfully enough to be able to replay it on a new set of at least three\n> revisions.  That can be simplified to two-way diffs only in very, very\n> special circumstances, and in all other cases this simplification will\n> simply fall on its nose.\n>\n> If the proposed solution was to extend `git apply` to process combined\n> diffs, I would agree that we're on to something. That is not the proposed\n> solution, though.\n>\n> In short: while I am sympathetic to the desire to keep things simple,\n> the idea to somehow side-step replaying the original merge seems to be\n> *prone* to be flawed. Any system that cannot accommodate\n> dropped/changed/added commits on either side of a merge is likely to be\n> too limited to be useful.\n>\n\n\nThe reason Sergey's solution works is because he cherry picks the\nmerge using each parent first, and then merges the result of those. So\neach branch of the merge gets one, and then you merge the result of\nthose cherry-picks. This preservers amendments and changes properly,\nand should result in a good solution.\n\nI agree that making \"git apply\" work with combined diffs could also be\nanother solution, but it may be trickier.\n\nIf this *doesn't* work, a test case showing that it doesn't work would\nbe appreciated. I'm hoping to be able to put together something soon,\nbut I haven't had time due to $dayjob.\n\n> Ciao,\n> Johannes\n"},{"id":"340409","messageId":"87zi3u4pd0.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802270051470.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-27T11:57:15Z","receivedAt":"2018-02-27T11:57:26Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Buga,\n>\n> On Tue, 20 Feb 2018, Igor Djordjevic wrote:\n>\n>> I`m really interested in this topic, which seems to (try to) address the\n>> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n>> losing amendments by actually trying to \"replay\" the merge (where\n>> additional and possibly important context is missing), instead of really\n>> \"rebasing\" it (somehow).\n>\n> If those amendments are what you are worried about, why not address them\n> specifically?\n>\n> In other words, rather than performing the equivalent of\n>\n> \tgit show <merge>^! | git apply\n>\n> (which would of course completely ignore if the rewritten <merge>^2\n> dropped a patch, amended a patch, or even added a new patch),\n\nYou've already bit this poor thingy to death. Please rather try your\nteeth on the proposed Trivial Merge (TM) method. Sorry, you will need to\nactually read the proposal should you decide to.\n\n> what you really want is to figure out what changes the user made when\n> merging,\n\nExactly! It's all and only about changes, I'm glad you are starting to\nget it.\n\n> and what merge strategy was used to begin with.\n\nNo. It's in Git core philosophy to store only result, independent on the\nway the result has been achieved. Only result matters. I could have got\nmerge result out of thin air, and Git won't care, and will store it for\nme safely.\n\nThe proposed (TM) method will ensure it's still stored safely after\nrebasing.\n\n> To see what I mean, look at the output of `git show 0fd90daba8`: it shows\n> how conflicts were resolved. By necessity, this is more complicated than a\n> simple diff: it is *not* as simple as taking a diff between two revisions\n> and applying that diff to a third revision. There were (at least) three\n> revisions involved in the original merge commit, and recreating that merge\n> commit faithfully means to represent the essence of the merge commit\n> faithfully enough to be able to replay it on a new set of at least three\n> revisions.\n\nEven better: we have at least 3 source revisions and 2 new revisions to\nbase 3-rd new revision upon. Proposed (TM) method will use all of them.\n\n> That can be simplified to two-way diffs only in very, very special\n> circumstances, and in all other cases this simplification will simply\n> fall on its nose.\n\nNo, Done Right (TM) it won't fall as N-way-diff is nothing more than N-1\nsimple diffs, trivially combined.\n\n> If the proposed solution was to extend `git apply` to process combined\n> diffs, I would agree that we're on to something. That is not the proposed\n> solution, though.\n\nI'm glad you finally got the point. Proposed (TM) method effectively\n'git apply' combined diffs, yes. I just defined it in terms of commits\nrather than diffs, as it's simpler to understand and to reason about it\nthat way.\n\n>\n> In short: while I am sympathetic to the desire to keep things simple,\n\nProposed (TM) method is complex enough to solve the problem at hand. No\nneed to ask for more complexity.\n\n> the idea to somehow side-step replaying the original merge seems to be\n> *prone* to be flawed.\n\nExactly! That's why current approach to rebase merges is flawed, and\nthat's why proposed (TM) method does reply entire original merges.\n\n-- Sergey\n"},{"id":"340412","messageId":"nycvar.QRO.7.76.6.1802271718090.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"CA+P7+xq8UUcLWomUi=PS_hTKfJd3dMAxMmhioDS1bixwcmKAqw@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-02-27T16:21:17Z","receivedAt":"2018-02-27T16:21:32Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Jake,\n\nOn Mon, 26 Feb 2018, Jacob Keller wrote:\n\n> On Mon, Feb 26, 2018 at 4:07 PM, Johannes Schindelin\n> <Johannes.Schindelin@gmx.de> wrote:\n> >\n> > On Tue, 20 Feb 2018, Igor Djordjevic wrote:\n> >\n> >> I`m really interested in this topic, which seems to (try to) address the\n> >> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n> >> losing amendments by actually trying to \"replay\" the merge (where\n> >> additional and possibly important context is missing), instead of really\n> >> \"rebasing\" it (somehow).\n> >\n> > If those amendments are what you are worried about, why not address them\n> > specifically?\n> >\n> > In other words, rather than performing the equivalent of\n> >\n> >         git show <merge>^! | git apply\n> >\n> > (which would of course completely ignore if the rewritten <merge>^2\n> > dropped a patch, amended a patch, or even added a new patch), what you\n> > really want is to figure out what changes the user made when merging, and\n> > what merge strategy was used to begin with.\n> >\n> > To see what I mean, look at the output of `git show 0fd90daba8`: it shows\n> > how conflicts were resolved. By necessity, this is more complicated than a\n> > simple diff: it is *not* as simple as taking a diff between two revisions\n> > and applying that diff to a third revision. There were (at least) three\n> > revisions involved in the original merge commit, and recreating that merge\n> > commit faithfully means to represent the essence of the merge commit\n> > faithfully enough to be able to replay it on a new set of at least three\n> > revisions.  That can be simplified to two-way diffs only in very, very\n> > special circumstances, and in all other cases this simplification will\n> > simply fall on its nose.\n> >\n> > If the proposed solution was to extend `git apply` to process combined\n> > diffs, I would agree that we're on to something. That is not the proposed\n> > solution, though.\n> >\n> > In short: while I am sympathetic to the desire to keep things simple,\n> > the idea to somehow side-step replaying the original merge seems to be\n> > *prone* to be flawed. Any system that cannot accommodate\n> > dropped/changed/added commits on either side of a merge is likely to be\n> > too limited to be useful.\n> >\n> \n> \n> The reason Sergey's solution works is because he cherry picks the\n> merge using each parent first, and then merges the result of those. So\n> each branch of the merge gets one, and then you merge the result of\n> those cherry-picks. This preservers amendments and changes properly,\n> and should result in a good solution.\n\nI saw your patch trying to add a minimal example, and I really want to run\naway screaming.\n\nDo you have any way to describe the idea in a simple, 3-5 lines long\nparagraph?\n\nSo far, I just know that it is some sort of confusing criss-cross\ncherry-picking and merging and stuff, but nothing in those steps shouts\nout to me what the *idea* is.\n\nIf it would be something like \"recreate the old merge, with merge\nconflicts and all, then generate the diff to the actual tree of the merge\ncommit, then apply that to the newly-generated merge\", I would understand.\n\nI would still suspect that -s ours would be a hard nut for that method,\nbut I would understand that idea.\n\nThanks,\nDscho\n"},{"id":"340416","messageId":"xmqqbmgaqp02.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"87zi3u4pd0.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-02-27T18:14:05Z","receivedAt":"2018-02-27T18:14:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sergey Organov <sorganov@gmail.com> writes:\n\n> You've already bit this poor thingy to death. Please rather try your\n> teeth on the proposed Trivial Merge (TM) method.\n\nWhatever you do, do *NOT* call any part of your proposal \"trivial\nmerge\", unless you are actually using the term to mean what Git\ncalls \"trivial merge\".  The phrase has an established meaning in Git\nand your attempt to abuse it to mean something entirely different is\nadding unnecessary hindrance for other people to understand what you\nwant to perform.\n"},{"id":"340424","messageId":"4d7f3406-b206-cc22-87df-85700d6a03d9@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802271718090.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-27T18:55:46Z","receivedAt":"2018-02-27T18:55:58Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 27/02/2018 17:21, Johannes Schindelin wrote:\n> \n> Do you have any way to describe the idea in a simple, 3-5 lines long \n> paragraph?\n> \n> So far, I just know that it is some sort of confusing criss-cross \n> cherry-picking and merging and stuff, but nothing in those steps\n> shouts out to me what the *idea* is.\n> \n> If it would be something like \"recreate the old merge, with merge \n> conflicts and all, then generate the diff to the actual tree of the\n> merge commit, then apply that to the newly-generated merge\", I would\n> understand.\n\nIt would be more along the lines of \"(1) rebase old merge commit parents, \n(2) generate separate diff between old merge commit and each of its \nparents, (3) apply each diff to their corresponding newly rebased \nparent respectively (as a temporary commit, one per rebased parent), \n(4) merge these temporary commits to generate 'rebased' merge commit, \n(5) drop temporary commits, recording their parents as parents of \n'rebased' merge commit (instead of dropped temporary commits)\".\n\nImplementation wise, steps (2) and (3) could also be done by simply \ncopying old merge commit _snapshot_ on top of each of its parents as \na temporary, non-merge commit, then rebasing (cherry-picking) these \ntemporary commits on top of their rebased parent commits to produce \nrebased temporary commits (to be merged for generating 'rebased' \nmerge commit in step (4)).\n\nRegards, Buga\n"},{"id":"340433","messageId":"33da31e9-9101-475d-8901-4b6b3df2f29d@gmail.com","threadId":"47864","inReplyTo":"4d7f3406-b206-cc22-87df-85700d6a03d9@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-27T19:59:55Z","receivedAt":"2018-02-27T20:00:09Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 27/02/2018 19:55, Igor Djordjevic wrote:\n> \n> It would be more along the lines of \"(1) rebase old merge commit parents, \n> (2) generate separate diff between old merge commit and each of its \n> parents, (3) apply each diff to their corresponding newly rebased \n> parent respectively (as a temporary commit, one per rebased parent), \n> (4) merge these temporary commits to generate 'rebased' merge commit, \n> (5) drop temporary commits, recording their parents as parents of \n> 'rebased' merge commit (instead of dropped temporary commits)\".\n> \n> Implementation wise, steps (2) and (3) could also be done by simply \n> copying old merge commit _snapshot_ on top of each of its parents as \n> a temporary, non-merge commit, then rebasing (cherry-picking) these \n> temporary commits on top of their rebased parent commits to produce \n> rebased temporary commits (to be merged for generating 'rebased' \n> merge commit in step (4)).\n\nFor those still tagging along (and still confused), here are some \ndiagrams (following what Sergey originally described). Note that \nactual implementation might be even simpler, but I believe it`s a bit \neasier to understand like this, using some \"temporary\" commits approach.\n\nHere`s our starting position:\n\n(0) ---X1---o---o---o---o---o---X2 (master)\n       |\\\n       | A1---A2---A3\n       |             \\\n       |              M (topic)\n       |             /\n       \\-B1---B2---B3\n\n\nNow, we want to rebase merge commit M from X1 onto X2. First, rebase\nmerge commit parents as usual:\n\n(1) ---X1---o---o---o---o---o---X2\n       |\\                       |\\\n       | A1---A2---A3           | A1'--A2'--A3'\n       |             \\          |\n       |              M         |\n       |             /          |\n       \\-B1---B2---B3           \\-B1'--B2'--B3'\n\n\nThat was commonly understandable part. Now, for \"rebasing\" the merge \ncommit (keeping possible amendments), we do some extra work. First, \nwe make two temporary commits on top of old merge parents, by using \nexact tree (snapshot) of commit M:\n\n(2) ---X1---o---o---o---o---o---X2\n       |\\                       |\\\n       | A1---A2---A3---U1      | A1'--A2'--A3'\n       |             \\          |\n       |              M         |\n       |             /          |\n       \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n\n\nSo here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M.\n\nNow, we rebase these temporary commits, too:\n\n(3) ---X1---o---o---o---o---o---X2\n       |\\                       |\\\n       | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n       |             \\          |\n       |              M         |\n       |             /          |\n       \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n\n\nAs a next step, we merge these temporary commits to produce our \n\"rebased\" merged commit M:\n\n(4) ---X1---o---o---o---o---o---X2\n       |\\                       |\\\n       | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n       |             \\          |                  \\\n       |              M         |                   M'\n       |             /          |                  /\n       \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n\n\nFinally, we drop temporary commits, and record rebased commits A3' \nand B3' as our \"rebased\" merge commit parents instead (merge commit \nM' keeps its same tree/snapshot state, just gets parents replaced):\n\n(5) ---X1---o---o---o---o---o---X2\n       |\\                       |\\\n       | A1---A2---A3---U1      | A1'--A2'--A3'\n       |             \\          |             \\\n       |              M         |              M'\n       |             /          |             /\n       \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n\n\nAnd that`s it, our merge commit M has been \"rebased\" to M' :)\n\n(6) ---X1---o---o---o---o---o---X2 (master)\n                                |\\\n                                | A1'--A2'--A3'\n                                |             \\\n                                |              M' (topic)\n                                |             /\n                                \\-B1'--B2'--B3'\n\n\nImportant thing to note here is that in our step (3) above, still in \nterms of trees/snapshots (not diffs), U1' could still be equal to \nU2', produced merge commit M' tree thus being equal to both of them \nas well (merge commit introducing no changes to either of its \nparents, originally described by Sergey as \"angel merge\").\n\nBut it doesn`t have to be so - if any of the rebased commits A1 to A3 \nor B1 to B3 was dropped or modified (or extra commits added, even), \nthat would influence the trees (snapshots) produced after rebasing U1 \nand U2 to U1' and U2', final merge M' reflecting all these changes as \nwell, besides keeping original merge commit M amendments (preserving \n\"evil merge\").\n\n\nWell, that`s some theory, now to hopefully confirm/test/polish all \nthis... or trash it, if flawed beyond correction :P\n\nRegards, Buga\n"},{"id":"340486","messageId":"nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"33da31e9-9101-475d-8901-4b6b3df2f29d@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-02-27T23:27:19Z","receivedAt":"2018-02-27T23:27:32Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nthank you for making this a lot more understandable to this thick\ndeveloper.\n\nOn Tue, 27 Feb 2018, Igor Djordjevic wrote:\n\n> On 27/02/2018 19:55, Igor Djordjevic wrote:\n> > \n> > It would be more along the lines of \"(1) rebase old merge commit parents, \n> > (2) generate separate diff between old merge commit and each of its \n> > parents, (3) apply each diff to their corresponding newly rebased \n> > parent respectively (as a temporary commit, one per rebased parent), \n> > (4) merge these temporary commits to generate 'rebased' merge commit, \n> > (5) drop temporary commits, recording their parents as parents of \n> > 'rebased' merge commit (instead of dropped temporary commits)\".\n> > \n> > Implementation wise, steps (2) and (3) could also be done by simply \n> > copying old merge commit _snapshot_ on top of each of its parents as \n> > a temporary, non-merge commit, then rebasing (cherry-picking) these \n> > temporary commits on top of their rebased parent commits to produce \n> > rebased temporary commits (to be merged for generating 'rebased' \n> > merge commit in step (4)).\n> \n> For those still tagging along (and still confused), here are some \n> diagrams (following what Sergey originally described). Note that \n> actual implementation might be even simpler, but I believe it`s a bit \n> easier to understand like this, using some \"temporary\" commits approach.\n> \n> Here`s our starting position:\n> \n> (0) ---X1---o---o---o---o---o---X2 (master)\n>        |\\\n>        | A1---A2---A3\n>        |             \\\n>        |              M (topic)\n>        |             /\n>        \\-B1---B2---B3\n> \n> \n> Now, we want to rebase merge commit M from X1 onto X2. First, rebase\n> merge commit parents as usual:\n> \n> (1) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3           | A1'--A2'--A3'\n>        |             \\          |\n>        |              M         |\n>        |             /          |\n>        \\-B1---B2---B3           \\-B1'--B2'--B3'\n> \n> \n> That was commonly understandable part.\n\nGood. Let's assume that I want to do this interactively (because let's\nface it, rebase is boring unless we shake up things a little). And let's\nassume that A1 is my only change to the README, and that I realized that\nit was incorrect and I do not want the world to see it, so I drop A1'.\n\nLet's see how things go from here:\n\n> Now, for \"rebasing\" the merge commit (keeping possible amendments), we\n> do some extra work. First, we make two temporary commits on top of old\n> merge parents, by using exact tree (snapshot) of commit M:\n> \n> (2) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3---U1      | A1'--A2'--A3'\n>        |             \\          |\n>        |              M         |\n>        |             /          |\n>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n\nOkay, everything would still be the same except that I still have dropped\nA1'.\n\n> So here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M.\n> \n> Now, we rebase these temporary commits, too:\n> \n> (3) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>        |             \\          |\n>        |              M         |\n>        |             /          |\n>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n\nI still want to drop A1 in this rebase, so A1' is still missing.\n\nAnd now it starts to get interesting.\n\nThe diff between A3 and U1 does not touch the README, of course, as I said\nthat only A1 changed the README.  But the diff between B3 and U2 does\nchange the README, thanks to M containing A1 change.\n\nTherefore, the diff between B3' and U2' will also have this change to the\nREADME. That change that I wanted to drop.\n\n> As a next step, we merge these temporary commits to produce our\n> \"rebased\" merged commit M:\n> \n> (4) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>        |             \\          |                  \\\n>        |              M         |                   M'\n>        |             /          |                  /\n>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n\nAnd here, thanks to B3'..U2' changing the README, M' will also have that\nchange that I wanted to see dropped.\n\nNote that A1' is still dropped in my example.\n\n> Finally, we drop temporary commits, and record rebased commits A3' \n> and B3' as our \"rebased\" merge commit parents instead (merge commit \n> M' keeps its same tree/snapshot state, just gets parents replaced):\n> \n> (5) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3---U1      | A1'--A2'--A3'\n>        |             \\          |             \\\n>        |              M         |              M'\n>        |             /          |             /\n>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n\nNow, thanks to U2' being dropped (and A1' *still* being dropped), the\nchange in the README that is still in M' is really only in M'. No other\nrebased commit has it. That makes it look as if M' introduced this change\nin addition to the changes that were merged between the merge parents.\n\nThis is what an \"evil merge\" is: it does more than just combine the\npreviously diverging branches. It introduces another change that was not\nin any non-merge commits before it.\n\nSometimes, such an \"evil merge\" is necessary. For example, when master\nconverted a couple more `hash` references to `oid` including, say, in a\nfunction signature, and the merged branch contains a new caller using that\nold function signature: in this case, the merge commit must convert those\n`hash` references to `oid` references, or the code won't compile.\n\nIn my example, where I dropped A1' specifically so that that embarrasingly\nincorrect change to the README would not be seen by the world, though, the\nevil merge would be truly evil: it would show said change to the world.\nThe exact opposite of what I wanted.\n\n> And that`s it, our merge commit M has been \"rebased\" to M' :)\n> \n> (6) ---X1---o---o---o---o---o---X2 (master)\n>                                 |\\\n>                                 | A1'--A2'--A3'\n>                                 |             \\\n>                                 |              M' (topic)\n>                                 |             /\n>                                 \\-B1'--B2'--B3'\n> \n> \n> Important thing to note here is that in our step (3) above, still in \n> terms of trees/snapshots (not diffs), U1' could still be equal to \n> U2', produced merge commit M' tree thus being equal to both of them \n> as well (merge commit introducing no changes to either of its \n> parents, originally described by Sergey as \"angel merge\").\n> \n> But it doesn`t have to be so - if any of the rebased commits A1 to A3 \n> or B1 to B3 was dropped or modified (or extra commits added, even), \n> that would influence the trees (snapshots) produced after rebasing U1 \n> and U2 to U1' and U2', final merge M' reflecting all these changes as \n> well, besides keeping original merge commit M amendments (preserving \n> \"evil merge\").\n\nSadly, it would also introduce evil merges in certain circumstances, as I\ndemonstrated above.\n\n> Well, that`s some theory, now to hopefully confirm/test/polish all \n> this... or trash it, if flawed beyond correction :P\n\nIt would have been nice to have such a simple solution ;-)\n\nSo the most obvious way to try to fix this design would be to recreate the\noriginal merge first, even with merge conflicts, and then trying to use the\ndiff between that and the actual original merge commit. In your example,\nthis would look like that:\n\n---X1---o---o---o---o---o---X2\n   |\\                       |\\\n   | A1---A2---A3--         | A1'--A2'--A3'\n   |             \\ \\        |\n   |              M M²      |\n   |             / /        |\n   \\-B1---B2---B3--         \\-B1'--B2'--B3'\n\nNote that M² would be generated somewhat like this: `git checkout\nA3; git merge -s recursive B3; git add -u; git commit`. If there are merge\nconflicts, then the result would include the conflict markers.\n\nNow we would generate something similar to those U1/U2 commits: a\nsingle-parent commit R that reflects the diff between M and M²:\n\n---X1---o---o---o---o---o---X2\n   |\\                       |\\\n   | A1---A2---A3           | A1'--A2'--A3'\n   |             \\          |\n   |              M---R     |\n   |             /          |\n   \\-B1---B2---B3           \\-B1'--B2'--B3'\n\nNote that the tree of R is identical to the tree of M². We can now\nproceed to generate the merge between A3' and B3' (possibly with merge\nconflicts) and then reverting R on top:\n\n---X1---o---o---o---o---o---X2\n   |\\                       |\\\n   | A1---A2---A3           | A1'--A2'--A3'\n   |             \\          |              \\\n   |              M---R     |               M'---M³\n   |             /          |              /\n   \\-B1---B2---B3           \\-B1'--B2'--B3'\n\nOf course, as before, the idea would be to squash the reverted\nchanges into the final merge commit.\n\nNow, would this work?\n\nI doubt it, for at least two reasons:\n\n- if there are merge conflicts between A3/B3 and between A3'/B3', those\n  merge conflicts will very likely look very different, and the conflicts\n  when reverting R will contain those nested conflicts: utterly confusing.\n  And those conflicts will look even more confusing if a patch (such as\n  A1') was dropped during an interactive rebase.\n\n- One of the promises was that the new way would also handle merge\n  strategies other than recursive. What would happen, for example, if M\n  was generated using `-s ours` (read: dropping the B* patches' changes)\n  and if B1 had been cherry-picked into the history between X1..X2?\n\n  Reverting R would obviously revert those B1 changes, even if B1' would\n  obviously not even be part of the rebased history!\n\nYes, I agree that this `-s ours` example is quite concocted, but the point\nof this example is not how plausible it is, but how easy it is to come up\nwith a scenario where this design to \"rebase merge commits\" results in\nvery, very unwanted behavior.\n\nBut maybe I missed something obvious, and the design can still be fixed\nsomehow?\n\nCiao,\nJohannes"},{"id":"340489","messageId":"940d959d-151d-68dd-0f13-320ebad0d75b@gmail.com","threadId":"47864","inReplyTo":"33da31e9-9101-475d-8901-4b6b3df2f29d@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-27T23:40:31Z","receivedAt":"2018-02-27T23:40:55Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 27/02/2018 20:59, Igor Djordjevic wrote:\n> \n> (3) ---X1---o---o---o---o---o---X2\n>        |\\                       |\\\n>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>        |             \\          |\n>        |              M         |\n>        |             /          |\n>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> \n\nMeh, I hope I`m rushing it now, but for example, if we had decided to \ndrop commit A2 during an interactive rebase (so losing A2' from \ndiagram above), wouldn`t U2' still introduce those changes back, once \nU1' and U2' are merged, being incorrect/unwanted behavior...? :/\n\np.s. Looks like Johannes already elaborated on this in the meantime, \nlet`s see... (goes reading that other e-mail[1])\n\n[1] https://public-inbox.org/git/nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/\n"},{"id":"340494","messageId":"xmqqwoyym0ry.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"940d959d-151d-68dd-0f13-320ebad0d75b@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-02-28T00:10:57Z","receivedAt":"2018-02-28T00:11:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 27/02/2018 20:59, Igor Djordjevic wrote:\n>> \n>> (3) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>> \n>\n> Meh, I hope I`m rushing it now, but for example, if we had decided to \n> drop commit A2 during an interactive rebase (so losing A2' from \n> diagram above), wouldn`t U2' still introduce those changes back, once \n> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>\n> p.s. Looks like Johannes already elaborated on this in the meantime, \n> let`s see... (goes reading that other e-mail[1])\n\nAs long as we are talking about rebase that allows us users to\nadjust and make changes (\"rebase -i\" being the prime and most\nflexible example), it is easy to imagine that A1'--A3' and B1'--B3'\nhave almost no relation to their original counterparts.  After all,\nmechanical merge won't be able to guess the intention of the change\nhumans make, so depending on what happend during X1 and X2 that\nhappend outside of these two topics, what's required to bring series\nA and B to series A' and B' can be unlimited.  So from that alone,\nit should be clear that replaying difference between M and A3 (and M\nand B3) on top of U1' and U2' is hopeless as a general solution.\n\nIt is acceptable as long as a solution fails loudly when it does the\nwrong thing, but I do not think the apporach can produce incorrect\nresult silently, as your example shows above.\n\nWhat you _COULD_ learn from an old merge is to compute:\n\n    - a trial and mechanical merge between A3 and B3; call that pre-M\n\n    - diff to bring pre-M to M (call that patch evil-M); which is\n      what the person who made M did to resolve the textual and\n      semantic conflicts necessary to merge these two topics.\n\nThen when merging A3' and B3', you could try to mechanically merge\nthem (call that pre-M'), and apply evil-M, which may apply cleanly\non top of pre-M', or it may not.  When there aren't so huge a\ndifference between series A and A' (and series B and B'), the result\nwould probably be a moral equivalent of Sergay's \"replay\" (so this\napproach will also silently produce a wrong result without human\nsupervision).  One edge the evil-M approach has over Sergey's \"dual\ncherry pick\" is that it separates and highlights non-mechanical\nconflict resolution out of mechanical merges in a human readable\nform (i.e. the patch evil-M).\n\n\n\n\n\n"},{"id":"340496","messageId":"CA+P7+xrXy1wCJ6D=3h_db93wLTzj9HGF6M6ptLXgEnSMW9KAwg@mail.gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802271718090.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-02-28T00:29:01Z","receivedAt":"2018-02-28T00:29:28Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Feb 27, 2018 at 8:21 AM, Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n> Hi Jake,\n>\n> On Mon, 26 Feb 2018, Jacob Keller wrote:\n>\n>> On Mon, Feb 26, 2018 at 4:07 PM, Johannes Schindelin\n>> <Johannes.Schindelin@gmx.de> wrote:\n>> >\n>> > On Tue, 20 Feb 2018, Igor Djordjevic wrote:\n>> >\n>> >> I`m really interested in this topic, which seems to (try to) address the\n>> >> only \"bad feeling\" I had with rebasing merges - being afraid of silently\n>> >> losing amendments by actually trying to \"replay\" the merge (where\n>> >> additional and possibly important context is missing), instead of really\n>> >> \"rebasing\" it (somehow).\n>> >\n>> > If those amendments are what you are worried about, why not address them\n>> > specifically?\n>> >\n>> > In other words, rather than performing the equivalent of\n>> >\n>> >         git show <merge>^! | git apply\n>> >\n>> > (which would of course completely ignore if the rewritten <merge>^2\n>> > dropped a patch, amended a patch, or even added a new patch), what you\n>> > really want is to figure out what changes the user made when merging, and\n>> > what merge strategy was used to begin with.\n>> >\n>> > To see what I mean, look at the output of `git show 0fd90daba8`: it shows\n>> > how conflicts were resolved. By necessity, this is more complicated than a\n>> > simple diff: it is *not* as simple as taking a diff between two revisions\n>> > and applying that diff to a third revision. There were (at least) three\n>> > revisions involved in the original merge commit, and recreating that merge\n>> > commit faithfully means to represent the essence of the merge commit\n>> > faithfully enough to be able to replay it on a new set of at least three\n>> > revisions.  That can be simplified to two-way diffs only in very, very\n>> > special circumstances, and in all other cases this simplification will\n>> > simply fall on its nose.\n>> >\n>> > If the proposed solution was to extend `git apply` to process combined\n>> > diffs, I would agree that we're on to something. That is not the proposed\n>> > solution, though.\n>> >\n>> > In short: while I am sympathetic to the desire to keep things simple,\n>> > the idea to somehow side-step replaying the original merge seems to be\n>> > *prone* to be flawed. Any system that cannot accommodate\n>> > dropped/changed/added commits on either side of a merge is likely to be\n>> > too limited to be useful.\n>> >\n>>\n>>\n>> The reason Sergey's solution works is because he cherry picks the\n>> merge using each parent first, and then merges the result of those. So\n>> each branch of the merge gets one, and then you merge the result of\n>> those cherry-picks. This preservers amendments and changes properly,\n>> and should result in a good solution.\n>\n> I saw your patch trying to add a minimal example, and I really want to run\n> away screaming.\n>\n> Do you have any way to describe the idea in a simple, 3-5 lines long\n> paragraph?\n>\n> So far, I just know that it is some sort of confusing criss-cross\n> cherry-picking and merging and stuff, but nothing in those steps shouts\n> out to me what the *idea* is.\n>\n\nSergey's posted explained it more in detail, at\nhttps://public-inbox.org/git/87y3jtqdyg.fsf@javad.com/\n\nI was mostly just attempting to re-create it in a test case to show\nthat it could work.\n\n> If it would be something like \"recreate the old merge, with merge\n> conflicts and all, then generate the diff to the actual tree of the merge\n> commit, then apply that to the newly-generated merge\", I would understand.\n>\n\nIt's more or less:\n\nRebase each parent, then cherry-pick -m<N> the original merge to that\nparent, then you merge the result of each cherry-pick, then use the\nresulting final merged tree to create the merge pointing at the real\nparents instead of the cherry-pick merges.\n\n> I would still suspect that -s ours would be a hard nut for that method,\n> but I would understand that idea.\n>\n\nThe goal of the process isn't to know or understand the \"-s ours\"\nstrategy, but simply re-create the contents of the original merge\nfaithfully, while still preserving the changes done when rebasing the\nside branches. Thus it should re-create the contents generated by \"-s\nours\" the first time, but it doesn't need to do or know anything\nspecial about how the content was created.\n\n> Thanks,\n> Dscho\n"},{"id":"340497","messageId":"CA+P7+xpNhEF0=QoR71v5Y=nc39OL4XKX36xXYjP1Kn_+DUCf_Q@mail.gmail.com","threadId":"47864","inReplyTo":"xmqqbmgaqp02.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-02-28T00:30:24Z","receivedAt":"2018-02-28T00:30:50Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Feb 27, 2018 at 10:14 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Sergey Organov <sorganov@gmail.com> writes:\n>\n>> You've already bit this poor thingy to death. Please rather try your\n>> teeth on the proposed Trivial Merge (TM) method.\n>\n> Whatever you do, do *NOT* call any part of your proposal \"trivial\n> merge\", unless you are actually using the term to mean what Git\n> calls \"trivial merge\".  The phrase has an established meaning in Git\n> and your attempt to abuse it to mean something entirely different is\n> adding unnecessary hindrance for other people to understand what you\n> want to perform.\n\nAgreed, I think we need better terminology here, the current words for\n(TM) are definitely *not* trivial merges. Same for \"angel merge\", I\ndon't think that term really works well either.\n\nThe goal of the process is to split the merge apart to its components\nfor each side branch and then bring them back together after applying\nthem to the newly rebased branches.\n"},{"id":"340498","messageId":"CA+P7+xrzxYSE0OyL8uyF+ErwfWFEgcqnHmaciwWkK-76sQ6ktw@mail.gmail.com","threadId":"47864","inReplyTo":"940d959d-151d-68dd-0f13-320ebad0d75b@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-02-28T00:36:44Z","receivedAt":"2018-02-28T00:37:10Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Tue, Feb 27, 2018 at 3:40 PM, Igor Djordjevic\n<igor.d.djordjevic@gmail.com> wrote:\n> On 27/02/2018 20:59, Igor Djordjevic wrote:\n>>\n>> (3) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>\n>\n> Meh, I hope I`m rushing it now, but for example, if we had decided to\n> drop commit A2 during an interactive rebase (so losing A2' from\n> diagram above), wouldn`t U2' still introduce those changes back, once\n> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>\n> p.s. Looks like Johannes already elaborated on this in the meantime,\n> let`s see... (goes reading that other e-mail[1])\n>\n> [1] https://public-inbox.org/git/nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/\n\n\nIn that case, the method won't work well at all, so I think we need a\ndifferent approach.\n\nThanks,\nJake\n"},{"id":"340520","messageId":"8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com","threadId":"47864","inReplyTo":"CA+P7+xrzxYSE0OyL8uyF+ErwfWFEgcqnHmaciwWkK-76sQ6ktw@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T01:33:56Z","receivedAt":"2018-02-28T01:34:09Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 28/02/2018 01:36, Jacob Keller wrote:\n> \n> > > (3) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> > >\n> >\n> > Meh, I hope I`m rushing it now, but for example, if we had decided to\n> > drop commit A2 during an interactive rebase (so losing A2' from\n> > diagram above), wouldn`t U2' still introduce those changes back, once\n> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> \n> In that case, the method won't work well at all, so I think we need a\n> different approach.\n> \n\nHmm, still rushing it, but what about adding an additional step, \nsomething like this: \n \n (4) ---X1---o---o---o---o---o---X2\n        |\\                       |\\\n        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'--R1\n        |             \\          |\n        |              M         |\n        |             /          |\n        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'--R2\n\n\n... where:\n\n  R1 = git diff U2 U2' | git apply --3way\n  R2 = git diff U1 U1' | git apply --3way\n\n(this is just to explain the point, might be there is a better way to \nproduce Rx)\n\nSo, we still use Ux' to preserve merge commit M amendments, but also \nRx to catch any changes happening between Ux and Ux' caused by \ninteractive rebase commit manipulation (add/amend/drop).\n\nNote that R*1* is produced by applying diff from U*2*' side, and vice \nversa (as it`s the other side that can erroneously introduce dropped \ncommit changes back, like U2' in case of dropped A2').\n\nFrom here we continue as before - merging R1 and R2, then rewriting \nmerge commit parents to point to A3' and B3' (dropping Ux` and Rx).\n\nThis seems to be working inside my (too trivial?) test case, for \ninteractive adding, dropping, and amending of rebased commits, \nresulting \"rebased\" merge containing all the added/modified/dropped \nchanges, plus the original merge amendment, all as expected :P\n\nRegards, Buga\n"},{"id":"340526","messageId":"6737f819-4629-8aef-c3fb-79d96ccd2306@gmail.com","threadId":"47864","inReplyTo":"8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T01:43:31Z","receivedAt":"2018-02-28T01:43:42Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 28/02/2018 02:33, Igor Djordjevic wrote:\n> \n> This seems to be working inside my (too trivial?) test case, for \n> interactive adding, dropping, and amending of rebased commits, \n> resulting \"rebased\" merge containing all the added/modified/dropped \n> changes, plus the original merge amendment, all as expected :P\n\nIn case anyone has a wish to examine my (now pretty messy) test \nscript, here it is - sorry for not having time to clean it up! :(\n\nWhat I get when I diff original and \"rebased\" merge is this:\n\n    diff --git a/test.txt b/test.txt\n    index a82470b..d458032 100644\n    --- a/test.txt\n    +++ b/test.txt\n    @@ -1,10 +1,14 @@\n    +A21\n    +A22\n    +A23\n    +A24\n    +A25\n     A1\n     A2\n    -B11\n    +B1111\n     A3\n     A4\n     A5\n    -B12\n     A6\n     A7\n     A8\n    @@ -14,6 +18,7 @@ A10\n     A11\n     A12\n     A13\n    +BX\n     A14\n     B2\n     A15\n\n\n... where A21 to A25 are additions due to new base, B11 was \ninteractively amended to B1111, B12 was interactively dropped, and BX \ninteractively added :)\n\nWe don`t see line X here, being an \"evil merge\" amendment being \ncorrectly preserved from original merge commit (thus not a \ndifference). If we do `git show` of the \"rebased\" merge, we get this, \nas expected:\n\n    diff --cc test.txt\n    index b173cef,fad39a8..d458032\n    --- a/test.txt\n    +++ b/test.txt\n    @@@ -13,6 -13,6 +13,7 @@@ A\n      A7\n      A8\n      A9\n    ++X\n      A10\n      A11\n      A12\n\n\nRegards, Buga\n\n-- 8< --\n#!/bin/sh\n\n# rm -rf ./.git\n# rm -f ./test.txt\n\ngit init\n\ntouch ./test.txt\ngit add -- test.txt\n\nfor i in {1..20}\ndo\n\techo A$i >>test.txt\n\tgit commit -am \"A$i\"\ndone\n\ngit checkout -b b1\nsed -i '3iB11' test.txt\ngit commit -am \"B11\"\nsed -i '7iB12' test.txt\ngit commit -am \"B12\"\n\ngit checkout -b b2 HEAD^\nsed -i '16iB2' test.txt\ngit commit -am \"B2\"\n\ngit checkout -b merge b1\ngit merge --no-commit b2\nsed -i '12iX' test.txt # amend merge commit\ngit commit -am \"M\"\ngit tag original-merge\n\ngit checkout master\nfor i in {1..5}\ndo\n\tj=`expr \"$i\" + 20`\n\tsed -i \"${i}iA${j}\" test.txt\n\tgit commit -am \"A$j\"\ndone\n\n# simple/naive demonstration of proposed merge rebasing logic\n# using described \"Trivial Merge\" (TM, or \"Angel Merge\"),\n# preserving merge commit manual amendments, but still respecting\n# interactively rebased added/modified/dropped commits :)\n\n# read -p \"Press enter to continue\"\ngit checkout b1\ngit cherry-pick -m1 original-merge && git tag U1\ngit reset --hard HEAD^^ # drop U1 and last b1 commit\nsed -i '/B11/c\\B1111' test.txt\ngit commit -a --amend --no-edit\ngit rebase master\ngit cherry-pick U1 && git tag U1-prime\n\n# read -p \"Press enter to continue\"\ngit checkout b2\ngit cherry-pick -m2 original-merge && git tag U2\ngit reset --hard HEAD^ # drop U2\ngit rebase master\nsed -i '20iBX' test.txt\ngit commit -am \"BX\" # add new commit\ngit cherry-pick U2 && git tag U2-prime\n\ngit diff U1 U1-prime | git apply --3way && git commit -m \"U2-second\" && git tag U2-second\ngit checkout b1\ngit diff U2 U2-prime | git apply --3way && git commit -m \"U1-second\" && git tag U1-second\n\n# read -p \"Press enter to continue\"\ngit branch -f merge b1\ngit checkout merge\ngit merge b2 --no-commit\ngit commit -a --reuse-message original-merge\ngit tag angel-merge\n\n# read -p \"Press enter to continue\"\ngit reset --hard b1^\ngit read-tree --reset angel-merge\ngit update-ref refs/heads/merge \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse b1^^)\" -p \"$(git rev-parse b2^^)\")\"\ngit tag -f angel-merge\ngit checkout angel-merge .\ngit branch -f b1 b1^^\ngit branch -f b2 b2^^\n\n# show resulting graph\necho\ngit log --all --decorate --oneline --graph\n\n# comparison between original merge and rebased merge,\n# showing merge commit amendment \"X\" being preserved during rebase\n# (not shown in diff)\necho\necho 'diff original-merge angel-merge:'\ngit diff original-merge angel-merge\n"},{"id":"340527","messageId":"3b562b51-2f1a-48f6-d6b4-8e0fbddd3a40@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T02:12:40Z","receivedAt":"2018-02-28T02:12:51Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Johannes,\n\nOn 28/02/2018 00:27, Johannes Schindelin wrote:\n> \n> thank you for making this a lot more understandable to this thick\n> developer.\n\nHehe, no problem, it primarily served fighting my own thickness ;)\n\n> > Finally, we drop temporary commits, and record rebased commits A3' \n> > and B3' as our \"rebased\" merge commit parents instead (merge commit \n> > M' keeps its same tree/snapshot state, just gets parents replaced):\n> >\n> > (5) ---X1---o---o---o---o---o---X2\n> >        |\\                       |\\\n> >        | A1---A2---A3---U1      | A1'--A2'--A3'\n> >        |             \\          |             \\\n> >        |              M         |              M'\n> >        |             /          |             /\n> >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n> \n> ...\n> \n> In my example, where I dropped A1' specifically so that that embarrasingly\n> incorrect change to the README would not be seen by the world, though, the\n> evil merge would be truly evil: it would show said change to the world.\n> The exact opposite of what I wanted.\n\nYeah, I`m afraid that`s what my testing produced as well :( Back to \nthe drawing board...\n\n> It would have been nice to have such a simple solution ;-)\n\nEh, the worst thing is the feeling I have, like it`s just around the \ncorner, but we`re somehow missing it :P\n\n> So the most obvious way to try to fix this design would be to recreate the\n> original merge first, even with merge conflicts, and then trying to use the\n> diff between that and the actual original merge commit.\n\nFor simplicity sake, this is something I would like to avoid (if \npossible), and also for the reasons you mentioned yourself:\n\n> Now, would this work?\n> \n> I doubt it, for at least two reasons:\n> \n> - if there are merge conflicts between A3/B3 and between A3'/B3', those\n>   merge conflicts will very likely look very different, and the conflicts\n>   when reverting R will contain those nested conflicts: utterly confusing.\n>   And those conflicts will look even more confusing if a patch (such as\n>   A1') was dropped during an interactive rebase.\n> \n> - One of the promises was that the new way would also handle merge\n>   strategies other than recursive. What would happen, for example, if M\n>   was generated using `-s ours` (read: dropping the B* patches' changes)\n>   and if B1 had been cherry-picked into the history between X1..X2?\n> \n>   Reverting R would obviously revert those B1 changes, even if B1' would\n>   obviously not even be part of the rebased history!\n> \n> ...\n> \n> But maybe I missed something obvious, and the design can still be fixed\n> somehow?\n\nWould additional step as suggested in [1] (using R1 and R2 to \"catch\" \ninteractive rebase additions/amendments/drops, on top of U1' and \nU2'), make more sense (or provide an additional clue, at least)?\n\nIt`s late here, and I`m really rushing it now, so please forgive me if \nit`s a stupid one... :$\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n"},{"id":"340530","messageId":"40fcf205-104e-b1e7-02af-0429866d0342@gmail.com","threadId":"47864","inReplyTo":"xmqqwoyym0ry.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T02:35:26Z","receivedAt":"2018-02-28T02:35:39Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Junio,\n\nOn 28/02/2018 01:10, Junio C Hamano wrote:\n> \n> > > (3) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> > >\n> >\n> > Meh, I hope I`m rushing it now, but for example, if we had decided to \n> > drop commit A2 during an interactive rebase (so losing A2' from \n> > diagram above), wouldn`t U2' still introduce those changes back, once \n> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> \n> As long as we are talking about rebase that allows us users to\n> adjust and make changes (\"rebase -i\" being the prime and most\n> flexible example), it is easy to imagine that A1'--A3' and B1'--B3'\n> have almost no relation to their original counterparts.  After all,\n> mechanical merge won't be able to guess the intention of the change\n> humans make, so depending on what happend during X1 and X2 that\n> happend outside of these two topics, what's required to bring series\n> A and B to series A' and B' can be unlimited.  So from that alone,\n> it should be clear that replaying difference between M and A3 (and M\n> and B3) on top of U1' and U2' is hopeless as a general solution.\n\nYeah, I`ve encountered it in my (trivial) test case :(\n\n> It is acceptable as long as a solution fails loudly when it does the\n> wrong thing, but I do not think the apporach can produce incorrect\n> result silently, as your example shows above.\n\nHmm, I think my example doesn`t even try to prevent failing, but it \nshould otherwise be perfectly capable of doing so (and doing it \nloudly) - for example, it`s enough to diff U1' and U2' - if not the \nsame, user might want to confirm the \"rebased\" merge outcome, as \neither something went wrong, or interactive rebase happened... or \nboth :) (it`s what Sergey originally explained, seeming to be a solid \nsafety net, though more testing would be good)\n\n> What you _COULD_ learn from an old merge is to compute:\n> \n>     - a trial and mechanical merge between A3 and B3; call that pre-M\n> \n>     - diff to bring pre-M to M (call that patch evil-M); which is\n>       what the person who made M did to resolve the textual and\n>       semantic conflicts necessary to merge these two topics.\n> \n> Then when merging A3' and B3', you could try to mechanically merge\n> them (call that pre-M'), and apply evil-M, which may apply cleanly\n> on top of pre-M', or it may not.  When there aren't so huge a\n> difference between series A and A' (and series B and B'), the result\n> would probably be a moral equivalent of Sergay's \"replay\" (so this\n> approach will also silently produce a wrong result without human\n> supervision).  One edge the evil-M approach has over Sergey's \"dual\n> cherry pick\" is that it separates and highlights non-mechanical\n> conflict resolution out of mechanical merges in a human readable\n> form (i.e. the patch evil-M).\n\nThis seems to be what Johannes wrote about[1], too, but also \nsomething I think would be good to avoid, if possible, not \ncomplicating it too much :P\n\nMaybe something like that latest thought[2] could help, using \nadditional R1 and R2 commits to handle interactive rebase \nadditions/amendments/drops, on top of U1' and U2'? Yeah, and \nthat`s not complicating it... ;) :D\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/\n[2] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n"},{"id":"340532","messageId":"b4367bca-79a0-879b-9503-ed4e667d8a64@gmail.com","threadId":"47864","inReplyTo":"3b562b51-2f1a-48f6-d6b4-8e0fbddd3a40@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T04:35:16Z","receivedAt":"2018-02-28T04:35:29Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 28/02/2018 03:12, Igor Djordjevic wrote:\n> \n> Would additional step as suggested in [1] (using R1 and R2 to \"catch\" \n> interactive rebase additions/amendments/drops, on top of U1' and \n> U2'), make more sense (or provide an additional clue, at least)?\n> \n> [1] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n\nHeh, no sleeping tonight :P\n\nAnyway, from (yet another) ad hoc test, additional step mentioned in \n[1] above seems to handle this case, too (merge with `-s ours` \ndropping B* patches, plus B1 cherry-picked between X1..X2):\n\nOn 28/02/2018 00:27, Johannes Schindelin wrote:\n> \n> - One of the promises was that the new way would also handle merge\n>   strategies other than recursive. What would happen, for example, if M\n>   was generated using `-s ours` (read: dropping the B* patches' changes)\n>   and if B1 had been cherry-picked into the history between X1..X2?\n> \n>   Reverting R would obviously revert those B1 changes, even if B1' would\n>   obviously not even be part of the rebased history!\n> \n> Yes, I agree that this `-s ours` example is quite concocted, but the point\n> of this example is not how plausible it is, but how easy it is to come up\n> with a scenario where this design to \"rebase merge commits\" results in\n> very, very unwanted behavior.\n\nAnd not just that - it worked with additional interactive rebase \nadding, amending and removing commits, on top of all this still \npreserving original `-s ours` merge commit evil-merge amendment, too, \nall as expected (or so it seems) :P\n\nAgain, for the brave ones, here`s another messy test script (not \ntightly related to the last discussed diagrams, but based on my \noriginal \"demonstration\" script[2])... Hopefully I get to make a \nproper (and sane) sample soon... if not missing something here in the \nfirst place ;)\n\nRegards, Buga\n\n[2] https://public-inbox.org/git/bbe64321-4d3a-d3fe-8bb9-58b600fabf35@gmail.com/\n\n-- 8< --\n#!/bin/sh\n\n# rm -rf ./.git\n# rm -f ./test.txt\n\ngit init\n\ntouch ./test.txt\ngit add -- test.txt\n\nfor i in {1..20}\ndo\n\techo A$i >>test.txt\n\tgit commit -am \"A$i\"\ndone\n\ngit checkout -b b1\nsed -i '3iB11' test.txt\ngit commit -am \"B11\"\nsed -i '7iB12' test.txt\ngit commit -am \"B12\"\n\ngit checkout -b b2 HEAD^\nsed -i '16iB21' test.txt\ngit commit -am \"B21\"\nsed -i '18iB22' test.txt\ngit commit -am \"B22\"\n\ngit checkout -b merge b1\ngit merge -s ours --no-commit b2\nsed -i '12iX' test.txt # amend merge commit\ngit commit -am \"M\"\ngit tag original-merge\n\ngit checkout master\ngit cherry-pick b2\nfor i in {1..5}\ndo\n\tj=`expr \"$i\" + 20`\n\tsed -i \"${i}iA${j}\" test.txt\n\tgit commit -am \"A$j\"\ndone\n\n# simple/naive demonstration of proposed merge rebasing logic\n# using described \"Trivial Merge\" (TM, or \"Angel Merge\"),\n# preserving merge commit manual amendments, but still respecting\n# interactively rebased added/modified/dropped commits :)\n\n# read -p \"Press enter to continue\"\ngit checkout b1\ngit cherry-pick -m1 original-merge && git tag U1\ngit reset --hard HEAD^^ # drop U1 and last b1 commit\nsed -i '/B11/c\\B1111' test.txt\ngit commit -a --amend --no-edit\ngit rebase master\ngit cherry-pick U1 && git tag U1-prime\n\n# read -p \"Press enter to continue\"\ngit checkout b2\ngit cherry-pick -m2 original-merge && git tag U2\ngit reset --hard HEAD^ # drop U2\ngit rebase master\nsed -i '20iBX' test.txt\ngit commit -am \"BX\" # add new commit\ngit cherry-pick U2 && git tag U2-prime\n\ngit diff U1 U1-prime | git apply --3way && git commit -m \"U2-second\" && git tag U2-second\ngit checkout b1\ngit diff U2 U2-prime | git apply --3way && git commit -m \"U1-second\" && git tag U1-second\n\n# read -p \"Press enter to continue\"\ngit branch -f merge b1\ngit checkout merge\ngit merge b2 --no-commit\ngit commit -a --reuse-message original-merge\ngit tag angel-merge\n\n# read -p \"Press enter to continue\"\ngit reset --hard b1^\ngit read-tree --reset angel-merge\ngit update-ref refs/heads/merge \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse b1^^)\" -p \"$(git rev-parse b2^^)\")\"\ngit tag -f angel-merge\ngit checkout angel-merge .\ngit branch -f b1 b1^^\ngit branch -f b2 b2^^\n\n# show resulting graph\necho\ngit log --all --decorate --oneline --graph\n\n# comparison between original merge and rebased merge,\n# showing merge commit amendment \"X\" being preserved during rebase\n# (not shown in diff)\necho\necho 'diff original-merge angel-merge:'\ngit diff original-merge angel-merge\n"},{"id":"340534","messageId":"87lgfdogts.fsf@javad.com","threadId":"47864","inReplyTo":"xmqqbmgaqp02.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T04:53:35Z","receivedAt":"2018-02-28T04:53:43Z","isPatch":false,"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>> You've already bit this poor thingy to death. Please rather try your\n>> teeth on the proposed Trivial Merge (TM) method.\n>\n> Whatever you do, do *NOT* call any part of your proposal \"trivial\n> merge\", unless you are actually using the term to mean what Git\n> calls \"trivial merge\".  The phrase has an established meaning in Git\n> and your attempt to abuse it to mean something entirely different is\n> adding unnecessary hindrance for other people to understand what you\n> want to perform.\n\nYeah, got it. It's confusing indeed.\n\n-- Sergey\n\n\n\n\n\n"},{"id":"340536","messageId":"87606hoflx.fsf@javad.com","threadId":"47864","inReplyTo":"940d959d-151d-68dd-0f13-320ebad0d75b@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T05:19:54Z","receivedAt":"2018-02-28T05:20:05Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 27/02/2018 20:59, Igor Djordjevic wrote:\n>> \n>> (3) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>> \n>\n> Meh, I hope I`m rushing it now, but for example, if we had decided to \n> drop commit A2 during an interactive rebase (so losing A2' from \n> diagram above), wouldn`t U2' still introduce those changes back, once \n> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n\nI think the method will handle this nicely.\n\nWhen you \"drop\" A2, will A3' change, or stay intact?\n\nIf it changes, say, to A3'', the U1' will change to U1'', and the method\nwill propagate the change automatically.\n\nIf it A3' doesn't change, then there are no changes to take.\n\n-- Sergey\n"},{"id":"340537","messageId":"871sh5ofil.fsf@javad.com","threadId":"47864","inReplyTo":"8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T05:21:54Z","receivedAt":"2018-02-28T05:22:01Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 28/02/2018 01:36, Jacob Keller wrote:\n>> \n>> > > (3) ---X1---o---o---o---o---o---X2\n>> > >        |\\                       |\\\n>> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>> > >        |             \\          |\n>> > >        |              M         |\n>> > >        |             /          |\n>> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>> > >\n>> >\n>> > Meh, I hope I`m rushing it now, but for example, if we had decided to\n>> > drop commit A2 during an interactive rebase (so losing A2' from\n>> > diagram above), wouldn`t U2' still introduce those changes back, once\n>> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>> \n>> In that case, the method won't work well at all, so I think we need a\n>> different approach.\n>> \n>\n> Hmm, still rushing it, but what about adding an additional step, \n> something like this:\n\nI think it's unneeded, as it should work fine without it, see another\nreply.\n\n-- Sergey\n"},{"id":"340538","messageId":"87zi3tn0p7.fsf@javad.com","threadId":"47864","inReplyTo":"xmqqwoyym0ry.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T05:27:16Z","receivedAt":"2018-02-28T05:27:25Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n>\n>> On 27/02/2018 20:59, Igor Djordjevic wrote:\n>>> \n>>> (3) ---X1---o---o---o---o---o---X2\n>>>        |\\                       |\\\n>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>>        |             \\          |\n>>>        |              M         |\n>>>        |             /          |\n>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>> \n>>\n>> Meh, I hope I`m rushing it now, but for example, if we had decided to \n>> drop commit A2 during an interactive rebase (so losing A2' from \n>> diagram above), wouldn`t U2' still introduce those changes back, once \n>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>>\n>> p.s. Looks like Johannes already elaborated on this in the meantime, \n>> let`s see... (goes reading that other e-mail[1])\n>\n> As long as we are talking about rebase that allows us users to\n> adjust and make changes (\"rebase -i\" being the prime and most\n> flexible example), it is easy to imagine that A1'--A3' and B1'--B3'\n> have almost no relation to their original counterparts.  After all,\n> mechanical merge won't be able to guess the intention of the change\n> humans make, so depending on what happend during X1 and X2 that\n> happend outside of these two topics, what's required to bring series\n> A and B to series A' and B' can be unlimited.\n\nYou discuss some different method here. In my original proposal U1' and\nU2' are to be merged. Nothing should be replayed on top of them. I.e.,\nU1' is _already_ the result of replaying difference between M and A3 on\ntop of A3'.\n\n> So from that alone, it should be clear that replaying difference\n> between M and A3 (and M and B3) on top of U1' and U2' is hopeless as a\n> general solution.\n\nGetting U1' from U1 is the same complexity as getting A3' from A3, with\nthe same caveats. So, as general solution, it's as good as rebase of\nnon-merge commit.\n\n> It is acceptable as long as a solution fails loudly when it does the\n> wrong thing, but I do not think the apporach can produce incorrect\n> result silently, as your example shows above.\n\nI still believe the method handles simple cases automatically and\ncorrectly and allows to immediately stop for amendment should something\nsuspect appear.\n\n-- Sergey\n"},{"id":"340539","messageId":"87sh9lmzwy.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T05:44:13Z","receivedAt":"2018-02-28T05:44:22Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Buga,\n>\n> thank you for making this a lot more understandable to this thick\n> developer.\n>\n> On Tue, 27 Feb 2018, Igor Djordjevic wrote:\n>\n>> On 27/02/2018 19:55, Igor Djordjevic wrote:\n>> > \n>> > It would be more along the lines of \"(1) rebase old merge commit parents, \n>> > (2) generate separate diff between old merge commit and each of its \n>> > parents, (3) apply each diff to their corresponding newly rebased \n>> > parent respectively (as a temporary commit, one per rebased parent), \n>> > (4) merge these temporary commits to generate 'rebased' merge commit, \n>> > (5) drop temporary commits, recording their parents as parents of \n>> > 'rebased' merge commit (instead of dropped temporary commits)\".\n>> > \n>> > Implementation wise, steps (2) and (3) could also be done by simply \n>> > copying old merge commit _snapshot_ on top of each of its parents as \n>> > a temporary, non-merge commit, then rebasing (cherry-picking) these \n>> > temporary commits on top of their rebased parent commits to produce \n>> > rebased temporary commits (to be merged for generating 'rebased' \n>> > merge commit in step (4)).\n>> \n>> For those still tagging along (and still confused), here are some \n>> diagrams (following what Sergey originally described). Note that \n>> actual implementation might be even simpler, but I believe it`s a bit \n>> easier to understand like this, using some \"temporary\" commits approach.\n>> \n>> Here`s our starting position:\n>> \n>> (0) ---X1---o---o---o---o---o---X2 (master)\n>>        |\\\n>>        | A1---A2---A3\n>>        |             \\\n>>        |              M (topic)\n>>        |             /\n>>        \\-B1---B2---B3\n>> \n>> \n>> Now, we want to rebase merge commit M from X1 onto X2. First, rebase\n>> merge commit parents as usual:\n>> \n>> (1) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3           | A1'--A2'--A3'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3           \\-B1'--B2'--B3'\n>> \n>> \n>> That was commonly understandable part.\n>\n> Good. Let's assume that I want to do this interactively (because let's\n> face it, rebase is boring unless we shake up things a little). And let's\n> assume that A1 is my only change to the README, and that I realized that\n> it was incorrect and I do not want the world to see it, so I drop A1'.\n>\n> Let's see how things go from here:\n>\n>> Now, for \"rebasing\" the merge commit (keeping possible amendments), we\n>> do some extra work. First, we make two temporary commits on top of old\n>> merge parents, by using exact tree (snapshot) of commit M:\n>> \n>> (2) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n>\n> Okay, everything would still be the same except that I still have dropped\n> A1'.\n>\n>> So here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M.\n>> \n>> Now, we rebase these temporary commits, too:\n>> \n>> (3) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>        |             \\          |\n>>        |              M         |\n>>        |             /          |\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>\n> I still want to drop A1 in this rebase, so A1' is still missing.\n>\n> And now it starts to get interesting.\n>\n> The diff between A3 and U1 does not touch the README, of course, as I said\n> that only A1 changed the README.  But the diff between B3 and U2 does\n> change the README, thanks to M containing A1 change.\n>\n> Therefore, the diff between B3' and U2' will also have this change to the\n> README. That change that I wanted to drop.\n>\n>> As a next step, we merge these temporary commits to produce our\n>> \"rebased\" merged commit M:\n>> \n>> (4) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>        |             \\          |                  \\\n>>        |              M         |                   M'\n>>        |             /          |                  /\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>\n> And here, thanks to B3'..U2' changing the README, M' will also have that\n> change that I wanted to see dropped.\n>\n> Note that A1' is still dropped in my example.\n>\n>> Finally, we drop temporary commits, and record rebased commits A3' \n>> and B3' as our \"rebased\" merge commit parents instead (merge commit \n>> M' keeps its same tree/snapshot state, just gets parents replaced):\n>> \n>> (5) ---X1---o---o---o---o---o---X2\n>>        |\\                       |\\\n>>        | A1---A2---A3---U1      | A1'--A2'--A3'\n>>        |             \\          |             \\\n>>        |              M         |              M'\n>>        |             /          |             /\n>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n>\n> Now, thanks to U2' being dropped (and A1' *still* being dropped), the\n> change in the README that is still in M' is really only in M'. No other\n> rebased commit has it. That makes it look as if M' introduced this change\n> in addition to the changes that were merged between the merge parents.\n\nExcept that original proposal suggests to cosider this a conflict and\nto stop for amendment, as U1' and U2' now differ.\n\n-- Sergey\n"},{"id":"340540","messageId":"87o9k9mzg9.fsf@javad.com","threadId":"47864","inReplyTo":"CA+P7+xpNhEF0=QoR71v5Y=nc39OL4XKX36xXYjP1Kn_+DUCf_Q@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T05:54:14Z","receivedAt":"2018-02-28T05:54:21Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Jacob Keller <jacob.keller@gmail.com> writes:\n\n> On Tue, Feb 27, 2018 at 10:14 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Sergey Organov <sorganov@gmail.com> writes:\n>>\n>>> You've already bit this poor thingy to death. Please rather try your\n>>> teeth on the proposed Trivial Merge (TM) method.\n>>\n>> Whatever you do, do *NOT* call any part of your proposal \"trivial\n>> merge\", unless you are actually using the term to mean what Git\n>> calls \"trivial merge\".  The phrase has an established meaning in Git\n>> and your attempt to abuse it to mean something entirely different is\n>> adding unnecessary hindrance for other people to understand what you\n>> want to perform.\n>\n> Agreed, I think we need better terminology here, the current words for\n> (TM) are definitely *not* trivial merges. Same for \"angel merge\", I\n> don't think that term really works well either.\n\nAgreed.\n\nHow do we call a merge that introduces no differences on either side of\nthe merge then? Is there some English for even more trivial than what\nGit calls \"trivial merge\"?\n\n-- Sergey\n"},{"id":"340541","messageId":"87k1uxmyib.fsf@javad.com","threadId":"47864","inReplyTo":"b4367bca-79a0-879b-9503-ed4e667d8a64@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-02-28T06:14:36Z","receivedAt":"2018-02-28T06:14:44Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 28/02/2018 03:12, Igor Djordjevic wrote:\n>> \n>> Would additional step as suggested in [1] (using R1 and R2 to \"catch\" \n>> interactive rebase additions/amendments/drops, on top of U1' and \n>> U2'), make more sense (or provide an additional clue, at least)?\n>> \n>> [1] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n>\n> Heh, no sleeping tonight :P\n>\n> Anyway, from (yet another) ad hoc test, additional step mentioned in \n> [1] above seems to handle this case, too (merge with `-s ours` \n> dropping B* patches, plus B1 cherry-picked between X1..X2):\n>\n> On 28/02/2018 00:27, Johannes Schindelin wrote:\n>> \n>> - One of the promises was that the new way would also handle merge\n>>   strategies other than recursive. What would happen, for example, if M\n>>   was generated using `-s ours` (read: dropping the B* patches' changes)\n>>   and if B1 had been cherry-picked into the history between X1..X2?\n>> \n>>   Reverting R would obviously revert those B1 changes, even if B1' would\n>>   obviously not even be part of the rebased history!\n>> \n>> Yes, I agree that this `-s ours` example is quite concocted, but the point\n>> of this example is not how plausible it is, but how easy it is to come up\n>> with a scenario where this design to \"rebase merge commits\" results in\n>> very, very unwanted behavior.\n>\n> And not just that - it worked with additional interactive rebase \n> adding, amending and removing commits, on top of all this still \n> preserving original `-s ours` merge commit evil-merge amendment, too, \n> all as expected (or so it seems) :P\n\nGreat! I do believe that once we start from some sensible approach, many\nkinds of improvements are possible. I'll definitely need to take close\nlook at what you came up with, thanks!\n\nI'd like to say though that nobody should expect miracles from automated\nrebasing of merges when we get to complex history editing. It will need\nto retreat to manual merge, sooner or later.\n\n-- Sergey\n"},{"id":"340606","messageId":"c8c2e915-cb55-9881-e54d-2c84ad7e16bb@gmail.com","threadId":"47864","inReplyTo":"871sh5ofil.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T19:09:23Z","receivedAt":"2018-02-28T19:09:37Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 28/02/2018 06:21, Sergey Organov wrote:\n> \n> > > > > (3) ---X1---o---o---o---o---o---X2\n> > > > >        |\\                       |\\\n> > > > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > > > >        |             \\          |\n> > > > >        |              M         |\n> > > > >        |             /          |\n> > > > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> > > > >\n> > > >\n> > > > Meh, I hope I`m rushing it now, but for example, if we had decided to\n> > > > drop commit A2 during an interactive rebase (so losing A2' from\n> > > > diagram above), wouldn`t U2' still introduce those changes back, once\n> > > > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> > >\n> > > In that case, the method won't work well at all, so I think we need a\n> > > different approach.\n> > >\n> >\n> > Hmm, still rushing it, but what about adding an additional step, \n> > something like this:\n> \n> I think it's unneeded, as it should work fine without it, see another\n> reply.\n\nUnfortunately, I have a broken test case saying different - it could \nvery well be a flawed test, too, but let`s elaborate in that \nother sub-thread[1], indeed.\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/87606hoflx.fsf@javad.com/\n"},{"id":"340609","messageId":"99fdde36-f616-7947-faa0-1b369d0bec97@gmail.com","threadId":"47864","inReplyTo":"87sh9lmzwy.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T19:42:28Z","receivedAt":"2018-02-28T19:42:43Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 28/02/2018 06:44, Sergey Organov wrote:\n> \n> > > Here`s our starting position:\n> > >\n> > > (0) ---X1---o---o---o---o---o---X2 (master)\n> > >        |\\\n> > >        | A1---A2---A3\n> > >        |             \\\n> > >        |              M (topic)\n> > >        |             /\n> > >        \\-B1---B2---B3\n> > >\n> > >\n> > > Now, we want to rebase merge commit M from X1 onto X2. First, rebase\n> > > merge commit parents as usual:\n> > >\n> > > (1) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3           | A1'--A2'--A3'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3           \\-B1'--B2'--B3'\n> > >\n> > >\n> > > That was commonly understandable part.\n> >\n> > Good. Let's assume that I want to do this interactively (because let's\n> > face it, rebase is boring unless we shake up things a little). And let's\n> > assume that A1 is my only change to the README, and that I realized that\n> > it was incorrect and I do not want the world to see it, so I drop A1'.\n> >\n> > Let's see how things go from here:\n> >\n> > > Now, for \"rebasing\" the merge commit (keeping possible amendments), we\n> > > do some extra work. First, we make two temporary commits on top of old\n> > > merge parents, by using exact tree (snapshot) of commit M:\n> > >\n> > > (2) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n> >\n> > Okay, everything would still be the same except that I still have dropped\n> > A1'.\n> >\n> > > So here, in terms of _snapshots_ (trees, not diffs), U1 = U2 = M.\n> > >\n> > > Now, we rebase these temporary commits, too:\n> > >\n> > > (3) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> >\n> > I still want to drop A1 in this rebase, so A1' is still missing.\n> >\n> > And now it starts to get interesting.\n> >\n> > The diff between A3 and U1 does not touch the README, of course, as I said\n> > that only A1 changed the README.  But the diff between B3 and U2 does\n> > change the README, thanks to M containing A1 change.\n> >\n> > Therefore, the diff between B3' and U2' will also have this change to the\n> > README. That change that I wanted to drop.\n> >\n> > > As a next step, we merge these temporary commits to produce our\n> > > \"rebased\" merged commit M:\n> > >\n> > > (4) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |                  \\\n> > >        |              M         |                   M'\n> > >        |             /          |                  /\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> >\n> > And here, thanks to B3'..U2' changing the README, M' will also have that\n> > change that I wanted to see dropped.\n> >\n> > Note that A1' is still dropped in my example.\n> >\n> > > Finally, we drop temporary commits, and record rebased commits A3' \n> > > and B3' as our \"rebased\" merge commit parents instead (merge commit \n> > > M' keeps its same tree/snapshot state, just gets parents replaced):\n> > >\n> > > (5) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'\n> > >        |             \\          |             \\\n> > >        |              M         |              M'\n> > >        |             /          |             /\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'\n> >\n> > Now, thanks to U2' being dropped (and A1' *still* being dropped), the\n> > change in the README that is still in M' is really only in M'. No other\n> > rebased commit has it. That makes it look as if M' introduced this change\n> > in addition to the changes that were merged between the merge parents.\n> \n> Except that original proposal suggests to cosider this a conflict and\n> to stop for amendment, as U1' and U2' now differ.\n\nThanks for bringing this one up again - I focused on a mere example \nof how the approach could work, not stressing enough the simplicity \nof recognizing when it really doesn`t, which is an important aspect \nto know as well, indeed, supporting much needed trust that no bad \nthings could happen behind our back.\n\nEither work as expected, or fail loudly, yes.\n\nRegards, Buga\n"},{"id":"340613","messageId":"0ac3a3fd-4053-e32e-75ed-8829f22c2e1f@gmail.com","threadId":"47864","inReplyTo":"87606hoflx.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T20:25:07Z","receivedAt":"2018-02-28T20:25:22Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 28/02/2018 06:19, Sergey Organov wrote:\n> \n> > > (3) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> > >\n> >\n> > Meh, I hope I`m rushing it now, but for example, if we had decided to \n> > drop commit A2 during an interactive rebase (so losing A2' from \n> > diagram above), wouldn`t U2' still introduce those changes back, once \n> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> \n> I think the method will handle this nicely.\n\nThat`s what I thought as well. And then I made a test. And then the \ntest broke... Now, might be the test was flawed in the first place, \nbut thinking about it a bit more, it does seem to make sense not to \nhandle this case nicely :/\n\n> When you \"drop\" A2, will A3' change, or stay intact?\n\nWhen you \"drop\" commit A2 from rebasing, patch (diff) A3' does stay \nthe same - but resulting tree (snapshot) after applying it does not.\n\nBy removing commit A2 from your rebase, you`re saying that changes \nintroduced in that commit shouldn`t ever happen in the rebased tree, \nso trees/snapshots of all rebased commits coming after dropped A2 \nwill have these changes missing, in comparison to trees of original \ncommits they`re being rebased from.\n\n> If it changes, say, to A3'', the U1' will change to U1'', and the method\n> will propagate the change automatically.\n> \n> If it A3' doesn't change, then there are no changes to take.\n\nAll true, but note what I wrote in the original message - the issue \nof dropping A2 is not U1, but U2, and that one doesn`t change.\n\nIn this case, U1' will correctly represent U1 rebased on top of A3' \n(where A2 is now missing), no problem there.\n\nBut on the other end, as U2 holds changes between original merge and \nB3 (being A1, A2, A3 and evil-merge M), it will also still hold \nchanges introduced by original A2.\n\nRebasing it onto B3' brings all these changes along, and once merged \nwith U1' to produce \"rebased\" merge it unexpectedly introduces \nsupposedly dropped commit A2 changes in their full glory.\n\nYes, considering this situation a conflict, as originally proposed, \nby simply noticing that U1' and U2' differ, helps this to fail \nloudly without doing the wrong thing.\n\nBut U1' and U2' are really to be expected to stay the same in \nnon-interactive rebase case only, where it doesn`t help interactive \nrebase case at all if it is to fail most of the time (where U1' and \nU2' don`t have to be, but should be expected to possibly be different).\n\nSo while your original proposal currently seems like it could be \nworking nicely for non-interactive rebase (and might be some simpler \ninteractive ones), now hitting/acknowledging its first real use \nlimit, my additional quick attempt[1] just tries to aid pretty \ninteresting case of complicated interactive rebase, too, where we \nmight be able to do better as well, still using you original proposal \nas a base idea :)\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n"},{"id":"340616","messageId":"d06dcf02-6b85-c4b3-936b-5bf3ca1c4b98@gmail.com","threadId":"47864","inReplyTo":"87k1uxmyib.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T20:53:24Z","receivedAt":"2018-02-28T20:53:32Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 28/02/2018 07:14, Sergey Organov wrote:\n> \n> > > Would additional step as suggested in [1] (using R1 and R2 to \"catch\" \n> > > interactive rebase additions/amendments/drops, on top of U1' and \n> > > U2'), make more sense (or provide an additional clue, at least)?\n> > > \n> > > [1] https://public-inbox.org/git/8829c395-fb84-2db0-9288-f7b28fa0d0d1@gmail.com/\n> > \n> > Anyway, from (yet another) ad hoc test, additional step mentioned in \n> > [1] above seems to handle this case, too (merge with `-s ours` \n> > dropping B* patches, plus B1 cherry-picked between X1..X2)\n> > \n> > ...\n> > \n> > And not just that - it worked with additional interactive rebase \n> > adding, amending and removing commits, on top of all this still \n> > preserving original `-s ours` merge commit evil-merge amendment, too, \n> > all as expected (or so it seems) :P\n> \n> Great! I do believe that once we start from some sensible approach, many\n> kinds of improvements are possible. I'll definitely need to take close\n> look at what you came up with, thanks!\n> \n> I'd like to say though that nobody should expect miracles from automated\n> rebasing of merges when we get to complex history editing. It will need\n> to retreat to manual merge, sooner or later.\n\nI agree, and as I really liked \"the feeling\" of the original approach \nyou described, it felt bad to (presumably) see it failing in what \ndoesn`t seem to be neither too complex nor rare situation of dropping \na commit during an interactive rebase, thus motivation to try to \nimprove it, if possible, wasn`t lacking :)\n \nEh, might be I`m just naively ignorant at the moment as well, but I`m \ntrying to work my way through it... ;)\n\nRegards, Buga\n"},{"id":"340631","messageId":"7c34a060-3013-6404-fe8e-c3ad015803a7@gmail.com","threadId":"47864","inReplyTo":"0ac3a3fd-4053-e32e-75ed-8829f22c2e1f@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-02-28T22:17:28Z","receivedAt":"2018-02-28T22:17:38Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 28/02/2018 21:25, Igor Djordjevic wrote:\n> \n> But U1' and U2' are really to be expected to stay the same in \n> non-interactive rebase case only...\n\nJust to rephrase to \"could be expected\" here, meaning still not \nnecessarily in this case, either - I`ve just witnessed \nnon-interactive rebase Johannes previously described[1], merge with \n`-s ours` (dropping B* patches), plus B1 cherry-picked between \nX1..X2, eventually coming up with different U1' and U2', too (which \nwould produce a wrong end result, if continued).\n\nBut I guess this should go to the \"complex history\" pile, good thing \nstill being that diff safety check between U1' and U2' works as \nexpected, thus automatic merge rebase can be aborted and command \ngiven back to the user for closer inspection.\n\n[1] https://public-inbox.org/git/nycvar.QRO.7.76.6.1802272330290.56@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/\n"},{"id":"340682","messageId":"87d10os77p.fsf@javad.com","threadId":"47864","inReplyTo":"7c34a060-3013-6404-fe8e-c3ad015803a7@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-01T05:19:54Z","receivedAt":"2018-03-01T05:20:03Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 28/02/2018 21:25, Igor Djordjevic wrote:\n>> \n>> But U1' and U2' are really to be expected to stay the same in \n>> non-interactive rebase case only...\n>\n> Just to rephrase to \"could be expected\" here, meaning still not \n> necessarily in this case, either - I`ve just witnessed \n> non-interactive rebase Johannes previously described[1], merge with \n> `-s ours` (dropping B* patches), plus B1 cherry-picked between \n> X1..X2, eventually coming up with different U1' and U2', too (which \n> would produce a wrong end result, if continued).\n\nEven non-interactive rebase may bring arbitrary asymmetric changes on\nboth sides of the merge, especially likely when resolving conflicts\nneeds to take place. OTOH, interactive history editing session could\nhave merges that we don't intend to edit at all. Overall, neither\nnon-interactive case is in fact much simpler, nor interactive case is so\nmuch different.\n\n> But I guess this should go to the \"complex history\" pile, good thing \n> still being that diff safety check between U1' and U2' works as \n> expected, thus automatic merge rebase can be aborted and command \n> given back to the user for closer inspection.\n\nExactly. This fact hopefully won't stop us from looking for more\nsuitable automated handling of the general case though. It should still\nbe our goal to reduce the number of such aborts and to suggest better\nmerge result for amendment when we are still aborting.\n\nYour proposal hopefully is such a valuable improvement.\n\n-- Sergey\n"},{"id":"340683","messageId":"87bmg8s6vs.fsf@javad.com","threadId":"47864","inReplyTo":"c8c2e915-cb55-9881-e54d-2c84ad7e16bb@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-01T05:27:03Z","receivedAt":"2018-03-01T05:27:10Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n[...]\n>> > Hmm, still rushing it, but what about adding an additional step, \n>> > something like this:\n>> \n>> I think it's unneeded, as it should work fine without it, see another\n>> reply.\n>\n> Unfortunately, I have a broken test case saying different - it could \n> very well be a flawed test, too, but let`s elaborate in that \n> other sub-thread[1], indeed.\n\nYeah, I was too fast to reply and I was wrong, sorry about it.\n\n-- Sergey\n"},{"id":"340684","messageId":"87a7vss6ax.fsf@javad.com","threadId":"47864","inReplyTo":"0ac3a3fd-4053-e32e-75ed-8829f22c2e1f@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-01T05:39:34Z","receivedAt":"2018-03-01T05:39:42Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 28/02/2018 06:19, Sergey Organov wrote:\n>> \n>> > > (3) ---X1---o---o---o---o---o---X2\n>> > >        |\\                       |\\\n>> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>> > >        |             \\          |\n>> > >        |              M         |\n>> > >        |             /          |\n>> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>> > >\n>> >\n>> > Meh, I hope I`m rushing it now, but for example, if we had decided to \n>> > drop commit A2 during an interactive rebase (so losing A2' from \n>> > diagram above), wouldn`t U2' still introduce those changes back, once \n>> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>> \n>> I think the method will handle this nicely.\n>\n> That`s what I thought as well. And then I made a test. And then the \n> test broke... Now, might be the test was flawed in the first place, \n> but thinking about it a bit more, it does seem to make sense not to \n> handle this case nicely :/\n\nYeah, I now see it myself. I'm sorry for being lazy and not inspecting\nthis more carefully in the first place.\n\n[...]\n\n> So while your original proposal currently seems like it could be \n> working nicely for non-interactive rebase (and might be some simpler \n> interactive ones), now hitting/acknowledging its first real use \n> limit, my additional quick attempt[1] just tries to aid pretty \n> interesting case of complicated interactive rebase, too, where we \n> might be able to do better as well, still using you original proposal \n> as a base idea :)\n\nYes, thank you for pushing me back to reality! :-) The work and thoughts\nyou are putting into solving the puzzle are greatly appreciated!\n\nThinking about it overnight, I now suspect that original proposal had a\nmistake in the final merge step. I think that what you did is a way to\nfix it, and I want to try to figure what exactly was wrong in the\noriginal proposal and to find simpler way of doing it right.\n\nThe likely solution is to use original UM as a merge-base for final\n3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\nthough, as that's exactly UM from which both U1' and U2' have diverged\ndue to rebasing and other history editing.\n\n-- Sergey\n"},{"id":"340774","messageId":"f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com","threadId":"47864","inReplyTo":"87a7vss6ax.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-02T01:16:05Z","receivedAt":"2018-03-02T01:16:33Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 01/03/2018 06:39, Sergey Organov wrote:\n> \n> > > (3) ---X1---o---o---o---o---o---X2\n> > >        |\\                       |\\\n> > >        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> > >        |             \\          |\n> > >        |              M         |\n> > >        |             /          |\n> > >        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> > >\n> > \n> > Meh, I hope I`m rushing it now, but for example, if we had decided to \n> > drop commit A2 during an interactive rebase (so losing A2' from \n> > diagram above), wouldn`t U2' still introduce those changes back, once \n> > U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> > \n> > [...]\n> \n> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n> this more carefully in the first place.\n\nNo problem, that`s why we`re discussing it, and I`m glad we`re \naligned now, so we can move forward :)\n\n> > So while your original proposal currently seems like it could be \n> > working nicely for non-interactive rebase (and might be some simpler \n> > interactive ones), now hitting/acknowledging its first real use \n> > limit, my additional quick attempt[1] just tries to aid pretty \n> > interesting case of complicated interactive rebase, too, where we \n> > might be able to do better as well, still using you original proposal \n> > as a base idea :)\n> \n> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n> you are putting into solving the puzzle are greatly appreciated!\n\nYou`re welcome, and I am enjoying it :)\n\n> Thinking about it overnight, I now suspect that original proposal had a\n> mistake in the final merge step. I think that what you did is a way to\n> fix it, and I want to try to figure what exactly was wrong in the\n> original proposal and to find simpler way of doing it right.\n> \n> The likely solution is to use original UM as a merge-base for final\n> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n> though, as that's exactly UM from which both U1' and U2' have diverged\n> due to rebasing and other history editing.\n\nYes, this might be it...! ;)\n\nTo prove myself it works, I`ve assembled a pretty crazy `-s ours`  \nmerge interactive rebase scenario, and it seems this passes the test, \nticking all the check boxes (I could think of) :P\n\nLet`s see our starting situation:\n\n (0) ---X8--B2'--X9 (master)\n        |\\\n        | A1---A2---A3 (A)\n        |             \\\n        |              M (topic)\n        |             /\n        \\-B1---B2---B3 (B)\n\n\nHere, merge commit M is done with `-s ours` (obsoleting branch \"B\"), \nplus amended to make it an \"evil merge\", where a commit B2 from \nobsoleted branch \"B\" is cherry picked to \"master\".\n\nNow, we want to rebase \"topic\" (M) onto updated \"master\" (X9), but to \nmake things more interesting, we`ll do it interactively, with some \namendments, drops, additions and even more cherry-picks!\n\nThis is what the final result looks like:\n\n (1) ---X8--B2'--X9 (master)\n                 |\\\n                 | A12--A2'---B3' (A)\n                 |             \\\n                 |              M' (topic)\n                 |             /\n                 \\-B1'--B3'---B4  (B)\n\n\nDuring interactive rebase, on branch \"A\", we amended A1 into A12, \ndropped A3 and cherry-picked B3. On branch \"B\", B4 is added, B2' being \nomitted automatically as already present in \"master\".\n\nSo... In comparison to original merge commit M, rebased merge commit \nM' is expected to:\n\n - Add X9, from updated \"master\"\n - Have A1 changed to A12, due to A12 commit amendment\n - Keep A2, rebased as A2'\n - Remove A3, due to dropped A3 commit\n - Keep amendment from original (evil) merge commit M\n - Miss B1' like M does B, due to original `-s ours` merge strategy\n - Add B2, cherry-picked as B2' into \"master\"\n - Add B3, cherry-picked as B3' into \"A\"\n - Add B4, added to \"B\"\n - Most important, provide safety mechanism to \"fail loud\", being \n   aware of non-trivial things going on, allowing to stop for user \n   inspection/decision\n\n\nThere, I hope I didn`t miss any expectation. And, it _seems_ to work \nexactly as expected :D\n\nNot to leave this to imagination only, and hopefully helping others \nto get to speed and possibly discuss this, pointing to still possible \nflaws, I`m adding a demo script[1], showing how this exact example \nworks.\n\nNote that script _is_ coined to avoid rebase conflicts, as they`re not \ncurrently important for the point to be made here.\n\nIn real life, except for usual possibility for conflicts during \ncommit rebasing, we might experience _three_ possible conflict \nsituations once \"rebased\" merge itself is to be created - two when \nrebasing each of temporary merge helper commits, and one on the \n\"rebased\" merge itself. This is something where we might think about \nuser experience, not introducing (too much) confusion...\n\nRegards, Buga\n\n[1] Demonstration script:\n-- >8 --\n#!/bin/sh\n\n# rm -rf ./.git\n# rm -f ./test.txt\n\ngit init\n\ntouch ./test.txt\ngit add -- test.txt\n\n# prepare repository\nfor i in {1..8}\ndo\n\techo X$i >>test.txt\n\tgit commit -am \"X$i\"\ndone\n\n# prepare branch A\ngit checkout -b A\nsed -i '2iA1' test.txt\ngit commit -am \"A1\"\nsed -i '4iA2' test.txt\ngit commit -am \"A2\"\nsed -i '6iA3' test.txt\ngit commit -am \"A3\"\n\n# prepare branch B\ngit checkout -b B master\nsed -i '5iB1' test.txt\ngit commit -am \"B1\"\nsed -i '7iB2' test.txt\ngit commit -am \"B2\"\nsed -i '9iB3' test.txt\ngit commit -am \"B3\"\n\ngit checkout -b topic A\ngit merge -s ours --no-commit B # merge A and B with `-s ours`\nsed -i '8iM' test.txt           # amend merge commit (\"evil merge\")\ngit commit -am \"M\"\ngit tag original-merge\n\n# master moves on...\ngit checkout master\ngit cherry-pick B^     # cherry-pick B2 into master\nsed -i \"1iX9\" test.txt # add X9\ngit commit -am \"X9\"\n\n# (0) ---X8--B2'--X9 (master)\n#        |\\\n#        | A1---A2---A3 (A)\n#        |             \\\n#        |              M (topic)\n#        |             /\n#        \\-B1---B2---B3 (B)\n\n# simple/naive demonstration of proposed merge rebasing logic\n# using described new approach, preserving merge commit manual\n# amendments, testing `-s ours` merge with cherry-picking from\n# obsoleted part, but still respecting interactively rebased\n# added/modified/dropped/cherry-picked commits :)\n\ngit checkout A\ngit cherry-pick -m1 original-merge # prepare temporary helper commit U1\ngit tag U1\ngit reset --hard HEAD^^            # drop U1 and A3 from A\nsed -i '/A1/c\\A12' test.txt        # amend A1 to A12\ngit commit -a --amend --no-edit\ngit rebase master                  # rebase A onto master\ngit cherry-pick B                  # cherry-pick B3 into A\ngit cherry-pick U1                 # \"rebase\" temporary helper commit U1\ngit tag U1-prime\n\ngit checkout B\ngit cherry-pick -m2 original-merge # prepare temporary helper commit U2\ngit tag U2\ngit reset --hard HEAD^             # drop U2 from B\ngit rebase master                  # rebase B onto master\nsed -i '12iB4' test.txt            # add B4\ngit commit -am \"B4\"\ngit cherry-pick U2                 # \"rebase\" temporary helper commit U2\ngit tag U2-prime\n\ngit branch -f topic A\ngit checkout topic\n# merge rebased temporary commits U1' and U2',\n# using original merge commit as a merge base,\n# producing \"rebased\" merge commit M'\ngit read-tree -m --aggressive original-merge A B\ngit merge-index -o git-merge-one-file -a\n\n# recognize complex stuff going on during rebasing merge commit,\n# allowing user to inspect result, edit, and continue or abort\ngit diff --quiet U1-prime U2-prime\nif test $? -ne 0\nthen\n\t# PLACEHOLDER\n\t# chance to inspect result, like:\n\tgit diff original-merge\n\t# edit if needed, continue or abort\nfi\n\n# drop rebased temporary commits U1' and U2'\ngit branch -f A A^\ngit branch -f B B^\n\n# record branches A and B as parents of \"rebased\" merge commit M',\n# updating topic branch\ngit update-ref refs/heads/topic \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse A)\" -p \"$(git rev-parse B)\")\"\ngit tag angel-merge\n\n# (1) ---X8--B2'--X9 (master)\n#                 |\\\n#                 | A12--A2'---B3' (A)\n#                 |             \\\n#                 |              M' (topic)\n#                 |             /\n#                 \\-B1'--B3'---B4  (B)\n\n# show resulting graph\n# echo\n# git log --all --decorate --oneline --graph\n\n# in comparison to original merge commit M, rebased merge commit \n# M' is expected to:\n#\n# - Add X9, from updated \"master\"\n# - Have A1 changed to A12, due to A12 commit amendment\n# - Keep A2, rebased as A2'\n# - Remove A3, due to dropped A3 commit\n# - Keep amendment from original (evil) merge commit M\n# - Miss B1' like M does B, due to original `-s ours` merge strategy\n# - Add B2, cherry-picked as B2' into \"master\"\n# - Add B3, cherry-picked as B3' into \"A\"\n# - Add B4, added to \"B\"\n#\n# echo\n# echo 'diff original-merge angel-merge:'\n# git diff original-merge angel-merge\n"},{"id":"340783","messageId":"87606fox0b.fsf@javad.com","threadId":"47864","inReplyTo":"f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-02T05:40:52Z","receivedAt":"2018-03-02T05:41:01Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 01/03/2018 06:39, Sergey Organov wrote:\n\n[...]\n\n>> \n>> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n>> this more carefully in the first place.\n>\n> No problem, that`s why we`re discussing it, and I`m glad we`re \n> aligned now, so we can move forward :)\n>\n>> > So while your original proposal currently seems like it could be \n>> > working nicely for non-interactive rebase (and might be some simpler \n>> > interactive ones), now hitting/acknowledging its first real use \n>> > limit, my additional quick attempt[1] just tries to aid pretty \n>> > interesting case of complicated interactive rebase, too, where we \n>> > might be able to do better as well, still using you original proposal \n>> > as a base idea :)\n>> \n>> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n>> you are putting into solving the puzzle are greatly appreciated!\n>\n> You`re welcome, and I am enjoying it :)\n>\n>> Thinking about it overnight, I now suspect that original proposal had a\n>> mistake in the final merge step. I think that what you did is a way to\n>> fix it, and I want to try to figure what exactly was wrong in the\n>> original proposal and to find simpler way of doing it right.\n>> \n>> The likely solution is to use original UM as a merge-base for final\n>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>> though, as that's exactly UM from which both U1' and U2' have diverged\n>> due to rebasing and other history editing.\n>\n> Yes, this might be it...! ;)\n>\n> To prove myself it works, I`ve assembled a pretty crazy `-s ours`  \n> merge interactive rebase scenario, and it seems this passes the test, \n> ticking all the check boxes (I could think of) :P\n\nI must admit it's quite a relief to hear this. What we now have is so\nsimple and obvious that it'd be a huge disappointment if didn't work!\n\n> Here, merge commit M is done with `-s ours` (obsoleting branch \"B\"), \n> plus amended to make it an \"evil merge\", where a commit B2 from \n> obsoleted branch \"B\" is cherry picked to \"master\".\n\n[...]\n\n> There, I hope I didn`t miss any expectation. And, it _seems_ to work \n> exactly as expected :D\n\nThat's very nice, to the level of being even suspect! :-)\n\nTo avoid falling into euphoria though, we need to keep in mind that\n\"expectations\" is rather vague concept, and we likely still need to stop\nfor user amendment unless we absolutely sure nothing surprising happens.\nI.e., we better require U1'==U2' test to succeed to proceed non-stop\nautomatically. Besides, it will be somewhat inline with what 'rerere'\ndoes.\n\n> In real life, except for usual possibility for conflicts during \n> commit rebasing, we might experience _three_ possible conflict \n> situations once \"rebased\" merge itself is to be created - two when \n> rebasing each of temporary merge helper commits, and one on the \n> \"rebased\" merge itself. This is something where we might think about \n> user experience, not introducing (too much) confusion...\n\nYeah, this is terribly important issue to take care of! Relative\nsimplicity of the concept itself raises the chances of finding a\nsuitable solution, I hope.\n\n-- Sergey\n"},{"id":"340800","messageId":"ed4d2b30-2dea-740b-6283-973c798f619d@philandanna.no-ip.org","threadId":"47864","inReplyTo":"f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Phillip Wood","fromEmail":"phil@philandanna.no-ip.org","sentAt":null,"receivedAt":"2018-03-02T11:26:30Z","isPatch":false,"sender":{"key":"phil@philandanna.no-ip.org","avatar":null},"body":"\nOn 02/03/18 01:16, Igor Djordjevic wrote:\n> \n> Hi Sergey,\n> \n> On 01/03/2018 06:39, Sergey Organov wrote:\n>>\n>>>> (3) ---X1---o---o---o---o---o---X2\n>>>>        |\\                       |\\\n>>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>>>        |             \\          |\n>>>>        |              M         |\n>>>>        |             /          |\n>>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>>>\n>>>\n>>> Meh, I hope I`m rushing it now, but for example, if we had decided to \n>>> drop commit A2 during an interactive rebase (so losing A2' from \n>>> diagram above), wouldn`t U2' still introduce those changes back, once \n>>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>>>\n>>> [...]\n>>\n>> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n>> this more carefully in the first place.\n> \n> No problem, that`s why we`re discussing it, and I`m glad we`re \n> aligned now, so we can move forward :)\n> \n>>> So while your original proposal currently seems like it could be \n>>> working nicely for non-interactive rebase (and might be some simpler \n>>> interactive ones), now hitting/acknowledging its first real use \n>>> limit, my additional quick attempt[1] just tries to aid pretty \n>>> interesting case of complicated interactive rebase, too, where we \n>>> might be able to do better as well, still using you original proposal \n>>> as a base idea :)\n>>\n>> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n>> you are putting into solving the puzzle are greatly appreciated!\n> \n> You`re welcome, and I am enjoying it :)\n> \n>> Thinking about it overnight, I now suspect that original proposal had a\n>> mistake in the final merge step. I think that what you did is a way to\n>> fix it, and I want to try to figure what exactly was wrong in the\n>> original proposal and to find simpler way of doing it right.\n>>\n>> The likely solution is to use original UM as a merge-base for final\n>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>> though, as that's exactly UM from which both U1' and U2' have diverged\n>> due to rebasing and other history editing.\n> \n> Yes, this might be it...! ;)\n> \n> To prove myself it works, I`ve assembled a pretty crazy `-s ours`  \n> merge interactive rebase scenario, and it seems this passes the test, \n> ticking all the check boxes (I could think of) :P\n\nIt is interesting to think what it means to faithfully rebase a '-s\nours' merge. In your example the rebase does not introduce any new\nchanges into branch B that it doesn't introduce to branch A. Had it\nadded a fixup to branch B1 for example or if the topology was more\ncomplex so that B ended up with some other changes that the rebase did\nnot introduce into A, then M' would contain those extra changes whereas\n'--recreate-merges' with '-s ours' (once it supports it) would not.\n\n> \n> Let`s see our starting situation:\n> \n>  (0) ---X8--B2'--X9 (master)\n>         |\\\n>         | A1---A2---A3 (A)\n>         |             \\\n>         |              M (topic)\n>         |             /\n>         \\-B1---B2---B3 (B)\n> \n> \n> Here, merge commit M is done with `-s ours` (obsoleting branch \"B\"), \n> plus amended to make it an \"evil merge\", where a commit B2 from \n> obsoleted branch \"B\" is cherry picked to \"master\".\n> \n> Now, we want to rebase \"topic\" (M) onto updated \"master\" (X9), but to \n> make things more interesting, we`ll do it interactively, with some \n> amendments, drops, additions and even more cherry-picks!\n> \n> This is what the final result looks like:\n> \n>  (1) ---X8--B2'--X9 (master)\n>                  |\\\n>                  | A12--A2'---B3' (A)\n>                  |             \\\n>                  |              M' (topic)\n>                  |             /\n>                  \\-B1'--B3'---B4  (B)\n> \n> \n> During interactive rebase, on branch \"A\", we amended A1 into A12, \n> dropped A3 and cherry-picked B3. On branch \"B\", B4 is added, B2' being \n> omitted automatically as already present in \"master\".\n> \n> So... In comparison to original merge commit M, rebased merge commit \n> M' is expected to:\n> \n>  - Add X9, from updated \"master\"\n>  - Have A1 changed to A12, due to A12 commit amendment\n>  - Keep A2, rebased as A2'\n>  - Remove A3, due to dropped A3 commit\n>  - Keep amendment from original (evil) merge commit M\n>  - Miss B1' like M does B, due to original `-s ours` merge strategy\n>  - Add B2, cherry-picked as B2' into \"master\"\n>  - Add B3, cherry-picked as B3' into \"A\"\n>  - Add B4, added to \"B\"\n>  - Most important, provide safety mechanism to \"fail loud\", being \n>    aware of non-trivial things going on, allowing to stop for user \n>    inspection/decision\n> \n> \n> There, I hope I didn`t miss any expectation. And, it _seems_ to work \n> exactly as expected :D\n> \n> Not to leave this to imagination only, and hopefully helping others \n> to get to speed and possibly discuss this, pointing to still possible \n> flaws, I`m adding a demo script[1], showing how this exact example \n> works.\n> \n> Note that script _is_ coined to avoid rebase conflicts, as they`re not \n> currently important for the point to be made here.\n> \n> In real life, except for usual possibility for conflicts during \n> commit rebasing, we might experience _three_ possible conflict \n> situations once \"rebased\" merge itself is to be created - two when \n> rebasing each of temporary merge helper commits, and one on the \n> \"rebased\" merge itself. This is something where we might think about \n> user experience, not introducing (too much) confusion...\n> \n> Regards, Buga\n> \n> [1] Demonstration script:\n> -- >8 --\n> #!/bin/sh\n> \n> # rm -rf ./.git\n> # rm -f ./test.txt\n> \n> git init\n> \n> touch ./test.txt\n> git add -- test.txt\n> \n> # prepare repository\n> for i in {1..8}\n> do\n> \techo X$i >>test.txt\n> \tgit commit -am \"X$i\"\n> done\n> \n> # prepare branch A\n> git checkout -b A\n> sed -i '2iA1' test.txt\n> git commit -am \"A1\"\n> sed -i '4iA2' test.txt\n> git commit -am \"A2\"\n> sed -i '6iA3' test.txt\n> git commit -am \"A3\"\n> \n> # prepare branch B\n> git checkout -b B master\n> sed -i '5iB1' test.txt\n> git commit -am \"B1\"\n> sed -i '7iB2' test.txt\n> git commit -am \"B2\"\n> sed -i '9iB3' test.txt\n> git commit -am \"B3\"\n> \n> git checkout -b topic A\n> git merge -s ours --no-commit B # merge A and B with `-s ours`\n> sed -i '8iM' test.txt           # amend merge commit (\"evil merge\")\n> git commit -am \"M\"\n> git tag original-merge\n> \n> # master moves on...\n> git checkout master\n> git cherry-pick B^     # cherry-pick B2 into master\n> sed -i \"1iX9\" test.txt # add X9\n> git commit -am \"X9\"\n> \n> # (0) ---X8--B2'--X9 (master)\n> #        |\\\n> #        | A1---A2---A3 (A)\n> #        |             \\\n> #        |              M (topic)\n> #        |             /\n> #        \\-B1---B2---B3 (B)\n> \n> # simple/naive demonstration of proposed merge rebasing logic\n> # using described new approach, preserving merge commit manual\n> # amendments, testing `-s ours` merge with cherry-picking from\n> # obsoleted part, but still respecting interactively rebased\n> # added/modified/dropped/cherry-picked commits :)\n> \n> git checkout A\n> git cherry-pick -m1 original-merge # prepare temporary helper commit U1\n> git tag U1\n> git reset --hard HEAD^^            # drop U1 and A3 from A\n> sed -i '/A1/c\\A12' test.txt        # amend A1 to A12\n> git commit -a --amend --no-edit\n> git rebase master                  # rebase A onto master\n> git cherry-pick B                  # cherry-pick B3 into A\n> git cherry-pick U1                 # \"rebase\" temporary helper commit U1\n> git tag U1-prime\n> \n> git checkout B\n> git cherry-pick -m2 original-merge # prepare temporary helper commit U2\n> git tag U2\n> git reset --hard HEAD^             # drop U2 from B\n> git rebase master                  # rebase B onto master\n> sed -i '12iB4' test.txt            # add B4\n> git commit -am \"B4\"\n> git cherry-pick U2                 # \"rebase\" temporary helper commit U2\n> git tag U2-prime\n> \n> git branch -f topic A\n> git checkout topic\n> # merge rebased temporary commits U1' and U2',\n> # using original merge commit as a merge base,\n> # producing \"rebased\" merge commit M'\n> git read-tree -m --aggressive original-merge A B\n> git merge-index -o git-merge-one-file -a\n> \n> # recognize complex stuff going on during rebasing merge commit,\n> # allowing user to inspect result, edit, and continue or abort\n> git diff --quiet U1-prime U2-prime\n> if test $? -ne 0\n> then\n> \t# PLACEHOLDER\n> \t# chance to inspect result, like:\n> \tgit diff original-merge\n> \t# edit if needed, continue or abort\n> fi\n> \n> # drop rebased temporary commits U1' and U2'\n> git branch -f A A^\n> git branch -f B B^\n> \n> # record branches A and B as parents of \"rebased\" merge commit M',\n> # updating topic branch\n> git update-ref refs/heads/topic \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse A)\" -p \"$(git rev-parse B)\")\"\n> git tag angel-merge\n> \n> # (1) ---X8--B2'--X9 (master)\n> #                 |\\\n> #                 | A12--A2'---B3' (A)\n> #                 |             \\\n> #                 |              M' (topic)\n> #                 |             /\n> #                 \\-B1'--B3'---B4  (B)\n> \n> # show resulting graph\n> # echo\n> # git log --all --decorate --oneline --graph\n> \n> # in comparison to original merge commit M, rebased merge commit \n> # M' is expected to:\n> #\n> # - Add X9, from updated \"master\"\n> # - Have A1 changed to A12, due to A12 commit amendment\n> # - Keep A2, rebased as A2'\n> # - Remove A3, due to dropped A3 commit\n> # - Keep amendment from original (evil) merge commit M\n> # - Miss B1' like M does B, due to original `-s ours` merge strategy\n> # - Add B2, cherry-picked as B2' into \"master\"\n> # - Add B3, cherry-picked as B3' into \"A\"\n> # - Add B4, added to \"B\"\n> #\n> # echo\n> # echo 'diff original-merge angel-merge:'\n> # git diff original-merge angel-merge\n> \n\n"},{"id":"340801","messageId":"6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net","threadId":"47864","inReplyTo":"87a7vss6ax.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-02T11:31:02Z","receivedAt":"2018-03-02T11:32:20Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 01/03/18 05:39, Sergey Organov wrote:\n> \n> Hi Igor,\n> \n> Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n> \n>> Hi Sergey,\n>>\n>> On 28/02/2018 06:19, Sergey Organov wrote:\n>>>\n>>>>> (3) ---X1---o---o---o---o---o---X2\n>>>>>        |\\                       |\\\n>>>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>>>>        |             \\          |\n>>>>>        |              M         |\n>>>>>        |             /          |\n>>>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>>>>\n>>>>\n>>>> Meh, I hope I`m rushing it now, but for example, if we had decided to \n>>>> drop commit A2 during an interactive rebase (so losing A2' from \n>>>> diagram above), wouldn`t U2' still introduce those changes back, once \n>>>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>>>\n>>> I think the method will handle this nicely.\n>>\n>> That`s what I thought as well. And then I made a test. And then the \n>> test broke... Now, might be the test was flawed in the first place, \n>> but thinking about it a bit more, it does seem to make sense not to \n>> handle this case nicely :/\n> \n> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n> this more carefully in the first place.\n> \n> [...]\n> \n>> So while your original proposal currently seems like it could be \n>> working nicely for non-interactive rebase (and might be some simpler \n>> interactive ones), now hitting/acknowledging its first real use \n>> limit, my additional quick attempt[1] just tries to aid pretty \n>> interesting case of complicated interactive rebase, too, where we \n>> might be able to do better as well, still using you original proposal \n>> as a base idea :)\n> \n> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n> you are putting into solving the puzzle are greatly appreciated!\n> \n> Thinking about it overnight, I now suspect that original proposal had a\n> mistake in the final merge step. I think that what you did is a way to\n> fix it, and I want to try to figure what exactly was wrong in the\n> original proposal and to find simpler way of doing it right.\n> \n> The likely solution is to use original UM as a merge-base for final\n> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n> though, as that's exactly UM from which both U1' and U2' have diverged\n> due to rebasing and other history editing.\n\nHi Sergey, I've been following this discussion from the sidelines,\nthough I haven't had time to study all the posts in this thread in\ndetail. I wonder if it would be helpful to think of rebasing a merge as\nmerging the changes in the parents due to the rebase back into the\noriginal merge. So for a merge M with parents A B C that are rebased to\nA' B' C' the rebased merge M' would be constructed by (ignoring shell\nquoting issues)\n\ngit checkout --detach M\ngit merge-recursive A -- M A'\ntree=$(git write-tree)\ngit merge-recursive B -- $tree B'\ntree=$(git write-tree)\ngit merge-recursive C -- $tree C'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n\nThis should pull in all the changes from the parents while preserving\nany evil conflict resolution in the original merge. It superficially\nreminds me of incremental merging [1] but it's so long since I looked at\nthat I'm not sure if there are any significant similarities.\n\nBest Wishes\n\nPhillip\n\n[1] https://github.com/mhagger/git-imerge\n\n"},{"id":"340805","messageId":"1298a701-a860-a675-83d7-72f29e14cd2b@talktalk.net","threadId":"47864","inReplyTo":"ed4d2b30-2dea-740b-6283-973c798f619d@philandanna.no-ip.org","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-02T12:36:48Z","receivedAt":"2018-03-02T12:37:00Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 02/03/18 11:17, Phillip Wood wrote:\n> \n> On 02/03/18 01:16, Igor Djordjevic wrote:\n>>\n>> Hi Sergey,\n>>\n>> On 01/03/2018 06:39, Sergey Organov wrote:\n>>>\n>>>>> (3) ---X1---o---o---o---o---o---X2\n>>>>>        |\\                       |\\\n>>>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>>>>        |             \\          |\n>>>>>        |              M         |\n>>>>>        |             /          |\n>>>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>>>>\n>>>>\n>>>> Meh, I hope I`m rushing it now, but for example, if we had decided to \n>>>> drop commit A2 during an interactive rebase (so losing A2' from \n>>>> diagram above), wouldn`t U2' still introduce those changes back, once \n>>>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>>>>\n>>>> [...]\n>>>\n>>> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n>>> this more carefully in the first place.\n>>\n>> No problem, that`s why we`re discussing it, and I`m glad we`re \n>> aligned now, so we can move forward :)\n>>\n>>>> So while your original proposal currently seems like it could be \n>>>> working nicely for non-interactive rebase (and might be some simpler \n>>>> interactive ones), now hitting/acknowledging its first real use \n>>>> limit, my additional quick attempt[1] just tries to aid pretty \n>>>> interesting case of complicated interactive rebase, too, where we \n>>>> might be able to do better as well, still using you original proposal \n>>>> as a base idea :)\n>>>\n>>> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n>>> you are putting into solving the puzzle are greatly appreciated!\n>>\n>> You`re welcome, and I am enjoying it :)\n>>\n>>> Thinking about it overnight, I now suspect that original proposal had a\n>>> mistake in the final merge step. I think that what you did is a way to\n>>> fix it, and I want to try to figure what exactly was wrong in the\n>>> original proposal and to find simpler way of doing it right.\n>>>\n>>> The likely solution is to use original UM as a merge-base for final\n>>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>>> though, as that's exactly UM from which both U1' and U2' have diverged\n>>> due to rebasing and other history editing.\n>>\n>> Yes, this might be it...! ;)\n>>\n>> To prove myself it works, I`ve assembled a pretty crazy `-s ours`  \n>> merge interactive rebase scenario, and it seems this passes the test, \n>> ticking all the check boxes (I could think of) :P\n\nHi Igor\n\n> It is interesting to think what it means to faithfully rebase a '-s\n> ours' merge.\nI should have explained that I mean is a faithful rebase one that\nadheres to the semantics of '-s ours' (i.e. ignores any changes in the\nside branch) or one that merges new changes from the side branch into\nthe content of the original merge? In your example you add B4 to B. If\nM' preserves the semantics of '-s ours' then it will not contain the\nchanges in B4. I think your result does (correct me if I'm wrong) so it\nis preserving the content of the original merge rather than the\nsemantics of it.\n\nBest Wishes\n\nPhillip\n\n(ignore the rest of what I wrote earlier I don't think it's correct)\n In your example the rebase does not introduce any new\n> changes into branch B that it doesn't introduce to branch A. Had it\n> added a fixup to branch B1 for example or if the topology was more\n> complex so that B ended up with some other changes that the rebase did\n> not introduce into A, then M' would contain those extra changes whereas\n> '--recreate-merges' with '-s ours' (once it supports it) would not.\n> \n>>\n>> Let`s see our starting situation:\n>>\n>>  (0) ---X8--B2'--X9 (master)\n>>         |\\\n>>         | A1---A2---A3 (A)\n>>         |             \\\n>>         |              M (topic)\n>>         |             /\n>>         \\-B1---B2---B3 (B)\n>>\n>>\n>> Here, merge commit M is done with `-s ours` (obsoleting branch \"B\"), \n>> plus amended to make it an \"evil merge\", where a commit B2 from \n>> obsoleted branch \"B\" is cherry picked to \"master\".\n>>\n>> Now, we want to rebase \"topic\" (M) onto updated \"master\" (X9), but to \n>> make things more interesting, we`ll do it interactively, with some \n>> amendments, drops, additions and even more cherry-picks!\n>>\n>> This is what the final result looks like:\n>>\n>>  (1) ---X8--B2'--X9 (master)\n>>                  |\\\n>>                  | A12--A2'---B3' (A)\n>>                  |             \\\n>>                  |              M' (topic)\n>>                  |             /\n>>                  \\-B1'--B3'---B4  (B)\n>>\n>>\n>> During interactive rebase, on branch \"A\", we amended A1 into A12, \n>> dropped A3 and cherry-picked B3. On branch \"B\", B4 is added, B2' being \n>> omitted automatically as already present in \"master\".\n>>\n>> So... In comparison to original merge commit M, rebased merge commit \n>> M' is expected to:\n>>\n>>  - Add X9, from updated \"master\"\n>>  - Have A1 changed to A12, due to A12 commit amendment\n>>  - Keep A2, rebased as A2'\n>>  - Remove A3, due to dropped A3 commit\n>>  - Keep amendment from original (evil) merge commit M\n>>  - Miss B1' like M does B, due to original `-s ours` merge strategy\n>>  - Add B2, cherry-picked as B2' into \"master\"\n>>  - Add B3, cherry-picked as B3' into \"A\"\n>>  - Add B4, added to \"B\"\n>>  - Most important, provide safety mechanism to \"fail loud\", being \n>>    aware of non-trivial things going on, allowing to stop for user \n>>    inspection/decision\n>>\n>>\n>> There, I hope I didn`t miss any expectation. And, it _seems_ to work \n>> exactly as expected :D\n>>\n>> Not to leave this to imagination only, and hopefully helping others \n>> to get to speed and possibly discuss this, pointing to still possible \n>> flaws, I`m adding a demo script[1], showing how this exact example \n>> works.\n>>\n>> Note that script _is_ coined to avoid rebase conflicts, as they`re not \n>> currently important for the point to be made here.\n>>\n>> In real life, except for usual possibility for conflicts during \n>> commit rebasing, we might experience _three_ possible conflict \n>> situations once \"rebased\" merge itself is to be created - two when \n>> rebasing each of temporary merge helper commits, and one on the \n>> \"rebased\" merge itself. This is something where we might think about \n>> user experience, not introducing (too much) confusion...\n>>\n>> Regards, Buga\n>>\n>> [1] Demonstration script:\n>> -- >8 --\n>> #!/bin/sh\n>>\n>> # rm -rf ./.git\n>> # rm -f ./test.txt\n>>\n>> git init\n>>\n>> touch ./test.txt\n>> git add -- test.txt\n>>\n>> # prepare repository\n>> for i in {1..8}\n>> do\n>> \techo X$i >>test.txt\n>> \tgit commit -am \"X$i\"\n>> done\n>>\n>> # prepare branch A\n>> git checkout -b A\n>> sed -i '2iA1' test.txt\n>> git commit -am \"A1\"\n>> sed -i '4iA2' test.txt\n>> git commit -am \"A2\"\n>> sed -i '6iA3' test.txt\n>> git commit -am \"A3\"\n>>\n>> # prepare branch B\n>> git checkout -b B master\n>> sed -i '5iB1' test.txt\n>> git commit -am \"B1\"\n>> sed -i '7iB2' test.txt\n>> git commit -am \"B2\"\n>> sed -i '9iB3' test.txt\n>> git commit -am \"B3\"\n>>\n>> git checkout -b topic A\n>> git merge -s ours --no-commit B # merge A and B with `-s ours`\n>> sed -i '8iM' test.txt           # amend merge commit (\"evil merge\")\n>> git commit -am \"M\"\n>> git tag original-merge\n>>\n>> # master moves on...\n>> git checkout master\n>> git cherry-pick B^     # cherry-pick B2 into master\n>> sed -i \"1iX9\" test.txt # add X9\n>> git commit -am \"X9\"\n>>\n>> # (0) ---X8--B2'--X9 (master)\n>> #        |\\\n>> #        | A1---A2---A3 (A)\n>> #        |             \\\n>> #        |              M (topic)\n>> #        |             /\n>> #        \\-B1---B2---B3 (B)\n>>\n>> # simple/naive demonstration of proposed merge rebasing logic\n>> # using described new approach, preserving merge commit manual\n>> # amendments, testing `-s ours` merge with cherry-picking from\n>> # obsoleted part, but still respecting interactively rebased\n>> # added/modified/dropped/cherry-picked commits :)\n>>\n>> git checkout A\n>> git cherry-pick -m1 original-merge # prepare temporary helper commit U1\n>> git tag U1\n>> git reset --hard HEAD^^            # drop U1 and A3 from A\n>> sed -i '/A1/c\\A12' test.txt        # amend A1 to A12\n>> git commit -a --amend --no-edit\n>> git rebase master                  # rebase A onto master\n>> git cherry-pick B                  # cherry-pick B3 into A\n>> git cherry-pick U1                 # \"rebase\" temporary helper commit U1\n>> git tag U1-prime\n>>\n>> git checkout B\n>> git cherry-pick -m2 original-merge # prepare temporary helper commit U2\n>> git tag U2\n>> git reset --hard HEAD^             # drop U2 from B\n>> git rebase master                  # rebase B onto master\n>> sed -i '12iB4' test.txt            # add B4\n>> git commit -am \"B4\"\n>> git cherry-pick U2                 # \"rebase\" temporary helper commit U2\n>> git tag U2-prime\n>>\n>> git branch -f topic A\n>> git checkout topic\n>> # merge rebased temporary commits U1' and U2',\n>> # using original merge commit as a merge base,\n>> # producing \"rebased\" merge commit M'\n>> git read-tree -m --aggressive original-merge A B\n>> git merge-index -o git-merge-one-file -a\n>>\n>> # recognize complex stuff going on during rebasing merge commit,\n>> # allowing user to inspect result, edit, and continue or abort\n>> git diff --quiet U1-prime U2-prime\n>> if test $? -ne 0\n>> then\n>> \t# PLACEHOLDER\n>> \t# chance to inspect result, like:\n>> \tgit diff original-merge\n>> \t# edit if needed, continue or abort\n>> fi\n>>\n>> # drop rebased temporary commits U1' and U2'\n>> git branch -f A A^\n>> git branch -f B B^\n>>\n>> # record branches A and B as parents of \"rebased\" merge commit M',\n>> # updating topic branch\n>> git update-ref refs/heads/topic \"$(git show -s --format=%B original-merge | git commit-tree \"$(git write-tree)\" -p \"$(git rev-parse A)\" -p \"$(git rev-parse B)\")\"\n>> git tag angel-merge\n>>\n>> # (1) ---X8--B2'--X9 (master)\n>> #                 |\\\n>> #                 | A12--A2'---B3' (A)\n>> #                 |             \\\n>> #                 |              M' (topic)\n>> #                 |             /\n>> #                 \\-B1'--B3'---B4  (B)\n>>\n>> # show resulting graph\n>> # echo\n>> # git log --all --decorate --oneline --graph\n>>\n>> # in comparison to original merge commit M, rebased merge commit \n>> # M' is expected to:\n>> #\n>> # - Add X9, from updated \"master\"\n>> # - Have A1 changed to A12, due to A12 commit amendment\n>> # - Keep A2, rebased as A2'\n>> # - Remove A3, due to dropped A3 commit\n>> # - Keep amendment from original (evil) merge commit M\n>> # - Miss B1' like M does B, due to original `-s ours` merge strategy\n>> # - Add B2, cherry-picked as B2' into \"master\"\n>> # - Add B3, cherry-picked as B3' into \"A\"\n>> # - Add B4, added to \"B\"\n>> #\n>> # echo\n>> # echo 'diff original-merge angel-merge:'\n>> # git diff original-merge angel-merge\n>>\n> \n\n"},{"id":"340811","messageId":"CA+P7+xrkAKB621Na3V-tE9cMtbnADX94FvTrJf26SkQYbXqMGw@mail.gmail.com","threadId":"47864","inReplyTo":"ed4d2b30-2dea-740b-6283-973c798f619d@philandanna.no-ip.org","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-03-02T16:00:50Z","receivedAt":"2018-03-02T16:01:20Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Fri, Mar 2, 2018 at 3:17 AM, Phillip Wood <phil@philandanna.no-ip.org> wrote:\n>\n> It is interesting to think what it means to faithfully rebase a '-s\n> ours' merge. In your example the rebase does not introduce any new\n> changes into branch B that it doesn't introduce to branch A. Had it\n> added a fixup to branch B1 for example or if the topology was more\n> complex so that B ended up with some other changes that the rebase did\n> not introduce into A, then M' would contain those extra changes whereas\n> '--recreate-merges' with '-s ours' (once it supports it) would not.\n>\n\nUnless the method of merging was stored, I don't think we *can*\ncorrectly automate resolving of \"-s ours\" because all we store is the\nresulting content, and we don't know how or why the user generated it\nas such. I believe the \"correct\" solution in any case would be to take\nthe content we DO know and then ask the user to stop for amendments.\n\nThanks,\nJake\n"},{"id":"340812","messageId":"CA+P7+xpgChuvh_vsPktBkOEhF=MjJh1n_3jD0-n4d67j9kYqzw@mail.gmail.com","threadId":"47864","inReplyTo":"1298a701-a860-a675-83d7-72f29e14cd2b@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-03-02T16:02:51Z","receivedAt":"2018-03-02T16:03:22Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Fri, Mar 2, 2018 at 4:36 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n> On 02/03/18 11:17, Phillip Wood wrote:\n>>\n>> On 02/03/18 01:16, Igor Djordjevic wrote:\n>>>\n>>> Hi Sergey,\n>>>\n>>> On 01/03/2018 06:39, Sergey Organov wrote:\n>>>>\n>>>>>> (3) ---X1---o---o---o---o---o---X2\n>>>>>>        |\\                       |\\\n>>>>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n>>>>>>        |             \\          |\n>>>>>>        |              M         |\n>>>>>>        |             /          |\n>>>>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n>>>>>>\n>>>>>\n>>>>> Meh, I hope I`m rushing it now, but for example, if we had decided to\n>>>>> drop commit A2 during an interactive rebase (so losing A2' from\n>>>>> diagram above), wouldn`t U2' still introduce those changes back, once\n>>>>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n>>>>>\n>>>>> [...]\n>>>>\n>>>> Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n>>>> this more carefully in the first place.\n>>>\n>>> No problem, that`s why we`re discussing it, and I`m glad we`re\n>>> aligned now, so we can move forward :)\n>>>\n>>>>> So while your original proposal currently seems like it could be\n>>>>> working nicely for non-interactive rebase (and might be some simpler\n>>>>> interactive ones), now hitting/acknowledging its first real use\n>>>>> limit, my additional quick attempt[1] just tries to aid pretty\n>>>>> interesting case of complicated interactive rebase, too, where we\n>>>>> might be able to do better as well, still using you original proposal\n>>>>> as a base idea :)\n>>>>\n>>>> Yes, thank you for pushing me back to reality! :-) The work and thoughts\n>>>> you are putting into solving the puzzle are greatly appreciated!\n>>>\n>>> You`re welcome, and I am enjoying it :)\n>>>\n>>>> Thinking about it overnight, I now suspect that original proposal had a\n>>>> mistake in the final merge step. I think that what you did is a way to\n>>>> fix it, and I want to try to figure what exactly was wrong in the\n>>>> original proposal and to find simpler way of doing it right.\n>>>>\n>>>> The likely solution is to use original UM as a merge-base for final\n>>>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>>>> though, as that's exactly UM from which both U1' and U2' have diverged\n>>>> due to rebasing and other history editing.\n>>>\n>>> Yes, this might be it...! ;)\n>>>\n>>> To prove myself it works, I`ve assembled a pretty crazy `-s ours`\n>>> merge interactive rebase scenario, and it seems this passes the test,\n>>> ticking all the check boxes (I could think of) :P\n>\n> Hi Igor\n>\n>> It is interesting to think what it means to faithfully rebase a '-s\n>> ours' merge.\n> I should have explained that I mean is a faithful rebase one that\n> adheres to the semantics of '-s ours' (i.e. ignores any changes in the\n> side branch) or one that merges new changes from the side branch into\n> the content of the original merge? In your example you add B4 to B. If\n> M' preserves the semantics of '-s ours' then it will not contain the\n> changes in B4. I think your result does (correct me if I'm wrong) so it\n> is preserving the content of the original merge rather than the\n> semantics of it.\n>\n> Best Wishes\n>\n> Phillip\n>\n\nI believe this was always the outline of this type of approach, as per\nSergey's original email.\n\nWe only have the content, and we don't know the semantics (nor, I\nthink, should we attempt to understand or figure out the semantics).\n\nRegards,\nJake\n"},{"id":"340826","messageId":"143023e6-a492-ec24-aac8-821941b14b1c@gmail.com","threadId":"47864","inReplyTo":"87606fox0b.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-02T17:45:53Z","receivedAt":"2018-03-02T17:46:08Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 02/03/2018 06:40, Sergey Organov wrote:\n> \n> > So... In comparison to original merge commit M, rebased merge commit \n> > M' is expected to:\n> > \n> >  - Add X9, from updated \"master\"\n> >  - Have A1 changed to A12, due to A12 commit amendment\n> >  - Keep A2, rebased as A2'\n> >  - Remove A3, due to dropped A3 commit\n> >  - Keep amendment from original (evil) merge commit M\n> >  - Miss B1' like M does B, due to original `-s ours` merge strategy\n> >  - Add B2, cherry-picked as B2' into \"master\"\n> >  - Add B3, cherry-picked as B3' into \"A\"\n> >  - Add B4, added to \"B\"\n> >  - Most important, provide safety mechanism to \"fail loud\", being \n> >    aware of non-trivial things going on, allowing to stop for user \n> >    inspection/decision\n> > \n> > \n> > There, I hope I didn`t miss any expectation. And, it _seems_ to work \n> > exactly as expected :D\n> \n> That's very nice, to the level of being even suspect! :-)\n\nHeh, indeed :) I`m already thinking of some even more complex \nsituations. The more use/test cases, the merrier.\n\nLike if number of merge parents (branches) gets changed during \ninteractive rebase...\n\n> To avoid falling into euphoria though, we need to keep in mind that\n> \"expectations\" is rather vague concept, and we likely still need to stop\n> for user amendment unless we absolutely sure nothing surprising happens.\n> I.e., we better require U1'==U2' test to succeed to proceed non-stop\n> automatically. Besides, it will be somewhat inline with what 'rerere'\n> does.\n\nI totally agree, and I think whatever we come up with, we`ll always \nbe missing some deeper context of the original merge, so U1'==U2' \ntest is a must - if it fails, even if we didn`t get any conflicts and \ncould otherwise proceed automatically, better stop for user sanity check.\n\nI`m still thinking if there could be a situation where test passes, \nbut result might still be suspicious (and worth inspecting), though.\n\nRegards, Buga\n"},{"id":"340830","messageId":"f26cdbe2-1bc3-02ff-7b99-12a6ebab5a70@gmail.com","threadId":"47864","inReplyTo":"CA+P7+xrkAKB621Na3V-tE9cMtbnADX94FvTrJf26SkQYbXqMGw@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-02T18:14:54Z","receivedAt":"2018-03-02T18:15:06Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Phillip,\n\nOn 02/03/2018 17:00, Jacob Keller wrote:\n> \n> > It is interesting to think what it means to faithfully rebase a '-s\n> > ours' merge. In your example the rebase does not introduce any new\n> > changes into branch B that it doesn't introduce to branch A. Had it\n> > added a fixup to branch B1 for example or if the topology was more\n> > complex so that B ended up with some other changes that the rebase did\n> > not introduce into A, then M' would contain those extra changes whereas\n> > '--recreate-merges' with '-s ours' (once it supports it) would not.\n> \n> Unless the method of merging was stored, I don't think we *can*\n> correctly automate resolving of \"-s ours\" because all we store is the\n> resulting content, and we don't know how or why the user generated it\n> as such. I believe the \"correct\" solution in any case would be to take\n> the content we DO know and then ask the user to stop for amendments.\n \nI agree with Jake, and for the exact same reasons.\n\nThat said, I`d like to see what mentioned '--recreate-merges' with \n'-s ours' does (or would do, once it supports it), would you have a \npointer for me where to look at?\n\nBut if that`s something yet to come, might be it`s still open for \ndiscussion. I mean, even this topic started inside original \n`--recreate-merges` one[1], and hopefully it can still bring \nimprovements there (sooner or later).\n\nThanks, Buga\n\n[1] https://public-inbox.org/git/cover.1516225925.git.johannes.schindelin@gmx.de/\n"},{"id":"340843","messageId":"ee809701-a6d8-157d-09cd-cebbf2e949ec@gmail.com","threadId":"47864","inReplyTo":"CA+P7+xpgChuvh_vsPktBkOEhF=MjJh1n_3jD0-n4d67j9kYqzw@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-02T23:33:05Z","receivedAt":"2018-03-02T23:33:17Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Phillip,\n\n> On Fri, Mar 2, 2018 at 4:36 AM, Phillip Wood wrote:\n> > \n> > > It is interesting to think what it means to faithfully rebase a '-s\n> > > ours' merge.\n> > \n> > I should have explained that I mean is a faithful rebase one that\n> > adheres to the semantics of '-s ours' (i.e. ignores any changes in the\n> > side branch) or one that merges new changes from the side branch into\n> > the content of the original merge? In your example you add B4 to B. If\n> > M' preserves the semantics of '-s ours' then it will not contain the\n> > changes in B4. I think your result does (correct me if I'm wrong) so it\n> > is preserving the content of the original merge rather than the\n> > semantics of it.\n\nYeah, I understood what you mean, and I see you noticed that B4 \ncommit, for which I did anticipate possibly bringing up a discussion \nlike this ;)\n\nI agree with Jake here, my thoughts exactly (what I wrote in that \nother subthread[1], too):\n\nOn 02/03/2018 17:02, Jacob Keller wrote:\n> \n> We only have the content, and we don't know the semantics (nor, I\n> think, should we attempt to understand or figure out the semantics).\n\nHmm, I wanted to elaborate a bit here, but that sentence seems to \nsummarize the pure essence of it, and whatever I write looks like \njust repeating the same stuff again...\n\nThat`s just it. And stopping to give the user a chance to \nreview/amend the result, where he might decide he actually did want \nsomething else - so all good.\n\nOtherwise, I would be interested to learn how context/semantics \nguessing could provide a better default action (without introducing \nmore complexity for might not be much benefit, if any).\n\nBut in the end, I guess we can just discuss the \"most sane default\" \nto present to the user (introduce or obsolete that new commit B4, in \nthe discussed example[2]), as we should definitely stop for amending \nanyway, not proceeding automatically whenever U1' != U2'.\n\nOh, and what about situations where we introduce new or drop existing \nbranches (which should be possible with new `--recreate-merges`)...? \n\"Preserving old branch semantics\" may have even less sense here - the \n(possibly heavily reorganized) content is the only thing we have, \nwhere context will (and should) be provided by the user.\n\nAnd I guess being consistent is pretty important, too - if you add \nnew content during merge rebase, it should always show up in the \nmerge, period. It seems pretty confusing to find out one of the \nbranches \"declared special\" (even more if it`s based on uncertain \nguess-work), so when you add something to it it`s just \"swallowed\", \nas the whole branch is always obsoleted, for now and ever.\n\nI might even see a value in such behavior, but only as a conscious \nuser action, not something done automatically... I guess? :)\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/f26cdbe2-1bc3-02ff-7b99-12a6ebab5a70@gmail.com/\n[2] https://public-inbox.org/git/f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com/\n"},{"id":"340844","messageId":"872944c4-ca97-9f55-a424-86d1e3299a22@gmail.com","threadId":"47864","inReplyTo":"6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-03T00:29:43Z","receivedAt":"2018-03-03T00:30:04Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Phillip,\n\nOn 02/03/2018 12:31, Phillip Wood wrote:\n> \n> > Thinking about it overnight, I now suspect that original proposal had a\n> > mistake in the final merge step. I think that what you did is a way to\n> > fix it, and I want to try to figure what exactly was wrong in the\n> > original proposal and to find simpler way of doing it right.\n> >\n> > The likely solution is to use original UM as a merge-base for final\n> > 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n> > though, as that's exactly UM from which both U1' and U2' have diverged\n> > due to rebasing and other history editing.\n> \n> Hi Sergey, I've been following this discussion from the sidelines,\n> though I haven't had time to study all the posts in this thread in\n> detail. I wonder if it would be helpful to think of rebasing a merge as\n> merging the changes in the parents due to the rebase back into the\n> original merge. So for a merge M with parents A B C that are rebased to\n> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n> quoting issues)\n> \n> git checkout --detach M\n> git merge-recursive A -- M A'\n> tree=$(git write-tree)\n> git merge-recursive B -- $tree B'\n> tree=$(git write-tree)\n> git merge-recursive C -- $tree C'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n> \n> This should pull in all the changes from the parents while preserving\n> any evil conflict resolution in the original merge. It superficially\n> reminds me of incremental merging [1] but it's so long since I looked at\n> that I'm not sure if there are any significant similarities.\n> \n> [1] https://github.com/mhagger/git-imerge\n\nInteresting, from quick test[3], this seems to produce the same \nresult as that other test I previously provided[2], where temporary \ncommits U1' and U2' are finally merged with original M as a base :)\n\nJust that this looks like even more straight-forward approach...?\n\nThe only thing I wonder of here is how would we check if the \n\"rebased\" merge M' was \"clean\", or should we stop for user amendment? \nWith that other approach Sergey described, we have U1'==U2' to test with.\n\nBy the way, is there documentation for `git merge-recursive` \nanywhere, besides the code itself...? :$\n\nThanks, Buga\n\n[2] https://public-inbox.org/git/f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com/\n[3] Quick test script:\n-- >8 --\n#!/bin/sh\n\n# rm -rf ./.git\n# rm -f ./test.txt\n\ngit init\n\ntouch ./test.txt\ngit add -- test.txt\n\n# prepare repository\nfor i in {1..8}\ndo\n\techo X$i >>test.txt\n\tgit commit -am \"X$i\"\ndone\n\n# prepare branch A\ngit checkout -b A\nsed -i '2iA1' test.txt\ngit commit -am \"A1\"\nsed -i '4iA2' test.txt\ngit commit -am \"A2\"\nsed -i '6iA3' test.txt\ngit commit -am \"A3\"\n\n# prepare branch B\ngit checkout -b B master\nsed -i '5iB1' test.txt\ngit commit -am \"B1\"\nsed -i '7iB2' test.txt\ngit commit -am \"B2\"\nsed -i '9iB3' test.txt\ngit commit -am \"B3\"\n\ngit checkout -b topic A\ngit merge -s ours --no-commit B # merge A and B with `-s ours`\nsed -i '8iM' test.txt           # amend merge commit (\"evil merge\")\ngit commit -am \"M\"\ngit tag M #original-merge\n\n# master moves on...\ngit checkout master\ngit cherry-pick B^     # cherry-pick B2 into master\nsed -i \"1iX9\" test.txt # add X9\ngit commit -am \"X9\"\n\n# (0) ---X8--B2'--X9 (master)\n#        |\\\n#        | A1---A2---A3 (A)\n#        |             \\\n#        |              M (topic)\n#        |             /\n#        \\-B1---B2---B3 (B)\n\n# simple/naive demonstration of proposed merge rebasing logic\n# using iterative merge-recursive, preserving merge commit manual\n# amendments, testing `-s ours` merge with cherry-picking from\n# obsoleted part, but still respecting interactively rebased\n# added/modified/dropped/cherry-picked commits :)\n\ngit checkout -b A-prime A\ngit reset --hard HEAD^             # drop A3 from A\nsed -i '/A1/c\\A12' test.txt        # amend A1 to A12\ngit commit -a --amend --no-edit\ngit rebase master                  # rebase A onto master\ngit cherry-pick B                  # cherry-pick B3 into A\n\ngit checkout -b B-prime B\ngit rebase master                  # rebase B onto master\nsed -i '12iB4' test.txt            # add B4\ngit commit -am \"B4\"\n\ngit checkout --detach M\ngit merge-recursive A -- M A-prime\ntree=\"$(git write-tree)\"\ngit merge-recursive B -- $tree B-prime\ntree=\"$(git write-tree)\"\ngit tag M-prime \"$(git log --pretty=%B -1 M | git commit-tree $tree -p A-prime -p B-prime)\"\n\ngit update-ref refs/heads/topic \"$(git rev-parse M-prime)\"\ngit checkout topic\n\n# (1) ---X8--B2'--X9 (master)\n#                 |\\\n#                 | A12--A2'---B3' (A)\n#                 |             \\\n#                 |              M' (topic)\n#                 |             /\n#                 \\-B1'--B3'---B4  (B)\n\n# show resulting graph\n# echo\n# git log --all --decorate --oneline --graph\n\n# in comparison to original merge commit M, rebased merge commit \n# M' is expected to:\n#\n# - Add X9, from updated \"master\"\n# - Have A1 changed to A12, due to A12 commit amendment\n# - Keep A2, rebased as A2'\n# - Remove A3, due to dropped A3 commit\n# - Keep amendment from original (evil) merge commit M\n# - Miss B1' like M does B, due to original `-s ours` merge strategy\n# - Add B2, cherry-picked as B2' into \"master\"\n# - Add B3, cherry-picked as B3' into \"A\"\n# - Add B4, added to \"B\"\n#\n# echo\n# echo 'diff M M-prime:'\n# git diff M M-prime\n"},{"id":"340957","messageId":"39aebd06-6022-7803-e27d-c1793fd72955@gmail.com","threadId":"47864","inReplyTo":"f26cdbe2-1bc3-02ff-7b99-12a6ebab5a70@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-03T17:29:35Z","receivedAt":"2018-03-03T17:29:49Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 02/03/2018 19:14, Igor Djordjevic wrote:\n> \n> > > It is interesting to think what it means to faithfully rebase a '-s\n> > > ours' merge. In your example the rebase does not introduce any new\n> > > changes into branch B that it doesn't introduce to branch A. Had it\n> > > added a fixup to branch B1 for example or if the topology was more\n> > > complex so that B ended up with some other changes that the rebase did\n> > > not introduce into A, then M' would contain those extra changes whereas\n> > > '--recreate-merges' with '-s ours' (once it supports it) would not.\n> >\n> > Unless the method of merging was stored, I don't think we *can*\n> > correctly automate resolving of \"-s ours\" because all we store is the\n> > resulting content, and we don't know how or why the user generated it\n> > as such. I believe the \"correct\" solution in any case would be to take\n> > the content we DO know and then ask the user to stop for amendments.\n>  \n> I agree with Jake, and for the exact same reasons.\n> \n> That said, I`d like to see what mentioned '--recreate-merges' with \n> '-s ours' does (or would do, once it supports it), would you have a \n> pointer for me where to look at?\n> \n> But if that`s something yet to come, might be it`s still open for \n> discussion. I mean, even this topic started inside original \n> `--recreate-merges` one[1], and hopefully it can still bring \n> improvements there (sooner or later).\n> \n> [1] https://public-inbox.org/git/cover.1516225925.git.johannes.schindelin@gmx.de/\n\nOk, I went through mentioned `--recreate-merges` topic again, and I \nthink I see one crucial merge commit handling difference.\n\nIn there, as it is at the moment, merge commits are really to be \n_recreated_... as the option name seems to imply ;)\n\nIn terms of interactive rebasing, it actually comes from \"todo list\" \nbecoming much more powerful, gaining ability to create (new) merges, \nwhich is wonderful from the aspect of history rewriting (what rebase \nis all about).\n\nBut, I would argue it is a different concept from actually _rebasing_ \nexisting merge commits, being what we`re discussing about here.\n\nYes, you can use merge commit (re)creation to \"rebase\" existing merge \ncommit so the end result is the same, being what `--recreate-merges` \nnow does, but that only goes for some (uninteresting?) merge commits \nwhere not knowing the deeper context of how the merge commit is \noriginally created is not important as no content is to be lost (due \nto missing that deeper and utterly unknown context).\n\nBut as soon as you try to do that with more complex merge commits, \nlike holding manual amendments and conflict resolutions, it doesn`t \nreally work as expected - which I demonstrated in my original example \nscript[1] in this topic, original merge commit amendment lost on \nrebase, and even worse - that happened silently.\n\nNow, not to get misinterpreted to pick sides in \"(re)create\" vs \n\"rebase\" merge commit discussion, I just think these two (should) have \na different purpose, and actually having both inside interactive rebase \nis what we should be aiming for.\n\nAnd that`s what I think is important to understand before any further \ndiscussion - _(re)creating_ existing merge commits is not the same as \n_rebasing_ them, even though the former can sometimes be used to \nachieve the latter.\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/bbe64321-4d3a-d3fe-8bb9-58b600fabf35@gmail.com/\n"},{"id":"340998","messageId":"87h8pvm7zz.fsf@javad.com","threadId":"47864","inReplyTo":"872944c4-ca97-9f55-a424-86d1e3299a22@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-05T05:00:48Z","receivedAt":"2018-03-05T05:00:57Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Plillip and Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n> Hi Phillip,\n>\n> On 02/03/2018 12:31, Phillip Wood wrote:\n>> \n>> > Thinking about it overnight, I now suspect that original proposal had a\n>> > mistake in the final merge step. I think that what you did is a way to\n>> > fix it, and I want to try to figure what exactly was wrong in the\n>> > original proposal and to find simpler way of doing it right.\n>> >\n>> > The likely solution is to use original UM as a merge-base for final\n>> > 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>> > though, as that's exactly UM from which both U1' and U2' have diverged\n>> > due to rebasing and other history editing.\n>> \n>> Hi Sergey, I've been following this discussion from the sidelines,\n>> though I haven't had time to study all the posts in this thread in\n>> detail. I wonder if it would be helpful to think of rebasing a merge as\n>> merging the changes in the parents due to the rebase back into the\n>> original merge. So for a merge M with parents A B C that are rebased to\n>> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n>> quoting issues)\n>> \n>> git checkout --detach M\n>> git merge-recursive A -- M A'\n>> tree=$(git write-tree)\n>> git merge-recursive B -- $tree B'\n>> tree=$(git write-tree)\n>> git merge-recursive C -- $tree C'\n>> tree=$(git write-tree)\n>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>> \n>> This should pull in all the changes from the parents while preserving\n>> any evil conflict resolution in the original merge. It superficially\n>> reminds me of incremental merging [1] but it's so long since I looked at\n>> that I'm not sure if there are any significant similarities.\n>> \n>> [1] https://github.com/mhagger/git-imerge\n>\n> Interesting, from quick test[3], this seems to produce the same \n> result as that other test I previously provided[2], where temporary \n> commits U1' and U2' are finally merged with original M as a base :)\n\nLooks like sound approach and it's interesting if these 2 methods do in\nfact always bring the same result. Because if we look at the (now fixed)\noriginal approach closely, it also just gathers the changes in merge\nparents into U1' and U2', then merges the changes back into the original\nM (=U1=U2=UM).\n\nOverall, this one looks like another implementation of essentially the\nsame method and confirms that we all have the right thought direction\nhere.\n\n>\n> Just that this looks like even more straight-forward approach...?\n>\n> The only thing I wonder of here is how would we check if the \n> \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n> With that other approach Sergey described, we have U1'==U2' to test\n> with.\n\nThat's an advantage of the original, yes.\n\n-- Sergey\n"},{"id":"340999","messageId":"878tb7m6ed.fsf@javad.com","threadId":"47864","inReplyTo":"39aebd06-6022-7803-e27d-c1793fd72955@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-05T05:35:22Z","receivedAt":"2018-03-05T05:35:30Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Igor,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n[...]\n\n> Now, not to get misinterpreted to pick sides in \"(re)create\" vs \n> \"rebase\" merge commit discussion, I just think these two (should) have \n> a different purpose, and actually having both inside interactive rebase \n> is what we should be aiming for.\n\nYes, if the user has an existing merge that he intends to throw away by\nre-merging from scratch, he should be given a way to do it during\nhistory editing session, no argues.\n\nWhat I argue against is that this mode of operation is the default one,\nlet alone the only one.\n\n> And that`s what I think is important to understand before any further \n> discussion - _(re)creating_ existing merge commits is not the same as \n> _rebasing_ them, even though the former can sometimes be used to \n> achieve the latter.\n\nYes, indeed. Sometimes creating new merge instead of original does the\njob of rebasing the original, only it does it by pure accident.\n\n-- Sergey\n"},{"id":"341035","messageId":"nycvar.QRO.7.76.6.1803051812330.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"872944c4-ca97-9f55-a424-86d1e3299a22@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-05T17:29:56Z","receivedAt":"2018-03-05T17:30:11Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Sat, 3 Mar 2018, Igor Djordjevic wrote:\n\n> By the way, is there documentation for `git merge-recursive` \n> anywhere, besides the code itself...? :$\n\nI am not aware of any. The commit message adding the command is not very\nilluminating (https://github.com/git-for-windows/git/commit/720d150c4):\n\n    Add a new merge strategy by Fredrik Kuivinen.\n\n    I really wanted to try this out, instead of asking for an adjustment\n    to the 'git merge' driver and waiting.  For now the new strategy is\n    called 'fredrik' and not in the list of default strategies to be tried.\n\n    The script wants Python 2.4 so this commit also adjusts Debian and RPM\n    build procecure files.\n\nDigging through https://public-inbox.org/git/ during that time frame comes\nup with this hit, though:\n\nhttps://public-inbox.org/git/20050907164734.GA20198@c165.ib.student.liu.se/\n\nwhich is still not a good documentation of the algorithm. You can probably\ndig further yourself, but I think I can describe it very quickly here:\n\nTo merge two commits recursively, you first have to find their \"merge\nbases\". If there was an obvious branch point, then that is the merge base.\nBut when you start a branch off of master, then work a bit, then merge\nmaster, you already have two merge bases.\n\nThe trick about the recursive merge is to reduce the number of merge bases\niteratively to one. It does that by taking two merge bases, and performing\na recursive merge on them, which generates a \"virtual\" commit, the\ncondensed merge base. That one is then merged recursively with the next\nmerge base, until there is only one left.\n\nA recursive merge of two commits with exactly one merge base is simply a\nthree-way merge.\n\nI vaguely remember that there was something funny about the order in which\norder you want to process the merge bases: if you did it in one\n(chronological) direction, it worked beautifully, in the other direction\nit would generate tons of merge conflicts or something like that.\n\nCiao,\nJohannes\n"},{"id":"341038","messageId":"nycvar.QRO.7.76.6.1803051836110.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-05T17:52:53Z","receivedAt":"2018-03-05T17:53:08Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Phillip,\n\nOn Fri, 2 Mar 2018, Phillip Wood wrote:\n\n> On 01/03/18 05:39, Sergey Organov wrote:\n> > \n> > Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n> > \n> >> On 28/02/2018 06:19, Sergey Organov wrote:\n> >>>\n> >>>>> (3) ---X1---o---o---o---o---o---X2\n> >>>>>        |\\                       |\\\n> >>>>>        | A1---A2---A3---U1      | A1'--A2'--A3'--U1'\n> >>>>>        |             \\          |\n> >>>>>        |              M         |\n> >>>>>        |             /          |\n> >>>>>        \\-B1---B2---B3---U2      \\-B1'--B2'--B3'--U2'\n> >>>>>\n> >>>>\n> >>>> Meh, I hope I`m rushing it now, but for example, if we had decided to \n> >>>> drop commit A2 during an interactive rebase (so losing A2' from \n> >>>> diagram above), wouldn`t U2' still introduce those changes back, once \n> >>>> U1' and U2' are merged, being incorrect/unwanted behavior...? :/\n> >>>\n> >>> I think the method will handle this nicely.\n> >>\n> >> That`s what I thought as well. And then I made a test. And then the \n> >> test broke... Now, might be the test was flawed in the first place, \n> >> but thinking about it a bit more, it does seem to make sense not to \n> >> handle this case nicely :/\n> > \n> > Yeah, I now see it myself. I'm sorry for being lazy and not inspecting\n> > this more carefully in the first place.\n> > \n> > [...]\n> > \n> >> So while your original proposal currently seems like it could be \n> >> working nicely for non-interactive rebase (and might be some simpler \n> >> interactive ones), now hitting/acknowledging its first real use \n> >> limit, my additional quick attempt[1] just tries to aid pretty \n> >> interesting case of complicated interactive rebase, too, where we \n> >> might be able to do better as well, still using you original proposal \n> >> as a base idea :)\n> > \n> > Yes, thank you for pushing me back to reality! :-) The work and thoughts\n> > you are putting into solving the puzzle are greatly appreciated!\n> > \n> > Thinking about it overnight, I now suspect that original proposal had a\n> > mistake in the final merge step. I think that what you did is a way to\n> > fix it, and I want to try to figure what exactly was wrong in the\n> > original proposal and to find simpler way of doing it right.\n> > \n> > The likely solution is to use original UM as a merge-base for final\n> > 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n> > though, as that's exactly UM from which both U1' and U2' have diverged\n> > due to rebasing and other history editing.\n> \n> Hi Sergey, I've been following this discussion from the sidelines,\n> though I haven't had time to study all the posts in this thread in\n> detail. I wonder if it would be helpful to think of rebasing a merge as\n> merging the changes in the parents due to the rebase back into the\n> original merge. So for a merge M with parents A B C that are rebased to\n> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n> quoting issues)\n> \n> git checkout --detach M\n> git merge-recursive A -- M A'\n> tree=$(git write-tree)\n> git merge-recursive B -- $tree B'\n> tree=$(git write-tree)\n> git merge-recursive C -- $tree C'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n\n(The $tree obviously wants to be passed as parameter to commit-tree, but\nit's easy to get the idea.)\n\n> This should pull in all the changes from the parents while preserving\n> any evil conflict resolution in the original merge. It superficially\n> reminds me of incremental merging [1] but it's so long since I looked at\n> that I'm not sure if there are any significant similarities.\n\nInteresting.\n\nBasically, this is pretending that A'/B'/C' were not the result of\nrebases, but of merges between A/B/C and upstream, and then performing an\noctopus merge of M, A', B' and C'.\n\nIt is a beautiful application of the duality between merges and rebases:\nideally, they both result in the same tree [*1*].\n\nThat is a pretty clean and simple-to-describe paradigm to work off of, and\nto reason about.\n\nCiao,\nDscho\n\nFootnote *1*: I frequently use that duality in work to rebase \"clean\"\npatches on top of upstream, and use that rebased branch to figure out how\nto resolve merge conflicts when merging upstream into a long-running\nbranch (whose tree is identical to the pre-rebase version of the clean\npatches). And yes, I *think* that this is essentially Michael Haggerty's\n`git-imerge` idea.\n"},{"id":"341117","messageId":"1580e48a-be44-38dd-79af-8a2a31c5712e@talktalk.net","threadId":"47864","inReplyTo":"ee809701-a6d8-157d-09cd-cebbf2e949ec@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-06T10:36:00Z","receivedAt":"2018-03-06T10:36:11Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 02/03/18 23:33, Igor Djordjevic wrote:\n> Hi Phillip,\n> \n>> On Fri, Mar 2, 2018 at 4:36 AM, Phillip Wood wrote:\n>>>\n>>>> It is interesting to think what it means to faithfully rebase a '-s\n>>>> ours' merge.\n>>>\n>>> I should have explained that I mean is a faithful rebase one that\n>>> adheres to the semantics of '-s ours' (i.e. ignores any changes in the\n>>> side branch) or one that merges new changes from the side branch into\n>>> the content of the original merge? In your example you add B4 to B. If\n>>> M' preserves the semantics of '-s ours' then it will not contain the\n>>> changes in B4. I think your result does (correct me if I'm wrong) so it\n>>> is preserving the content of the original merge rather than the\n>>> semantics of it.\n> \n> Yeah, I understood what you mean, and I see you noticed that B4 \n> commit, for which I did anticipate possibly bringing up a discussion \n> like this ;)\n> \n> I agree with Jake here, my thoughts exactly (what I wrote in that \n> other subthread[1], too):\n> \n> On 02/03/2018 17:02, Jacob Keller wrote:\n>>\n>> We only have the content, and we don't know the semantics (nor, I\n>> think, should we attempt to understand or figure out the semantics).\n> \n> Hmm, I wanted to elaborate a bit here, but that sentence seems to \n> summarize the pure essence of it, and whatever I write looks like \n> just repeating the same stuff again...\n> \n> That`s just it. And stopping to give the user a chance to \n> review/amend the result, where he might decide he actually did want \n> something else - so all good.\n> \n> Otherwise, I would be interested to learn how context/semantics \n> guessing could provide a better default action (without introducing \n> more complexity for might not be much benefit, if any).\n\nI don't think its possible to guess the semantics of the original merge\nas users can use custom merge strategies and amend the result. It would\nbe possible to detect and unamended '-s ours' merge but special casing\nthat may end up causing users more confusion rather than helping them.\n\n> But in the end, I guess we can just discuss the \"most sane default\" \n> to present to the user (introduce or obsolete that new commit B4, in \n> the discussed example[2]), as we should definitely stop for amending \n> anyway, not proceeding automatically whenever U1' != U2'.\n\nI can see the reason for that but I'm concerned that it might get\nannoying with an interactive rebase as it would stop whenever one of the\ncommits on a topic branch that is a parent of a merge gets amended.\n(squashing and reordering existing commits on a topic branch would be OK\nthough)\n\n> Oh, and what about situations where we introduce new or drop existing \n> branches (which should be possible with new `--recreate-merges`)...? \n> \"Preserving old branch semantics\" may have even less sense here - the \n> (possibly heavily reorganized) content is the only thing we have, \n> where context will (and should) be provided by the user.\n\nIn this scheme there is now way to change the parents of a merge so\npreserving the old branch sementics is well defined. If the user wants\nto change the parents of the merge then this scheme wont help them.\n\n> And I guess being consistent is pretty important, too - if you add \n> new content during merge rebase, it should always show up in the \n> merge, period. \n\nYes, that should make it easy for the user to know what to expect from\nrebase.\n\n> It seems pretty confusing to find out one of the \n> branches \"declared special\" (even more if it`s based on uncertain \n> guess-work), so when you add something to it it`s just \"swallowed\", \n> as the whole branch is always obsoleted, for now and ever.\n> \n> I might even see a value in such behavior, but only as a conscious \n> user action, not something done automatically... I guess? :)\n> \n> Regards, Buga\n> \n> [1] https://public-inbox.org/git/f26cdbe2-1bc3-02ff-7b99-12a6ebab5a70@gmail.com/\n> [2] https://public-inbox.org/git/f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com/\n> \n\n"},{"id":"341124","messageId":"1c912980-8ce8-6281-fa99-040a5e3e1103@talktalk.net","threadId":"47864","inReplyTo":"872944c4-ca97-9f55-a424-86d1e3299a22@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-06T10:45:27Z","receivedAt":"2018-03-06T10:45:35Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 03/03/18 00:29, Igor Djordjevic wrote:\n> Hi Phillip,\n> \n> On 02/03/2018 12:31, Phillip Wood wrote:\n>>\n>>> Thinking about it overnight, I now suspect that original proposal had a\n>>> mistake in the final merge step. I think that what you did is a way to\n>>> fix it, and I want to try to figure what exactly was wrong in the\n>>> original proposal and to find simpler way of doing it right.\n>>>\n>>> The likely solution is to use original UM as a merge-base for final\n>>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>>> though, as that's exactly UM from which both U1' and U2' have diverged\n>>> due to rebasing and other history editing.\n>>\n>> Hi Sergey, I've been following this discussion from the sidelines,\n>> though I haven't had time to study all the posts in this thread in\n>> detail. I wonder if it would be helpful to think of rebasing a merge as\n>> merging the changes in the parents due to the rebase back into the\n>> original merge. So for a merge M with parents A B C that are rebased to\n>> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n>> quoting issues)\n>>\n>> git checkout --detach M\n>> git merge-recursive A -- M A'\n>> tree=$(git write-tree)\n>> git merge-recursive B -- $tree B'\n>> tree=$(git write-tree)\n>> git merge-recursive C -- $tree C'\n>> tree=$(git write-tree)\n>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>>\n>> This should pull in all the changes from the parents while preserving\n>> any evil conflict resolution in the original merge. It superficially\n>> reminds me of incremental merging [1] but it's so long since I looked at\n>> that I'm not sure if there are any significant similarities.\n>>\n>> [1] https://github.com/mhagger/git-imerge\n> \n> Interesting, from quick test[3], this seems to produce the same \n> result as that other test I previously provided[2], where temporary \n> commits U1' and U2' are finally merged with original M as a base :)\n> \n> Just that this looks like even more straight-forward approach...?\n> \n> The only thing I wonder of here is how would we check if the \n> \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n> With that other approach Sergey described, we have U1'==U2' to test with.\n\nI think (though I haven't rigorously proved to myself) that in the\nabsence of conflicts this scheme has well defined semantics (the merges\ncan be commuted), so the result should be predicable from the users\npoint of view so maybe it could just offer an option to stop.\n\n> \n> By the way, is there documentation for `git merge-recursive` \n> anywhere, besides the code itself...? :$\n\nNot that I'm aware of unfortunately. It's pretty simple though\n\ngit merge-recursive [<options>] <merge-bases> -- <our-head> <their-head>\n\nThe options are listed on the 'git merge' man page but you specify them\nas '--option' rather than '-Xoption'. I'm not sure what the exact\nrequirements are for the index, having it match <our-head> should always\nbe safe.\n\n> \n> Thanks, Buga\n> \n> [2] https://public-inbox.org/git/f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com/\n> [3] Quick test script:\n> -- >8 --\n> #!/bin/sh\n> \n> # rm -rf ./.git\n> # rm -f ./test.txt\n> \n> git init\n> \n> touch ./test.txt\n> git add -- test.txt\n> \n> # prepare repository\n> for i in {1..8}\n> do\n> \techo X$i >>test.txt\n> \tgit commit -am \"X$i\"\n> done\n> \n> # prepare branch A\n> git checkout -b A\n> sed -i '2iA1' test.txt\n> git commit -am \"A1\"\n> sed -i '4iA2' test.txt\n> git commit -am \"A2\"\n> sed -i '6iA3' test.txt\n> git commit -am \"A3\"\n> \n> # prepare branch B\n> git checkout -b B master\n> sed -i '5iB1' test.txt\n> git commit -am \"B1\"\n> sed -i '7iB2' test.txt\n> git commit -am \"B2\"\n> sed -i '9iB3' test.txt\n> git commit -am \"B3\"\n> \n> git checkout -b topic A\n> git merge -s ours --no-commit B # merge A and B with `-s ours`\n> sed -i '8iM' test.txt           # amend merge commit (\"evil merge\")\n> git commit -am \"M\"\n> git tag M #original-merge\n> \n> # master moves on...\n> git checkout master\n> git cherry-pick B^     # cherry-pick B2 into master\n> sed -i \"1iX9\" test.txt # add X9\n> git commit -am \"X9\"\n> \n> # (0) ---X8--B2'--X9 (master)\n> #        |\\\n> #        | A1---A2---A3 (A)\n> #        |             \\\n> #        |              M (topic)\n> #        |             /\n> #        \\-B1---B2---B3 (B)\n> \n> # simple/naive demonstration of proposed merge rebasing logic\n> # using iterative merge-recursive, preserving merge commit manual\n> # amendments, testing `-s ours` merge with cherry-picking from\n> # obsoleted part, but still respecting interactively rebased\n> # added/modified/dropped/cherry-picked commits :)\n> \n> git checkout -b A-prime A\n> git reset --hard HEAD^             # drop A3 from A\n> sed -i '/A1/c\\A12' test.txt        # amend A1 to A12\n> git commit -a --amend --no-edit\n> git rebase master                  # rebase A onto master\n> git cherry-pick B                  # cherry-pick B3 into A\n> \n> git checkout -b B-prime B\n> git rebase master                  # rebase B onto master\n> sed -i '12iB4' test.txt            # add B4\n> git commit -am \"B4\"\n> \n> git checkout --detach M\n> git merge-recursive A -- M A-prime\n> tree=\"$(git write-tree)\"\n> git merge-recursive B -- $tree B-prime\n> tree=\"$(git write-tree)\"\n> git tag M-prime \"$(git log --pretty=%B -1 M | git commit-tree $tree -p A-prime -p B-prime)\"\n> \n> git update-ref refs/heads/topic \"$(git rev-parse M-prime)\"\n> git checkout topic\n> \n> # (1) ---X8--B2'--X9 (master)\n> #                 |\\\n> #                 | A12--A2'---B3' (A)\n> #                 |             \\\n> #                 |              M' (topic)\n> #                 |             /\n> #                 \\-B1'--B3'---B4  (B)\n> \n> # show resulting graph\n> # echo\n> # git log --all --decorate --oneline --graph\n> \n> # in comparison to original merge commit M, rebased merge commit \n> # M' is expected to:\n> #\n> # - Add X9, from updated \"master\"\n> # - Have A1 changed to A12, due to A12 commit amendment\n> # - Keep A2, rebased as A2'\n> # - Remove A3, due to dropped A3 commit\n> # - Keep amendment from original (evil) merge commit M\n> # - Miss B1' like M does B, due to original `-s ours` merge strategy\n> # - Add B2, cherry-picked as B2' into \"master\"\n> # - Add B3, cherry-picked as B3' into \"A\"\n> # - Add B4, added to \"B\"\n> #\n> # echo\n> # echo 'diff M M-prime:'\n> # git diff M M-prime\n> \n\n"},{"id":"341125","messageId":"ebc73962-8dff-520c-e19d-8fcc1ef63ab0@talktalk.net","threadId":"47864","inReplyTo":"87h8pvm7zz.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-06T10:52:36Z","receivedAt":"2018-03-06T10:52:44Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 05/03/18 05:00, Sergey Organov wrote:\n> Hi Plillip and Igor,\n> \n> Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n>> Hi Phillip,\n>>\n>> On 02/03/2018 12:31, Phillip Wood wrote:\n>>>\n>>>> Thinking about it overnight, I now suspect that original proposal had a\n>>>> mistake in the final merge step. I think that what you did is a way to\n>>>> fix it, and I want to try to figure what exactly was wrong in the\n>>>> original proposal and to find simpler way of doing it right.\n>>>>\n>>>> The likely solution is to use original UM as a merge-base for final\n>>>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty natural\n>>>> though, as that's exactly UM from which both U1' and U2' have diverged\n>>>> due to rebasing and other history editing.\n>>>\n>>> Hi Sergey, I've been following this discussion from the sidelines,\n>>> though I haven't had time to study all the posts in this thread in\n>>> detail. I wonder if it would be helpful to think of rebasing a merge as\n>>> merging the changes in the parents due to the rebase back into the\n>>> original merge. So for a merge M with parents A B C that are rebased to\n>>> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n>>> quoting issues)\n>>>\n>>> git checkout --detach M\n>>> git merge-recursive A -- M A'\n>>> tree=$(git write-tree)\n>>> git merge-recursive B -- $tree B'\n>>> tree=$(git write-tree)\n>>> git merge-recursive C -- $tree C'\n>>> tree=$(git write-tree)\n>>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>>>\n>>> This should pull in all the changes from the parents while preserving\n>>> any evil conflict resolution in the original merge. It superficially\n>>> reminds me of incremental merging [1] but it's so long since I looked at\n>>> that I'm not sure if there are any significant similarities.\n>>>\n>>> [1] https://github.com/mhagger/git-imerge\n>>\n>> Interesting, from quick test[3], this seems to produce the same \n>> result as that other test I previously provided[2], where temporary \n>> commits U1' and U2' are finally merged with original M as a base :)\n> \n> Looks like sound approach and it's interesting if these 2 methods do in\n> fact always bring the same result. Because if we look at the (now fixed)\n> original approach closely, it also just gathers the changes in merge\n> parents into U1' and U2', then merges the changes back into the original\n> M (=U1=U2=UM).\n> \n> Overall, this one looks like another implementation of essentially the\n> same method and confirms that we all have the right thought direction\n> here.\n> \n\nYes, I think they are doing the same thing. If there are no conflicts\nthen U1' is the should as \"git merge-recursive A -- M A'\". My patch\nalgebra isn't very good, but I think one ought to be able to show that\nin the absence of conflicts the two approaches are equivalent.\n\n>>\n>> Just that this looks like even more straight-forward approach...?\n>>\n>> The only thing I wonder of here is how would we check if the \n>> \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n>> With that other approach Sergey described, we have U1'==U2' to test\n>> with.\n> \n> That's an advantage of the original, yes.\n\nI wonder if just having a predicable result rather than forcing the\nrebase to stop if the user just squashes a fixup commit into a topic\nbranch that is the parent of a merge might be more convenient in practice.\n\nBest Wishes\n\nPhillip\n\n> -- Sergey\n> \n\n"},{"id":"341126","messageId":"87r2oxfmwo.fsf@javad.com","threadId":"47864","inReplyTo":"1c912980-8ce8-6281-fa99-040a5e3e1103@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-06T11:45:11Z","receivedAt":"2018-03-06T11:45:19Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Phillip,\n\nPhillip Wood <phillip.wood@talktalk.net> writes:\n\n> On 03/03/18 00:29, Igor Djordjevic wrote:\n>> Hi Phillip,\n\n[...]\n\n>> \n>> The only thing I wonder of here is how would we check if the \n>> \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n>> With that other approach Sergey described, we have U1'==U2' to test with.\n>\n> I think (though I haven't rigorously proved to myself) that in the\n> absence of conflicts this scheme has well defined semantics (the merges\n> can be commuted), so the result should be predicable from the users\n> point of view so maybe it could just offer an option to stop.\n\nYes, hopefully it's predictable, but is it the intended one? We don't\nknow, so there is still some level of uncertainty.\n\nWhen in doubt, I try to find similar cases. There are two I'm aware of:\n\n1. \"git merge\" just commits the result when there are no conflicts.\nHowever, it supposedly has been run by the user just now, and thus user\ncan amend what he gets. That's effectively a stop for amendment from our\nPOV.\n\n2. When rebasing, \"rerere\", when fires, stages the changes, and rebasing\nstops for amendment. For me \"rerere\" behavior is rather annoying (I've\nnever in fact amended what it prepared), but I always assumed there are\ngood reasons it behaves this way.\n\nOverall, to be consistent, it seems we do need to stop at U1' != U2', at\nleast by default. Additional options could be supported then to specify\nuser intentions, both on the command level and in the todo list,\nprovided it proves to be useful.\n\n-- Sergey\n"},{"id":"341129","messageId":"87r2oxe3o1.fsf@javad.com","threadId":"47864","inReplyTo":"87y3jtqdyg.fsf@javad.com","subject":"[RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-06T13:26:06Z","receivedAt":"2018-03-06T13:26:17Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi,\n\nThis is v2 of my \"Rebasing merges\" proposal.\n\nSignificant changes are:\n\n1. Fixed mistake in the final merge step in the original proposal: wrong\n   merge base was used. Thanks everybody who provided test-cases, and\n   special thanks to Igor Djordjevic <igor.d.djordjevic@gmail.com> for\n   implementing and testing a few variants of the method.\n\n2. Added discussion of the exact place where handling of special\n   frequent cases such as \"git merge -ours\", if any, should go.\n\n3. I now use \"True Merge\" name instead of former \"Trivial Merge\", to\n   avoid confusion with what Git documentation calls \"trivial merge\",\n   thanks to Junio C Hamano <gitster@pobox.com> for pointing this out.\n\nDuring discussion of the original proposal, yet another way of\nimplementing a true rebase of a merge commit has been suggested by\nPhillip Wood <phillip.wood@dunelm.org.uk>[1]. His method also gathers\nthe changes on both sides of the merge and then merges them back to the\noriginal merge, so both methods have similar concept and differ in\nimplementation. It looks like both implementations bring the same\nresult, at least it was so in the limited testing that Igor performed.\n\n[1] https://public-inbox.org/git/6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net/\n\n\n-------8<-------------8<------\n\nBy accepting the challenges raised in recent discussion of advanced\nsupport for history rebasing and editing in Git, I hopefully figured out\na clean and elegant method of rebasing merges that I think is \"The Right\nWay (TM)\" to perform this so far troublesome operation. [\"(TM)\" here has\nsecond meaning: \"True Merge\" (TM), see below.]\n\nLet me begin with quick outline of the method, to illustrate the\nsimplicity of the approach, and special thanks here must go to \"Johannes\nSixt\" <j6t@kdbg.org> for his original bright idea to use \"cherry-pick\n-m1\" to rebase merge commits.\n\nGiven 2 original branches, b1 and b2, and a merge commit M that joins\nthem, suppose we've already rebased b1 to b1', and b2 to b2'. Suppose\nalso that B1' and B2' happen to be the tip commits on b1' and b2',\nrespectively.\n\nTo produce merge commit M' that joins b1' and b2', the following\noperations will suffice:\n\n1. Checkout b2' and cherry-pick -m2 M, to produce U2' (and new b2').\n2. Checkout b1' and cherry-pick -m1 M, to produce U1' (and new b1').\n3. Perform 3-way merge of U1' and U2' using original M as merge base,\n   to get UM'.\n4. Get rid of U1' and U2' by re-writing parent references of UM' from\n   U1' and U2' to  B1' and B2', respectively, to produce M'.\n5. Mission complete.\n\nLet's now turn to the method itself and see why and how it actually\nworks.\n\nFirst off, let me introduce you to my new friend, the True Merge, or\n(TM) for short. By definition, (TM) is a merge that brings absolutely\nno differences to the sides of the merge. (I also like to call him\n\"Angel Merge\" (AM), both as being the most beautiful of all merges, and\nas direct antithesis to \"[d]evil merge\"; or even \"Perfect Merge\" (PM),\nbut the latter goes after lunch time.)\n\nBeing trivial history joint and nothing else, (TM)/(AM)/(PM) is safe and\neasy to be rebased (see below). However, since most of us have never met\n(TM) in practice, you probably wonder how (TM) can actually help us\nhandle general case of rebasing of some random merge.\n\nLet's start with this history:\n\n    M\n   / \\\n  B1  B2\n\nwhere B1 and B2 are tip commits of 2 branches, and M is the merge commit\nthat joins them. Let's transform this history to the following one,\ncontextually equivalent to the original, by introducing 2 non-merge\nutility commits U1 and U2, and a new utility merge commit UM:\n\n    UM\n   /  \\\n  U1   U2\n  |    |\n  B1   B2\n\nwere contents of all the created commits match, and are exact copies of\nthe original content of M. I.e., provided [A] denotes \"content of commit\nA\", we have:\n\n  [UM] = [U1] = [U2] = [M]\n\nStress again how these changes to the history preserve the exact content\nof the original merge ([UM] = [M]), how U1 an U2 represent content\nchanges due to the merge on either side[*], and how content of neither\npreceding nor subsequent commits is affected by the change of\nrepresentation.\n\nNow observe that as [U1] = [UM], and [U2] = [UM], the UM happens to be\nexactly our new friend -- the \"True Merge (TM)\" his true self,\nintroducing exactly zero changes to content. Pure history joint.\n\nNext, we separately rebase both branches of our new representation of\nthe history to whatever new base we need, and we get:\n\n  U1'  U2'\n  |    |\n  B1'  B2'\n\nwhere U1' and U2' are rebased versions of U1 and U2, obtained by usual\nrebasing methods for non-merge commits.\n\nFinally, let's merge back our branches.\n\nTo perform the right kind of merge, notice that U1' and U2' have\ndiverged from U1 and U2, respectively. Further, provided [U1] = [U2] =\n[UM] = [M], they have both diverged from the original merge commit\nM. Therefore, to merge U1' and U2' into UM', it suffices to use 3-way\nmerge using original M as the merge base:\n\n    UM'\n   /  \\\n  U1'  U2'\n   \\  /\n    M\n\nNote that unlike merging of B1' and B2' that current \"git rebase\n--preserve-merges/--recreate-merges\" performs, merging of U1' and U2' is\nsafe, as original UM, being (TM), doesn't itself carry any content\nchanges, and thus none could be missed by ignoring the UM. Essentially,\nreproducing a (TM) is just joining corresponding histories back, and\nthat's what merge operation is all about.\n\nIf the resulting U1' and U2' happen to match ([U1'] = [U2']), we have\ngot our lovely (TM) back and we are clear to proceed automatically.\n\nOTOH, if the resulting U1' and U2' differ, we should better stop for\nuser inspection and possible amendment of the resulting UM'. At this\npoint special treatment of any rather frequent cases (such as \"git merge\n-ours\") could be applied before amendment, if need to be. Amendment by\nreplacing UM' with re-merge of B2' and B1' could be suggested to the\nuser as well. Options are plenty.\n\nFinally, to get to our required merge commit M', we get the content of\nUM' (possibly amended by the user), and record two actual parents of the\nmerge:\n\n    M'\n   / \\\n  B1' B2'\n\nwhere [M'] = [UM'].\n\nThat's it. Mission complete.\n\nThe method is expected to have the following nice features:\n\n- it carefully preserves user changes by rebasing the merge commit\nitself, in a way that is semantically similar to rebasing simple\n(non-merge) commits, yet it allows changes made to branches during\nhistory editing to propagate over corresponding merge commit that joins\nthe branches, even automatically when the changes don't conflict, as\nexpected.\n\n- it has provision for detection of even slightest chances of ending up\nwith surprising merge (just check if UM' is still (TM)), so that\nimplementation could stop for user inspection and amendment when\nappropriate, yet it is capable of handling trivial cases smoothly and\nautomatically.\n\n- it never falls back to simple invocation of merge operation on rebased\noriginal branches themselves, thus avoiding the problem of lack of\nknowledge of how the merge at hand has been performed in the first\nplace.\n\n- it allows implementation to let user manually perform whatever merge\nshe wishes when suspect result is automatically detected.\n\n- it extends trivially to octopus merges.\n\n- it appears to be shiny to the point that it will likely be able to\nhandle even darkest [d]evil merges nicely, no special treatment\nrequired.\n\nFootnote:\n\n[*] We may as well consider the (UM,U1,U2) trio to be semantically split\nrepresentation of git merge commit, where U1 and U2 represent content\nchanges to the sides, and UM represents pure history joint. Or, the\nother way around, we may consider git merge commit to be optimized\nrepresentation of this trio. I think this split representation could\nhelp to simplify reasoning about git merges in general.\n\n-- Sergey\n"},{"id":"341133","messageId":"xmqqwoyp5eig.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"ebc73962-8dff-520c-e19d-8fcc1ef63ab0@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-06T16:56:39Z","receivedAt":"2018-03-06T16:57:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood@talktalk.net> writes:\n\n> I wonder if just having a predicable result rather than forcing the\n> rebase to stop if the user just squashes a fixup commit into a topic\n> branch that is the parent of a merge might be more convenient in practice.\n\nUnless I am misunderstanding what you are saying, that is pretty\nmuch what I have automated for my daily rebuild of the 'pu' branch\n\nNon-textual semantic conflicts are made (in the best case just once)\nas a separate commit on top of mechanical auto-merge whose focus is\npredictability (rather than cleverness) done by Git, and then that\nseparate commit is kept outside the history.  When replaying these\nmerges to rebuild the 'pu' branch, after resetting the tip to\n'master', each topic is merged mechanically, and if such a fix-up\ncommit is present, \"cherry-pick --no-commit\" applies it and then\n\"commit --amend --no-edit\" to adjust the merge.  I find it quite\nvaluable to have a separate record of what \"evil\" non-mechanical\nadjustment was done, which I know won't be lost in the noise when\nthese merges need to be redone daily or more often.\n\nThe Appendix in Documentation/howto/maintain-git.txt talks about\nthis process.  You can see what topics have such merge-fix defined\nby peeking https://github.com/gitster/git/ repository.\n\n"},{"id":"341137","messageId":"nycvar.QRO.7.76.6.1803061829460.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"1c912980-8ce8-6281-fa99-040a5e3e1103@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-06T18:12:10Z","receivedAt":"2018-03-06T18:12:25Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Phillip,\n\nOn Tue, 6 Mar 2018, Phillip Wood wrote:\n\n> On 03/03/18 00:29, Igor Djordjevic wrote:\n> > \n> > On 02/03/2018 12:31, Phillip Wood wrote:\n> >>\n> >>> Thinking about it overnight, I now suspect that original proposal\n> >>> had a mistake in the final merge step. I think that what you did is\n> >>> a way to fix it, and I want to try to figure what exactly was wrong\n> >>> in the original proposal and to find simpler way of doing it right.\n> >>>\n> >>> The likely solution is to use original UM as a merge-base for final\n> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty\n> >>> natural though, as that's exactly UM from which both U1' and U2'\n> >>> have diverged due to rebasing and other history editing.\n> >>\n> >> Hi Sergey, I've been following this discussion from the sidelines,\n> >> though I haven't had time to study all the posts in this thread in\n> >> detail. I wonder if it would be helpful to think of rebasing a merge\n> >> as merging the changes in the parents due to the rebase back into the\n> >> original merge. So for a merge M with parents A B C that are rebased\n> >> to A' B' C' the rebased merge M' would be constructed by (ignoring\n> >> shell quoting issues)\n> >>\n> >> git checkout --detach M\n> >> git merge-recursive A -- M A'\n> >> tree=$(git write-tree)\n> >> git merge-recursive B -- $tree B'\n> >> tree=$(git write-tree)\n> >> git merge-recursive C -- $tree C'\n> >> tree=$(git write-tree)\n> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n> >>\n> >> This should pull in all the changes from the parents while preserving\n> >> any evil conflict resolution in the original merge. It superficially\n> >> reminds me of incremental merging [1] but it's so long since I looked at\n> >> that I'm not sure if there are any significant similarities.\n> >>\n> >> [1] https://github.com/mhagger/git-imerge\n> > \n> > Interesting, from quick test[3], this seems to produce the same \n> > result as that other test I previously provided[2], where temporary \n> > commits U1' and U2' are finally merged with original M as a base :)\n> > \n> > Just that this looks like even more straight-forward approach...?\n> > \n> > The only thing I wonder of here is how would we check if the \n> > \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n> > With that other approach Sergey described, we have U1'==U2' to test with.\n> \n> I think (though I haven't rigorously proved to myself) that in the\n> absence of conflicts this scheme has well defined semantics (the merges\n> can be commuted), so the result should be predicable from the users\n> point of view so maybe it could just offer an option to stop.\n\nI am not so sure that the result is independent of the order of the\nmerges. In other words, I am not necessarily certain that it is impossible\nto concoct A,A',B,B' commits where merging B'/B before A'/A has a\ndifferent result than merging A'/A before B'/B.\n\nRemember, when constructing counter-examples to hypotheses, those\ncounter-examples do not really *have* to make sense on their own. For\nexample, A' could introduce *completely different* changes from A, and the\nsame is true for B' and B.\n\nI could imagine, for example, that using a ton of consecutive empty lines,\nand using patches that insert something into these empty lines (and are\nthusly inherently ambiguous when said set of empty lines has changed),\ncould even introduce a merge conflict in one order, but no conflict in the\nother.\n\nEven so, I think that merging in the order of the parents makes the most\nsense, and that using that strategy makes sense, too, because you really\nhave to try hard to make it fail.\n\nCiao,\nDscho\n"},{"id":"341138","messageId":"nycvar.QRO.7.76.6.1803061812090.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"1580e48a-be44-38dd-79af-8a2a31c5712e@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-06T18:12:16Z","receivedAt":"2018-03-06T18:12:29Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Phillip & Buga,\n\nOn Tue, 6 Mar 2018, Phillip Wood wrote:\n\n> On 02/03/18 23:33, Igor Djordjevic wrote:\n> > \n> > [...]\n> > Otherwise, I would be interested to learn how context/semantics \n> > guessing could provide a better default action (without introducing \n> > more complexity for might not be much benefit, if any).\n> \n> I don't think its possible to guess the semantics of the original merge\n> as users can use custom merge strategies and amend the result. It would\n> be possible to detect and unamended '-s ours' merge but special casing\n> that may end up causing users more confusion rather than helping them.\n\nFWIW I agree.\n\nMy original plan was to always merge recursively and suggest to use `exec`\ncommands if anything else is needed.\n\nBut now with that excellent new idea to perform successive three-way\nmerges of the original merge commit with the new tips, using the old tips\nas merge base, I am considering to change that.\n\nThere is a big problem here, though: consistency. See below for more\nmusings about that.\n\n> > And I guess being consistent is pretty important, too - if you add new\n> > content during merge rebase, it should always show up in the merge,\n> > period. \n> \n> Yes, that should make it easy for the user to know what to expect from\n> rebase.\n\nIndeed. We have seen time and time again that consistent behavior is the\nonly thing that lets us adhere to the Law of Least Surprise.\n\nAnd here lies the rub: do we really want to let `merge -C <commit>` behave\ncompletely differently than `merge`? Granted, in one case we provide a\ntemplate merge commit, in the other case, we do not. And the idea is\nalready to behave differently, although that difference only extends to\nthe commit message so far.\n\nBut given the benefit (i.e. that the strategy to transform the original\nmerge commit into the new merge commit), I am willing to run that risk,\nespecially since I foresee only few users wanting to create new merge\ncommits from scratch using the `merge` todo command.\n\nOf course, even then we need to be careful: the user might have\n*changed* or *moved* the original `merge` command. For example, if the\nmerge command read:\n\n\tmerge -C deadbee cafecafe bedbedbed\n\nand the user switched the order of the merged branches into\n\n\tmerge -C deadbee bedbedbed cafecafe\n\nwe would have to detect the changed order of the arguments so that we\ncould still find the original branch tips.\n\nBut the user might also have changed the branch(es) to merge completely,\nin which case we might not even be able to find original branch tips.\n\nMy preferred solution would be to let the `merge` command figure out\nwhether the passed arguments correspond to the rewritten versions of the\noriginal merge parents. And only in that case would we use the fancy\nstrategy, in all other cases we would fall back to performing a regular\nrecursive (or octopus) merge.\n\nHow does that sound?\n\nIt will be slightly inconsistent. But in a defendable way, I think.\n\nCiao,\nDscho\n"},{"id":"341146","messageId":"754e2735-1288-9a8d-c8bd-ab39cf733812@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803061812090.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-06T19:43:09Z","receivedAt":"2018-03-06T19:44:05Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 06/03/2018 19:12, Johannes Schindelin wrote:\n> \n> > > And I guess being consistent is pretty important, too - if you add new\n> > > content during merge rebase, it should always show up in the merge,\n> > > period. \n> >\n> > Yes, that should make it easy for the user to know what to expect from\n> > rebase.\n> \n> Indeed. We have seen time and time again that consistent behavior is the\n> only thing that lets us adhere to the Law of Least Surprise.\n> \n> And here lies the rub: do we really want to let `merge -C <commit>` behave\n> completely differently than `merge`? Granted, in one case we provide a\n> template merge commit, in the other case, we do not. And the idea is\n> already to behave differently, although that difference only extends to\n> the commit message so far.\n> \n> But given the benefit (i.e. that the strategy to transform the original\n> merge commit into the new merge commit), I am willing to run that risk,\n> especially since I foresee only few users wanting to create new merge\n> commits from scratch using the `merge` todo command.\n> \n> Of course, even then we need to be careful: the user might have\n> *changed* or *moved* the original `merge` command. For example, if the\n> merge command read:\n> \n> \tmerge -C deadbee cafecafe bedbedbed\n> \n> and the user switched the order of the merged branches into\n> \n> \tmerge -C deadbee bedbedbed cafecafe\n> \n> we would have to detect the changed order of the arguments so that we\n> could still find the original branch tips.\n> \n> But the user might also have changed the branch(es) to merge completely,\n> in which case we might not even be able to find original branch tips.\n> \n> My preferred solution would be to let the `merge` command figure out\n> whether the passed arguments correspond to the rewritten versions of the\n> original merge parents. And only in that case would we use the fancy\n> strategy, in all other cases we would fall back to performing a regular\n> recursive (or octopus) merge.\n> \n> How does that sound?\n> \n> It will be slightly inconsistent. But in a defendable way, I think.\n\nI like where this discussion is heading, and here`s what I thought \nabout it :)\n\nFirst, starting from non-interactive rebase, I guess we may now agree \nthat _rebasing_ merges is an actually expected behavior, not recreating \nthem (thus keeping manual conflict resolutions and amendments, not \nlosing them).\n\nNow, interactive rebase is a totally different story, we already said \nuser can change pretty much about everything, making merge \n_recreation_ to be a more sane choice, but let`s leave this other \nextreme for a brief moment.\n\nIn the least interesting situation, though, user could just review \nand close todo list, without changing anything - and in that case it \nwould be important, consistency wise, to behave exactly like in case \nof non-interactive rebase, meaning still rebasing merges, not \nrecreating them.\n\nOk, so that still aligns with what`s written so far - we need to be \nable to rebase merges interactively, too (not just recreate them), to \nstay consistent in less complex interactive rebases.\n\nBut, what if user really wants to _recreate_ merges, for whatever \nreason? Come on, this is interactive rebase we`re talking about, why \nbeing restrictive? :)\n\nHere`s a twist - not letting `merge` trying to be too smart by \nfiguring out whether passed arguments correspond to rewritten \nversions of the original merge parents (which would be too \nrestrictive, too, I`m afraid), but just be explicit about it, instead!\n\nSo, it could be something like:\n\n\tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n\n\nThe format is still something to think about, but the point is rather \nsimple - explicitly map old and new merge parents, showing this \ninside todo list by default.\n\nThis makes it much easier for later processing (and correct, no need \nto guess which one goes where), but also gives more power to the \nuser, being able to decide which merge parents get \"rebased\", and \nwhich ones should go into the merge just like \"new\".\n\nSo if a user gets an interactive todo list like that and just closes \nit, we still have exact situation like non-interactive rebase (and no \nguessing on implementation side).\n\nBut, user might still decide to introduce new merge parents into the \nmix, even, where we could then just be merging those (as there is no \nold merge parent to actually rebase from):\n\n\tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed new-branch\n\t\nHere, \"new-branch\" is something new, introduced inside interactive \nrebase, and it will be just merged into the other two (which are \nstill being rebased).\n\nAlso, another example - if original merge parent \"123abc\" was merged \nfrom the other side using `-s ours` strategy, that means all the \ncontent this branch originally had will still be missing from the \nrebased merge (expect for what`s been cherry-picked elsewhere).\n\nBut, I would argue it`s quite legit to want to revise that decision, \nand let that content in this time. To make that happen, one would \njust remove \"123abc:\" from the todo list:\n\n\tmerge -C deadbee cafecafe 234bcd:bedbedbed new-branch\n\n..., meaning that only \"bedbedbed\" should be rebased according \noriginal merge parent \"234bcd\", where both \"cafecafe\" and \"new-branch\" \nshould be just merged in, no previous context existing (no rebase).\n\nIn the end, user might even decide to swap old/new parent mapping, \nand that should be possible, too (might be pretty strange, though, \ncausing conflicts, but we shouldn`t judge).\n\nOr, one could map old merge parent to some totally new merge parent, \nlike \"new-branch\" in that example above, all this being a fair game.\n\nAs one might suspect, to recreate merge from scratch instead, just \ndrop all the old merge parents mappings:\n\n\tmerge -C deadbee cafecafe bedbedbed\n\n\nThere, in my opinion, something like this provides the most \nconsistent user experience (we always behave the same), while adding \nadditional possibilities on top (getting to actually decide which \nmerge parents get rebased, and which just merged), plus avoids all \nguess work (old and new merge parents, to be used for merge rebasing, \nare explicitly mapped).\n\nWhat do you think? (unrelated to the parent mapping format itself, \nwhich could/should probably be made better, if possible)\n\nRegards, Buga\n"},{"id":"341175","messageId":"77349f89-16c5-8f14-10da-e15381d11dc1@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803051812330.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-06T23:21:20Z","receivedAt":"2018-03-06T23:21:37Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Johannes,\n\nOn 05/03/2018 18:29, Johannes Schindelin wrote:\n> \n> > By the way, is there documentation for `git merge-recursive` \n> > anywhere, besides the code itself...? :$\n> \n> I am not aware of any. The commit message adding the command is not very\n> illuminating (https://github.com/git-for-windows/git/commit/720d150c4):\n> \n>     Add a new merge strategy by Fredrik Kuivinen.\n> \n>     I really wanted to try this out, instead of asking for an adjustment\n>     to the 'git merge' driver and waiting.  For now the new strategy is\n>     called 'fredrik' and not in the list of default strategies to be tried.\n> \n>     The script wants Python 2.4 so this commit also adjusts Debian and RPM\n>     build procecure files.\n> \n> Digging through https://public-inbox.org/git/ during that time frame comes\n> up with this hit, though:\n> \n> https://public-inbox.org/git/20050907164734.GA20198@c165.ib.student.liu.se/\n> \n> which is still not a good documentation of the algorithm. You can probably\n> dig further yourself, but I think I can describe it very quickly here:\n> \n> To merge two commits recursively, you first have to find their \"merge\n> bases\". If there was an obvious branch point, then that is the merge base.\n> But when you start a branch off of master, then work a bit, then merge\n> master, you already have two merge bases.\n> \n> The trick about the recursive merge is to reduce the number of merge bases\n> iteratively to one. It does that by taking two merge bases, and performing\n> a recursive merge on them, which generates a \"virtual\" commit, the\n> condensed merge base. That one is then merged recursively with the next\n> merge base, until there is only one left.\n> \n> A recursive merge of two commits with exactly one merge base is simply a\n> three-way merge.\n> \n> I vaguely remember that there was something funny about the order in which\n> order you want to process the merge bases: if you did it in one\n> (chronological) direction, it worked beautifully, in the other direction\n> it would generate tons of merge conflicts or something like that.\n\nThanks, this is very informative (together with the linked discussion).\n\nNot remembering seeing this before, I wasn`t really sure if this was \nsome undocumented core Git (plumbing?) utility (used withing Git \nitself, too), or just a leftover (yet still useful) sample tool.\n\nRegards, Buga\n"},{"id":"341176","messageId":"xmqqzi3k23fu.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803061812090.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-06T23:24:05Z","receivedAt":"2018-03-06T23:24:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> I don't think its possible to guess the semantics of the original merge\n>> as users can use custom merge strategies and amend the result. It would\n>> be possible to detect and unamended '-s ours' merge but special casing\n>> that may end up causing users more confusion rather than helping them.\n>\n> FWIW I agree.\n\nI think it is a mistake to sacrifice predictability only to add\ncleverness that sometimes work.  Elsewhere in the thread, I think I\nsaw an argument to treat interactive and non-interactive something\nvery different, but there is no fundamental difference between them\n(it is far easier with interactive to force the command to \"port\"\neach change to a vastly different context) so having consistent\nbehaviour between the two cases is important, too.\n\n>\n> My original plan was to always merge recursively and suggest to use `exec`\n> commands if anything else is needed.\n>\n> But now with that excellent new idea to perform successive three-way\n> merges of the original merge commit with the new tips, using the old tips\n> as merge base, I am considering to change that.\n\nOK, does this mean we want to wait before merging the \"recreate\nmerge\" topic down to 'next'?  For more than a few weeks, it has been\nslated for 'next'.\n\n"},{"id":"341186","messageId":"87h8pscw0r.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803061829460.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-07T05:08:52Z","receivedAt":"2018-03-07T05:09:01Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Phillip,\n>\n> On Tue, 6 Mar 2018, Phillip Wood wrote:\n>\n>> On 03/03/18 00:29, Igor Djordjevic wrote:\n>> > \n>> > On 02/03/2018 12:31, Phillip Wood wrote:\n>> >>\n>> >>> Thinking about it overnight, I now suspect that original proposal\n>> >>> had a mistake in the final merge step. I think that what you did is\n>> >>> a way to fix it, and I want to try to figure what exactly was wrong\n>> >>> in the original proposal and to find simpler way of doing it right.\n>> >>>\n>> >>> The likely solution is to use original UM as a merge-base for final\n>> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty\n>> >>> natural though, as that's exactly UM from which both U1' and U2'\n>> >>> have diverged due to rebasing and other history editing.\n>> >>\n>> >> Hi Sergey, I've been following this discussion from the sidelines,\n>> >> though I haven't had time to study all the posts in this thread in\n>> >> detail. I wonder if it would be helpful to think of rebasing a merge\n>> >> as merging the changes in the parents due to the rebase back into the\n>> >> original merge. So for a merge M with parents A B C that are rebased\n>> >> to A' B' C' the rebased merge M' would be constructed by (ignoring\n>> >> shell quoting issues)\n>> >>\n>> >> git checkout --detach M\n>> >> git merge-recursive A -- M A'\n>> >> tree=$(git write-tree)\n>> >> git merge-recursive B -- $tree B'\n>> >> tree=$(git write-tree)\n>> >> git merge-recursive C -- $tree C'\n>> >> tree=$(git write-tree)\n>> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>> >>\n>> >> This should pull in all the changes from the parents while preserving\n>> >> any evil conflict resolution in the original merge. It superficially\n>> >> reminds me of incremental merging [1] but it's so long since I looked at\n>> >> that I'm not sure if there are any significant similarities.\n>> >>\n>> >> [1] https://github.com/mhagger/git-imerge\n>> > \n>> > Interesting, from quick test[3], this seems to produce the same \n>> > result as that other test I previously provided[2], where temporary \n>> > commits U1' and U2' are finally merged with original M as a base :)\n>> > \n>> > Just that this looks like even more straight-forward approach...?\n>> > \n>> > The only thing I wonder of here is how would we check if the \n>> > \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n>> > With that other approach Sergey described, we have U1'==U2' to test with.\n>> \n>> I think (though I haven't rigorously proved to myself) that in the\n>> absence of conflicts this scheme has well defined semantics (the merges\n>> can be commuted), so the result should be predicable from the users\n>> point of view so maybe it could just offer an option to stop.\n>\n> I am not so sure that the result is independent of the order of the\n> merges. In other words, I am not necessarily certain that it is impossible\n> to concoct A,A',B,B' commits where merging B'/B before A'/A has a\n> different result than merging A'/A before B'/B.\n>\n> Remember, when constructing counter-examples to hypotheses, those\n> counter-examples do not really *have* to make sense on their own. For\n> example, A' could introduce *completely different* changes from A, and the\n> same is true for B' and B.\n>\n> I could imagine, for example, that using a ton of consecutive empty lines,\n> and using patches that insert something into these empty lines (and are\n> thusly inherently ambiguous when said set of empty lines has changed),\n> could even introduce a merge conflict in one order, but no conflict in the\n> other.\n>\n> Even so, I think that merging in the order of the parents makes the most\n> sense, and that using that strategy makes sense, too, because you really\n> have to try hard to make it fail.\n\nAlternatively, consider to adopt the original approach that has none of\nthese issues as it uses exactly the same method for rebasing merge\ncommits that you are already using for rebasing simple commits, not to\nmention the advantage of the built-in consistency check.\n\n-- Sergey\n"},{"id":"341187","messageId":"nycvar.QRO.7.76.6.1803070742580.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87r2oxe3o1.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T06:46:17Z","receivedAt":"2018-03-07T06:46:59Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Tue, 6 Mar 2018, Sergey Organov wrote:\n\n> This is v2 of my \"Rebasing merges\" proposal.\n\nDidn't we settle on Phillip's \"perform successive three-way merges between\nthe original merge commit and the new tips with the old tips as base\"\nstrategy? It has the following advantages:\n\n- it is *very simple* to describe\n\n- it is *very easy* to reason about, once it is pointed out that rebases\n  and merges result in the same trees.\n\n... and BTW...\n\n> 3. I now use \"True Merge\" name instead of former \"Trivial Merge\", to\n>    avoid confusion with what Git documentation calls \"trivial merge\",\n>    thanks to Junio C Hamano <gitster@pobox.com> for pointing this out.\n\n\"True Merge\" is probably also a candidate for improvement. If what you\nrefer to is a \"true\" merge, that means all others are \"untrue\" merges???\n\nCiao,\nJohannes\n"},{"id":"341188","messageId":"nycvar.QRO.7.76.6.1803070756550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87h8pscw0r.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T06:58:43Z","receivedAt":"2018-03-07T06:59:03Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 7 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 6 Mar 2018, Phillip Wood wrote:\n> >\n> >> On 03/03/18 00:29, Igor Djordjevic wrote:\n> >> > \n> >> > On 02/03/2018 12:31, Phillip Wood wrote:\n> >> >>\n> >> >>> Thinking about it overnight, I now suspect that original proposal\n> >> >>> had a mistake in the final merge step. I think that what you did is\n> >> >>> a way to fix it, and I want to try to figure what exactly was wrong\n> >> >>> in the original proposal and to find simpler way of doing it right.\n> >> >>>\n> >> >>> The likely solution is to use original UM as a merge-base for final\n> >> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty\n> >> >>> natural though, as that's exactly UM from which both U1' and U2'\n> >> >>> have diverged due to rebasing and other history editing.\n> >> >>\n> >> >> Hi Sergey, I've been following this discussion from the sidelines,\n> >> >> though I haven't had time to study all the posts in this thread in\n> >> >> detail. I wonder if it would be helpful to think of rebasing a merge\n> >> >> as merging the changes in the parents due to the rebase back into the\n> >> >> original merge. So for a merge M with parents A B C that are rebased\n> >> >> to A' B' C' the rebased merge M' would be constructed by (ignoring\n> >> >> shell quoting issues)\n> >> >>\n> >> >> git checkout --detach M\n> >> >> git merge-recursive A -- M A'\n> >> >> tree=$(git write-tree)\n> >> >> git merge-recursive B -- $tree B'\n> >> >> tree=$(git write-tree)\n> >> >> git merge-recursive C -- $tree C'\n> >> >> tree=$(git write-tree)\n> >> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n> >> >>\n> >> >> This should pull in all the changes from the parents while preserving\n> >> >> any evil conflict resolution in the original merge. It superficially\n> >> >> reminds me of incremental merging [1] but it's so long since I looked at\n> >> >> that I'm not sure if there are any significant similarities.\n> >> >>\n> >> >> [1] https://github.com/mhagger/git-imerge\n> >> > \n> >> > Interesting, from quick test[3], this seems to produce the same \n> >> > result as that other test I previously provided[2], where temporary \n> >> > commits U1' and U2' are finally merged with original M as a base :)\n> >> > \n> >> > Just that this looks like even more straight-forward approach...?\n> >> > \n> >> > The only thing I wonder of here is how would we check if the \n> >> > \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n> >> > With that other approach Sergey described, we have U1'==U2' to test with.\n> >> \n> >> I think (though I haven't rigorously proved to myself) that in the\n> >> absence of conflicts this scheme has well defined semantics (the merges\n> >> can be commuted), so the result should be predicable from the users\n> >> point of view so maybe it could just offer an option to stop.\n> >\n> > I am not so sure that the result is independent of the order of the\n> > merges. In other words, I am not necessarily certain that it is impossible\n> > to concoct A,A',B,B' commits where merging B'/B before A'/A has a\n> > different result than merging A'/A before B'/B.\n> >\n> > Remember, when constructing counter-examples to hypotheses, those\n> > counter-examples do not really *have* to make sense on their own. For\n> > example, A' could introduce *completely different* changes from A, and the\n> > same is true for B' and B.\n> >\n> > I could imagine, for example, that using a ton of consecutive empty lines,\n> > and using patches that insert something into these empty lines (and are\n> > thusly inherently ambiguous when said set of empty lines has changed),\n> > could even introduce a merge conflict in one order, but no conflict in the\n> > other.\n> >\n> > Even so, I think that merging in the order of the parents makes the most\n> > sense, and that using that strategy makes sense, too, because you really\n> > have to try hard to make it fail.\n> \n> Alternatively, consider to adopt the original approach that has none of\n> these issues as it uses exactly the same method for rebasing merge\n> commits that you are already using for rebasing simple commits, not to\n> mention the advantage of the built-in consistency check.\n\nSurely I misunderstand?\n\nHow can your approach -- which relies *very much* on having the original\nparent commits -- not *require* that consistency check?\n\nWhat would your approach (that still has no satisfyingly trivial\nexplanation, in my mind) do if somebody edited a `merge` command and let\nit merge a completely unrelated commit?\n\nCiao,\nJohannes\n"},{"id":"341189","messageId":"nycvar.QRO.7.76.6.1803070803360.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"77349f89-16c5-8f14-10da-e15381d11dc1@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T07:04:30Z","receivedAt":"2018-03-07T07:04:54Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Wed, 7 Mar 2018, Igor Djordjevic wrote:\n\n> On 05/03/2018 18:29, Johannes Schindelin wrote:\n> > \n> > > By the way, is there documentation for `git merge-recursive`\n> > > anywhere, besides the code itself...? :$\n> > \n> > I am not aware of any. The commit message adding the command is not very\n> > illuminating (https://github.com/git-for-windows/git/commit/720d150c4):\n> > \n> >     Add a new merge strategy by Fredrik Kuivinen.\n> > \n> >     I really wanted to try this out, instead of asking for an adjustment\n> >     to the 'git merge' driver and waiting.  For now the new strategy is\n> >     called 'fredrik' and not in the list of default strategies to be tried.\n> > \n> >     The script wants Python 2.4 so this commit also adjusts Debian and RPM\n> >     build procecure files.\n> > \n> > Digging through https://public-inbox.org/git/ during that time frame comes\n> > up with this hit, though:\n> > \n> > https://public-inbox.org/git/20050907164734.GA20198@c165.ib.student.liu.se/\n> > \n> > which is still not a good documentation of the algorithm. You can probably\n> > dig further yourself, but I think I can describe it very quickly here:\n> > \n> > To merge two commits recursively, you first have to find their \"merge\n> > bases\". If there was an obvious branch point, then that is the merge base.\n> > But when you start a branch off of master, then work a bit, then merge\n> > master, you already have two merge bases.\n> > \n> > The trick about the recursive merge is to reduce the number of merge bases\n> > iteratively to one. It does that by taking two merge bases, and performing\n> > a recursive merge on them, which generates a \"virtual\" commit, the\n> > condensed merge base. That one is then merged recursively with the next\n> > merge base, until there is only one left.\n> > \n> > A recursive merge of two commits with exactly one merge base is simply a\n> > three-way merge.\n> > \n> > I vaguely remember that there was something funny about the order in which\n> > order you want to process the merge bases: if you did it in one\n> > (chronological) direction, it worked beautifully, in the other direction\n> > it would generate tons of merge conflicts or something like that.\n> \n> Thanks, this is very informative (together with the linked discussion).\n> \n> Not remembering seeing this before, I wasn`t really sure if this was \n> some undocumented core Git (plumbing?) utility (used withing Git \n> itself, too), or just a leftover (yet still useful) sample tool.\n\nYou raise a good point. The \"recursive merge\" is not really documented\nproperly. Maybe you can enhance my vague description and provide a patch\nfor Documentation/technical/?\n\nThanks,\nDscho\n"},{"id":"341190","messageId":"nycvar.QRO.7.76.6.1803070804440.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqzi3k23fu.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T07:09:57Z","receivedAt":"2018-03-07T07:10:23Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 6 Mar 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> I don't think its possible to guess the semantics of the original merge\n> >> as users can use custom merge strategies and amend the result. It would\n> >> be possible to detect and unamended '-s ours' merge but special casing\n> >> that may end up causing users more confusion rather than helping them.\n> >\n> > FWIW I agree.\n> \n> I think it is a mistake to sacrifice predictability only to add\n> cleverness that sometimes work.  Elsewhere in the thread, I think I\n> saw an argument to treat interactive and non-interactive something\n> very different, but there is no fundamental difference between them\n> (it is far easier with interactive to force the command to \"port\"\n> each change to a vastly different context) so having consistent\n> behaviour between the two cases is important, too.\n\nI could be swayed both ways, but Buga already pointed out that we do not\nhave to compromise any consistency, simply by adding some syntactic sugar\nto the `merge` command so that the different behavior is *explicit*.\n\n> > My original plan was to always merge recursively and suggest to use `exec`\n> > commands if anything else is needed.\n> >\n> > But now with that excellent new idea to perform successive three-way\n> > merges of the original merge commit with the new tips, using the old tips\n> > as merge base, I am considering to change that.\n> \n> OK, does this mean we want to wait before merging the \"recreate\n> merge\" topic down to 'next'?  For more than a few weeks, it has been\n> slated for 'next'.\n\nMaybe a few more days.\n\nMy current thinking is to rework the handling of -c vs -C and *not* have\ntwo different todo_command enum values, but rather introduce an unsigned\ninteger that has flags such as TODO_MERGE_EDIT.\n\nAnd for this new behavior, we could introduce a new flag\n(TODO_MERGE_REBASE_MERGE_COMMIT or something less unwieldy) and set that\nflag via\n\n\tmerge -R -C <commit> <merge>...\n\n(i.e. via a new flag `-R`).\n\nI want to discuss this in the other subthread, though.\n\nCiao,\nDscho\n"},{"id":"341191","messageId":"nycvar.QRO.7.76.6.1803070810550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"754e2735-1288-9a8d-c8bd-ab39cf733812@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T07:26:32Z","receivedAt":"2018-03-07T07:26:57Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Tue, 6 Mar 2018, Igor Djordjevic wrote:\n\n> On 06/03/2018 19:12, Johannes Schindelin wrote:\n> > \n> > > > And I guess being consistent is pretty important, too - if you add new\n> > > > content during merge rebase, it should always show up in the merge,\n> > > > period. \n> > >\n> > > Yes, that should make it easy for the user to know what to expect from\n> > > rebase.\n> > \n> > [...]\n> > \n> > It will be slightly inconsistent. But in a defendable way, I think.\n> \n> I like where this discussion is heading, and here`s what I thought \n> about it :)\n> \n> [...]\n> \n> Here`s a twist - not letting `merge` trying to be too smart by \n> figuring out whether passed arguments correspond to rewritten \n> versions of the original merge parents (which would be too \n> restrictive, too, I`m afraid), but just be explicit about it, instead!\n\nThat's the missing piece, I think.\n\n> So, it could be something like:\n> \n> \tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n\nI like where this is heading, too, but I do not think that we can do this\non a per-MERGE_HEAD basis. The vast majority of merge commits, in\npractice, have two parents. So the `merge` command would actually only\nhave one revision to merge (because HEAD is the implicit first parent). So\nthat is easy.\n\nBut as soon as you go octopus, you can either perform an octopus merge, or\nrebase the original merge commit. You cannot really mix and match here.\n\nUnless we reimplement the octopus merge (which works quite a bit\ndifferently from the \"rebase merge commit\" strategy, even if it is\nincremental, too), which has its own challenges: if there are merge\nconflicts before merging the last MERGE_HEAD, the octopus merge will exit\nwith status 2, telling you \"Should not be doing an octopus.\". While we\nwill want to keep merge conflict markers and continue with the \"rebase the\noriginal merge commit\" strategy.\n\nAnd it would slam the door shut for adding support for *other* merge\nstrategies to perform a more-than-two-parents merge.\n\nAlso, I do not think that it makes a whole lot of sense in practice to let\nusers edit what will be used for \"original parent\". If the user wants to\ndo complicated stuff, they can already do that, via `exec`. The `merge`\ncommand really should be about facilitating common workflows, guiding the\nuser to what is sane.\n\nCurrently my favorite idea is to introduce a new flag: -R (for \"rebase the\noriginal merge commit\"). It would look like this:\n\n\tmerge -R -C <original-merge> <merge-head> # <oneline>\n\nThis flag would of course trigger the consistency check (does the number\nof parents of the original merge commit agree with the parameter list? Was\nan original merge commit specified to begin with?), and it would not fall\nback to the recursive merge, but error out if that check failed.\n\nSide note: I wonder whether we really need to perform the additional check\nthat ensures that the <merge-head> refers to the rewritten version of the\noriginal merge commit's parent.\n\nSecond side note: if we can fast-forward, currently we prefer that, and I\nthink we should keep that behavior with -R, too.\n\nIf the user wants to force a new merge, they simply remove that -R flag.\n\nWhat do you think?\n\nCiao,\nDscho\n"},{"id":"341201","messageId":"87vae8yq15.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803070742580.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-07T13:27:18Z","receivedAt":"2018-03-07T13:27:27Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Tue, 6 Mar 2018, Sergey Organov wrote:\n>\n>> This is v2 of my \"Rebasing merges\" proposal.\n>\n> Didn't we settle on Phillip's \"perform successive three-way merges between\n> the original merge commit and the new tips with the old tips as base\"\n> strategy?\n\nIt seems you did, dunno exactly why.\n\nThe main problem with this decision is that we still don't see how and\nwhen to stop for user amendment using this method. OTOH, the original\nhas this issue carefully discussed.\n\n> It has the following advantages:\n>\n> - it is *very simple* to describe\n\nThe original is as simple if not simpler:\n\n\"rebase sides of the merge commit and then three-way merge them back\nusing original merge commit as base\"\n\nNo problems with octopuses, and no virtual merge bases of recursive\nmerges to reason about.\n\n> - it is *very easy* to reason about, once it is pointed out that rebases\n>   and merges result in the same trees.\n\nThe original is as easy to reason about, if not easier, especially\nas recursive merge strategy is not being used there in new ways.\n\nI honestly don't see any advantages of Phillip's method over the\noriginal, except personal preferences. At the same time, I have no\nobjection of using it either, provided consistency check problem is\nsolved there as well.\n\n>\n> ... and BTW...\n>\n>> 3. I now use \"True Merge\" name instead of former \"Trivial Merge\", to\n>>    avoid confusion with what Git documentation calls \"trivial merge\",\n>>    thanks to Junio C Hamano <gitster@pobox.com> for pointing this out.\n>\n> \"True Merge\" is probably also a candidate for improvement. If what you\n> refer to is a \"true\" merge, that means all others are \"untrue\"\n> merges???\n\n[d]evil merges, obviously.\n\nSeriously, it's pure history joint. Just \"joint' will do.\n\n-- Sergey\n"},{"id":"341204","messageId":"nycvar.QRO.7.76.6.1803071450511.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87vae8yq15.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-07T14:08:41Z","receivedAt":"2018-03-07T14:08:53Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 7 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 6 Mar 2018, Sergey Organov wrote:\n> >\n> >> This is v2 of my \"Rebasing merges\" proposal.\n> >\n> > Didn't we settle on Phillip's \"perform successive three-way merges\n> > between the original merge commit and the new tips with the old tips\n> > as base\" strategy?\n> \n> It seems you did, dunno exactly why.\n\nThat is not true. You make it sound like I was the only one who liked\nthis, and not Phillip and Buga, too.\n\nAre you interested in the best solution, or in your solution :-)\n\n> The main problem with this decision is that we still don't see how and\n> when to stop for user amendment using this method. OTOH, the original\n> has this issue carefully discussed.\n\nWhy would we want to stop, unless there are merge conflicts?\n\n> > It has the following advantages:\n> >\n> > - it is *very simple* to describe\n> \n> The original is as simple if not simpler:\n> \n> \"rebase sides of the merge commit and then three-way merge them back\n> using original merge commit as base\"\n\nAnd that is also wrong, as I had proved already! Only Buga's addition made\nit robust against dropping/modifying commits, and that addition also makes\nit more complicated.\n\nAnd it still has no satisfactory simple explanation why it works.\n\n> No problems with octopuses, and no virtual merge bases of recursive\n> merges to reason about.\n\nBut those are no problems for Phillip's strategy, either!\n\nSo your point is...?\n\n> > - it is *very easy* to reason about, once it is pointed out that\n> > rebases and merges result in the same trees.\n> \n> The original is as easy to reason about, if not easier, especially as\n> recursive merge strategy is not being used there in new ways.\n\nSo do it. I still have to hear a single-sentence, clear and obvious\nexplanation why it works.\n\nAnd please do not describe why your original version works, because it\ndoes not work. Describe why the one amended with Buga's hack works.\n\n> I honestly don't see any advantages of Phillip's method over the\n> original, except personal preferences. At the same time, I have no\n> objection of using it either, provided consistency check problem is\n> solved there as well.\n\nOkay, let me reiterate then, because I do not want this point to be\nmissed:\n\nPhillip's method is essentially merging the new tips into the original\nmerge, pretending that the new tips were not rebased but merged into\nupstream.\n\nSo it exploits the duality of the rebase and merge operation, which both\nresult in identical trees (potentially after resolving merge conflicts).\n\nI cannot think of any such interpretation for your proposal augmented by\nBuga's fix-ups. And I haven't heard any such interpretation from your\nside, either.\n\n> >> 3. I now use \"True Merge\" name instead of former \"Trivial Merge\", to\n> >>    avoid confusion with what Git documentation calls \"trivial merge\",\n> >>    thanks to Junio C Hamano <gitster@pobox.com> for pointing this out.\n> >\n> > \"True Merge\" is probably also a candidate for improvement. If what you\n> > refer to is a \"true\" merge, that means all others are \"untrue\"\n> > merges???\n> \n> [d]evil merges, obviously.\n> \n> Seriously, it's pure history joint. Just \"joint' will do.\n\nYou might want to try harder to stick with the existing nomenclature. That\nwould make it a lot easier to discuss.\n\nCiao,\nJohannes\n"},{"id":"341206","messageId":"87ina8ymxs.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803070756550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-07T14:34:07Z","receivedAt":"2018-03-07T14:34:16Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Wed, 7 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > On Tue, 6 Mar 2018, Phillip Wood wrote:\n>> >\n>> >> On 03/03/18 00:29, Igor Djordjevic wrote:\n>> >> > \n>> >> > On 02/03/2018 12:31, Phillip Wood wrote:\n>> >> >>\n>> >> >>> Thinking about it overnight, I now suspect that original proposal\n>> >> >>> had a mistake in the final merge step. I think that what you did is\n>> >> >>> a way to fix it, and I want to try to figure what exactly was wrong\n>> >> >>> in the original proposal and to find simpler way of doing it right.\n>> >> >>>\n>> >> >>> The likely solution is to use original UM as a merge-base for final\n>> >> >>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty\n>> >> >>> natural though, as that's exactly UM from which both U1' and U2'\n>> >> >>> have diverged due to rebasing and other history editing.\n>> >> >>\n>> >> >> Hi Sergey, I've been following this discussion from the sidelines,\n>> >> >> though I haven't had time to study all the posts in this thread in\n>> >> >> detail. I wonder if it would be helpful to think of rebasing a merge\n>> >> >> as merging the changes in the parents due to the rebase back into the\n>> >> >> original merge. So for a merge M with parents A B C that are rebased\n>> >> >> to A' B' C' the rebased merge M' would be constructed by (ignoring\n>> >> >> shell quoting issues)\n>> >> >>\n>> >> >> git checkout --detach M\n>> >> >> git merge-recursive A -- M A'\n>> >> >> tree=$(git write-tree)\n>> >> >> git merge-recursive B -- $tree B'\n>> >> >> tree=$(git write-tree)\n>> >> >> git merge-recursive C -- $tree C'\n>> >> >> tree=$(git write-tree)\n>> >> >> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>> >> >>\n>> >> >> This should pull in all the changes from the parents while preserving\n>> >> >> any evil conflict resolution in the original merge. It superficially\n>> >> >> reminds me of incremental merging [1] but it's so long since I looked at\n>> >> >> that I'm not sure if there are any significant similarities.\n>> >> >>\n>> >> >> [1] https://github.com/mhagger/git-imerge\n>> >> > \n>> >> > Interesting, from quick test[3], this seems to produce the same \n>> >> > result as that other test I previously provided[2], where temporary \n>> >> > commits U1' and U2' are finally merged with original M as a base :)\n>> >> > \n>> >> > Just that this looks like even more straight-forward approach...?\n>> >> > \n>> >> > The only thing I wonder of here is how would we check if the \n>> >> > \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n>> >> > With that other approach Sergey described, we have U1'==U2' to test with.\n>> >> \n>> >> I think (though I haven't rigorously proved to myself) that in the\n>> >> absence of conflicts this scheme has well defined semantics (the merges\n>> >> can be commuted), so the result should be predicable from the users\n>> >> point of view so maybe it could just offer an option to stop.\n>> >\n>> > I am not so sure that the result is independent of the order of the\n>> > merges. In other words, I am not necessarily certain that it is impossible\n>> > to concoct A,A',B,B' commits where merging B'/B before A'/A has a\n>> > different result than merging A'/A before B'/B.\n>> >\n>> > Remember, when constructing counter-examples to hypotheses, those\n>> > counter-examples do not really *have* to make sense on their own. For\n>> > example, A' could introduce *completely different* changes from A, and the\n>> > same is true for B' and B.\n>> >\n>> > I could imagine, for example, that using a ton of consecutive empty lines,\n>> > and using patches that insert something into these empty lines (and are\n>> > thusly inherently ambiguous when said set of empty lines has changed),\n>> > could even introduce a merge conflict in one order, but no conflict in the\n>> > other.\n>> >\n>> > Even so, I think that merging in the order of the parents makes the most\n>> > sense, and that using that strategy makes sense, too, because you really\n>> > have to try hard to make it fail.\n>> \n>> Alternatively, consider to adopt the original approach that has none of\n>> these issues as it uses exactly the same method for rebasing merge\n>> commits that you are already using for rebasing simple commits, not to\n>> mention the advantage of the built-in consistency check.\n>\n> Surely I misunderstand?\n>\n> How can your approach -- which relies *very much* on having the original\n> parent commits -- not *require* that consistency check?\n\nI don't understand what you mean, sorry. Could you please point me\nto the *require* you talk about in the original proposal?\n\n> What would your approach (that still has no satisfyingly trivial\n> explanation, in my mind)\n\nHere is one-liner: rebase sides of the merge commit and then 3-way\nmerge them, using original merge commit as merge base.\n\n> do if somebody edited a `merge` command and let it merge a completely\n> unrelated commit?\n\nDon't see a problem, sorry. The method should still work, provided you have\noriginal merge commit and two new parents for the new merge.\n\nYou rebase sides of original merge to the new parents, then 3-way merge\nthe results using original merge as base.\n\nOnce again, if you can rebase simple commit, the method allows to rebase\nthe merge either.\n\n-- Sergey\n"},{"id":"341208","messageId":"87vae7ykys.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803071450511.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-07T15:16:43Z","receivedAt":"2018-03-07T15:16:52Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Sergey,\n>\n> On Wed, 7 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > On Tue, 6 Mar 2018, Sergey Organov wrote:\n>> >\n>> >> This is v2 of my \"Rebasing merges\" proposal.\n>> >\n>> > Didn't we settle on Phillip's \"perform successive three-way merges\n>> > between the original merge commit and the new tips with the old tips\n>> > as base\" strategy?\n>> \n>> It seems you did, dunno exactly why.\n>\n> That is not true. You make it sound like I was the only one who liked\n> this, and not Phillip and Buga, too.\n>\n> Are you interested in the best solution, or in your solution :-)\n\nI'm interested in any that works, and only you say that those suggested\nby Phillip is somehow superior. I still believe it's mine that superior,\neven if slightly.\n\n>\n>> The main problem with this decision is that we still don't see how and\n>> when to stop for user amendment using this method. OTOH, the original\n>> has this issue carefully discussed.\n>\n> Why would we want to stop, unless there are merge conflicts?\n\nThere is somewhat lengthy discussion about it that you probably missed.\nNot to repeat it, just see how 'rerere' works when it fires during\nrebase, even with no conflicts.\n\n>\n>> > It has the following advantages:\n>> >\n>> > - it is *very simple* to describe\n>> \n>> The original is as simple if not simpler:\n>> \n>> \"rebase sides of the merge commit and then three-way merge them back\n>> using original merge commit as base\"\n>\n> And that is also wrong, as I had proved already! Only Buga's addition made\n> it robust against dropping/modifying commits, and that addition also makes\n> it more complicated.\n\nNo. Get your facts straight. The [RFC v2] already fixed that original\nmistake. Could you please finally read it?\n\n> And it still has no satisfactory simple explanation why it works.\n\nIt has. It's there in the [RFC v2]. You seem to be the only one who\ndoesn't get it. I suppose you just didn't bother to read.\n\n>> No problems with octopuses, and no virtual merge bases of recursive\n>> merges to reason about.\n>\n> But those are no problems for Phillip's strategy, either!\n\nI thought it was you who started to discuss virtual merge bases and\nrelated problems, as well as how it's difficult to support octopus\nmerges, but it's fine with me if there are none of these problems.\n\n>\n> So your point is...?\n\nStill the same -- use what's better, the [RFC v2].\n\n>\n>> > - it is *very easy* to reason about, once it is pointed out that\n>> > rebases and merges result in the same trees.\n>> \n>> The original is as easy to reason about, if not easier, especially as\n>> recursive merge strategy is not being used there in new ways.\n>\n> So do it. I still have to hear a single-sentence, clear and obvious\n> explanation why it works.\n>\n> And please do not describe why your original version works, because it\n> does not work.\n\nOriginal [RFC] didn't work because of rather simple mistake that I've\nalready admitted and fixed. [RFC v2] has got the fix. Read [RFC v2] and\nget your facts straight.\n\n> Describe why the one amended with Buga's hack works.\n\nIt doesn't matter as these hacks are not needed anymore.\n\n>\n>> I honestly don't see any advantages of Phillip's method over the\n>> original, except personal preferences. At the same time, I have no\n>> objection of using it either, provided consistency check problem is\n>> solved there as well.\n>\n> Okay, let me reiterate then, because I do not want this point to be\n> missed:\n>\n> Phillip's method is essentially merging the new tips into the original\n> merge, pretending that the new tips were not rebased but merged into\n> upstream.\n>\n> So it exploits the duality of the rebase and merge operation, which both\n> result in identical trees (potentially after resolving merge\n> conflicts).\n>\n> I cannot think of any such interpretation for your proposal augmented by\n> Buga's fix-ups. And I haven't heard any such interpretation from your\n> side, either.\n\nNo fix-ups or augmentations are needed. It was a mistake that has been\nfixed in [RFC v2]. You've missed essential part of the discussion.\n\nRead the [RFC v2], please:\n\nSignificant changes are:\n\n1. Fixed mistake in the final merge step in the original proposal: wrong\n   merge base was used.\n\n-- Sergey\n"},{"id":"341222","messageId":"xmqqh8pr21f3.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803070804440.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-07T18:20:00Z","receivedAt":"2018-03-07T18:20:09Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> OK, does this mean we want to wait before merging the \"recreate\n>> merge\" topic down to 'next'?  For more than a few weeks, it has been\n>> slated for 'next'.\n>\n> Maybe a few more days.\n> ...\n> I want to discuss this in the other subthread, though.\n\nIf we are talking about a drastic change, a few more days may not be\nsufficient, but we are not in a hurry, as this already sounds like a\n2.18 material anyway.  As you made it clear that it is OK not to\nmerge the current one for now, my objective of asking the question\nis already satisfied ;-)\n\n"},{"id":"341252","messageId":"nycvar.QRO.7.76.6.1803080741160.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87ina8ymxs.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-08T06:45:51Z","receivedAt":"2018-03-08T06:46:08Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 7 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > How can your approach -- which relies *very much* on having the\n> > original parent commits -- not *require* that consistency check?\n> \n> I don't understand what you mean, sorry. Could you please point me to\n> the *require* you talk about in the original proposal?\n\nImagine a todo list that contains this line\n\n\tmerge -C abcdef 123456\n\nand now the user edits it (this is an interactive rebase, after all),\nadding another merge head:\n\n\tmerge -C abcdef 987654 123456\n\nNow your strategy would have a serious problem: to find the original\nversion of 987654. If there was one.\n\n> > What would your approach (that still has no satisfyingly trivial\n> > explanation, in my mind)\n> \n> Here is one-liner: rebase sides of the merge commit and then 3-way\n> merge them, using original merge commit as merge base.\n\nBut I already pointed out how that would undo a commit having been\ndropped.\n\n> > do if somebody edited a `merge` command and let it merge a completely\n> > unrelated commit?\n> \n> Don't see a problem, sorry. The method should still work, provided you have\n> original merge commit and two new parents for the new merge.\n\nThat is assuming a lot. That is exactly what this consistency check is\nfor, that I mentioned earlier, and which you listed as a downside of\nPhillip's strategy (forgetting that your strategy has the same downside,\nso...).\n\nBut I guess that you are still talking about the non-interactive version\nof the rebase, and missed that our conversation proceeded to the point\nwhere we want that same strategy to work *also* in the interactive version\n(and not have a completely different functionality depending whether you\nuse --interactive or not)?\n\nCiao,\nJohannes\n"},{"id":"341253","messageId":"nycvar.QRO.7.76.6.1803080746460.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87vae7ykys.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-08T07:01:08Z","receivedAt":"2018-03-08T07:01:50Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 7 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >\n> > On Wed, 7 Mar 2018, Sergey Organov wrote:\n> >\n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> \n> >> > On Tue, 6 Mar 2018, Sergey Organov wrote:\n> >> >\n> >> >> This is v2 of my \"Rebasing merges\" proposal.\n> >> >\n> >> > Didn't we settle on Phillip's \"perform successive three-way merges\n> >> > between the original merge commit and the new tips with the old\n> >> > tips as base\" strategy?\n> >> \n> >> It seems you did, dunno exactly why.\n> >\n> > That is not true. You make it sound like I was the only one who liked\n> > this, and not Phillip and Buga, too.\n> >\n> > Are you interested in the best solution, or in your solution :-)\n> \n> I'm interested in any that works, and only you say that those suggested\n> by Phillip is somehow superior. I still believe it's mine that superior,\n> even if slightly.\n\nThat is misrepresenting what happened.\n\nFirst, you came up with a strategy. I pointed out shortcomings that\nimplied that we cannot use it unchanged. Then, Buga fixed your strategy by\nusing additional steps (making the process more complicated than before,\nstill without a simple-enough explanation for my liking, fixing the\nshortcomings). Then, Phillip presented a super-simple strategy and Buga\nconfirmed that it also fixes the shortcomings I pointed out.\n\nI am very excited that we finally found something that works *and* is easy\nto reason about.\n\nLet's focus on that strategy rather than going back to the strategy which\nhas known flaws and only an unsatisfyingly complex explanation.\n\n> >> The main problem with this decision is that we still don't see how\n> >> and when to stop for user amendment using this method. OTOH, the\n> >> original has this issue carefully discussed.\n> >\n> > Why would we want to stop, unless there are merge conflicts?\n> \n> There is somewhat lengthy discussion about it that you probably missed.\n> Not to repeat it, just see how 'rerere' works when it fires during\n> rebase, even with no conflicts.\n\nI did not miss that discussion. My question was a follow-up: Why would we\nwant to stop, unless there are merge conflicts?\n\n> >> > It has the following advantages:\n> >> >\n> >> > - it is *very simple* to describe\n> >> \n> >> The original is as simple if not simpler:\n> >> \n> >> \"rebase sides of the merge commit and then three-way merge them back\n> >> using original merge commit as base\"\n> >\n> > And that is also wrong, as I had proved already! Only Buga's addition made\n> > it robust against dropping/modifying commits, and that addition also makes\n> > it more complicated.\n> \n> No. Get your facts straight. The [RFC v2] already fixed that original\n> mistake. Could you please finally read it?\n\nI do not see Buga's additions, and it is still a lengthy document that is\nhard to understand.\n\nPhillip's alternative, in contrast, fit in at most two 80x25 pages and was\nintuitive (at least after seeing that the tree resulting from a merge is\nidentical to the tree resulting from a rebase, once all merge conflicts\nare handled appropriately).\n\n> > And it still has no satisfactory simple explanation why it works.\n> \n> It has. It's there in the [RFC v2]. You seem to be the only one who\n> doesn't get it. I suppose you just didn't bother to read.\n\nI tried to read it, and got lost in all those figures that really do not\ndo anything to make this strategy obvious to me.\n\nGranted, I now know *how* it works.\n\nI gave up understanding *why* it is supposed to work.\n\nWith Phillip's mail, it only took me 5 minutes to get a rudimentary\nunderstanding why it works.\n\n> >> No problems with octopuses, and no virtual merge bases of recursive\n> >> merges to reason about.\n> >\n> > But those are no problems for Phillip's strategy, either!\n> \n> I thought it was you who started to discuss virtual merge bases and\n> related problems, as well as how it's difficult to support octopus\n> merges, but it's fine with me if there are none of these problems.\n\nYes, I started explaining virtual merge bases, and how they are used in\nthe recursive merge. Because I was asked how the recursive merge works,\nand I happen to know how it works very intimately.\n\n> > So your point is...?\n> \n> Still the same -- use what's better, the [RFC v2].\n\nI strongly disagree that your approach is superior. It is more complex,\nand still has no simple answer to the question \"why is this supposed to do\nwhat I want it to do?\"\n\nIt does a lot of criss-crossing, and when I see that, I immediately\nsuspect that it would lose information e.g. when commits were amended\nduring the rebase. There are just way too many paths for obsolete changes\nto creep in again.\n\n> >> > - it is *very easy* to reason about, once it is pointed out that\n> >> > rebases and merges result in the same trees.\n> >> \n> >> The original is as easy to reason about, if not easier, especially as\n> >> recursive merge strategy is not being used there in new ways.\n> >\n> > So do it. I still have to hear a single-sentence, clear and obvious\n> > explanation why it works.\n\nPlease.\n\n> > And please do not describe why your original version works, because it\n> > does not work.\n> \n> Original [RFC] didn't work because of rather simple mistake that I've\n> already admitted and fixed. [RFC v2] has got the fix. Read [RFC v2] and\n> get your facts straight.\n\nI don't care how many mistakes you made, and where the original ideas had\nto be enhanced. I am only interested in the outcome.\n\nWe already have a nice, simple outcome, and to be quite honest: I find\nthis discussion here a bit pointless. Why would I abandon a simple\nstrategy that obviously works for a complex strategy where it still is not\nobvious under what circumstances it works, and why?\n\n> > Describe why the one amended with Buga's hack works.\n> \n> It doesn't matter as these hacks are not needed anymore.\n\nSo maybe you want to also describe the \"interdiff\", and not expect anybody\nto read two lengthy documents and figure out where the changes are.\n\n> >> I honestly don't see any advantages of Phillip's method over the\n> >> original, except personal preferences. At the same time, I have no\n> >> objection of using it either, provided consistency check problem is\n> >> solved there as well.\n> >\n> > Okay, let me reiterate then, because I do not want this point to be\n> > missed:\n> >\n> > Phillip's method is essentially merging the new tips into the original\n> > merge, pretending that the new tips were not rebased but merged into\n> > upstream.\n> >\n> > So it exploits the duality of the rebase and merge operation, which both\n> > result in identical trees (potentially after resolving merge\n> > conflicts).\n> >\n> > I cannot think of any such interpretation for your proposal augmented by\n> > Buga's fix-ups. And I haven't heard any such interpretation from your\n> > side, either.\n> \n> No fix-ups or augmentations are needed. It was a mistake that has been\n> fixed in [RFC v2]. You've missed essential part of the discussion.\n> \n> Read the [RFC v2], please:\n\nOkay, I am done here. If all my questions and all my concerns are answered\nwith the suggestion to spend an hour pouring over a lengthy description of\nyour strategy that is so much more complex than my preferred alternative,\nasking me to figure out from that long document what the answers to my\nquestions are, then I respectfully decline. I do have other things to care\nabout, too, and I will *not* spend an hour trying to figure out answers\nonly because you refuse to give them directly.\n\nCiao,\nJohannes\n"},{"id":"341254","messageId":"nycvar.QRO.7.76.6.1803080801230.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqh8pr21f3.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-08T07:03:32Z","receivedAt":"2018-03-08T07:03:50Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Wed, 7 Mar 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> OK, does this mean we want to wait before merging the \"recreate\n> >> merge\" topic down to 'next'?  For more than a few weeks, it has been\n> >> slated for 'next'.\n> >\n> > Maybe a few more days.\n> > ...\n> > I want to discuss this in the other subthread, though.\n> \n> If we are talking about a drastic change, a few more days may not be\n> sufficient, but we are not in a hurry, as this already sounds like a\n> 2.18 material anyway.\n\nIt is not at all a drastic change. It will actually make the current patch\nseries better (simplifying the \"can we fast-forward?\" check).\n\nI just want to make sure that I already have Phillip's strategy working,\nbut it will be yet another topic branch on top of the topic branch that\nwill add support for octopus merges *after* the current --recreate-merges\ntopic branch ;-)\n\n> As you made it clear that it is OK not to merge the current one for now,\n> my objective of asking the question is already satisfied ;-)\n\nDepending how much GitMerge will occupy my time, I hope to have something\npolished by tomorrow.\n\nCiao,\nDscho\n"},{"id":"341255","messageId":"nycvar.QRO.7.76.6.1803080804420.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqwoyp5eig.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-08T07:05:41Z","receivedAt":"2018-03-08T07:06:16Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 6 Mar 2018, Junio C Hamano wrote:\n\n> Phillip Wood <phillip.wood@talktalk.net> writes:\n> \n> > I wonder if just having a predicable result rather than forcing the\n> > rebase to stop if the user just squashes a fixup commit into a topic\n> > branch that is the parent of a merge might be more convenient in\n> > practice.\n> \n> Unless I am misunderstanding what you are saying, that is pretty much\n> what I have automated for my daily rebuild of the 'pu' branch\n> \n> Non-textual semantic conflicts are made (in the best case just once)\n> as a separate commit on top of mechanical auto-merge whose focus is\n> predictability (rather than cleverness) done by Git, and then that\n> separate commit is kept outside the history.  When replaying these\n> merges to rebuild the 'pu' branch, after resetting the tip to\n> 'master', each topic is merged mechanically, and if such a fix-up\n> commit is present, \"cherry-pick --no-commit\" applies it and then\n> \"commit --amend --no-edit\" to adjust the merge.  I find it quite\n> valuable to have a separate record of what \"evil\" non-mechanical\n> adjustment was done, which I know won't be lost in the noise when\n> these merges need to be redone daily or more often.\n\nSo essentially, you have something that `git rerere` would have learned,\nbut as a commit?\n\nMight make sense to make that procedure more accessible to others, too ;-)\nI know that *I* would use it.\n\nCiao,\nDscho\n"},{"id":"341256","messageId":"xmqqfu5bx9zd.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803080801230.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-08T08:11:34Z","receivedAt":"2018-03-08T08:11:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> If we are talking about a drastic change, a few more days may not be\n>> sufficient, but we are not in a hurry, as this already sounds like a\n>> 2.18 material anyway.\n>\n> It is not at all a drastic change. It will actually make the current patch\n> series better (simplifying the \"can we fast-forward?\" check).\n>\n> I just want to make sure that I already have Phillip's strategy working,\n> but it will be yet another topic branch on top of the topic branch that\n> will add support for octopus merges *after* the current --recreate-merges\n> topic branch ;-)\n\nOh, if the \"not redoing the merge afresh, but attempt to reuse the\nprevious merge\" that was discussed is going to be done as an\nupdate/addition to the \"redo the merge afresh\" you already had in\nproduction forever (and I had in 'pu' for quite a while in various\npolished-ness during iteration), then I do prefer merging down what\nhas already proven to be 'next' worthy without waiting for the\ndiscussion and your local verification of Phillip's new thing,\nespecially given that you'll be giving an explicit control to the\nusers which variant of \"merge\" insn will be used and the addition\nof the Phillip's thing won't be a backward-compatibility issue when\nit comes later.\n\n>> As you made it clear that it is OK not to merge the current one for now,\n>> my objective of asking the question is already satisfied ;-)\n>\n> Depending how much GitMerge will occupy my time, I hope to have something\n> polished by tomorrow.\n\nMy \"for now\" above was just for the coming few days.  Don't rush\nthings, and use valuable in-person time wisely, and have fun.\n\nThanks.\n\n"},{"id":"341257","messageId":"xmqqbmfzx9n0.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803080804420.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-08T08:18:59Z","receivedAt":"2018-03-08T08:19:06Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Non-textual semantic conflicts are made (in the best case just once)\n>> as a separate commit on top of mechanical auto-merge whose focus is\n>> predictability (rather than cleverness) done by Git, and then that\n>> separate commit is kept outside the history.  When replaying these\n>> merges to rebuild the 'pu' branch, after resetting the tip to\n>> 'master', each topic is merged mechanically, and if such a fix-up\n>> commit is present, \"cherry-pick --no-commit\" applies it and then\n>> \"commit --amend --no-edit\" to adjust the merge.  I find it quite\n>> valuable to have a separate record of what \"evil\" non-mechanical\n>> adjustment was done, which I know won't be lost in the noise when\n>> these merges need to be redone daily or more often.\n>\n> So essentially, you have something that `git rerere` would have learned,\n> but as a commit?\n\nYou probably wouldn't be asking that if you read what you cut out\nwhen you quoted above ;-) \n\nThere are a collection of cherry-pickable commits in hierarchy under\nrefs/merge-fix.  They are indexed by the branch that will cause\nsemantic conflicts that do not involve textual conflicts at all (the\nimportant implication of which is that 'rerere' fundamentally will\nnot trigger to help resolving them) [*1*], and are used to create\nevil merge when a corresponding branch is merged to 'pu' (and down).\n\n[Footnote]\n\n*1* One topic adds an extra parameter to read_index_from() that has\nbeen and still is defined in a file and merged to 'pu' first, while\nanother topic adds a new callsite for the same function in a file\nthat the former topic does not touch, hence a merge of the latter\ntopic has no textual conflict to the file with a new callsite, but\nstill needs adjusting.  That sort of think.\n"},{"id":"341267","messageId":"aef84393-d980-81b3-8d8f-3525819bcdc3@talktalk.net","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803061829460.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-08T11:08:25Z","receivedAt":"2018-03-08T11:08:34Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 06/03/18 18:12, Johannes Schindelin wrote:\n> Hi Phillip,\n> \n> On Tue, 6 Mar 2018, Phillip Wood wrote:\n> \n>> On 03/03/18 00:29, Igor Djordjevic wrote:\n>>>\n>>> On 02/03/2018 12:31, Phillip Wood wrote:\n>>>>\n>>>>> Thinking about it overnight, I now suspect that original proposal\n>>>>> had a mistake in the final merge step. I think that what you did is\n>>>>> a way to fix it, and I want to try to figure what exactly was wrong\n>>>>> in the original proposal and to find simpler way of doing it right.\n>>>>>\n>>>>> The likely solution is to use original UM as a merge-base for final\n>>>>> 3-way merge of U1' and U2', but I'm not sure yet. Sounds pretty\n>>>>> natural though, as that's exactly UM from which both U1' and U2'\n>>>>> have diverged due to rebasing and other history editing.\n>>>>\n>>>> Hi Sergey, I've been following this discussion from the sidelines,\n>>>> though I haven't had time to study all the posts in this thread in\n>>>> detail. I wonder if it would be helpful to think of rebasing a merge\n>>>> as merging the changes in the parents due to the rebase back into the\n>>>> original merge. So for a merge M with parents A B C that are rebased\n>>>> to A' B' C' the rebased merge M' would be constructed by (ignoring\n>>>> shell quoting issues)\n>>>>\n>>>> git checkout --detach M\n>>>> git merge-recursive A -- M A'\n>>>> tree=$(git write-tree)\n>>>> git merge-recursive B -- $tree B'\n>>>> tree=$(git write-tree)\n>>>> git merge-recursive C -- $tree C'\n>>>> tree=$(git write-tree)\n>>>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>>>>\n>>>> This should pull in all the changes from the parents while preserving\n>>>> any evil conflict resolution in the original merge. It superficially\n>>>> reminds me of incremental merging [1] but it's so long since I looked at\n>>>> that I'm not sure if there are any significant similarities.\n>>>>\n>>>> [1] https://github.com/mhagger/git-imerge\n>>>\n>>> Interesting, from quick test[3], this seems to produce the same \n>>> result as that other test I previously provided[2], where temporary \n>>> commits U1' and U2' are finally merged with original M as a base :)\n>>>\n>>> Just that this looks like even more straight-forward approach...?\n>>>\n>>> The only thing I wonder of here is how would we check if the \n>>> \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n>>> With that other approach Sergey described, we have U1'==U2' to test with.\n>>\n>> I think (though I haven't rigorously proved to myself) that in the\n>> absence of conflicts this scheme has well defined semantics (the merges\n>> can be commuted), so the result should be predicable from the users\n>> point of view so maybe it could just offer an option to stop.\n> \n> I am not so sure that the result is independent of the order of the\n> merges. In other words, I am not necessarily certain that it is impossible\n> to concoct A,A',B,B' commits where merging B'/B before A'/A has a\n> different result than merging A'/A before B'/B.\n> \n> Remember, when constructing counter-examples to hypotheses, those\n> counter-examples do not really *have* to make sense on their own. For\n> example, A' could introduce *completely different* changes from A, and the\n> same is true for B' and B.\n> \n> I could imagine, for example, that using a ton of consecutive empty lines,\n> and using patches that insert something into these empty lines (and are\n> thusly inherently ambiguous when said set of empty lines has changed),\n> could even introduce a merge conflict in one order, but no conflict in the\n> other.\n\nYes I should have thought of that given I've just been working on making\n'add -p' more robust when there are lots of identical lines.\n\n> Even so, I think that merging in the order of the parents makes the most\n> sense, and that using that strategy makes sense, too, because you really\n> have to try hard to make it fail.\n> \n> Ciao,\n> Dscho\n> \n\n"},{"id":"341268","messageId":"c5a5c2cc-6a11-440f-5b9b-964ae1ca07dd@talktalk.net","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803070810550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-08T11:20:33Z","receivedAt":"2018-03-08T11:20:42Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 07/03/18 07:26, Johannes Schindelin wrote:\n> Hi Buga,\n> \n> On Tue, 6 Mar 2018, Igor Djordjevic wrote:\n> \n>> On 06/03/2018 19:12, Johannes Schindelin wrote:\n>>>\n>>>>> And I guess being consistent is pretty important, too - if you add new\n>>>>> content during merge rebase, it should always show up in the merge,\n>>>>> period. \n>>>>\n>>>> Yes, that should make it easy for the user to know what to expect from\n>>>> rebase.\n>>>\n>>> [...]\n>>>\n>>> It will be slightly inconsistent. But in a defendable way, I think.\n>>\n>> I like where this discussion is heading, and here`s what I thought \n>> about it :)\n>>\n>> [...]\n>>\n>> Here`s a twist - not letting `merge` trying to be too smart by \n>> figuring out whether passed arguments correspond to rewritten \n>> versions of the original merge parents (which would be too \n>> restrictive, too, I`m afraid), but just be explicit about it, instead!\n> \n> That's the missing piece, I think.\n> \n>> So, it could be something like:\n>>\n>> \tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n> \n> I like where this is heading, too, but I do not think that we can do this\n> on a per-MERGE_HEAD basis. The vast majority of merge commits, in\n> practice, have two parents. So the `merge` command would actually only\n> have one revision to merge (because HEAD is the implicit first parent). So\n> that is easy.\n> \n> But as soon as you go octopus, you can either perform an octopus merge, or\n> rebase the original merge commit. You cannot really mix and match here.\n> \n> Unless we reimplement the octopus merge (which works quite a bit\n> differently from the \"rebase merge commit\" strategy, even if it is\n> incremental, too), which has its own challenges: if there are merge\n> conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n> with status 2, telling you \"Should not be doing an octopus.\". While we\n> will want to keep merge conflict markers and continue with the \"rebase the\n> original merge commit\" strategy.\n> \n> And it would slam the door shut for adding support for *other* merge\n> strategies to perform a more-than-two-parents merge.\n> \n> Also, I do not think that it makes a whole lot of sense in practice to let\n> users edit what will be used for \"original parent\". If the user wants to\n> do complicated stuff, they can already do that, via `exec`. The `merge`\n> command really should be about facilitating common workflows, guiding the\n> user to what is sane.\n> \n> Currently my favorite idea is to introduce a new flag: -R (for \"rebase the\n> original merge commit\"). It would look like this:\n> \n> \tmerge -R -C <original-merge> <merge-head> # <oneline>\n>\n> This flag would of course trigger the consistency check (does the number\n> of parents of the original merge commit agree with the parameter list? Was\n> an original merge commit specified to begin with?), and it would not fall\n> back to the recursive merge, but error out if that check failed.\n> \n> Side note: I wonder whether we really need to perform the additional check\n> that ensures that the <merge-head> refers to the rewritten version of the\n> original merge commit's parent.\n> \n> Second side note: if we can fast-forward, currently we prefer that, and I\n> think we should keep that behavior with -R, too.\n\nI think that would be a good idea to avoid unpleasant surprises.\n\n> If the user wants to force a new merge, they simply remove that -R flag.\n> \n> What do you think?\n\nI did wonder about using 'pick <original-merge>' for rebasing merges and\nkeeping 'merge ...' for recreating them but I'm not sure if that is a\ngood idea. It has the advantage that the user cannot specify the wrong\nparents for the merge to be rebased as 'git rebase' would work out if\nthe parents have been rebased, but maybe it's a bit magical to use pick\nfor merge commits. Also there isn't such a simple way for the user to go\nfrom 'rabase this merge' to 'recreate this merge' as they'd have to\nwrite the whole merge line themselves (though I guess something like\nemacs' git-rebase.el would be able to help with that)\n\nBest Wishes\n\nPhillip\n\n\n> Ciao,\n> Dscho\n> \n\n"},{"id":"341283","messageId":"483674f8-4097-a374-c8f3-cf56cbb92042@talktalk.net","threadId":"47864","inReplyTo":"c5a5c2cc-6a11-440f-5b9b-964ae1ca07dd@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Phillip Wood","fromEmail":"phillip.wood@talktalk.net","sentAt":"2018-03-08T12:16:41Z","receivedAt":"2018-03-08T12:16:49Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 08/03/18 11:20, Phillip Wood wrote:\n> On 07/03/18 07:26, Johannes Schindelin wrote:\n>> Hi Buga,\n>>\n>> On Tue, 6 Mar 2018, Igor Djordjevic wrote:\n>>\n>>> On 06/03/2018 19:12, Johannes Schindelin wrote:\n>>>>\n>>>>>> And I guess being consistent is pretty important, too - if you add new\n>>>>>> content during merge rebase, it should always show up in the merge,\n>>>>>> period. \n>>>>>\n>>>>> Yes, that should make it easy for the user to know what to expect from\n>>>>> rebase.\n>>>>\n>>>> [...]\n>>>>\n>>>> It will be slightly inconsistent. But in a defendable way, I think.\n>>>\n>>> I like where this discussion is heading, and here`s what I thought \n>>> about it :)\n>>>\n>>> [...]\n>>>\n>>> Here`s a twist - not letting `merge` trying to be too smart by \n>>> figuring out whether passed arguments correspond to rewritten \n>>> versions of the original merge parents (which would be too \n>>> restrictive, too, I`m afraid), but just be explicit about it, instead!\n>>\n>> That's the missing piece, I think.\n>>\n>>> So, it could be something like:\n>>>\n>>> \tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n>>\n>> I like where this is heading, too, but I do not think that we can do this\n>> on a per-MERGE_HEAD basis. The vast majority of merge commits, in\n>> practice, have two parents. So the `merge` command would actually only\n>> have one revision to merge (because HEAD is the implicit first parent). So\n>> that is easy.\n>>\n>> But as soon as you go octopus, you can either perform an octopus merge, or\n>> rebase the original merge commit. You cannot really mix and match here.\n>>\n>> Unless we reimplement the octopus merge (which works quite a bit\n>> differently from the \"rebase merge commit\" strategy, even if it is\n>> incremental, too), which has its own challenges: if there are merge\n>> conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n>> with status 2, telling you \"Should not be doing an octopus.\". While we\n>> will want to keep merge conflict markers and continue with the \"rebase the\n>> original merge commit\" strategy.\n>>\n>> And it would slam the door shut for adding support for *other* merge\n>> strategies to perform a more-than-two-parents merge.\n>>\n>> Also, I do not think that it makes a whole lot of sense in practice to let\n>> users edit what will be used for \"original parent\". If the user wants to\n>> do complicated stuff, they can already do that, via `exec`. The `merge`\n>> command really should be about facilitating common workflows, guiding the\n>> user to what is sane.\n>>\n>> Currently my favorite idea is to introduce a new flag: -R (for \"rebase the\n>> original merge commit\"). It would look like this:\n>>\n>> \tmerge -R -C <original-merge> <merge-head> # <oneline>\n>>\n>> This flag would of course trigger the consistency check (does the number\n>> of parents of the original merge commit agree with the parameter list? Was\n>> an original merge commit specified to begin with?), and it would not fall\n>> back to the recursive merge, but error out if that check failed.\n>>\n>> Side note: I wonder whether we really need to perform the additional check\n>> that ensures that the <merge-head> refers to the rewritten version of the\n>> original merge commit's parent.\n>>\n>> Second side note: if we can fast-forward, currently we prefer that, and I\n>> think we should keep that behavior with -R, too.\n> \n> I think that would be a good idea to avoid unpleasant surprises.\n\nOops that was referring to the first side note. I think fast forwarding\nis a good idea. I'm not so sure about checking that <merge-head> refers\nto the rewritten version of the original merge commit's parent any more\nthough. Having thought some more, I think we would want to allow the\nuser to rearrange a topic branch that is the parent of a merge and that\nwould require allowing a different parent as the old parent could be\ndropped or swapped with another commit in the branch. I can't think of a\nway to mechanically check that the new parent is 'somehow derived from'\nthe old one.\n\n>> If the user wants to force a new merge, they simply remove that -R flag.\n>>\n>> What do you think?\n> \n> I did wonder about using 'pick <original-merge>' for rebasing merges and\n> keeping 'merge ...' for recreating them but I'm not sure if that is a\n> good idea. It has the advantage that the user cannot specify the wrong\n> parents for the merge to be rebased as 'git rebase' would work out if\n> the parents have been rebased, but maybe it's a bit magical to use pick\n> for merge commits. Also there isn't such a simple way for the user to go\n> from 'rabase this merge' to 'recreate this merge' as they'd have to\n> write the whole merge line themselves (though I guess something like\n> emacs' git-rebase.el would be able to help with that)\n\nScrub that, it is too magical and I don't think it would work with\nrearranged commits - it's making the --preserve-merges mistake all over\nagain. It's a shame to have 'merge' mean 'recreate the merge' and\n'rebase the merge' but I don't think there is an easy way round that.\n\n> Best Wishes\n> \n> Phillip\n> \n> \n>> Ciao,\n>> Dscho\n>>\n> \n\n"},{"id":"341291","messageId":"2749ce78-8917-c821-6116-0c8d67b5e16e@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803070810550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T15:16:33Z","receivedAt":"2018-03-08T15:16:51Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 07/03/2018 08:26, Johannes Schindelin wrote:\n> \n> > So, it could be something like:\n> >\n> > \tmerge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n> \n> I like where this is heading, too, but I do not think that we can do this\n> on a per-MERGE_HEAD basis. The vast majority of merge commits, in\n> practice, have two parents. So the `merge` command would actually only\n> have one revision to merge (because HEAD is the implicit first parent). So\n> that is easy.\n> \n> But as soon as you go octopus, you can either perform an octopus merge, or\n> rebase the original merge commit. You cannot really mix and match here.\n> \n> Unless we reimplement the octopus merge (which works quite a bit\n> differently from the \"rebase merge commit\" strategy, even if it is\n> incremental, too), which has its own challenges: if there are merge\n> conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n> with status 2, telling you \"Should not be doing an octopus.\". While we\n> will want to keep merge conflict markers and continue with the \"rebase the\n> original merge commit\" strategy.\n> \n> And it would slam the door shut for adding support for *other* merge\n> strategies to perform a more-than-two-parents merge.\n\nThe thing is, in my opinion, as long as we are _rebasing_, you can`t \npick any merge strategy, as it doesn`t really make much sense. If you \ndo want a specific strategy, than that`s _recreating_ a merge, and it \ngoes fine with what you already have for `--recreate-merges`.\n\nOn merge rebasing, the underline strategy we decide to use is just an \nimplementation detail, picking the one that works best (or the only \none that works, even), user should have nothing to do with it.\n\n> Also, I do not think that it makes a whole lot of sense in practice to let\n> users edit what will be used for \"original parent\". If the user wants to\n> do complicated stuff, they can already do that, via `exec`. The `merge`\n> command really should be about facilitating common workflows, guiding the\n> user to what is sane.\n\nI thought of a situation like this:\n\n(1) ---o---o---o---M--- (master)\n        \\         /\n         X1--X2--X3 (topic)\n\n\nMerge M was done with `-s ours`, obsoleting \"topic\" branch. But, I \nlater realized that I actually do want that X2 commit in master.\n\nNow, I guess the most obvious approach is just cherry-picking it, but \nwhat if I would like to do something like this instead, with an \ninteractive rebase (and rebasing the merge, not recreating it):\n\n(2) ---o---o---o---M'--- (master)\n       |\\         /|\n       | X1'-X3'-/ | (topic)\n       |           |\n       \\--X2'------/ (new)\n\n\nThis way, and having \"topic\" inherit original merge behavior due to \nmerge rebasing, X1' and X3' would still be missing from M' as they \ndid originally from M, but X2' would now be included, as it`s coming \nfrom a new branch, forged during interactive rebase.\n\n(note - implementation wise, this still wouldn`t be an octopus merge ;)\n\n> The vast majority of merge commits, in practice, have two parents. So\n> the `merge` command would actually only have one revision to merge\n> (because HEAD is the implicit first parent).\n\nNow, this is something I actually overlooked :( \n\nI guess order of parent commits could then be used to map to old \ncommit parents, being a limitation in comparison to direct \nold-parent:new-parent mapping, but might be a more straightforward \nuser experience...\n\nThough in case of octopus merge, where one would like to drop a \nbranch from the middle, being merged with `-s ours`, that would be \nimpossible, as then the next branch would be taking over dropped \nbranch merge parent, yielding an incorrect result.\n\nSo in this case:\n\n(3) ---o---o---o---M--- (master)\n       |\\         /|\n       | X1--X3--/ | (topic)\n       |           |\n       \\--X2-------/ (new)\n\n... where \"topic\" was merged using `-s ours`, we wouldn`t be able to \njust remove whole \"topic\" branch from the rebased merge without \ninfluencing it incorrectly.\n\nWith (any kind of) explicit old-parent:new-parent mapping, this is \npossible (and shouldn`t be any harder, implementation wise).\n\nNow, it`s a different story if we`re interested in such exotic \nscenarios in the first place, but if possible, I would be all for \nit... :)\n\n> Currently my favorite idea is to introduce a new flag: -R (for \"rebase the\n> original merge commit\"). It would look like this:\n> \n> \tmerge -R -C <original-merge> <merge-head> # <oneline>\n> \n> This flag would of course trigger the consistency check (does the number\n> of parents of the original merge commit agree with the parameter list? Was\n> an original merge commit specified to begin with?), and it would not fall\n> back to the recursive merge, but error out if that check failed.\n> \n> Side note: I wonder whether we really need to perform the additional check\n> that ensures that the <merge-head> refers to the rewritten version of the\n> original merge commit's parent.\n\nNo, and even worse - I think we must not do that, as that merge \nparent might be moved elsewhere, which should be allowed.\n\nWhen I say \"merge parent\", I really mean \"merge parent _branch_\" (or \nso to say, merge parent context), I was deliberately avoiding term \n\"merge parent commit\" as it`s more than that.\n\n> Second side note: if we can fast-forward, currently we prefer that, and I\n> think we should keep that behavior with -R, too.\n\nI agree.\n\n> If the user wants to force a new merge, they simply remove that -R flag.\n> \n> What do you think?\n\nHaving more replies in the thread, I`ll comment the format there, \nmight be more appropriate, as discussion already evolved since the \nlast time I`ve checked, and I might have a new idea... ;) :P\n\nRegards, Buga\n"},{"id":"341293","messageId":"f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com","threadId":"47864","inReplyTo":"c5a5c2cc-6a11-440f-5b9b-964ae1ca07dd@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T15:56:09Z","receivedAt":"2018-03-08T15:56:27Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Phillip and Johannes, \n\nOn 08/03/2018 12:20, Phillip Wood wrote:\n> \n> I did wonder about using 'pick <original-merge>' for rebasing merges and\n> keeping 'merge ...' for recreating them but I'm not sure if that is a\n> good idea. It has the advantage that the user cannot specify the wrong\n> parents for the merge to be rebased as 'git rebase' would work out if\n> the parents have been rebased, but maybe it's a bit magical to use pick\n> for merge commits. Also there isn't such a simple way for the user to go\n> from 'rabase this merge' to 'recreate this merge' as they'd have to\n> write the whole merge line themselves (though I guess something like\n> emacs' git-rebase.el would be able to help with that)\n\nHmm, funny enough, `pick <original merge>` was something I though \nabout originally, too, feeling that it might make more sense in terms \non what`s really going on, but I guess I wanted it incorporated into \n`--recreate-merges` too much that I tried really hard to fit it in, \nwithout changing it much :/\n\nAnd now that I said this in a previous reply:\n\n> The thing is, in my opinion, as long as we are _rebasing_, you can`t \n> pick any merge strategy, as it doesn`t really make much sense. If you \n> do want a specific strategy, than that`s _recreating_ a merge, and it \n> goes fine with what you already have for `--recreate-merges`.\n> \n> On merge rebasing, the underline strategy we decide to use is just an \n> implementation detail, picking the one that works best (or the only \n> one that works, even), user should have nothing to do with it.\n\nThe difference between \"rebase merge commit\" and \"recreate merge \ncommit\" might starting to be more evident.\n\nSo... I might actually go for this one now. And (trying to stick with \nexplicit mappings, still :P), now that we`re not married to `merge` \nexpectations a user may already have, maybe a format like this:\n\n  pick <original-merge> <original-parent1>:HEAD <original-parent2>:<new-parent2>\n\n\nHere, original-merge is a _commit_, where original-parent and \nnew-parent are _labels_ (in terms of `--recreate-merges`).\n\nEverything else I previously said still holds - one is allowed to \nchange or drop mappings, and add or drop new merge parents. Yes, in \ncase user does something \"stupid\", he`ll get a lot of conflicts, but \nhey, we shouldn`t judge.\n\np.s. Are we moving towards `--rebase-merges` I mentioned in that \nother topic[1], as an add-on series after `--recreate-merges` hits \nthe mainstream (as-is)...? :P\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/bc9f82fb-fd18-ee45-36a4-921a1381b32e@gmail.com/\n"},{"id":"341295","messageId":"29bc6661-1d78-8f89-194e-1dcc9d88c34e@gmail.com","threadId":"47864","inReplyTo":"483674f8-4097-a374-c8f3-cf56cbb92042@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T16:05:03Z","receivedAt":"2018-03-08T16:05:24Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 08/03/2018 13:16, Phillip Wood wrote:\n> \n> > Side note: I wonder whether we really need to perform the additional check\n> > that ensures that the <merge-head> refers to the rewritten version of the\n> > original merge commit's parent.\n> > \n> > [...]\n> \n> Oops that was referring to the first side note. I think fast forwarding\n> is a good idea. I'm not so sure about checking that <merge-head> refers\n> to the rewritten version of the original merge commit's parent any more\n> though. Having thought some more, I think we would want to allow the\n> user to rearrange a topic branch that is the parent of a merge and that\n> would require allowing a different parent as the old parent could be\n> dropped or swapped with another commit in the branch. I can't think of a\n> way to mechanically check that the new parent is 'somehow derived from'\n> the old one.\n\nExactly, we must not depend on exact parent commits, but on parent \n\"branches\" (so to say).\n\nAnd that is why I think explicit mapping would be pretty helpful (if \nnot the only approach).\n\n> > I did wonder about using 'pick <original-merge>' for rebasing merges and\n> > keeping 'merge ...' for recreating them but I'm not sure if that is a\n> > good idea. It has the advantage that the user cannot specify the wrong\n> > parents for the merge to be rebased as 'git rebase' would work out if\n> > the parents have been rebased, but maybe it's a bit magical to use pick\n> > for merge commits. Also there isn't such a simple way for the user to go\n> > from 'rabase this merge' to 'recreate this merge' as they'd have to\n> > write the whole merge line themselves (though I guess something like\n> > emacs' git-rebase.el would be able to help with that)\n> \n> Scrub that, it is too magical and I don't think it would work with\n> rearranged commits - it's making the --preserve-merges mistake all over\n> again. It's a shame to have 'merge' mean 'recreate the merge' and\n> 'rebase the merge' but I don't think there is an easy way round that.\n\nI actually like `pick` for _rebasing_ merge commits, as `pick` is \nalready used for rebasing non-merge commits, too, so it feels natural.\n\nThen `merge` is left to do what it is meant for - merging (or \n\"recreate the merge\", in the given context).\n\nI tried to outline a possible user interface in that other reply[1], \nelaborating it a bit, too,\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com/\n"},{"id":"341296","messageId":"CA+P7+xoOVzxnmZN893ND4+55=OhtrE-gt7jRhtxoOUL=G_CrgA@mail.gmail.com","threadId":"47864","inReplyTo":"c5a5c2cc-6a11-440f-5b9b-964ae1ca07dd@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-03-08T16:07:55Z","receivedAt":"2018-03-08T16:08:22Z","isPatch":false,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Thu, Mar 8, 2018 at 3:20 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n> On 07/03/18 07:26, Johannes Schindelin wrote:\n>> Hi Buga,\n>>\n>> On Tue, 6 Mar 2018, Igor Djordjevic wrote:\n>>\n>>> On 06/03/2018 19:12, Johannes Schindelin wrote:\n>>>>\n>>>>>> And I guess being consistent is pretty important, too - if you add new\n>>>>>> content during merge rebase, it should always show up in the merge,\n>>>>>> period.\n>>>>>\n>>>>> Yes, that should make it easy for the user to know what to expect from\n>>>>> rebase.\n>>>>\n>>>> [...]\n>>>>\n>>>> It will be slightly inconsistent. But in a defendable way, I think.\n>>>\n>>> I like where this discussion is heading, and here`s what I thought\n>>> about it :)\n>>>\n>>> [...]\n>>>\n>>> Here`s a twist - not letting `merge` trying to be too smart by\n>>> figuring out whether passed arguments correspond to rewritten\n>>> versions of the original merge parents (which would be too\n>>> restrictive, too, I`m afraid), but just be explicit about it, instead!\n>>\n>> That's the missing piece, I think.\n>>\n>>> So, it could be something like:\n>>>\n>>>      merge -C deadbee 123abc:cafecafe 234bcd:bedbedbed\n>>\n>> I like where this is heading, too, but I do not think that we can do this\n>> on a per-MERGE_HEAD basis. The vast majority of merge commits, in\n>> practice, have two parents. So the `merge` command would actually only\n>> have one revision to merge (because HEAD is the implicit first parent). So\n>> that is easy.\n>>\n>> But as soon as you go octopus, you can either perform an octopus merge, or\n>> rebase the original merge commit. You cannot really mix and match here.\n>>\n>> Unless we reimplement the octopus merge (which works quite a bit\n>> differently from the \"rebase merge commit\" strategy, even if it is\n>> incremental, too), which has its own challenges: if there are merge\n>> conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n>> with status 2, telling you \"Should not be doing an octopus.\". While we\n>> will want to keep merge conflict markers and continue with the \"rebase the\n>> original merge commit\" strategy.\n>>\n>> And it would slam the door shut for adding support for *other* merge\n>> strategies to perform a more-than-two-parents merge.\n>>\n>> Also, I do not think that it makes a whole lot of sense in practice to let\n>> users edit what will be used for \"original parent\". If the user wants to\n>> do complicated stuff, they can already do that, via `exec`. The `merge`\n>> command really should be about facilitating common workflows, guiding the\n>> user to what is sane.\n>>\n>> Currently my favorite idea is to introduce a new flag: -R (for \"rebase the\n>> original merge commit\"). It would look like this:\n>>\n>>       merge -R -C <original-merge> <merge-head> # <oneline>\n>>\n>> This flag would of course trigger the consistency check (does the number\n>> of parents of the original merge commit agree with the parameter list? Was\n>> an original merge commit specified to begin with?), and it would not fall\n>> back to the recursive merge, but error out if that check failed.\n>>\n>> Side note: I wonder whether we really need to perform the additional check\n>> that ensures that the <merge-head> refers to the rewritten version of the\n>> original merge commit's parent.\n>>\n>> Second side note: if we can fast-forward, currently we prefer that, and I\n>> think we should keep that behavior with -R, too.\n>\n> I think that would be a good idea to avoid unpleasant surprises.\n>\n>> If the user wants to force a new merge, they simply remove that -R flag.\n>>\n>> What do you think?\n>\n> I did wonder about using 'pick <original-merge>' for rebasing merges and\n> keeping 'merge ...' for recreating them but I'm not sure if that is a\n> good idea. It has the advantage that the user cannot specify the wrong\n> parents for the merge to be rebased as 'git rebase' would work out if\n> the parents have been rebased, but maybe it's a bit magical to use pick\n> for merge commits. Also there isn't such a simple way for the user to go\n> from 'rabase this merge' to 'recreate this merge' as they'd have to\n> write the whole merge line themselves (though I guess something like\n> emacs' git-rebase.el would be able to help with that)\n>\n> Best Wishes\n>\n> Phillip\n>\n\nSince the ultimate commit hashes of newly rebased commits would be\nunknown at the time of writing the todo file, I'm not sure how this\nwould work to specify the parents?\n\n>\n>> Ciao,\n>> Dscho\n>>\n>\n"},{"id":"341298","messageId":"230856e0-7056-6273-cdd2-2e9969927271@gmail.com","threadId":"47864","inReplyTo":"2749ce78-8917-c821-6116-0c8d67b5e16e@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T16:21:26Z","receivedAt":"2018-03-08T16:21:44Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 08/03/2018 16:16, Igor Djordjevic wrote:\n> \n> > Unless we reimplement the octopus merge (which works quite a bit\n> > differently from the \"rebase merge commit\" strategy, even if it is\n> > incremental, too), which has its own challenges: if there are merge\n> > conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n> > with status 2, telling you \"Should not be doing an octopus.\". While we\n> > will want to keep merge conflict markers and continue with the \"rebase the\n> > original merge commit\" strategy.\n> >\n> > [...]\n> \n> The thing is, in my opinion, as long as we are _rebasing_, you can`t \n> pick any merge strategy, as it doesn`t really make much sense. If you \n> do want a specific strategy, than that`s _recreating_ a merge, and it \n> goes fine with what you already have for `--recreate-merges`.\n> \n> On merge rebasing, the underlying strategy we decide to use is just an \n> implementation detail, picking the one that works best (or the only \n> one that works, even), user should have nothing to do with it.\n\nJust to add, if not already assumable, that I think we should stop \nand let user react on conflicts on each of the \"rebase the original \ncommit\" strategy steps (rebase first parent, rebase second parent... \nmerge parents).\n\nI guess this stresses not using real \"octopus merge\" strategy even in \ncase where we`re rebasing octopus merge commit even more (and aligns \nnicely with what you seem to expect already).\n"},{"id":"341300","messageId":"1abcbc94-44b1-f729-686f-58efba3f9dea@gmail.com","threadId":"47864","inReplyTo":"87r2oxfmwo.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T16:30:23Z","receivedAt":"2018-03-08T16:30:39Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 06/03/2018 12:45, Sergey Organov wrote:\n> \n> > > The only thing I wonder of here is how would we check if the \n> > > \"rebased\" merge M' was \"clean\", or should we stop for user amendment? \n> > > With that other approach Sergey described, we have U1'==U2' to test with.\n> >\n> > I think (though I haven't rigorously proved to myself) that in the\n> > absence of conflicts this scheme has well defined semantics (the merges\n> > can be commuted), so the result should be predicable from the users\n> > point of view so maybe it could just offer an option to stop.\n> \n> Yes, hopefully it's predictable, but is it the intended one? We don't\n> know, so there is still some level of uncertainty.\n> \n> When in doubt, I try to find similar cases. There are two I'm aware of:\n> \n> 1. \"git merge\" just commits the result when there are no conflicts.\n> However, it supposedly has been run by the user just now, and thus user\n> can amend what he gets. That's effectively a stop for amendment from our\n> POV.\n> \n> 2. When rebasing, \"rerere\", when fires, stages the changes, and rebasing\n> stops for amendment. For me \"rerere\" behavior is rather annoying (I've\n> never in fact amended what it prepared), but I always assumed there are\n> good reasons it behaves this way.\n> \n> Overall, to be consistent, it seems we do need to stop at U1' != U2', at\n> least by default. Additional options could be supported then to specify\n> user intentions, both on the command level and in the todo list,\n> provided it proves to be useful.\n\nJust to say I agree with this, `if U1' == U2' then proceed else stop` \nseems as a good sanity check.\n"},{"id":"341313","messageId":"a0cc88d2-bfed-ce7b-1b3f-3c447d2b32da@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803071450511.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T19:58:59Z","receivedAt":"2018-03-08T19:59:18Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Johannes,\n\nOn 07/03/2018 15:08, Johannes Schindelin wrote:\n> \n> > > Didn't we settle on Phillip's \"perform successive three-way merges\n> > > between the original merge commit and the new tips with the old tips\n> > > as base\" strategy?\n> >\n> > It seems you did, dunno exactly why.\n> \n> That is not true. You make it sound like I was the only one who liked\n> this, and not Phillip and Buga, too.\n\nFor myself, I do actually favor Sergey`s approach in general, but \n_implemented_ through what Phillip described (or a mixture of both, to \nbe precise). But, let me explain... :)\n\n> > The main problem with this decision is that we still don't see how and\n> > when to stop for user amendment using this method. OTOH, the original\n> > has this issue carefully discussed.\n> \n> Why would we want to stop, unless there are merge conflicts?\n\nBecause we can reliably know that something \"unusual\" happened - and \nby that I don`t necessarily mean \"wrong\", but just might be worth \nuser inspection.\n\nFor example, situation like this (M is made on A3 with `-s ours`, \nobsoleting Bx commits):\n\n(1) ---X8--X9 (master)\n       |\\\n       | A1---A2---A3\n       |             \\\n       |              M (topic)\n       |             /\n       \\-B1---B2---B3\n\n... where we want to rebase M onto X9 is what I would call \"usual \nstuff\", but this situation (M is still made on A3 with `-s ours`, \nobsoleting Bx commits, but note cherry-picked B2'):\n\n(2) ---X8--B2'--X9 (master)\n       |\\\n       | A1---A2---A3\n       |             \\\n       |              M (topic)\n       |             /\n       \\-B1---B2---B3\n\n... where we still want to rebase M onto X9 is what we might consider \n\"unusual\", because we noticed that something that shouldn`t be part \nof the rebased merge commit (due to previous `-s ours`) actually got \nin there (due to later cherry-pick), and just wanting the user to \ncheck and confirm.\n\nThis is the major reason why I would prefer Sergey`s approach in \ngeneral... and might be I also have a good explanation on *why* it \nworks, but let`s get there ;)\n\n(p.s. This is only one, but certainly not the only case)\n\n> > \"rebase sides of the merge commit and then three-way merge them back\n> > using original merge commit as base\"\n> \n> And that is also wrong, as I had proved already! Only Buga's addition made\n> it robust against dropping/modifying commits, and that addition also makes\n> it more complicated.\n\nNo, this is actually right, that sentence nicely describing _how_ it \nworks. That addition of mine was just including the correct merge \nbase (being the original merge commit that we are \"rebasing\"), and \nthat`s what Sergey is talking about.\n\n> And it still has no satisfactory simple explanation why it works.\n\nGetting there... :)\n\n> > > - it is *very easy* to reason about, once it is pointed out that\n> > > rebases and merges result in the same trees.\n> >\n> > The original is as easy to reason about, if not easier, especially as\n> > recursive merge strategy is not being used there in new ways.\n> \n> So do it. I still have to hear a single-sentence, clear and obvious\n> explanation why it works.\n> \n> And please do not describe why your original version works, because it\n> does not work. Describe why the one amended with Buga's hack works.\n> \n> > I honestly don't see any advantages of Phillip's method over the\n> > original, except personal preferences. At the same time, I have no\n> > objection of using it either, provided consistency check problem is\n> > solved there as well.\n> \n> Okay, let me reiterate then, because I do not want this point to be\n> missed:\n> \n> Phillip's method is essentially merging the new tips into the original\n> merge, pretending that the new tips were not rebased but merged into\n> upstream.\n> \n> So it exploits the duality of the rebase and merge operation, which both\n> result in identical trees (potentially after resolving merge conflicts).\n> \n> I cannot think of any such interpretation for your proposal augmented by\n> Buga's fix-ups. And I haven't heard any such interpretation from your\n> side, either.\n\nOk here it goes (I might be still wrong, but please bare with me).\n\nWhat Sergey originally described also uses the \"duality of the rebase \nand merge operation\", too ;) Just in a bit different way (and might \nbe a more straightforward one?).\n\nHere`s a starting point, two commits A and B, merged into M:\n\n(3) ---A\n        \\\n         M\n        /\n    ---B\n\n\nAccording the \"patch theory\"[1] (which might not be too popular \naround here, but should serve the purpose for what I`m trying to \nexplain), each merge commit can be \"transformed\" to two non-merge \ncommits, one on top of each of the merge parents, where new commit \nbrings its original merge parent commit tree to the state of the \nmerge commit tree:\n\n(4) ---A---U1\n\n\n\n    ---B---U2\n\n\nNow, we have two new commits, U1 and U2, each having the same tree as \nprevious merge commit M, but representing changes in regards to \nspecific parents - and this is essentially what Sergey`s original \napproach was using (whether he knew it, or not).\n\nWhen it comes to rebasing, it`s pretty simple, too. As this:\n\n(5) ---X1---o---o---o---o---o---X2 (master)\n       |\\\n       | A1---A2---A3\n       |             \\\n       |              M\n       |             /\n       \\-B1---B2---B3\n\n... actually equals this:\n\n(6) ---X1---o---o---o---o---o---X2 (master)\n       |\\\n       | A1---A2---A3---U1\n       |\n       |\n       |\n       \\-B1---B2---B3---U2\n\n... where trees of M, U1 and U2 are same, and we can use the regular \nrebase semantics and rebase it to this:\n\n(7) ---X1---o---o---o---o---o---X2 (master)\n                                |\\\n                                | A1'--A2'--A3'--U1'\n                                |\n                                |\n                                |\n                                \\-B1'--B2'--B3'--U2'\n\n... which is essentially this again:\n\n(8) ---X1---o---o---o---o---o---X2 (master)\n                                |\\\n                                | A1'--A2'--A3'\n                                |            \\\n                                |             M'\n                                |            /\n                                \\-B1'--B2'--B3'\n\n... where it is still true that trees of U1', U2' and M' are still \nthe same. So we managed to rebase a merge commit without ever doing a \nmerge :) (note that, practically, we _can_ finally even merge U1' and \nU2' to produce M', it shouldn`t really matter as all the trees are \nthe same, so merge will be a no-op)\n\nBut, as we saw (what you`ve explained), this doesn`t really work in \ncase one of the sides of the merge gets \"disbalanced\" (so to say), \nlike dropping a commit (which could also happen non-interactively, \nwhere a commit has been cherry-picked to a different branch, but\npreviously obsoleted by `-s ours` merge).\n\nAs observed, dropped commit could still wrongly get into final merge \ncommit tree (or cherry-picked commit wrongly not get there), due to \nthe nature of those rebased U1 and U2 temporary commits to hold all \nthe differences in regards to their specific merge commit parent.\n\nA natural improvement to original idea which Sergey eventually came \nup with after my findings (which you now ended up calling a hack, even, \nbut I would respectfully disagree), is to use original merge commit M \nas a merge base for final merge of U1' and U2' - and here is why it \nworks, too, and why I wouldn`t consider it a hack, but a proper (and \na solid) solution.\n\nMerge commit M is what we are rebasing, so we should have a way to \nsomehow learn from it, alongside U1 and U2 temporary commits - and \nthat is what using original merge commit M as a base does for us. It \nhelps us spot any \"disbalances\" that happened in comparison to original \nmerge parent trees, which is exactly what we`re interested in.\n\nIn ideal case (as per \"patch theory\"[1]), final merge of rebased U1' \nand U2' with original merge commit M as a base would be rather simple, \ntoo (not to say pointless again), as both U1' and U2' would have same \nchanges in comparison to M, namely all the changes from commit we are \nrebasing from (X1 above) to commit we are rebasing to (X2 above).\n\nBut in a more complex case like this:\n\n(9) ---X1---B2'---o---o---o---o---X2 (master)\n                                  |\\\n                                  | A12--A2'---B3'\n                                  |             \\\n                                  |              M'\n                                  |             /\n                                  \\-B1'--B3'---B4\n\n..., being what we are ultimately interested in, it helps us notice \nall kind of changes on our rebased merge parent branches, and act \naccordingly (as shown by my previously posted test script[2]).\n\nAll this said (and hoping anyone is still reading this), to shed some \nlight on what I meant by \"favoring Sergey`s approach in general, but \n_implemented_ through what Phillip described\".\n\nI think we should use temporary commits U1 and U2, being a sound \napproach backed up by the \"patch theory\"[1], as it helps us notice \nany \"disbalances\" of the rebased merge commit parents trees (so we \ncan stop for user inspection), finally merging them with original \nmerge commit as a base, in order to spot additional changes on trees \nof the merge commit parents we are rebasing.\n\nBut, the merging steps themselves, backed up by a need to stop for \nconflict resolution as soon as one happens, should be performed \n_iteratively_, like Phillip showed us... I would think :)\n\nAnd, for example, that would do wonders when we introduce completely \nnew branch during an interactive rebase, too, for example:\n\n(10) ---X1---B2'---o---o---o---o---X2 (master)\n        |\\                        /|\\\n        | A1---A2---A3---U1       || A12--A2'---B3'---U1'\n        |             \\           ||             \\\n        |              M          ||              M'\n        |             /           ||             /|\n        \\-B1---B2---B3---U2       |\\---B3'---B4-/-|---U2'\n                                  |               |\n                                  \\-----B1'-------/\n\n\nIn this situation, we would merge all temporary Ux commits using \noriginal merge M as a merge base, and then merge _that_ resulting \ntree with B1' (being a newly introduced merge commit parent), using \nwhatever merge base is most appropriate between the two (in this \ncase, X2).\n\nSo, for diagram (10) above, I guess something like this:\n\n\tgit merge-recursive U1' -- M U2'\n\ttree=\"$(git write-tree)\"\n\t# in case of original merge being octopus, we would continue like:\n\t# git merge-recursive $tree -- M U3'\n\t# tree=\"$(git write-tree)\"\n\t# git merge-recursive $tree -- M U4'\n\t# ... and so on, then finally:\n\tgit merge-recursive $tree -- \"$(git merge-base U1' U2' B1')\" B1'\n\t# in more general case, it would be:\n\t# git merge-recursive $tree -- \"$(git merge-base <all-parents-of-new-merge-commit>)\" B1'\n\ttree=\"$(git write-tree)\"\n\tgit tag M' \"$(git log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1')\"\n\n... where we would stop for conflict resolution after each failing \nmerge-recursive attempt (which is also true for producing rebased U1' \nand U2' in the first place).\n\nThere, I would still need to make a test script doing this, but I \nhope the concept is clear, and I`m not missing something crucial here.\n\nComments welcome :)\n\nRegards, Buga\n\n[1] https://en.wikibooks.org/wiki/Understanding_Darcs/Patch_theory\n[2] https://public-inbox.org/git/f1a960dc-cc5c-e7b0-10b6-39e5516655b3@gmail.com/\n"},{"id":"341314","messageId":"4918cc79-79ba-5dd2-ea84-dc47db47d835@gmail.com","threadId":"47864","inReplyTo":"a0cc88d2-bfed-ce7b-1b3f-3c447d2b32da@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T20:27:27Z","receivedAt":"2018-03-08T20:27:45Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 08/03/2018 20:58, Igor Djordjevic wrote:\n> \n> \tgit merge-recursive U1' -- M U2'\n> \ttree=\"$(git write-tree)\"\n> \t# in case of original merge being octopus, we would continue like:\n> \t# git merge-recursive $tree -- M U3'\n> \t# tree=\"$(git write-tree)\"\n> \t# git merge-recursive $tree -- M U4'\n> \t# ... and so on, then finally:\n> \tgit merge-recursive $tree -- \"$(git merge-base U1' U2' B1')\" B1'\n> \t# in more general case, it would be:\n> \t# git merge-recursive $tree -- \"$(git merge-base <all-parents-of-new-merge-commit>)\" B1'\n> \ttree=\"$(git write-tree)\"\n> \tgit tag M' \"$(git log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1')\"\n\nThat last line should obviously read just:\n\n\tgit log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1'\n\n..., above mentioned `git tag M'` part being a leftover from my other test script.\n"},{"id":"341319","messageId":"b11785bd-5c96-43c1-95d8-b28eccfd13c8@gmail.com","threadId":"47864","inReplyTo":"4918cc79-79ba-5dd2-ea84-dc47db47d835@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T22:05:51Z","receivedAt":"2018-03-08T22:06:07Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 08/03/2018 21:27, Igor Djordjevic wrote:\n> \n> > \tgit merge-recursive U1' -- M U2'\n> > \ttree=\"$(git write-tree)\"\n> > \t# in case of original merge being octopus, we would continue like:\n> > \t# git merge-recursive $tree -- M U3'\n> > \t# tree=\"$(git write-tree)\"\n> > \t# git merge-recursive $tree -- M U4'\n> > \t# ... and so on, then finally:\n> > \tgit merge-recursive $tree -- \"$(git merge-base U1' U2' B1')\" B1'\n> > \t# in more general case, it would be:\n> > \t# git merge-recursive $tree -- \"$(git merge-base <all-parents-of-new-merge-commit>)\" B1'\n> > \ttree=\"$(git write-tree)\"\n> > \tgit tag M' \"$(git log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1')\"\n> \n> That last line should obviously read just:\n> \n> \tgit log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1'\n> \n> ..., above mentioned `git tag M'` part being a leftover from my other test script.\n\nEh, pardon me, I managed to mess up all the merge-recursive lines, \ntoo, in regards to where the merge-base commit goes... Here`s a \ncomplete (and corrected) sample:\n\n\tgit merge-recursive M -- U1' U2'\n\ttree=\"$(git write-tree)\"\n\t# in case of original merge being octopus, we would continue like:\n\t# git merge-recursive M -- $tree U3'\n\t# tree=\"$(git write-tree)\"\n\t# git merge-recursive M -- $tree U4'\n\t# ... and so on, then finally:\n\tgit merge-recursive \"$(git merge-base U1' U2' B1')\" -- $tree B1'\n\t# ... or even:\n\t# git merge-recursive \"$(git merge-base B3' B4 B1')\" -- $tree B1'\n\t# as in more general case, it would be:\n\t# git merge-recursive \"$(git merge-base <all-parents-of-new-merge-commit>)\" -- $tree B1'\n\ttree=\"$(git write-tree)\"\n\tgit log --pretty=%B -1 M | git commit-tree $tree -p B3' -p B4 -p B1'\n"},{"id":"341324","messageId":"d29d3c0e-6473-0461-c8ea-02975ce4de14@gmail.com","threadId":"47864","inReplyTo":"b11785bd-5c96-43c1-95d8-b28eccfd13c8@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-08T23:31:11Z","receivedAt":"2018-03-08T23:31:27Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 08/03/2018 20:58, Igor Djordjevic wrote:\n> \n> > Phillip's method is essentially merging the new tips into the original\n> > merge, pretending that the new tips were not rebased but merged into\n> > upstream.\n> \n> [...]\n> \n> Here`s a starting point, two commits A and B, merged into M:\n> \n> (3) ---A\n>         \\\n>          M\n>         /\n>     ---B\n> \n> \n> According the \"patch theory\"[1] (which might not be too popular \n> around here, but should serve the purpose for what I`m trying to \n> explain), each merge commit can be \"transformed\" to two non-merge \n> commits, one on top of each of the merge parents, where new commit \n> brings its original merge parent commit tree to the state of the \n> merge commit tree:\n> \n> (4) ---A---U1\n> \n> \n> \n>     ---B---U2\n> \n> \n> Now, we have two new commits, U1 and U2, each having the same tree as \n> previous merge commit M, but representing changes in regards to \n> specific parents - and this is essentially what Sergey`s original \n> approach was using (whether he knew it, or not).\n> \n> When it comes to rebasing, it`s pretty simple, too. As this:\n> \n> (5) ---X1---o---o---o---o---o---X2 (master)\n>        |\\\n>        | A1---A2---A3\n>        |             \\\n>        |              M\n>        |             /\n>        \\-B1---B2---B3\n> \n> ... actually equals this:\n> \n> (6) ---X1---o---o---o---o---o---X2 (master)\n>        |\\\n>        | A1---A2---A3---U1\n>        |\n>        |\n>        |\n>        \\-B1---B2---B3---U2\n> \n> ... where trees of M, U1 and U2 are same, and we can use the regular \n> rebase semantics and rebase it to this:\n> \n> (7) ---X1---o---o---o---o---o---X2 (master)\n>                                 |\\\n>                                 | A1'--A2'--A3'--U1'\n>                                 |\n>                                 |\n>                                 |\n>                                 \\-B1'--B2'--B3'--U2'\n> \n> ... which is essentially this again:\n> \n> (8) ---X1---o---o---o---o---o---X2 (master)\n>                                 |\\\n>                                 | A1'--A2'--A3'\n>                                 |            \\\n>                                 |             M'\n>                                 |            /\n>                                 \\-B1'--B2'--B3'\n> \n\nHaving explained all this, I realized this is the same \"essentially \nmerging the new tips into the original pretending that the new tips \nwere not rebased but merged into upstream\" as Phillip`s one, just \nthat we have additional temporary commits U1 and U2 (as per mentioned \n\"patch theory\") :)\n\nMerging U1' and U2' with M as a base can initially be presented like \nthis as well (what Phillip`s approach would yield):\n\n\tgit merge-recursive U1 -- M U1'\n\ttree=\"$(git write-tree)\"\n\tgit merge-recursive U2 -- $tree U2'\n\ttree=\"$(git write-tree)\"\n\t\n..., where we know U1 = U2 = M (in regards to trees), so this is the \nsame as:\n\n\tgit merge-recursive M -- M U1'\n\ttree=\"$(git write-tree)\"\n\tgit merge-recursive M -- $tree U2'\n\ttree=\"$(git write-tree)\"\n\n..., which can be further simplified, being the same as:\n\n\tgit merge-recursive M -- U1' U2'\n\ttree=\"$(git write-tree)\"\n\n... which is exactly what Sergey`s (updated) approach suggests, \nmerging U1' and U2' with M as merge-base (and shown inside that \nsample implementation script I provided[1]) :)\n\nWith all this said, I think it`s safe to say these two approaches are \nexactly the same, just Sergey`s being simplified (thus harder to \ninitially understand), and the only actual question is whether we \nvalue U1' and U2' enough, as possible \"something suspicious happened\" \nindicators, to use them, or not.\n\nI would think yes, but I would be open for more samples of where do \nthey become useful for reporting \"suspicious activity\", too.\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/b11785bd-5c96-43c1-95d8-b28eccfd13c8@gmail.com/\n"},{"id":"341346","messageId":"nycvar.QRO.7.76.6.1803091759250.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqfu5bx9zd.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-09T17:09:07Z","receivedAt":"2018-03-09T17:09:26Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 8 Mar 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> If we are talking about a drastic change, a few more days may not be\n> >> sufficient, but we are not in a hurry, as this already sounds like a\n> >> 2.18 material anyway.\n> >\n> > It is not at all a drastic change. It will actually make the current patch\n> > series better (simplifying the \"can we fast-forward?\" check).\n> >\n> > I just want to make sure that I already have Phillip's strategy working,\n> > but it will be yet another topic branch on top of the topic branch that\n> > will add support for octopus merges *after* the current --recreate-merges\n> > topic branch ;-)\n> \n> Oh, if the \"not redoing the merge afresh, but attempt to reuse the\n> previous merge\" that was discussed is going to be done as an\n> update/addition to the \"redo the merge afresh\" you already had in\n> production forever (and I had in 'pu' for quite a while in various\n> polished-ness during iteration), then I do prefer merging down what\n> has already proven to be 'next' worthy without waiting for the\n> discussion and your local verification of Phillip's new thing,\n> especially given that you'll be giving an explicit control to the\n> users which variant of \"merge\" insn will be used and the addition\n> of the Phillip's thing won't be a backward-compatibility issue when\n> it comes later.\n\nI would like to stress that the `--recreate-merges` functionality has\n*not* beed in production forever. It is a reimplementation in pure C of\nthe Unix shell script that has been in production for five years\n(unchanged only for the last half year, the last critical fix happened in\nJanuary last year).\n\nSo I do see the value here to use `next` as test bed, and once the patch\nseries will hit `next`, I will also merge it into Git for Windows (as an\nEXPERIMENTAL feature).\n\nAs such, I am quite comfortable with refactoring a bit here and there, for\nexample how to handle the case where a `merge` can be fast-forwarded.\n\nI think the changes I made in the last few days were an actual improvement\nto readability, even if the only reason for those changes was that I\nwanted to accommodate the \"rebase merge commits\" thing.\n\nFWIW I am fine with bumping this down to 2.18. I got a little bit of\nvaluable feedback at GitMerge, e.g. that --recreate-merges does not (yet)\nhave a mode where it can update refs corresponding to the rebased commits.\n(This could actually turn out to be independent of --recreate-merges,\neven).\n\nI already pushed out the updated branch, and it can be inspected at\n\n\thttps://github.com/git/git/pull/447\n\nThe reason I did not send this out yet is that I want to give it a final\nlook-over myself, so that I do not waste people's time again (as I did\nwith that monster interdiff that was pretty bogus, too).\n\nCiao,\nDscho\n"},{"id":"341408","messageId":"nycvar.QRO.7.76.6.1803111248200.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqbmfzx9n0.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T11:56:04Z","receivedAt":"2018-03-11T11:56:16Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Thu, 8 Mar 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Non-textual semantic conflicts are made (in the best case just once)\n> >> as a separate commit on top of mechanical auto-merge whose focus is\n> >> predictability (rather than cleverness) done by Git, and then that\n> >> separate commit is kept outside the history.  When replaying these\n> >> merges to rebuild the 'pu' branch, after resetting the tip to\n> >> 'master', each topic is merged mechanically, and if such a fix-up\n> >> commit is present, \"cherry-pick --no-commit\" applies it and then\n> >> \"commit --amend --no-edit\" to adjust the merge.  I find it quite\n> >> valuable to have a separate record of what \"evil\" non-mechanical\n> >> adjustment was done, which I know won't be lost in the noise when\n> >> these merges need to be redone daily or more often.\n> >\n> > So essentially, you have something that `git rerere` would have learned,\n> > but as a commit?\n> \n> You probably wouldn't be asking that if you read what you cut out\n> when you quoted above ;-) \n\nSorry to be so stupid, and no, the part I cut did not clarify it for me,\nhence my question.\n\n> There are a collection of cherry-pickable commits in hierarchy under\n> refs/merge-fix.  They are indexed by the branch that will cause\n> semantic conflicts that do not involve textual conflicts at all (the\n> important implication of which is that 'rerere' fundamentally will\n> not trigger to help resolving them) [*1*], and are used to create\n> evil merge when a corresponding branch is merged to 'pu' (and down).\n\nI see. My question was unclear, I agree. Please let me re-try:\n\nSo essentially, what your cherry-pick'able commits are is a way to store\nwhat rerere would have stored (i.e. the set of merge conflicts together\nwith their resolution)?\n\nIf so, what tooling do you have to identify quickly what to cherry-pick,\ngiven merge conflicts?\n\n(I know I could spend some half hour to scour your `todo` branch and the\ndocumentation you wrote about how you maintain Git, but you already know\nthe answer to this question, and it would probably be interesting to\nothers who are as eager to have better tools for handling merge conflicts\nas I am, too, so it would save time overall to discuss this single\nquestion here.)\n\n> *1* One topic adds an extra parameter to read_index_from() that has\n> been and still is defined in a file and merged to 'pu' first, while\n> another topic adds a new callsite for the same function in a file\n> that the former topic does not touch, hence a merge of the latter\n> topic has no textual conflict to the file with a new callsite, but\n> still needs adjusting.  That sort of think.\n\nOkay, so it is even more intricate than `rerere`: it does not only store\nthe merge conflicts (by grace of using the \"patch ID\" of the merge\nconflicts) together with their resolution, but instead it has some sort of\nidea of what context needs to be met to require the resolution?\n\nColor me intrigued.\n\nIf you really found a way to automate describing, say, that a function\nsignature changed in one branch, and a caller was introduced in another,\nand that merging those requires adjusting the caller in a specific way, I\nnow *really* think that this should be made available more broadly.\n\nCiao,\nDscho\n"},{"id":"341409","messageId":"nycvar.QRO.7.76.6.1803111256410.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"29bc6661-1d78-8f89-194e-1dcc9d88c34e@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T12:00:16Z","receivedAt":"2018-03-11T12:00:31Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Thu, 8 Mar 2018, Igor Djordjevic wrote:\n\n> On 08/03/2018 13:16, Phillip Wood wrote:\n> > \n> > > I did wonder about using 'pick <original-merge>' for rebasing merges\n> > > and keeping 'merge ...' for recreating them but I'm not sure if that\n> > > is a good idea. It has the advantage that the user cannot specify\n> > > the wrong parents for the merge to be rebased as 'git rebase' would\n> > > work out if the parents have been rebased, but maybe it's a bit\n> > > magical to use pick for merge commits. Also there isn't such a\n> > > simple way for the user to go from 'rabase this merge' to 'recreate\n> > > this merge' as they'd have to write the whole merge line themselves\n> > > (though I guess something like emacs' git-rebase.el would be able to\n> > > help with that)\n> > \n> > Scrub that, it is too magical and I don't think it would work with\n> > rearranged commits - it's making the --preserve-merges mistake all\n> > over again. It's a shame to have 'merge' mean 'recreate the merge' and\n> > 'rebase the merge' but I don't think there is an easy way round that.\n> \n> I actually like `pick` for _rebasing_ merge commits, as `pick` is \n> already used for rebasing non-merge commits, too, so it feels natural.\n\nPhillip is right, though: this would repeat the design mistake of\n--preserve-merges.\n\nWe must not forget that the interactive mode is the target here, and that\nthe syntax (as well as the generated todo list) must allow for easy\nmodification. The `pick <merge>` approach does not allow that, so we\ncannot use it.\n\nThe `merge -R -C <original-commit> <merge-head>` approach is a lot better:\nit offers the flexibility, without sacrificing the ease when not modifying\nthe todo list.\n\nCiao,\nDscho\n"},{"id":"341410","messageId":"nycvar.QRO.7.76.6.1803111301340.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T12:08:03Z","receivedAt":"2018-03-11T12:11:33Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Thu, 8 Mar 2018, Igor Djordjevic wrote:\n\n> On 08/03/2018 12:20, Phillip Wood wrote:\n> > \n> > I did wonder about using 'pick <original-merge>' for rebasing merges\n> > and keeping 'merge ...' for recreating them but I'm not sure if that\n> > is a good idea. It has the advantage that the user cannot specify the\n> > wrong parents for the merge to be rebased as 'git rebase' would work\n> > out if the parents have been rebased, but maybe it's a bit magical to\n> > use pick for merge commits. Also there isn't such a simple way for the\n> > user to go from 'rabase this merge' to 'recreate this merge' as they'd\n> > have to write the whole merge line themselves (though I guess\n> > something like emacs' git-rebase.el would be able to help with that)\n> \n> Hmm, funny enough, `pick <original merge>` was something I though about\n> originally, too, feeling that it might make more sense in terms on\n> what`s really going on, but I guess I wanted it incorporated into\n> `--recreate-merges` too much that I tried really hard to fit it in,\n> without changing it much :/\n\nThe `pick <original-merge>` syntax is too limited to allow reordering, let\nalone changing the parents.\n\n> And now that I said this in a previous reply:\n> \n> > The thing is, in my opinion, as long as we are _rebasing_, you can`t \n> > pick any merge strategy, as it doesn`t really make much sense. If you \n> > do want a specific strategy, than that`s _recreating_ a merge, and it \n> > goes fine with what you already have for `--recreate-merges`.\n> > \n> > On merge rebasing, the underline strategy we decide to use is just an \n> > implementation detail, picking the one that works best (or the only \n> > one that works, even), user should have nothing to do with it.\n> \n> The difference between \"rebase merge commit\" and \"recreate merge \n> commit\" might starting to be more evident.\n\nTrue.\n\n> So... I might actually go for this one now. And (trying to stick with \n> explicit mappings, still :P), now that we`re not married to `merge` \n> expectations a user may already have, maybe a format like this:\n> \n>   pick <original-merge> <original-parent1>:HEAD <original-parent2>:<new-parent2>\n\nI do not really like it, as it makes things a ton less intuitive. If you\ndid not know about this here discussion, and you did not read the manual\n(and let's face it: a UI that does not require users to read the manual is\nvastly superior to a UI that does), and you encountered this command:\n\n\tmerge deadbeef cafecafe:download-button\n\nwhat would you think those parameters would mean?\n\nGranted, encountering\n\n\tmerge -R -C deadbeef download-button # Merge branch 'download-button'\n\nis still not *quite* as intuitive as I would wish. Although, to be honest,\nif I encountered this, I would think that I should probably leave the -R\nand the -C deadbeef alone, and that I could change what is getting merged\nby changing the `download-button` parameter.\n\n> p.s. Are we moving towards `--rebase-merges` I mentioned in that \n> other topic[1], as an add-on series after `--recreate-merges` hits \n> the mainstream (as-is)...? :P\n\nThat's an interesting question. One that I do not want to answer alone,\nbut I would be in favor of `--rebase-merges` as it is IMHO a much better\nname for what this option is all about.\n\nOther opinions?\n\nCiao,\nDscho\n"},{"id":"341411","messageId":"nycvar.QRO.7.76.6.1803111308320.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"CA+P7+xoOVzxnmZN893ND4+55=OhtrE-gt7jRhtxoOUL=G_CrgA@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T12:11:55Z","receivedAt":"2018-03-11T12:12:04Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Jake,\n\nOn Thu, 8 Mar 2018, Jacob Keller wrote:\n\n> On Thu, Mar 8, 2018 at 3:20 AM, Phillip Wood <phillip.wood@talktalk.net> wrote:\n> > I did wonder about using 'pick <original-merge>' for rebasing merges\n> > and keeping 'merge ...' for recreating them but I'm not sure if that\n> > is a good idea. It has the advantage that the user cannot specify the\n> > wrong parents for the merge to be rebased as 'git rebase' would work\n> > out if the parents have been rebased, but maybe it's a bit magical to\n> > use pick for merge commits. Also there isn't such a simple way for the\n> > user to go from 'rabase this merge' to 'recreate this merge' as they'd\n> > have to write the whole merge line themselves (though I guess\n> > something like emacs' git-rebase.el would be able to help with that)\n> \n> Since the ultimate commit hashes of newly rebased commits would be\n> unknown at the time of writing the todo file, I'm not sure how this\n> would work to specify the parents?\n\nI agree with Phillip's follow-up that the `pick <original-merge>` syntax\nwould pose a problem, but for different reasons: We already tried it, with\n--preserve-merges, and it is just a really stupid syntax that does not\nallow the user even to reorder commits. Or drop commits (except at the\nvery end of the todo list).\n\nAs to your concern: The ultimate commit hashes do not have to be known\nuntil the merge commit is rebased. The current approach is to use labels\nfor them (`label <name>`), which Simply Works.\n\nCiao,\nDscho\n"},{"id":"341412","messageId":"nycvar.QRO.7.76.6.1803111315200.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"230856e0-7056-6273-cdd2-2e9969927271@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T12:22:44Z","receivedAt":"2018-03-11T12:22:53Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Thu, 8 Mar 2018, Igor Djordjevic wrote:\n\n> On 08/03/2018 16:16, Igor Djordjevic wrote:\n> > \n> > > Unless we reimplement the octopus merge (which works quite a bit\n> > > differently from the \"rebase merge commit\" strategy, even if it is\n> > > incremental, too), which has its own challenges: if there are merge\n> > > conflicts before merging the last MERGE_HEAD, the octopus merge will exit\n> > > with status 2, telling you \"Should not be doing an octopus.\". While we\n> > > will want to keep merge conflict markers and continue with the \"rebase the\n> > > original merge commit\" strategy.\n> > >\n> > > [...]\n> > \n> > The thing is, in my opinion, as long as we are _rebasing_, you can`t \n> > pick any merge strategy, as it doesn`t really make much sense. If you \n> > do want a specific strategy, than that`s _recreating_ a merge, and it \n> > goes fine with what you already have for `--recreate-merges`.\n> > \n> > On merge rebasing, the underlying strategy we decide to use is just an \n> > implementation detail, picking the one that works best (or the only \n> > one that works, even), user should have nothing to do with it.\n> \n> Just to add, if not already assumable, that I think we should stop \n> and let user react on conflicts on each of the \"rebase the original \n> commit\" strategy steps (rebase first parent, rebase second parent... \n> merge parents).\n\nI am not sure about that. Actually, I am pretty certain that we should\nimitate the recursive merge, which \"accumulates\" merge conflicts and only\npresents the final result, possibly with nested merge conflicts.\n\nIn practice, we see that rarely, and more often than not, in those cases\nthe user wants to re-do the merge differently, anyway.\n\nIn the scenario we discuss here, I would wager a bet that the user\nencountering nested merge conflicts would most likely see that the rebase\ntried to rebase a merge, then `git reset --hard` and re-do the merge\nmanually (i.e. *recreate* rather than *rebase*, most likely with\n(non-nested) merge conflicts).\n\n> I guess this stresses not using real \"octopus merge\" strategy even in \n> case where we`re rebasing octopus merge commit even more (and aligns \n> nicely with what you seem to expect already).\n\nMy mistake, I should have pointed you my implementation:\n\nhttps://github.com/git/git/commit/d41a29ceb61ff445efd0f97a836f381de57c5a41\n\nThe full thicket of branches can be found here:\n\nhttps://github.com/git/git/compare/master...dscho:sequencer-shears\n\nI chose to make this an add-on patch after adding support for octopus\nmerges because it actually makes it easier to think about \"rebase merge\ncommits\" independently of the number of merge parents.\n\nCiao,\nDscho\n"},{"id":"341421","messageId":"nycvar.QRO.7.76.6.1803111324390.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"a0cc88d2-bfed-ce7b-1b3f-3c447d2b32da@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T15:40:45Z","receivedAt":"2018-03-11T15:40:56Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Thu, 8 Mar 2018, Igor Djordjevic wrote:\n\n> On 07/03/2018 15:08, Johannes Schindelin wrote:\n> > \n> > > > Didn't we settle on Phillip's \"perform successive three-way merges\n> > > > between the original merge commit and the new tips with the old tips\n> > > > as base\" strategy?\n> > >\n> > > It seems you did, dunno exactly why.\n> > \n> > That is not true. You make it sound like I was the only one who liked\n> > this, and not Phillip and Buga, too.\n> \n> For myself, I do actually favor Sergey`s approach in general, but \n> _implemented_ through what Phillip described (or a mixture of both, to \n> be precise). But, let me explain... :)\n\nSo as you explained later in this sub-thread, Sergey's approach is\nessentially the same as Phillip's.\n\nI still do not understand Sergey's approach on a fundamental level. I\nmean, I can follow his instructions how to implement his algorithm, but it\nis as if I had a blindfold on and somebody guided me through a maze: I\nunderstand *what* I am supposed to do, but I have no clue *why*.\n\nAnd admittedly, I got very frustrated when a document was thrown my way\nthat is too long to read in one sitting, and all of my attempts at getting\nclear and comprehensible answers to specific questions were met with \"go\nand read that document, I am sure you will understand then\".\n\nFor something as fundamental to my daily workflow as an interactive rebase\n(*especially* when trying to maintain the branch topology), this is no\ngood at all.\n\nSince you already confirmed that there is essentially no difference\nbetween the two approaches, I will simply go with the one I understand, in\nparticular I understand *why* it works.\n\nBut let's read on, maybe I will change my mind based on your explanations\n(which do answer my questions, thank you so much for that)...\n\n> > > The main problem with this decision is that we still don't see how\n> > > and when to stop for user amendment using this method. OTOH, the\n> > > original has this issue carefully discussed.\n> > \n> > Why would we want to stop, unless there are merge conflicts?\n> \n> Because we can reliably know that something \"unusual\" happened - and by\n> that I don`t necessarily mean \"wrong\", but just might be worth user\n> inspection.\n\nWe have a similar conundrum in recursive merges. Remember how multiple\nmerge bases are merged recursively? There can be merge conflicts, too, in\n*any* of the individual merges involved, and indeed, there are (under\nrelatively rare circumstances).\n\nSince we already faced that problem, and we already answered it by\npresenting possibly nested merge conflicts, I am in strong favor of\nkeeping our new scenario consistent: present possibly-nested merge\nconflicts.\n\nAs far as I understand, one of the arguments in favor of the current\napproach was: there is no good way to tell the user where they are, and\nhow to continue from there. So better just to continue and present the\nuser with the entire set of conflicts, and have an obvious way out.\n\n> For example, situation like this (M is made on A3 with `-s ours`, \n> obsoleting Bx commits):\n> \n> (1) ---X8--X9 (master)\n>        |\\\n>        | A1---A2---A3\n>        |             \\\n>        |              M (topic)\n>        |             /\n>        \\-B1---B2---B3\n> \n> ... where we want to rebase M onto X9 is what I would call \"usual \n> stuff\", but this situation (M is still made on A3 with `-s ours`, \n> obsoleting Bx commits, but note cherry-picked B2'):\n> \n> (2) ---X8--B2'--X9 (master)\n>        |\\\n>        | A1---A2---A3\n>        |             \\\n>        |              M (topic)\n>        |             /\n>        \\-B1---B2---B3\n> \n> ... where we still want to rebase M onto X9 is what we might consider \n> \"unusual\", because we noticed that something that shouldn`t be part \n> of the rebased merge commit (due to previous `-s ours`) actually got \n> in there (due to later cherry-pick), and just wanting the user to \n> check and confirm.\n\nWe already have those scenarios when performing a regular interactive\nrebase, where a patch was already applied upstream. In the normal case,\nthe user is not even shown B2, thanks to the --cherry-pick option used in\ngenerating the todo list.\n\nGranted, in some cases --cherry-pick does not detect that, and then we\ngenerate a todo list including B2, and when that patch is applied, the\ninteractive rebase stops, saying that there are no changes to be\ncommitted.\n\nAnd this behavior is exactly the same with --recreate-merges!\n\nSo I do not think that it would make sense to bother the user *again* when\nrebasing the merge commit.\n\nIf there are merge conflicts, yes, we will have to. If there are none\n(even if your U1' != U2'), it would be outright annoying to stop.\n\n> > > \"rebase sides of the merge commit and then three-way merge them back\n> > > using original merge commit as base\"\n> > \n> > And that is also wrong, as I had proved already! Only Buga's addition\n> > made it robust against dropping/modifying commits, and that addition\n> > also makes it more complicated.\n> \n> No, this is actually right, that sentence nicely describing _how_ it \n> works.\n\nDoes it? Because that's exactly backwards from how Phillip's approach\nworks: it certainly does not use the original merge commit as base. It\nuses the non-rebased merge parent as base, one at a time.\n\nNow I am curious...\n\n> That addition of mine was just including the correct merge base (being\n> the original merge commit that we are \"rebasing\"), and that`s what\n> Sergey is talking about.\n\nOkay, render me still unconvinced that Sergey's approach is actually\ncorrect.\n\n> > > > - it is *very easy* to reason about, once it is pointed out that\n> > > > rebases and merges result in the same trees.\n> > >\n> > > The original is as easy to reason about, if not easier, especially as\n> > > recursive merge strategy is not being used there in new ways.\n> > \n> > So do it. I still have to hear a single-sentence, clear and obvious\n> > explanation why it works.\n\nSo the closest I got was the description with the *original merge commit*\nas merge base, which I disagree with. It does not make sense to me.\n\nConsecutive three-way merges between the original merge commit and the\nmerge parents (with the *original merge parents* as merge base,\nrespectively), still makes the most sense to me: it is a merge between the\namendmends to the merge commit and the changes introduced by rebasing the\nmerge parents.\n\nI am now getting the sense as if Sergey's approach (with your, let's say,\n\"fix\") is trying to apply too much, and by using the original merge commit\nas merge base then tries to undo part of that.\n\n> > > I honestly don't see any advantages of Phillip's method over the\n> > > original, except personal preferences. At the same time, I have no\n> > > objection of using it either, provided consistency check problem is\n> > > solved there as well.\n> > \n> > Okay, let me reiterate then, because I do not want this point to be\n> > missed:\n> > \n> > Phillip's method is essentially merging the new tips into the original\n> > merge, pretending that the new tips were not rebased but merged into\n> > upstream.\n> > \n> > So it exploits the duality of the rebase and merge operation, which both\n> > result in identical trees (potentially after resolving merge conflicts).\n> > \n> > I cannot think of any such interpretation for your proposal augmented by\n> > Buga's fix-ups. And I haven't heard any such interpretation from your\n> > side, either.\n> \n> Ok here it goes (I might be still wrong, but please bare with me).\n> \n> What Sergey originally described also uses the \"duality of the rebase \n> and merge operation\", too ;) Just in a bit different way (and might \n> be a more straightforward one?).\n\nI will be the judge whether it looks more straight-forward to me. :-)\n\n> Here`s a starting point, two commits A and B, merged into M:\n> \n> (3) ---A\n>         \\\n>          M\n>         /\n>     ---B\n> \n> \n> According the \"patch theory\"[1] (which might not be too popular \n> around here, but should serve the purpose for what I`m trying to \n> explain),\n\nI think that the patch theory is not usually quoted here because\n\n1) originally, Darcs had this snake oil way of (over-)selling its theory\n   as having \"roots in quantum mechanics\" [*1*] at the time Git took off,\n   and\n\n2) it does not really have a good concept of rebasing, even if it should\n   be theoretically possible to integrate that into the \"theory of\n   patches\".\n\n> each merge commit can be \"transformed\" to two non-merge commits, one on\n> top of each of the merge parents, where new commit brings its original\n> merge parent commit tree to the state of the merge commit tree:\n> \n> (4) ---A---U1\n> \n> \n> \n>     ---B---U2\n\nYou get the same result if you stick to regular graph theory, of course.\nAll you need to do is to interpret the directed vertices between nodes as\na patch & parent relationship. Simple.\n\n> Now, we have two new commits, U1 and U2, each having the same tree as \n> previous merge commit M, but representing changes in regards to \n> specific parents - and this is essentially what Sergey`s original \n> approach was using (whether he knew it, or not).\n> \n> When it comes to rebasing, it`s pretty simple, too. As this:\n> \n> (5) ---X1---o---o---o---o---o---X2 (master)\n>        |\\\n>        | A1---A2---A3\n>        |             \\\n>        |              M\n>        |             /\n>        \\-B1---B2---B3\n> \n> ... actually equals this:\n> \n> (6) ---X1---o---o---o---o---o---X2 (master)\n>        |\\\n>        | A1---A2---A3---U1\n>        |\n>        |\n>        |\n>        \\-B1---B2---B3---U2\n> \n> ... where trees of M, U1 and U2 are same,\n\nOkay, so you basically duplicated the merge commit and dropped its\nsemantics as a merge commit. That is a very big difference to Phillip's\napproach already.\n\nIt opens the door to ambiguities, as we will see later.\n\n> and we can use the regular rebase semantics and rebase it to this:\n> \n> (7) ---X1---o---o---o---o---o---X2 (master)\n>                                 |\\\n>                                 | A1'--A2'--A3'--U1'\n>                                 |\n>                                 |\n>                                 |\n>                                 \\-B1'--B2'--B3'--U2'\n> \n> ... which is essentially this again:\n> \n> (8) ---X1---o---o---o---o---o---X2 (master)\n>                                 |\\\n>                                 | A1'--A2'--A3'\n>                                 |            \\\n>                                 |             M'\n>                                 |            /\n>                                 \\-B1'--B2'--B3'\n> \n> ... where it is still true that trees of U1', U2' and M' are still \n> the same. So we managed to rebase a merge commit without ever doing a \n> merge :) (note that, practically, we _can_ finally even merge U1' and \n> U2' to produce M', it shouldn`t really matter as all the trees are \n> the same, so merge will be a no-op)\n\nU1' and U2' do not have the same tree, though *especially* when the user\ndid not edit the todo list to insert/modify/drop/reorder commits.\n\nThis violation of expectations is of course caused by \"duplicating the\nmerge commit\" into U1 and U2.\n\nBut let's continue.\n\n> But, as we saw (what you`ve explained), this doesn`t really work in \n> case one of the sides of the merge gets \"disbalanced\" (so to say), \n> like dropping a commit (which could also happen non-interactively, \n> where a commit has been cherry-picked to a different branch, but\n> previously obsoleted by `-s ours` merge).\n\nPrecisely. A *very* important counter-argument to this approach so far.\n\n> As observed, dropped commit could still wrongly get into final merge \n> commit tree (or cherry-picked commit wrongly not get there), due to \n> the nature of those rebased U1 and U2 temporary commits to hold all \n> the differences in regards to their specific merge commit parent.\n\nThe reason for this, of course, is that either U1's or U2's diff will show\nthose differences, *and we still try to rebase them even if the user\nalready dropped them*.\n\nBut let's continue.\n\n> A natural improvement to original idea which Sergey eventually came \n> up with after my findings (which you now ended up calling a hack, even, \n> but I would respectfully disagree), is to use original merge commit M \n> as a merge base for final merge of U1' and U2' - and here is why it \n> works, too, and why I wouldn`t consider it a hack, but a proper (and \n> a solid) solution.\n> \n> Merge commit M is what we are rebasing, so we should have a way to \n> somehow learn from it, alongside U1 and U2 temporary commits - and \n> that is what using original merge commit M as a base does for us. It \n> helps us spot any \"disbalances\" that happened in comparison to original \n> merge parent trees, which is exactly what we`re interested in.\n\n... except that it gets the direction wrong. Rather than trying to *avoid*\nrebasing possibly dropped changes, it tries to kind of \"undo\" them by\nusing a merge base that does not really make sense (unless you think of it\nas a \"revert\").\n\nIt would make sense if M could interpreted as a branch point. But it\ncannot, as we specifically did *not* continue to develop the merge parents\nfrom that merge commit.\n\nInstead, what we did was to branch off of the original branch point X1.\n\nReframing the rebase of a sub-branch (X1..A3) as merge with upstream,\nhowever, we can interpret M and A3' as revisions we want to merge, with A3\nas the merge base.\n\n(You can think of it in terms of the \"theory of patches\" thusly: if X1..A3\nis represented by patch K, X1..X2 by patch L, and X2..A3' by K', then what\nwe want to merge into M is K^(-1).L.K', which is precisely what A3..A3'\ntranslates to.)\n\nYou can also think of it as diverging changes going from A3: one direction\nwas to merge (resulting in the commit M), the other direction was to\nrebase onto X2 (resulting in A3'), and a 3-way merge M <- A3 -> A3' will\nreconcile those changes (and you will want to repeat with B3/B3', too).\n\nLet's put that into the context of your example: instead of introducing U1\nand U2, we introduce V1 and V2 right away, as temporary *merge* commits,\nwhere the tree of V1 is identical to the one of A3', and the tree of V2\nto that of B3'.\n\n ---X1---o---o---o---o---o---X2 (master)\n    |                        |\\\n    |                        | A1'--A2'--A3'--V1\n    |\\                       |               /\n    | -A1---A2---A3----------+---------------\n    |              \\         |\n    |               M        \\-B1'--B2'--B3'--V2\n    |              /                         /\n     \\-B1---B2---B3--------------------------\n\nNote: the *really* important difference is that these temporary commits\nare based on the *rebased* history rather than the *unrebased* history.\n\nSecond note: this is very related to Git for Windows' original strategy of\ncoping with the non-fast-forwarding nature of rebases: after rebasing the\nWindows-specific patches on top of core Git, we merged (with `-s ours`)\nthe unrebased history. This 1) makes it fast-forwardable, and 2) still\nrebases the patches [*2*].\n\nThird note: my favorite mental model is still the duality of rebasing and\nmerging, in which case V1 and V2 would not have A3' and B3' as first\nparents, but X2.\n\nPhillip's strategy is to merge M with V1 and V2.\n\nThis translates to \"merge the amendments of the merge commit M with the\nchanges introduced by rebasing its merge parents\".\n\nThe really cute part about this is that (in contrast to using U1' and\nU2'), we do not merge the amendments of the merge commit multiple times,\nbut exactly once. And therefore, we do not need to \"undo\" them by using\nthe original merge commit as merge base, either (which would introduce\nmany more opportunities for merge conflicts to creep in, oftentimes\nunnecessary conflicts to begin with).\n\n> In ideal case (as per \"patch theory\"[1]), final merge of rebased U1' \n> and U2' with original merge commit M as a base would be rather simple, \n> too (not to say pointless again), as both U1' and U2' would have same \n> changes in comparison to M, namely all the changes from commit we are \n> rebasing from (X1 above) to commit we are rebasing to (X2 above).\n> \n> But in a more complex case like this:\n> \n> (9) ---X1---B2'---o---o---o---o---X2 (master)\n>                                   |\\\n>                                   | A12--A2'---B3'\n>                                   |             \\\n>                                   |              M'\n>                                   |             /\n>                                   \\-B1'--B3'---B4\n> \n> ..., being what we are ultimately interested in, it helps us notice \n> all kind of changes on our rebased merge parent branches, and act \n> accordingly (as shown by my previously posted test script[2]).\n\nTo use the \"theory of patches\" to explain why Phillip's approach is so\nmuch more appealing: in Sergey's approach, we will rebase U1 (which is\n\"sort of\" B1.B2.B3 in the \"theory of patches\"). If the cherry-pick of B2'\ncaused merge conflicts that had to be resolved, then these merge conflicts\nwill have to be resolved *again* when rebasing U1 (because B2 is *part of*\nU1). And of course they will have to be resolved *again* when merging U1'\nwith U2'.\n\nIn short: Phillip's approach is a short-cut that avoids unnecessary merge\nconflicts because it avoids rebasing changes that would need to be undone\nright away anyway.\n\n> All this said (and hoping anyone is still reading this), to shed some \n> light on what I meant by \"favoring Sergey`s approach in general, but \n> _implemented_ through what Phillip described\".\n> \n> I think we should use temporary commits U1 and U2, being a sound \n> approach backed up by the \"patch theory\"[1], as it helps us notice \n> any \"disbalances\" of the rebased merge commit parents trees (so we \n> can stop for user inspection), finally merging them with original \n> merge commit as a base, in order to spot additional changes on trees \n> of the merge commit parents we are rebasing.\n\nIn Phillip's approach, we do not need to rebase the amendments of the\nmerge commit M twice (or even more times, for octopus merges). Therefore,\nthere is no opportunity for these imbalances.\n\n> But, the merging steps themselves, backed up by a need to stop for \n> conflict resolution as soon as one happens, should be performed \n> _iteratively_, like Phillip showed us... I would think :)\n\nFrom a user interface perspective, this is a bad idea: you would now have\nto communicate to the user *where* in the process they are.\n\nAnd for that you would have to explain that process to them. Including\n\"theory of patches\" and all.\n\nTaking me as a prime example, you now know how tedious and impractical\nthat would be.\n\n> And, for example, that would do wonders when we introduce completely \n> new branch during an interactive rebase, too, for example:\n> \n> (10) ---X1---B2'---o---o---o---o---X2 (master)\n>         |\\                        /|\\\n>         | A1---A2---A3---U1       || A12--A2'---B3'---U1'\n>         |             \\           ||             \\\n>         |              M          ||              M'\n>         |             /           ||             /|\n>         \\-B1---B2---B3---U2       |\\---B3'---B4-/-|---U2'\n>                                   |               |\n>                                   \\-----B1'-------/\n> \n> \n> In this situation, we would merge all temporary Ux commits using \n> original merge M as a merge base, and then merge _that_ resulting \n> tree with B1' (being a newly introduced merge commit parent), using \n> whatever merge base is most appropriate between the two (in this \n> case, X2).\n\nThe semantics of octopus merges are very different from regular recursive\nmerges. I am not sure that we want to go there in this discussion...\n\nIf, on the other hand, you do not try to turn M from a regular 2-parent\nmerge commit into an octopus merge during an interactive rebase, but\ninstead split the B branch into two branches *before* merging the result\ninto the rebased merge commit, we are in the same square as\nreordering/dropping/inserting/modifying patches: to neither of the\npresented strategies would it matter what kind of branch topology the\nmerge parents have.\n\nFor the record: I am still not convinced that Phillip's and Sergey's\napproach are equivalent, even in terms of the \"theory of patches\". But if\nthey are, then Phillip's version is a shorter version that avoids applying\nchanges just to revert them right away. And in a setting where each patch\ncan cause merge conflicts (as the interactive rebase is), the less changes\nyou have to apply, the better.\n\nCiao,\nDscho\n\n> [1] https://en.wikibooks.org/wiki/Understanding_Darcs/Patch_theory\n\nFootnote *1*: https://web.archive.org/web/20050511033324/http://darcs.net/\nAnd it must be said: the \"theory of patches\" are not rooted in quantum\nmechanics. They might be inspired by Darc's inventor being more familiar\nwith it than with fundamental algebra, for sure. The \"theory of patches\"\nis nothing else than an algebra on graph vertices, though.\n\nFootnote *2*: We called this strategy the rebasing merge. We replaced it\nby the opposite strategy (\"merging rebase\", i.e. starting with the `git\nmerge -s ours <unrebased>` and *then* applying the rebased patches)\nbecause the latter makes it really obvious where the Windows-specific\npatches *start*.\n\nOf course, you could draw the diagram very easily also using the merging\nrebase, the conclusion would still be the same.\n"},{"id":"341422","messageId":"nycvar.QRO.7.76.6.1803111644380.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"d29d3c0e-6473-0461-c8ea-02975ce4de14@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-11T15:47:20Z","receivedAt":"2018-03-11T15:47:29Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Fri, 9 Mar 2018, Igor Djordjevic wrote:\n\n> On 08/03/2018 20:58, Igor Djordjevic wrote:\n> > \n> > > Phillip's method is essentially merging the new tips into the original\n> > > merge, pretending that the new tips were not rebased but merged into\n> > > upstream.\n> > \n> > [...]\n> > \n> > Here`s a starting point, two commits A and B, merged into M:\n> > \n> > (3) ---A\n> >         \\\n> >          M\n> >         /\n> >     ---B\n> > \n> > \n> > According the \"patch theory\"[1] (which might not be too popular \n> > around here, but should serve the purpose for what I`m trying to \n> > explain), each merge commit can be \"transformed\" to two non-merge \n> > commits, one on top of each of the merge parents, where new commit \n> > brings its original merge parent commit tree to the state of the \n> > merge commit tree:\n> > \n> > (4) ---A---U1\n> > \n> > \n> > \n> >     ---B---U2\n> > \n> > \n> > Now, we have two new commits, U1 and U2, each having the same tree as \n> > previous merge commit M, but representing changes in regards to \n> > specific parents - and this is essentially what Sergey`s original \n> > approach was using (whether he knew it, or not).\n> > \n> > When it comes to rebasing, it`s pretty simple, too. As this:\n> > \n> > (5) ---X1---o---o---o---o---o---X2 (master)\n> >        |\\\n> >        | A1---A2---A3\n> >        |             \\\n> >        |              M\n> >        |             /\n> >        \\-B1---B2---B3\n> > \n> > ... actually equals this:\n> > \n> > (6) ---X1---o---o---o---o---o---X2 (master)\n> >        |\\\n> >        | A1---A2---A3---U1\n> >        |\n> >        |\n> >        |\n> >        \\-B1---B2---B3---U2\n> > \n> > ... where trees of M, U1 and U2 are same, and we can use the regular \n> > rebase semantics and rebase it to this:\n> > \n> > (7) ---X1---o---o---o---o---o---X2 (master)\n> >                                 |\\\n> >                                 | A1'--A2'--A3'--U1'\n> >                                 |\n> >                                 |\n> >                                 |\n> >                                 \\-B1'--B2'--B3'--U2'\n> > \n> > ... which is essentially this again:\n> > \n> > (8) ---X1---o---o---o---o---o---X2 (master)\n> >                                 |\\\n> >                                 | A1'--A2'--A3'\n> >                                 |            \\\n> >                                 |             M'\n> >                                 |            /\n> >                                 \\-B1'--B2'--B3'\n> > \n> \n> Having explained all this, I realized this is the same \"essentially \n> merging the new tips into the original pretending that the new tips \n> were not rebased but merged into upstream\" as Phillip`s one, just \n> that we have additional temporary commits U1 and U2 (as per mentioned \n> \"patch theory\") :)\n\nBut if the old tips had been merged into upstream (resulting in the new\ntips), then the merge bases would be *the old tips*.\n\nI am still not sure for what scenarios Phillip's strategy is the same as\nSergey's (updated) one, as the former strategy can do completely without\ntemporary commits, and cannot introduce ambiguities when rebasing the\nchanges introduced by M (i.e. the \"amendmendts\" we talked about).\n\nCiao,\nDscho\n"},{"id":"341423","messageId":"f4e6237a-84dc-1aa8-150d-041806e2416e@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111256410.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-11T16:33:12Z","receivedAt":"2018-03-11T16:33:37Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 11/03/2018 13:00, Johannes Schindelin wrote:\n> \n> > I actually like `pick` for _rebasing_ merge commits, as `pick` is \n> > already used for rebasing non-merge commits, too, so it feels natural.\n> \n> Phillip is right, though: this would repeat the design mistake of\n> --preserve-merges.\n> \n> We must not forget that the interactive mode is the target here, and that\n> the syntax (as well as the generated todo list) must allow for easy\n> modification. The `pick <merge>` approach does not allow that, so we\n> cannot use it.\n> \n> The `merge -R -C <original-commit> <merge-head>` approach is a lot better:\n> it offers the flexibility, without sacrificing the ease when not modifying\n> the todo list.\n\nEh, I`m afraid the quote you took is missing the rest of its \n(important) context, where I mentioned already proposed format for \n`pick` in that other subthread[1], including other parameters beside \nmerge commit to pick, as that parent mapping.\n\nI agree with both of you that `pick <merge-commit>` is inflexible \n(not to say just plain wrong), but I never thought about it like that.\n\nIf we are to extract further mentioned explicit old:new merge \nparameter mapping to a separate discussion point, what we`re \neventually left with is just replacing this:\n\n\tmerge -R -C <original--merge-commit> <merge-head>\n\n... with this:\n\n\tpick <original--merge-commit> <merge-head>\n\n\nThat is what I had in mind, seeming possibly more straightforward and \nbeautifully aligned with previously existing (and well known) \n`rebase` terminology.\n\nNot to say this would make it possible to use other `rebase -i` todo \nlist commands, too, like if you want to amend/edit merge commit after \nit was rebased, you would write:\n\n\tedit <original--merge-commit> <merge-head>\n\n..., where in case you would simply like to reword its commit \nmessage, it would be just:\n\n\treword <original--merge-commit> <merge-head>\n\n\nEven `squash` and `fixup` could have their place in combination with \na (to be rebased) merge commit, albeit in a pretty exotic rebases, \nthus these could probably be just disallowed - for the time being, at \nleast.\n\nThe real power would be buried in implementation, learning to rebase \nmerge commits, so user is left with a very familiar interface, slightly \nadapted do accommodate a bit different nature of merge commit in \ncomparison to an ordinary one, also to allow a bit more of interactive \nrebase functionality, but it would pretty much stay the same, without \neven a need to learn about new `merge`, `-R`, `-C`, and so on.\n\nYes, those would have its purpose, but for real merging then \n(creating new merges, or recreating old ones), not necessarily for \nmerge rebasing.\n\nWith state of `merge -R -C ...` (that `-R` being the culprit), it \nkind of feels like we`re now trying to bolt \"rebase merges\" \nfunctionality onto a totally different one (recreate merges, serving \na different purpose), making them both needlessly dependent on each \nother, further complicating user interface, making it more confusing \nand less tunable as per each separate functionality needs (rebase vs. \nrecreate).\n\nI guess I`m the one to pretty much blame here, too, as I really \nwanted `--recreate-merges` to handle \"rebase merges\" better, only to \nlater realize it might not be the best tool for the job, and that a \nmore separate approach would be better (at least not through the same \n`merge` todo list command)...\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com/\n"},{"id":"341425","messageId":"b329bb98-f9d6-3d51-2513-465aad2fa37a@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111301340.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-11T17:34:12Z","receivedAt":"2018-03-11T17:34:36Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 11/03/2018 13:08, Johannes Schindelin wrote:\n> \n> > Hmm, funny enough, `pick <original merge>` was something I though about\n> > originally, too, feeling that it might make more sense in terms on\n> > what`s really going on, but I guess I wanted it incorporated into\n> > `--recreate-merges` too much that I tried really hard to fit it in,\n> > without changing it much :/\n> \n> The `pick <original-merge>` syntax is too limited to allow reordering, let\n> alone changing the parents.\n\nI agree, `pick <original-merge>` syntax alone is never what I had in \nmind, so it`s missing further context here, touched in that other \nsubthread[1]. My fault, sorry for confusion.\n\n> >   pick <original-merge> <original-parent1>:HEAD <original-parent2>:<new-parent2>\n> \n> I do not really like it, as it makes things a ton less intuitive. If you\n> did not know about this here discussion, and you did not read the manual\n> (and let's face it: a UI that does not require users to read the manual is\n> vastly superior to a UI that does), and you encountered this command:\n> \n> \tmerge deadbeef cafecafe:download-button\n> \n> what would you think those parameters would mean?\n> \n> Granted, encountering\n> \n> \tmerge -R -C deadbeef download-button # Merge branch 'download-button'\n> \n> is still not *quite* as intuitive as I would wish. Although, to be honest,\n> if I encountered this, I would think that I should probably leave the -R\n> and the -C deadbeef alone, and that I could change what is getting merged\n> by changing the `download-button` parameter.\n\nAgreed, encountering mapping is slightly more complicated, but I \nwould argue it`s much more powerful at the same time, too, thus \npretty much worth it.\n\nWithout it, actually, it seems like we`re repeating the mistake of \n`--preserve-merges`, where we`re assuming too much (order of new and \nold parents being the same, and I guess number of them, too).\n\nOh, and as we`re still discussing in terms of `merge` command, using \n(elsewhere mentioned[1]) `pick` instead, it might be even less \nnon-intuitive, as we`re not married to `merge` semantics any more:\n\n\tpick deadbeef cafecafe:download-button\n\n\nAnd might be calling it \"non-intuitive\" is unfair, I guess it would \nrather be \"not familiar yet\", being case with any new functionality, \nlet alone a very powerful one, where getting a clue on what it does \nat the beginning could do wonders later.\n\nSacrificing that power for a bit of perceived simplicity, where it \nactually assumes stuff on its own (trying to stay simple for the \nuser), doesn`t seem as a good way to go in the long run.\n\nSometimes one just needs to read the manual, and I don`t really think \nthis is a ton complicated, but just something we didn`t really have \nbefore (real merge rebasing), so it requires a moment to grasp the \nconcept.\n\nBut I`m still not sure if there isn`t a better way to present \nexplicit mapping, just that <old>:<new> seemed as the most straightforward \none to pass on the point for the purpose of discussing it.\n\nAnd I`m not reluctant to simplifying user interface, or for dropping \nthe explicit mapping altogether, even, just for carefully measuring \nwhat we could lose without explicit mapping - think flexibility, but \nease and correctness of implementation, too, as we need to guess the \nold merge parents and which new one they should correspond to.\n\n> > p.s. Are we moving towards `--rebase-merges` I mentioned in that \n> > other topic[1], as an add-on series after `--recreate-merges` hits \n> > the mainstream (as-is)...? :P\n> \n> That's an interesting question. One that I do not want to answer alone,\n> but I would be in favor of `--rebase-merges` as it is IMHO a much better\n> name for what this option is all about.\n\nSaying in favor of `--rebase-merges`, you mean as a separate option, \nalongside `--recreate-merges` (once that series lands)?\n\nThat does seem as the most clean, intuitive and straightforward \nsolution. Depending on the option you provide (recreate vs rebase), \ntodo list would be populated accordingly by default - but important \nthing is \"todo list parser\" would know to parse both, so one can \nstill adapt todo list to both recreate (some) and rebase (some other) \nmerges at the same time.\n\nOf course, this only once `--rebase-merges` gets implemented, too, \nbut as we had waited for it for so long, it won`t hurt to wait a bit \nmore and possibly do it more properly, than rush it now and make a \nconfusing user interface, needlessly welding two functionalities \ntogether (rebase vs. recreate).\n\nBut I guess you already knew my thoughts, so let`s see what other`s \nthink, too ;)\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/f4e6237a-84dc-1aa8-150d-041806e2416e@gmail.com/\n"},{"id":"341426","messageId":"89fe98ed-461e-bd48-a833-baa15252cdcd@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111308320.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-11T17:46:33Z","receivedAt":"2018-03-11T17:46:56Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 11/03/2018 13:11, Johannes Schindelin wrote:\n> \n> > > I did wonder about using 'pick <original-merge>' for rebasing merges\n> > > and keeping 'merge ...' for recreating them but I'm not sure if that\n> > > is a good idea. It has the advantage that the user cannot specify the\n> > > wrong parents for the merge to be rebased as 'git rebase' would work\n> > > out if the parents have been rebased, but maybe it's a bit magical to\n> > > use pick for merge commits. Also there isn't such a simple way for the\n> > > user to go from 'rabase this merge' to 'recreate this merge' as they'd\n> > > have to write the whole merge line themselves (though I guess\n> > > something like emacs' git-rebase.el would be able to help with that)\n> >\n> > Since the ultimate commit hashes of newly rebased commits would be\n> > unknown at the time of writing the todo file, I'm not sure how this\n> > would work to specify the parents?\n> \n> I agree with Phillip's follow-up that the `pick <original-merge>` syntax\n> would pose a problem, but for different reasons: We already tried it, with\n> --preserve-merges, and it is just a really stupid syntax that does not\n> allow the user even to reorder commits. Or drop commits (except at the\n> very end of the todo list).\n\nHehe, please excuse me, but in the light of that other explicit (or \nnot) parent mapping discussion[1], I would take a chance to be really \nsneaky here and say that being non-explicit \"is just a really stupid \nsyntax that does not allow the user even to reorder rebased merge \nparents. Or drop parents (except at the very end of the parent list).\" ;)\n\n[1] https://public-inbox.org/git/b329bb98-f9d6-3d51-2513-465aad2fa37a@gmail.com/\n"},{"id":"341427","messageId":"6362804d-e204-a9e0-9ff0-51d8497ce921@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111644380.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-11T20:53:17Z","receivedAt":"2018-03-11T20:53:41Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 11/03/2018 16:47, Johannes Schindelin wrote:\n> \n> > > > Phillip's method is essentially merging the new tips into the original\n> > > > merge, pretending that the new tips were not rebased but merged into\n> > > > upstream.\n> > >\n> > > [...]\n> > >\n> > > Here`s a starting point, two commits A and B, merged into M:\n> > >\n> > > (3) ---A\n> > >         \\\n> > >          M\n> > >         /\n> > >     ---B\n> > >\n> > >\n> > > According the \"patch theory\"[1] (which might not be too popular \n> > > around here, but should serve the purpose for what I`m trying to \n> > > explain), each merge commit can be \"transformed\" to two non-merge \n> > > commits, one on top of each of the merge parents, where new commit \n> > > brings its original merge parent commit tree to the state of the \n> > > merge commit tree:\n> > >\n> > > (4) ---A---U1\n> > >\n> > >\n> > >\n> > >     ---B---U2\n> > >\n> > >\n> > > Now, we have two new commits, U1 and U2, each having the same tree as \n> > > previous merge commit M, but representing changes in regards to \n> > > specific parents - and this is essentially what Sergey`s original \n> > > approach was using (whether he knew it, or not).\n> > >\n> > > When it comes to rebasing, it`s pretty simple, too. As this:\n> > >\n> > > (5) ---X1---o---o---o---o---o---X2 (master)\n> > >        |\\\n> > >        | A1---A2---A3\n> > >        |             \\\n> > >        |              M\n> > >        |             /\n> > >        \\-B1---B2---B3\n> > >\n> > > ... actually equals this:\n> > >\n> > > (6) ---X1---o---o---o---o---o---X2 (master)\n> > >        |\\\n> > >        | A1---A2---A3---U1\n> > >        |\n> > >        |\n> > >        |\n> > >        \\-B1---B2---B3---U2\n> > >\n> > > ... where trees of M, U1 and U2 are same, and we can use the regular \n> > > rebase semantics and rebase it to this:\n> > >\n> > > (7) ---X1---o---o---o---o---o---X2 (master)\n> > >                                 |\\\n> > >                                 | A1'--A2'--A3'--U1'\n> > >                                 |\n> > >                                 |\n> > >                                 |\n> > >                                 \\-B1'--B2'--B3'--U2'\n> > >\n> > > ... which is essentially this again:\n> > >\n> > > (8) ---X1---o---o---o---o---o---X2 (master)\n> > >                                 |\\\n> > >                                 | A1'--A2'--A3'\n> > >                                 |            \\\n> > >                                 |             M'\n> > >                                 |            /\n> > >                                 \\-B1'--B2'--B3'\n> > >\n> >\n> > Having explained all this, I realized this is the same \"essentially \n> > merging the new tips into the original pretending that the new tips \n> > were not rebased but merged into upstream\" as Phillip`s one, just \n> > that we have additional temporary commits U1 and U2 (as per mentioned \n> > \"patch theory\") :)\n> \n> But if the old tips had been merged into upstream (resulting in the new\n> tips), then the merge bases would be *the old tips*.\n\nExactly, and that is what part you`ve cut out of the quote was \nshowing :) By Phillip`s implementation, we would start with *old tips* \nas merge bases, indeed (old tips being U1 and U2 in this case), where \nit further gets transformed as previously written:\n\n> \tgit merge-recursive U1 -- M U1'\n> \ttree=\"$(git write-tree)\"\n> \tgit merge-recursive U2 -- $tree U2'\n> \ttree=\"$(git write-tree)\"\n> \n> ..., where we know U1 = U2 = M (in regards to trees), so this is the \n> same as:\n> \n> \tgit merge-recursive M -- M U1'\n> \ttree=\"$(git write-tree)\"\n> \tgit merge-recursive M -- $tree U2'\n> \ttree=\"$(git write-tree)\"\n\nHere, `git merge-recursive M -- M U1'` simply equals to U1' tree \n(being a fast-forward merge), so we can write the two merges above as\na single merge, too:\n\n> \tgit merge-recursive M -- U1' U2'\n> \ttree=\"$(git write-tree)\"\n> \n> ... which is exactly what Sergey`s (updated) approach suggests, \n> merging U1' and U2' with M as merge-base (and shown inside that \n> sample implementation script I provided[1]) :)\n\nSo from *old tips* being the rebased merge base (Phillip), we got to \n*old merge commit* being the rebased merge base (Sergey), or vice \nversa. Does this shed a bit more light on it now? Or you wanted to \npoint out something else in the first place...?\n\n> I am still not sure for what scenarios Phillip's strategy is the same as\n> Sergey's (updated) one, as the former strategy can do completely without\n> temporary commits [...]\n\nI think the root of misunderstanding might be coming from the fact \nthat Sergey was mainly describing a general concept (without a \nstrictly defined implementation strategy, not being restricted to a \nspecific one), where Phillip came up with a solution that eventually \nseems to use the same concept (as those transformations above should \nshow), but simplifying it further inside a concrete implementation.\n\nBy saying that Phillip \"simplified it\", even though transformations \nshown above might show different, I mean he managed to further \ndecompose what Sergey was aiming for, abstracting temporary commits U1 \nand U2 out of the equation, thus making them optional, but not \nrequired.\n\nSo, if easier to implement and reason about, I think what Phillip \ndescribed is a way to go to produce the rebased merged commit - but \nin case we want to have that \"clean rebased merge\" check that U1' == \nU2' comparison does provide, as they should really be the same (tree \nwise) in simple (and the most used?) merge rebasing, we can do that \nafter the fact, even.\n\nMight be this check could be the most useful in non-interactive \nrebases, where rebased merge parents` trees could be expected to stay \n\"balanced\" more often (U1' == U2'), without interactive fiddling to \n\"disbalance\" them. I don`t know, just thinking out loud.\n\n> [...] and cannot introduce ambiguities when rebasing the\n> changes introduced by M (i.e. the \"amendmendts\" we talked about).\n\nHmm, not following here, which ambiguities are we talking about?\n\nThanks, Buga\n"},{"id":"341428","messageId":"d18a6e73-ce6f-b4aa-8ead-7aaabddf454d@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111324390.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-11T22:04:27Z","receivedAt":"2018-03-11T22:04:50Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nI`m yet to read (and reason about) your whole (very informative) \nreply, but I just wanted to address this part first, as it might be a \nclear end-game situation already, due to a mutual agreement, all the \nrest being purely academic, interesting, but not any more (that) \nimportant to discuss.\n\nOn 11/03/2018 16:40, Johannes Schindelin wrote:\n> \n> > For myself, I do actually favor Sergey`s approach in general, but \n> > _implemented_ through what Phillip described (or a mixture of both, to \n> > be precise). But, let me explain... :)\n> \n> So as you explained later in this sub-thread, Sergey's approach is\n> essentially the same as Phillip's.\n> \n> I still do not understand Sergey's approach on a fundamental level. I\n> mean, I can follow his instructions how to implement his algorithm, but it\n> is as if I had a blindfold on and somebody guided me through a maze: I\n> understand *what* I am supposed to do, but I have no clue *why*.\n> \n> And admittedly, I got very frustrated when a document was thrown my way\n> that is too long to read in one sitting, and all of my attempts at getting\n> clear and comprehensible answers to specific questions were met with \"go\n> and read that document, I am sure you will understand then\".\n> \n> For something as fundamental to my daily workflow as an interactive rebase\n> (*especially* when trying to maintain the branch topology), this is no\n> good at all.\n> \n> Since you already confirmed that there is essentially no difference\n> between the two approaches, I will simply go with the one I understand, in\n> particular I understand *why* it works.\n> \n> But let's read on, maybe I will change my mind based on your explanations\n> (which do answer my questions, thank you so much for that)...\n\nNo problem, I learned much myself trying to write those explanations \nin the first place, and I still need to read on yet myself, seeing \nhow well my explanations actually fared :) Thank you for still \nholding on, though.\n\nBut I just wanted to point out that you can really just go with what \nPhillip described if you find that easier to reason about (and/or \nimplement), there`s even no need for mind changing, as essentially, \nand in my opinion, it seems to be just a bit different implementation \nof the same concept (but not requiring temporary commits).\n\nThat said, *if* we decide we like temporary commit U1' == U2' consistency \ncheck (especially for non-interactive rebase, maybe), we can produce \nthese after the fact for the sake of the check only.\n\nI will come with a follow-up, but all the rest might be less important.\n\nRegards, Buga\n"},{"id":"341472","messageId":"nycvar.QRO.7.76.6.1803121056400.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"6362804d-e204-a9e0-9ff0-51d8497ce921@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-12T10:20:00Z","receivedAt":"2018-03-12T10:20:13Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Sun, 11 Mar 2018, Igor Djordjevic wrote:\n\n> On 11/03/2018 16:47, Johannes Schindelin wrote:\n> > \n> > > Having explained all this, I realized this is the same \"essentially\n> > > merging the new tips into the original pretending that the new tips\n> > > were not rebased but merged into upstream\" as Phillip`s one, just\n> > > that we have additional temporary commits U1 and U2 (as per\n> > > mentioned \"patch theory\") :)\n> > \n> > But if the old tips had been merged into upstream (resulting in the\n> > new tips), then the merge bases would be *the old tips*.\n> \n> Exactly, and that is what part you`ve cut out of the quote was \n> showing :) By Phillip`s implementation, we would start with *old tips* \n> as merge bases, indeed (old tips being U1 and U2 in this case),\n\nI really do not see how it would make sense to take the original merge\ncommit as merge base in this scenario. It makes no *logical* sense: in\nwhich interpretation did you develop changes in two divergent directions\nfrom that merge commit?\n\nWhereas if you use the old tips as merge bases, you can say very easily\nwhat those two directions were: one merged with other merge parents, the\nother direction rebased on top of upstream. There. Two divergent sets of\nchanges that we want to reconcile (\"merge\"). Easy as apple pie.\n\n> where it further gets transformed as previously written:\n> \n> > \tgit merge-recursive U1 -- M U1'\n> > \ttree=\"$(git write-tree)\"\n> > \tgit merge-recursive U2 -- $tree U2'\n> > \ttree=\"$(git write-tree)\"\n> > \n> > ..., where we know U1 = U2 = M (in regards to trees), so this is the \n> > same as:\n> > \n> > \tgit merge-recursive M -- M U1'\n> > \ttree=\"$(git write-tree)\"\n> > \tgit merge-recursive M -- $tree U2'\n> > \ttree=\"$(git write-tree)\"\n> \n> Here, `git merge-recursive M -- M U1'` simply equals to U1' tree \n> (being a fast-forward merge), so we can write the two merges above as\n> a single merge, too:\n> \n> > \tgit merge-recursive M -- U1' U2'\n> > \ttree=\"$(git write-tree)\"\n> > \n> > ... which is exactly what Sergey`s (updated) approach suggests, \n> > merging U1' and U2' with M as merge-base (and shown inside that \n> > sample implementation script I provided[1]) :)\n> \n> So from *old tips* being the rebased merge base (Phillip), we got to \n> *old merge commit* being the rebased merge base (Sergey), or vice \n> versa. Does this shed a bit more light on it now? Or you wanted to \n> point out something else in the first place...?\n\nOkay, I'll trust you that these stunts show that the two strategies are\nequivalent as to what their results are.\n\nThe biggest difference is that it is easy for me to see the motivation\nbehind Phillip's strategy, whereas I am still puzzled why one would come\nup with a complicated strategy that splits merge commits and re-merges\nthem later, and why it should work in general (I still suspect that this\nis not the case).\n\nWhere \"easy\" meant that I had to spend 1h still to figure out why using\nthe unrebased merge parents as merge bases. The same amount of time did\nnot allow me to wrap my head around Sergey's verbose explanations.\n\nBut I'll take your word for it that the strategies are equivalent, and go\nwith the one that has both a simpler explanation (in my mind, at least),\nand an more robust implementation.\n\n> > I am still not sure for what scenarios Phillip's strategy is the same as\n> > Sergey's (updated) one, as the former strategy can do completely without\n> > temporary commits [...]\n> \n> I think the root of misunderstanding might be coming from the fact \n> that Sergey was mainly describing a general concept (without a \n> strictly defined implementation strategy, not being restricted to a \n> specific one), where Phillip came up with a solution that eventually \n> seems to use the same concept (as those transformations above should \n> show), but simplifying it further inside a concrete implementation.\n\nWell, Sergey started off by suggesting the \"rebase the patch relatively to\nthe first parent always\" strategy, then came up with a long-ish email\ndescribing a different approach (which I slowly realize is related to the\nfirst strategy, and it would have been *much* appreciated if it was not\nleft to the reader to figure that one out), then incorporated what I\ncalled your hack (again, no clear and concise description what changed,\njust throwing a bunch of big bones to the dogs with the next long-ish\ndocument).\n\nSo I will not apologize for stopping to pay so much attention to that\nsub-thread at some point.\n\n> By saying that Phillip \"simplified it\", even though transformations\n> shown above might show different, I mean he managed to further decompose\n> what Sergey was aiming for, abstracting temporary commits U1 and U2 out\n> of the equation, thus making them optional, but not required.\n\nThat is not how I read Phillip's mail. It was more like \"how about this\ninstead\". And it was simple enough, with clear example how to implement\nit, that I thought about that single mail for an hour, until I was\nsatisfied that the motivation behind this strategy is sound.\n\nThen you confirmed that it worked on your examples, and that's what\nsettled the score here.\n\n> So, if easier to implement and reason about, I think what Phillip \n> described is a way to go to produce the rebased merged commit - but \n> in case we want to have that \"clean rebased merge\" check that U1' == \n> U2' comparison does provide, as they should really be the same (tree \n> wise) in simple (and the most used?) merge rebasing, we can do that \n> after the fact, even.\n\nI do not know what that U1' == U2' check would buy us, as Phillip's\nstrategy does not require rebasing the amendments *twice*.\n\n> Might be this check could be the most useful in non-interactive \n> rebases, where rebased merge parents` trees could be expected to stay \n> \"balanced\" more often (U1' == U2'), without interactive fiddling to \n> \"disbalance\" them. I don`t know, just thinking out loud.\n\nAgain, Phillip's strategy does not leave things to be \"disbalanced\".\n\n> > [...] and cannot introduce ambiguities when rebasing the\n> > changes introduced by M (i.e. the \"amendmendts\" we talked about).\n> \n> Hmm, not following here, which ambiguities are we talking about?\n\nU1' vs U2' of course. Those are two things that can be different, even if\nthey ideally would have identical trees.\n\nPhillip's strategy does not leave that room for ambiguity.\n\nCiao,\nDscho\n"},{"id":"341473","messageId":"nycvar.QRO.7.76.6.1803121122390.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"f4e6237a-84dc-1aa8-150d-041806e2416e@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-12T10:37:41Z","receivedAt":"2018-03-12T10:37:49Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Sun, 11 Mar 2018, Igor Djordjevic wrote:\n\n> I agree with both of you that `pick <merge-commit>` is inflexible \n> (not to say just plain wrong), but I never thought about it like that.\n> \n> If we are to extract further mentioned explicit old:new merge \n> parameter mapping to a separate discussion point, what we`re \n> eventually left with is just replacing this:\n> \n> \tmerge -R -C <original--merge-commit> <merge-head>\n> \n> ... with this:\n> \n> \tpick <original--merge-commit> <merge-head>\n\nI see where you are coming from.\n\nI also see where users will be coming from. Reading a todo list in the\neditor is as much documentation as it is a \"program to execute\". And I am\nafraid that reading a command without even mentioning the term \"merge\"\nonce is pretty misleading in this setting.\n\nAnd even from the theoretical point of view: cherry-picking non-merge\ncommits is *so much different* from \"rebasing merge commits\" as discussed\nhere, so much so that using the same command would be even more\nmisleading.\n\n> That is what I had in mind, seeming possibly more straightforward and \n> beautifully aligned with previously existing (and well known) \n> `rebase` terminology.\n> \n> Not to say this would make it possible to use other `rebase -i` todo \n> list commands, too, like if you want to amend/edit merge commit after \n> it was rebased, you would write:\n> \n> \tedit <original--merge-commit> <merge-head>\n> \n> ..., where in case you would simply like to reword its commit \n> message, it would be just:\n> \n> \treword <original--merge-commit> <merge-head>\n> \n> \n> Even `squash` and `fixup` could have their place in combination with \n> a (to be rebased) merge commit, albeit in a pretty exotic rebases, \n> thus these could probably be just disallowed - for the time being, at \n> least.\n\nSure, for someone who read the manual, that would be easy to use. Of\ncourse, that's the minority.\n\nAlso: the `edit` command is poorly named to begin with. A much cleaner\ndesign would be to introduce the `break` command as suggested by Stephan.\n\n> The real power would be buried in implementation, learning to rebase \n> merge commits, so user is left with a very familiar interface, slightly \n> adapted do accommodate a bit different nature of merge commit in \n> comparison to an ordinary one, also to allow a bit more of interactive \n> rebase functionality, but it would pretty much stay the same, without \n> even a need to learn about new `merge`, `-R`, `-C`, and so on.\n> \n> Yes, those would have its purpose, but for real merging then \n> (creating new merges, or recreating old ones), not necessarily for \n> merge rebasing.\n> \n> With state of `merge -R -C ...` (that `-R` being the culprit), it \n> kind of feels like we`re now trying to bolt \"rebase merges\" \n> functionality onto a totally different one (recreate merges, serving \n> a different purpose), making them both needlessly dependent on each \n> other, further complicating user interface, making it more confusing \n> and less tunable as per each separate functionality needs (rebase vs. \n> recreate).\n> \n> I guess I`m the one to pretty much blame here, too, as I really \n> wanted `--recreate-merges` to handle \"rebase merges\" better, only to \n> later realize it might not be the best tool for the job, and that a \n> more separate approach would be better (at least not through the same \n> `merge` todo list command)...\n> \n> [1] https://public-inbox.org/git/f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com/\n\nWell, the `-R` option is no worse than `git merge`'s `-s <strategy>`\noption (which *also* changes the strategies rather drastically).\n\nCiao,\nDscho\n"},{"id":"341474","messageId":"nycvar.QRO.7.76.6.1803121142550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"b329bb98-f9d6-3d51-2513-465aad2fa37a@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-12T10:46:02Z","receivedAt":"2018-03-12T10:46:10Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nI just have two thoughts to contribute as answer, so please excuse the\nheavily cut quoted text:\n\nOn Sun, 11 Mar 2018, Igor Djordjevic wrote:\n\n> Sometimes one just needs to read the manual, and I don`t really think\n> this is a ton complicated, but just something we didn`t really have\n> before (real merge rebasing), so it requires a moment to grasp the\n> concept.\n\nIf that were the case, we would not keep getting bug reports about\n--preserve-merges failing to reorder patches.\n\n> Saying in favor of `--rebase-merges`, you mean as a separate option,\n> alongside `--recreate-merges` (once that series lands)?\n\nNo. I am against yet another option. The only reason I pollute the option\nname space further with --recreate-merges is that it would be confusing to\nusers if the new mode was called --preserve-merges=v2 (but work *totally\ndifferently*).\n\nCiao,\nDscho\n"},{"id":"341475","messageId":"87zi3dh53k.fsf@javad.com","threadId":"47864","inReplyTo":"d18a6e73-ce6f-b4aa-8ead-7aaabddf454d@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T12:05:03Z","receivedAt":"2018-03-12T12:05:13Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n[...]\n\n> That said, *if* we decide we like temporary commit U1' == U2' consistency \n> check (especially for non-interactive rebase, maybe), we can produce \n> these after the fact for the sake of the check only.\n\nI don't believe interactive vs. non-interactive split is actually\nhelpful. I'd consider non-interactive just a special case of interactive\nwhen user didn't edit the todo list, nothing more. No special treatment\nshould be required.\n\nFor one, consistency checks in both modes has similar importance, even\nif only because there could be parts of history being interactively\nrebased which the user didn't intend to edit, nor actually edited during\ngiven session.\n\nNow let me get back to pros and cons of the two approaches to rebasing\nmerges we have. Below I still advocate my approach by further discussing\nthe differences, but simultaneously I'd like to emphasize that whatever\nparticular way of rebasing merges will finally be used, it will be a\nhuge step forward and I'm glad I've raised the issue in the first place.\n\nFirst, please consider the fact that my \"rebase sides\" method has yet\nanother nice property: it reduces back to original \"rebase the commit\"\noperation when you apply it to a non-merge commit. In other words, it's\ntrue generalization on top of rebasing of simple commit.\n\nOTOH, Phillip's approach, when reduced to non-merge commit, still does a\nversion of rebase, but very specific one, and in inverse manner. I.e.,\nrather than merging changes of the commit to be rebased into the new\nbase, it merges changes introduced by the new base into the commit being\nrebased.\n\nOne consequence is that when conflict occurs, Phillip's approach will\ngive surprising order of ours vs theirs changes, inverted with respect\nto those of the usual rebase of non-merge commit, while my approach will\ngive exact non-merge commit semantics. It could likely be fixed by\nslightly modifying Phillip's approach, but it will make its\nimplementation more complex.\n\nAnother consequence is that, provided my version is used, all options\nthat tune \"simple commit rebase\" behavior will automagically work for\nrebasing merge commits, in exactly the same manner. OTOH, Phillip's\napproach, without special attention in implementation, will do the same\nthing no matter what -m -s, or -X options say.\n\nYet another consequence is that my approach will likely result in better\ncode reuse. Even though mine seems to be harder to implement stand-alone\nthan Phillip's one, it should be actually easier to implement inside the\n\"git rebase\", as it will use exactly the same machinery that \"git\nrebase\" already uses to rebase simple commits, adding only final \"git\nmerge-recursive\" (or \"git merge-resolve\", or \"git merge-octopus\", -- any\nof them  will do the job), which current implementation already performs\nas well, for re-creating merges from scratch.\n\nSecond thought, unrelated to the above. To me it seems that my \"rebasing\nsides\" approach, being entirely symmetric, is cleaner than incremental\nmerging suggested by Phillip, as with my approach one will still deal\nwith branches independently, in the same way as for simple commits,\nuntil the single final merge operation. This comes with drawback of 1\nadditional step in my approach when compared to the Phillip's one\nthough, but then mine has definitely no issues with the exact order of\nmerges.\n\nOverall, to me it seems that unmodified Phillip's approach will bring\nunnecessarily wide set of new user experiences, and fixing it will\nrequire some tricks in implementation, for no apparent reason.\n\n-- Sergey\n"},{"id":"341476","messageId":"87vae1h3uo.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803080741160.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T12:31:59Z","receivedAt":"2018-03-12T12:32:07Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Sergey,\n>\n> On Wed, 7 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > How can your approach -- which relies *very much* on having the\n>> > original parent commits -- not *require* that consistency check?\n>> \n>> I don't understand what you mean, sorry. Could you please point me to\n>> the *require* you talk about in the original proposal?\n>\n> Imagine a todo list that contains this line\n>\n> \tmerge -C abcdef 123456\n>\n> and now the user edits it (this is an interactive rebase, after all),\n> adding another merge head:\n>\n> \tmerge -C abcdef 987654 123456\n>\n> Now your strategy would have a serious problem: to find the original\n> version of 987654. If there was one.\n\nWe are talking about different checks then. My method has a built-in\ncheck that Pillip's one doesn't. All the external checks, if any, will\nhave to be the same.\n\n>\n>> > What would your approach (that still has no satisfyingly trivial\n>> > explanation, in my mind)\n>> \n>> Here is one-liner: rebase sides of the merge commit and then 3-way\n>> merge them, using original merge commit as merge base.\n>\n> But I already pointed out how that would undo a commit having been\n> dropped.\n\nNo. Not for this version. You did it for originally flawed version of\nthe method, that has been already fixed by addition of \"using original\nmerge commit as merge base\" in the above sentence, and that was the\nexact reason for [RFC v2], that in turn is explicitly stated at the\nbeginning of [RFC v2].\n\n>\n>> > do if somebody edited a `merge` command and let it merge a completely\n>> > unrelated commit?\n>> \n>> Don't see a problem, sorry. The method should still work, provided you have\n>> original merge commit and two new parents for the new merge.\n>\n> That is assuming a lot. That is exactly what this consistency check is\n> for, that I mentioned earlier, and which you listed as a downside of\n> Phillip's strategy (forgetting that your strategy has the same downside,\n> so...).\n\nAgain, we are talking about different checks. My method has a built-in\ncheck that Pillip's doesn't. All the external checks, if any, will have\nto be the same.\n\n> But I guess that you are still talking about the non-interactive version\n> of the rebase, and missed that our conversation proceeded to the point\n> where we want that same strategy to work *also* in the interactive version\n> (and not have a completely different functionality depending whether you\n> use --interactive or not)?\n\nFor me, non-interactive is an interactive one with unmodified todo list.\n\n-- Sergey\n"},{"id":"341477","messageId":"87r2oph3cj.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803080746460.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T12:42:52Z","receivedAt":"2018-03-12T12:43:01Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Sergey,\n\n[...]\n\n> That is misrepresenting what happened.\n\nNo, it's you who are spreading misinformation, probably unintentional,\nbut still.\n\n> First, you came up with a strategy. I pointed out shortcomings that\n> implied that we cannot use it unchanged. Then, Buga fixed your strategy by\n> using additional steps (making the process more complicated than before,\n> still without a simple-enough explanation for my liking, fixing the\n> shortcomings). Then, Phillip presented a super-simple strategy and Buga\n> confirmed that it also fixes the shortcomings I pointed out.\n\nExcept that you've missed very essential thing: even before Phillip\npresented his method, the original has been fixed and simultaneously\nbecame even simpler. It's now entirely described in [RFC v2] that you\napparently still refuse to read.\n\n> I am very excited that we finally found something that works *and* is easy\n> to reason about.\n\nYou have chances to be even more exited as we in fact have 2 of them\nthat both work and are both easy to reason about.\n\n> Let's focus on that strategy rather than going back to the strategy which\n> has known flaws and only an unsatisfyingly complex explanation.\n\nNot that fast, as it now has no known flaws and still has surprisingly\nsimple explanation. It also has its own niceties that are currently\nbeing discussed elsewhere in the thread.\n\n-- Sergey\n"},{"id":"341478","messageId":"87h8plh2qd.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803121122390.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T12:56:10Z","receivedAt":"2018-03-12T12:56:22Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Buga,\n>\n> On Sun, 11 Mar 2018, Igor Djordjevic wrote:\n>\n>> I agree with both of you that `pick <merge-commit>` is inflexible \n>> (not to say just plain wrong), but I never thought about it like that.\n>> \n>> If we are to extract further mentioned explicit old:new merge \n>> parameter mapping to a separate discussion point, what we`re \n>> eventually left with is just replacing this:\n>> \n>> \tmerge -R -C <original--merge-commit> <merge-head>\n>> \n>> ... with this:\n>> \n>> \tpick <original--merge-commit> <merge-head>\n>\n> I see where you are coming from.\n>\n> I also see where users will be coming from. Reading a todo list in the\n> editor is as much documentation as it is a \"program to execute\". And I am\n> afraid that reading a command without even mentioning the term \"merge\"\n> once is pretty misleading in this setting.\n>\n> And even from the theoretical point of view: cherry-picking non-merge\n> commits is *so much different* from \"rebasing merge commits\" as discussed\n> here, so much so that using the same command would be even more\n> misleading.\n\nThis last statement is plain wrong when applied to the method in the\n[RFC] you are replying to. Using the method in [RFC], \"cherry-pick\nnon-merge\" is nothing more or less than reduced version of generic\n\"cherry-pick merge\", exactly as it should be.\n\nOr, in other words, \"cherry-pick merge\" is generalization of\n\"cherry-pick non-merge\" to multiple parents.\n\n-- Sergey\n"},{"id":"341479","messageId":"87a7vdh271.fsf@javad.com","threadId":"47864","inReplyTo":"6362804d-e204-a9e0-9ff0-51d8497ce921@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T13:07:46Z","receivedAt":"2018-03-12T13:07:53Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Dscho,\n\n[...]\n\n> I think the root of misunderstanding might be coming from the fact\n> that Sergey was mainly describing a general concept (without a\n> strictly defined implementation strategy, not being restricted to a\n> specific one), where Phillip came up with a solution that eventually\n> seems to use the same concept (as those transformations above should\n> show), but simplifying it further inside a concrete implementation.\n\nAs a side-note, starting from sound general concept leaves a hope to\nend-up with something like Git, while starting from an implementation,\nhowever nice it is, gives a danger of ending-up with something like Bzr.\n\n-- Sergey\n"},{"id":"341481","messageId":"874lllh09b.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803121056400.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-12T13:49:36Z","receivedAt":"2018-03-12T13:49:43Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n[...]\n\n> The biggest difference is that it is easy for me to see the motivation\n> behind Phillip's strategy, whereas I am still puzzled why one would come\n> up with a complicated strategy that splits merge commits and re-merges\n> them later, and why it should work in general (I still suspect that this\n> is not the case).\n\nBecause I believe that rebasing simple commit (1 parent) should be\nnothing else but reduced version of rebasing any commit (N parents) at\nN=1. The [RFC v2] being discussed provides exactly such a method.\n\nOTOH, check what Phillip's version does at N=1. Is it the same as\n\"rebase simple commit\" strategy you already happily use? If not, please\nexplain why it must be different.\n\n> Where \"easy\" meant that I had to spend 1h still to figure out why using\n> the unrebased merge parents as merge bases.\n\nThat's because you try to figure out something that is not there in the\n[RFC v2]. I suggest to forget everything you've already imagined and\njust read the [RFC v2] proposal afresh. It should take about 10 minutes\nor less to get it. Really.\n\n> The same amount of time did not allow me to wrap my head around\n> Sergey's verbose explanations.\n\nHonestly, I don't believe it, sorry, but I'm willing to explain anything\nyou wish to be explained in _[RFC v2]_.\n\n> But I'll take your word for it that the strategies are equivalent, and go\n> with the one that has both a simpler explanation (in my mind, at least),\n> and an more robust implementation.\n\nIt's up to you, and it'd still be much better than what we have now, but\nyou will need to face the (I think unfortunate) consequences I just\nsummarized elsewhere in the thread.\n\n-- Sergey\n"},{"id":"341503","messageId":"2228813d-5b85-3371-b2a1-0a5633d26336@gmail.com","threadId":"47864","inReplyTo":"d18a6e73-ce6f-b4aa-8ead-7aaabddf454d@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-12T22:41:12Z","receivedAt":"2018-03-12T22:41:39Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 11/03/2018 23:04, Igor Djordjevic wrote:\n> \n> I`m yet to read (and reason about) your whole (very informative) \n> reply, but I just wanted to address this part first, as it might be a \n> clear end-game situation already, due to a mutual agreement, all the \n> rest being purely academic, interesting, but not any more (that) \n> important to discuss.\n\nOk, here`s the follow-up.\n\nIt`s \"for discussion sake only\", nothing really groundbreaking in \nhere, I would think.\n\nOn 11/03/2018 16:40, Johannes Schindelin wrote:\n> \n> > > > The main problem with this decision is that we still don't see how\n> > > > and when to stop for user amendment using this method. OTOH, the\n> > > > original has this issue carefully discussed.\n> > >\n> > > Why would we want to stop, unless there are merge conflicts?\n> >\n> > Because we can reliably know that something \"unusual\" happened - and by\n> > that I don`t necessarily mean \"wrong\", but just might be worth user\n> > inspection.\n> \n> We have a similar conundrum in recursive merges. Remember how multiple\n> merge bases are merged recursively? There can be merge conflicts, too, in\n> *any* of the individual merges involved, and indeed, there are (under\n> relatively rare circumstances).\n> \n> Since we already faced that problem, and we already answered it by\n> presenting possibly nested merge conflicts, I am in strong favor of\n> keeping our new scenario consistent: present possibly-nested merge\n> conflicts.\n\nThis is something I didn`t really know (possibly-nested merge \nconflicts already being a regular part of Git user experience), \nthanks for explaining it.\n\nIn the light of this, I can only agree, let`s keep it consistent.\n\nIf anyone ever decides / finds out there`s a better approach in \nregards to user experience, this might get revised, but it`s a \ndifferent beast altogether, yes.\n\n> As far as I understand, one of the arguments in favor of the current\n> approach was: there is no good way to tell the user where they are, and\n> how to continue from there. So better just to continue and present the\n> user with the entire set of conflicts, and have an obvious way out.\n\nYes, I see this as the main concern, too. I would have expected that \nbeing in a kind of a \"limbo\" for a while shouldn`t be too bad, but I \nguess that`s too academic (and inexperienced) thought, and from a \npractical point of view one may not really know how to approach the \n(iterative) conflicts in the first place, not knowing his exact \nposition (nor what`s to come)...?\n\nOr, might be we _can_ provide enough clues on where we currently are \n(even if still inside some intermediate state)...? But, this still \nmight be a topic for the future, indeed, and unrelated to rebasing \nmerges alone (as you pointed out already).\n\n> > For example, situation like this (M is made on A3 with `-s ours`, \n> > obsoleting Bx commits):\n> >\n> > (1) ---X8--X9 (master)\n> >        |\\\n> >        | A1---A2---A3\n> >        |             \\\n> >        |              M (topic)\n> >        |             /\n> >        \\-B1---B2---B3\n> >\n> > ... where we want to rebase M onto X9 is what I would call \"usual \n> > stuff\", but this situation (M is still made on A3 with `-s ours`, \n> > obsoleting Bx commits, but note cherry-picked B2'):\n> >\n> > (2) ---X8--B2'--X9 (master)\n> >        |\\\n> >        | A1---A2---A3\n> >        |             \\\n> >        |              M (topic)\n> >        |             /\n> >        \\-B1---B2---B3\n> >\n> > ... where we still want to rebase M onto X9 is what we might consider \n> > \"unusual\", because we noticed that something that shouldn`t be part \n> > of the rebased merge commit (due to previous `-s ours`) actually got \n> > in there (due to later cherry-pick), and just wanting the user to \n> > check and confirm.\n> \n> We already have those scenarios when performing a regular interactive\n> rebase, where a patch was already applied upstream. In the normal case,\n> the user is not even shown B2, thanks to the --cherry-pick option used in\n> generating the todo list.\n> \n> Granted, in some cases --cherry-pick does not detect that, and then we\n> generate a todo list including B2, and when that patch is applied, the\n> interactive rebase stops, saying that there are no changes to be\n> committed.\n> \n> And this behavior is exactly the same with --recreate-merges!\n> \n> So I do not think that it would make sense to bother the user *again* when\n> rebasing the merge commit.\n\nThis seems fair enough. Phillip also pointed out it might be more \nannoyance then help, but as no one was really sure of the possibilities \nwe`re discussing here, I thought being better to play it a bit on the \nsafe side, for the first time, at least.\n\nI would still like to see more examples of where this U1' == U2' \ncheck actually helps, and counter ones, where it only serves to annoy. \nMight be we only discover them in the future, though, once the new \nfunctionality is in use.\n\n> If there are merge conflicts, yes, we will have to. If there are none\n> (even if your U1' != U2'), it would be outright annoying to stop.\n\nI hope you`re right :)\n\n> > > > \"rebase sides of the merge commit and then three-way merge them back\n> > > > using original merge commit as base\"\n> > >\n> > > And that is also wrong, as I had proved already! Only Buga's addition\n> > > made it robust against dropping/modifying commits, and that addition\n> > > also makes it more complicated.\n> >\n> > No, this is actually right, that sentence nicely describing _how_ it \n> > works.\n> \n> Does it? Because that's exactly backwards from how Phillip's approach\n> works: it certainly does not use the original merge commit as base. It\n> uses the non-rebased merge parent as base, one at a time.\n\nHmm, might we are all misunderstanding each other here - what I meant \nis that what Sergey wrote about his approach is exactly how _his_ \napproach works (quoted above): \"rebase sides of the merge commit and \nthen three-way merge them back using original merge commit as base\".\n\n> So the closest I got was the description with the *original merge commit*\n> as merge base, which I disagree with. It does not make sense to me.\n> \n> Consecutive three-way merges between the original merge commit and the\n> merge parents (with the *original merge parents* as merge base,\n> respectively), still makes the most sense to me: it is a merge between the\n> amendmends to the merge commit and the changes introduced by rebasing the\n> merge parents.\n\nThis is what I hopefully managed to explain as essentially being the \nsame concept, using those \"merge-recursive transformations\", where we \ncan get from using *original merge parents* as a merge base, to using \n*original merge commit* as a merge base[1] (when using U1 and U2).\n\n> I am now getting the sense as if Sergey's approach (with your, let's say,\n> \"fix\") is trying to apply too much, and by using the original merge commit\n> as merge base then tries to undo part of that.\n\nThis is an interesting way to look at it. If you observe rebased \ntemporary commits U1' and U2' alone, then I guess the answer would be \n*yes*, even.\n\nBut I think they should only be observed as an intermediate step to \nreach a final (rebased) merge commit, and the missing (and inseparable) \nlink is that original merge commit used as a base for merging them.\n\nThey _did_ become from that original merge commit (tree) in the first \nplace, merge commit alone transformed to more separate (but dependent \ncommits), thus they are still somewhat related/dependent to it after \ntheir rebasing and prior the final merge (more on it in a graph later).\n\n> > > > I honestly don't see any advantages of Phillip's method over the\n> > > > original, except personal preferences. At the same time, I have no\n> > > > objection of using it either, provided consistency check problem is\n> > > > solved there as well.\n> > >\n> > > Okay, let me reiterate then, because I do not want this point to be\n> > > missed:\n> > >\n> > > Phillip's method is essentially merging the new tips into the original\n> > > merge, pretending that the new tips were not rebased but merged into\n> > > upstream.\n> > >\n> > > So it exploits the duality of the rebase and merge operation, which both\n> > > result in identical trees (potentially after resolving merge conflicts).\n> > >\n> > > I cannot think of any such interpretation for your proposal augmented by\n> > > Buga's fix-ups. And I haven't heard any such interpretation from your\n> > > side, either.\n> >\n> > Ok here it goes (I might be still wrong, but please bare with me).\n> >\n> > What Sergey originally described also uses the \"duality of the rebase \n> > and merge operation\", too ;) Just in a bit different way (and might \n> > be a more straightforward one?).\n> \n> I will be the judge whether it looks more straight-forward to me. :-)\n\nHehe, fair enough ;) I was speaking mainly for myself (at the time) :)\n\n> > Here`s a starting point, two commits A and B, merged into M:\n> >\n> > (3) ---A\n> >         \\\n> >          M\n> >         /\n> >     ---B\n> >\n> >\n> > According the \"patch theory\"[1] (which might not be too popular \n> > around here, but should serve the purpose for what I`m trying to \n> > explain),\n> \n> I think that the patch theory is not usually quoted here because\n> \n> 1) originally, Darcs had this snake oil way of (over-)selling its theory\n>    as having \"roots in quantum mechanics\" [*1*] at the time Git took off,\n>    and\n> \n> 2) it does not really have a good concept of rebasing, even if it should\n>    be theoretically possible to integrate that into the \"theory of\n>    patches\".\n\nYeah, I actually remembered some Linus` comment about \"theory of \npatches\" being nice... well, in theory (like for scientist), but not \nthat much useful in practice - I`m paraphrasing now, here`s a proper \nreference[2].\n\nBasically, it did provide me with a hint to take \"patch theory\" with \na grain of salt, just that I did seem to find a logical explanation \nin there for what Sergey was originally describing, and what otherwise \ndid \"feel\" as a good thing, but I wanted some more support on _why_ \nit feels so (on why it works, as you asked yourself, while it did seem \nto work, nonetheless).\n\n> > each merge commit can be \"transformed\" to two non-merge commits, one on\n> > top of each of the merge parents, where new commit brings its original\n> > merge parent commit tree to the state of the merge commit tree:\n> >\n> > (4) ---A---U1\n> >\n> >\n> >\n> >     ---B---U2\n> \n> You get the same result if you stick to regular graph theory, of course.\n> All you need to do is to interpret the directed vertices between nodes as\n> a patch & parent relationship. Simple.\n\nNot knowing much about graph theory myself (other than what I grasped \nthrough Git so far), I`ll take your word here - and might be educate \nmyself more about it, too :)\n\n> > Now, we have two new commits, U1 and U2, each having the same tree as \n> > previous merge commit M, but representing changes in regards to \n> > specific parents - and this is essentially what Sergey`s original \n> > approach was using (whether he knew it, or not).\n> >\n> > When it comes to rebasing, it`s pretty simple, too. As this:\n> >\n> > (5) ---X1---o---o---o---o---o---X2 (master)\n> >        |\\\n> >        | A1---A2---A3\n> >        |             \\\n> >        |              M\n> >        |             /\n> >        \\-B1---B2---B3\n> >\n> > ... actually equals this:\n> >\n> > (6) ---X1---o---o---o---o---o---X2 (master)\n> >        |\\\n> >        | A1---A2---A3---U1\n> >        |\n> >        |\n> >        |\n> >        \\-B1---B2---B3---U2\n> >\n> > ... where trees of M, U1 and U2 are same,\n> \n> Okay, so you basically duplicated the merge commit and dropped its\n> semantics as a merge commit. That is a very big difference to Phillip's\n> approach already.\n\nYes, the purpose here was to explain why Sergey`s approach (still) \nworks, not to compare it with Phillip`s (which also works).\n\nFrom here on, we can use simple (and existing) rebase functionality / \nsemantics to really rebase that original merge. There are no new \nconcepts needed, it just works (TM) :)\n\n> It opens the door to ambiguities, as we will see later.\n> \n> > and we can use the regular rebase semantics and rebase it to this:\n> >\n> > (7) ---X1---o---o---o---o---o---X2 (master)\n> >                                 |\\\n> >                                 | A1'--A2'--A3'--U1'\n> >                                 |\n> >                                 |\n> >                                 |\n> >                                 \\-B1'--B2'--B3'--U2'\n> >\n> > ... which is essentially this again:\n> >\n> > (8) ---X1---o---o---o---o---o---X2 (master)\n> >                                 |\\\n> >                                 | A1'--A2'--A3'\n> >                                 |            \\\n> >                                 |             M'\n> >                                 |            /\n> >                                 \\-B1'--B2'--B3'\n> >\n> > ... where it is still true that trees of U1', U2' and M' are still \n> > the same. So we managed to rebase a merge commit without ever doing a \n> > merge :) (note that, practically, we _can_ finally even merge U1' and \n> > U2' to produce M', it shouldn`t really matter as all the trees are \n> > the same, so merge will be a no-op)\n> \n> U1' and U2' do not have the same tree, though *especially* when the user\n> did not edit the todo list to insert/modify/drop/reorder commits.\n\nI lost you here - how come they don`t? The only difference between U1 \nand U1' will be what`s between X1 and X2, and the same is true for U2 \nand U2'. And as we know U1 = U2, it means U1' = U2' still holds.\n\nI`m following further...\n\n> This violation of expectations is of course caused by \"duplicating the\n> merge commit\" into U1 and U2.\n\nIt`s just a change of semantics, a natural transformation (I wouldn`t \nknow a more \"proper, scientific\" term, sorry), all still being \ncorrect. But I guess we can call it \"duplicating\" as well.\n\n> But let's continue.\n> \n> > But, as we saw (what you`ve explained), this doesn`t really work in \n> > case one of the sides of the merge gets \"disbalanced\" (so to say), \n> > like dropping a commit (which could also happen non-interactively, \n> > where a commit has been cherry-picked to a different branch, but\n> > previously obsoleted by `-s ours` merge).\n> \n> Precisely. A *very* important counter-argument to this approach so far.\n> \n> > As observed, dropped commit could still wrongly get into final merge \n> > commit tree (or cherry-picked commit wrongly not get there), due to \n> > the nature of those rebased U1 and U2 temporary commits to hold all \n> > the differences in regards to their specific merge commit parent.\n> \n> The reason for this, of course, is that either U1's or U2's diff will show\n> those differences, *and we still try to rebase them even if the user\n> already dropped them*.\n> \n> But let's continue.\n> \n> > A natural improvement to original idea which Sergey eventually came \n> > up with after my findings (which you now ended up calling a hack, even, \n> > but I would respectfully disagree), is to use original merge commit M \n> > as a merge base for final merge of U1' and U2' - and here is why it \n> > works, too, and why I wouldn`t consider it a hack, but a proper (and \n> > a solid) solution.\n> >\n> > Merge commit M is what we are rebasing, so we should have a way to \n> > somehow learn from it, alongside U1 and U2 temporary commits - and \n> > that is what using original merge commit M as a base does for us. It \n> > helps us spot any \"disbalances\" that happened in comparison to original \n> > merge parent trees, which is exactly what we`re interested in.\n> \n> ... except that it gets the direction wrong. Rather than trying to *avoid*\n> rebasing possibly dropped changes, it tries to kind of \"undo\" them by\n> using a merge base that does not really make sense (unless you think of it\n> as a \"revert\").\n\nI disagree, but I`ll explain more later. The point is that we are \nreally rebasing original merge commit, where rebased merge commit \nmight have missed some stuff (due to possibly dropped changes) - so \nonce we successfully rebased the original merge commit, we are to \nacknowledge additional changes we didn`t catch so far (as we would \ncatch additions), and act accordingly.\n\nUsing original merge commit for the purpose feels natural to me - \nit`s where we are starting from, using both parent branches evolution \nto get where we`re heading to, being a rebased merge commit.\n\n> It would make sense if M could interpreted as a branch point. But it\n> cannot, as we specifically did *not* continue to develop the merge parents\n> from that merge commit.\n\nBut we did (for the sake of rebasing), transforming the very merge \ncommit into those commits developed on top of its merge parents :)\n\n> Instead, what we did was to branch off of the original branch point X1.\n> \n> Reframing the rebase of a sub-branch (X1..A3) as merge with upstream,\n> however, we can interpret M and A3' as revisions we want to merge, with A3\n> as the merge base.\n> \n> (You can think of it in terms of the \"theory of patches\" thusly: if X1..A3\n> is represented by patch K, X1..X2 by patch L, and X2..A3' by K', then what\n> we want to merge into M is K^(-1).L.K', which is precisely what A3..A3'\n> translates to.)\n> \n> You can also think of it as diverging changes going from A3: one direction\n> was to merge (resulting in the commit M), the other direction was to\n> rebase onto X2 (resulting in A3'), and a 3-way merge M <- A3 -> A3' will\n> reconcile those changes (and you will want to repeat with B3/B3', too).\n> \n> Let's put that into the context of your example: instead of introducing U1\n> and U2, we introduce V1 and V2 right away, as temporary *merge* commits,\n> where the tree of V1 is identical to the one of A3', and the tree of V2\n> to that of B3'.\n> \n>  ---X1---o---o---o---o---o---X2 (master)\n>     |                        |\\\n>     |                        | A1'--A2'--A3'--V1\n>     |\\                       |               /\n>     | -A1---A2---A3----------+---------------\n>     |              \\         |\n>     |               M        \\-B1'--B2'--B3'--V2\n>     |              /                         /\n>      \\-B1---B2---B3--------------------------\n> \n> Note: the *really* important difference is that these temporary commits\n> are based on the *rebased* history rather than the *unrebased* history.\n\nThis might be an important advantage of Phillip`s \"simplification\", \nindeed.\n\n> Third note: my favorite mental model is still the duality of rebasing and\n> merging, in which case V1 and V2 would not have A3' and B3' as first\n> parents, but X2.\n> \n> Phillip's strategy is to merge M with V1 and V2.\n> \n> This translates to \"merge the amendments of the merge commit M with the\n> changes introduced by rebasing its merge parents\".\n\nAll this I agree with. And all this can be used to support what \nSergey described, too (being a bit different, though) :) Let`s see...\n\n ---X1---o---o---o---o---o---X2 (master)\n    |                        |\\\n    |                        | A1'--A2'--A3'--U1'\n    |\\                       |               /\n    | -A1---A2---A3---U1-----+---------------\n    |              \\ /       |\n    |               M        \\-B1'--B2'--B3'--U2'\n    |              / \\                       /\n     \\-B1---B2---B3---U2---------------------\n\n\nTo get the original merge commit M, you can just merge U1 and U2 \nagain back to single commit - original commit M is a natural merge-base. \nIt`s the same with rebased commits U1' and U2' - to get rebased merge \ncommit, you merge them. Again, original commit M is a natural \nmerge-base.\n\nThis is why I disagreed above with statement that merging U1' and U2' \nwith base M doesn`t make sense. I think this shows it does.\n\n> The really cute part about this is that (in contrast to using U1' and\n> U2'), we do not merge the amendments of the merge commit multiple times,\n> but exactly once. And therefore, we do not need to \"undo\" them by using\n> the original merge commit as merge base, either (which would introduce\n> many more opportunities for merge conflicts to creep in, oftentimes\n> unnecessary conflicts to begin with).\n\nThis might be true, which is why I might find Phillip`s approach to \nbe a further optimization of what Sergey came up with. But I would \nstill like to do some tests concerning manually amended conflicts, \nwill report once I do.\n\nThough, we do not merge the amendments of the merge commit multiple \ntimes here either, but we do rebase them multiple times, true (being \nheld in each rebased Ux' commit again).\n\n> > In ideal case (as per \"patch theory\"[1]), final merge of rebased U1' \n> > and U2' with original merge commit M as a base would be rather simple, \n> > too (not to say pointless again), as both U1' and U2' would have same \n> > changes in comparison to M, namely all the changes from commit we are \n> > rebasing from (X1 above) to commit we are rebasing to (X2 above).\n> >\n> > But in a more complex case like this:\n> >\n> > (9) ---X1---B2'---o---o---o---o---X2 (master)\n> >                                   |\\\n> >                                   | A12--A2'---B3'\n> >                                   |             \\\n> >                                   |              M'\n> >                                   |             /\n> >                                   \\-B1'--B3'---B4\n> >\n> > ..., being what we are ultimately interested in, it helps us notice \n> > all kind of changes on our rebased merge parent branches, and act \n> > accordingly (as shown by my previously posted test script).\n> \n> To use the \"theory of patches\" to explain why Phillip's approach is so\n> much more appealing: in Sergey's approach, we will rebase U1 (which is\n> \"sort of\" B1.B2.B3 in the \"theory of patches\"). If the cherry-pick of B2'\n> caused merge conflicts that had to be resolved, then these merge conflicts\n> will have to be resolved *again* when rebasing U1 (because B2 is *part of*\n> U1). And of course they will have to be resolved *again* when merging U1'\n> with U2'.\n\nI think I disagree here - U1 doesn`t purely hold B1.B2.B3, but their \n_application onto A3 tree_ - with all conflicts resolutions that might \nhave happened. Thus rebasing U1 on top of A3' should be as safe as it \ngets.\n\nAm I missing something?\n\n> In short: Phillip's approach is a short-cut that avoids unnecessary merge\n> conflicts because it avoids rebasing changes that would need to be undone\n> right away anyway.\n\nI don`t agree it avoids conflicts (as resolutions of those are already \npart of U1, I`ll need to test), but I do agree on Phillip`s approach \nseeming to be a shortcut, though.\n\n> > All this said (and hoping anyone is still reading this), to shed some \n> > light on what I meant by \"favoring Sergey`s approach in general, but \n> > _implemented_ through what Phillip described\".\n> >\n> > I think we should use temporary commits U1 and U2, being a sound \n> > approach backed up by the \"patch theory\"[1], as it helps us notice \n> > any \"disbalances\" of the rebased merge commit parents trees (so we \n> > can stop for user inspection), finally merging them with original \n> > merge commit as a base, in order to spot additional changes on trees \n> > of the merge commit parents we are rebasing.\n> \n> In Phillip's approach, we do not need to rebase the amendments of the\n> merge commit M twice (or even more times, for octopus merges). Therefore,\n> there is no opportunity for these imbalances.\n\nFirst sentence is true, conclusion not (necessarily) - it`s not \nrebasing amendments that introduces \"disbalances\", but changes in \nrebased merge parents` trees other than what found inside X1.X2.\n\n> > But, the merging steps themselves, backed up by a need to stop for \n> > conflict resolution as soon as one happens, should be performed \n> > _iteratively_, like Phillip showed us... I would think :)\n> \n> From a user interface perspective, this is a bad idea: you would now have\n> to communicate to the user *where* in the process they are.\n> \n> And for that you would have to explain that process to them. Including\n> \"theory of patches\" and all.\n> \n> Taking me as a prime example, you now know how tedious and impractical\n> that would be.\n\nI don`t (or didn`t, at least) find this as terrible as you`re \ndescribing it - yes, we`d need a way to explain people that they`re \nin an intermediate state, on the way to rebase a merge commit, but \nthat`s all they would really need to know.\n\nMight be it would be enough to say \"currently rebasing merge parent \nX\" (or \"commit X\"), then later \"currently rebasing merge parent Y\", \nor something along the lines of what rebase already does, just to \nprovide a hint so one can act accordingly (resolve conflicts), and \n--continue.\n\nBut, as you previously mentioned this already being a known issue \n(possibly nested merge conflicts), which I wasn`t really aware of, I \nwould refrain from further discussing it now and just agree to do \nwhat we do in the other case, too, as you suggested.\n\n> > And, for example, that would do wonders when we introduce completely \n> > new branch during an interactive rebase, too, for example:\n> >\n> > (10) ---X1---B2'---o---o---o---o---X2 (master)\n> >         |\\                        /|\\\n> >         | A1---A2---A3---U1       || A12--A2'---B3'---U1'\n> >         |             \\           ||             \\\n> >         |              M          ||              M'\n> >         |             /           ||             /|\n> >         \\-B1---B2---B3---U2       |\\---B3'---B4-/-|---U2'\n> >                                   |               |\n> >                                   \\-----B1'-------/\n> >\n> >\n> > In this situation, we would merge all temporary Ux commits using \n> > original merge M as a merge base, and then merge _that_ resulting \n> > tree with B1' (being a newly introduced merge commit parent), using \n> > whatever merge base is most appropriate between the two (in this \n> > case, X2).\n> \n> The semantics of octopus merges are very different from regular recursive\n> merges. I am not sure that we want to go there in this discussion...\n> \n> If, on the other hand, you do not try to turn M from a regular 2-parent\n> merge commit into an octopus merge during an interactive rebase, but\n> instead split the B branch into two branches *before* merging the result\n> into the rebased merge commit, we are in the same square as\n> reordering/dropping/inserting/modifying patches: to neither of the\n> presented strategies would it matter what kind of branch topology the\n> merge parents have.\n> \n> For the record: I am still not convinced that Phillip's and Sergey's\n> approach are equivalent, even in terms of the \"theory of patches\". [...]\n\nAnd you shouldn`t be, nor it was my wish to conclude so, but only to \n(try to) explain _why_ Sergey`s approach works _as well_, without anything \nmagical about it (nor wrong), thus no need to be afraid of it, either.\n\n> [...] But if\n> they are, then Phillip's version is a shorter version that avoids applying\n> changes just to revert them right away. And in a setting where each patch\n> can cause merge conflicts (as the interactive rebase is), the less changes\n> you have to apply, the better.\n\nI would still like to see some comparisons (for myself), but this is \nfair enough for now, and understandable.\n\nThank you for a very interesting (and educative!) read :)\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/6362804d-e204-a9e0-9ff0-51d8497ce921@gmail.com/\n[2] https://public-inbox.org/git/Pine.LNX.4.64.0604030727250.3781@g5.osdl.org/\n"},{"id":"341513","messageId":"77b695d0-7564-80d7-d9e6-70a531e66eda@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803121122390.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-12T23:54:57Z","receivedAt":"2018-03-12T23:55:22Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 12/03/2018 11:37, Johannes Schindelin wrote:\n> \n> > If we are to extract further mentioned explicit old:new merge \n> > parameter mapping to a separate discussion point, what we`re \n> > eventually left with is just replacing this:\n> >\n> > \tmerge -R -C <original--merge-commit> <merge-head>\n> >\n> > ... with this:\n> >\n> > \tpick <original--merge-commit> <merge-head>\n> \n> I see where you are coming from.\n> \n> I also see where users will be coming from. Reading a todo list in the\n> editor is as much documentation as it is a \"program to execute\". And I am\n> afraid that reading a command without even mentioning the term \"merge\"\n> once is pretty misleading in this setting.\n> \n> And even from the theoretical point of view: cherry-picking non-merge\n> commits is *so much different* from \"rebasing merge commits\" as discussed\n> here, so much so that using the same command would be even more\n> misleading.\n\nI would disagree here, as it seems you`re going too much into \nimplementation and theory here, where it shouldn`t really matter from \nthe user`s point of view - the point is to rebase a commit, `pick` it \nfrom one place and plant it elsewhere.\n\nYes, some commits might have a bit different semantics then others \n(merge vs non-merge), but it should just be an implementation detail, \nin my opinion, no need to leak it in user`s face (more than necessary).\n\nI feel that \"merge\" is a command that works really well in the \nmindset of (re)creating merges. But if we are \"only\" rebasing an \nexisting merge, `pick` seems much more appropriate (to me, at least), \nand it aligns with what I`m already expecting `pick` to be doing.\n\nDown below, if we are (re)creating the merge, or doing magic to \nsomehow just port it over, should be irrelevant. So \"rebase\" equals \n\"pick and plant\" (port), not \"merge\".\n\n> > That is what I had in mind, seeming possibly more straightforward and \n> > beautifully aligned with previously existing (and well known) \n> > `rebase` terminology.\n> >\n> > Not to say this would make it possible to use other `rebase -i` todo \n> > list commands, too, like if you want to amend/edit merge commit after \n> > it was rebased, you would write:\n> >\n> > \tedit <original--merge-commit> <merge-head>\n> >\n> > ..., where in case you would simply like to reword its commit \n> > message, it would be just:\n> >\n> > \treword <original--merge-commit> <merge-head>\n> >\n> >\n> > Even `squash` and `fixup` could have their place in combination with \n> > a (to be rebased) merge commit, albeit in a pretty exotic rebases, \n> > thus these could probably be just disallowed - for the time being, at \n> > least.\n> \n> Sure, for someone who read the manual, that would be easy to use. Of\n> course, that's the minority.\n\nI`m not following you here - the point is these are already existing \ncommands, which would still fit in just nicely, so nothing new to \nlearn nor read.\n\nNow, if we are to discuss use cases where people don`t even know what \nthey`re doing, I would think that misses the point. Besides, it`s \nalways easier to make more mistakes when you introduce yet more \ncommands/semantics to think about/learn, and I think it can be avoided \nhere, for the better.\n\n> Also: the `edit` command is poorly named to begin with. A much cleaner\n> design would be to introduce the `break` command as suggested by Stephan.\n\nThis is orthogonal to what we`re discussing. Existing commands might \nnot be perfect, but that`s what we have now, so let`s be consistent, \nnot putting additional burden on the user there, at least.\n\nBut for the record - I tend to agree, I often find myself wondering \nif `edit`-ed commit means `rebase` stops after applying the changes \nand _before_ making the commit itself (so we just edit and \n--continue), or _after_ it (so we edit, `commit --amend` and \n--continue).\n\n> > The real power would be buried in implementation, learning to rebase \n> > merge commits, so user is left with a very familiar interface, slightly \n> > adapted do accommodate a bit different nature of merge commit in \n> > comparison to an ordinary one, also to allow a bit more of interactive \n> > rebase functionality, but it would pretty much stay the same, without \n> > even a need to learn about new `merge`, `-R`, `-C`, and so on.\n> >\n> > Yes, those would have its purpose, but for real merging then \n> > (creating new merges, or recreating old ones), not necessarily for \n> > merge rebasing.\n> >\n> > With state of `merge -R -C ...` (that `-R` being the culprit), it \n> > kind of feels like we`re now trying to bolt \"rebase merges\" \n> > functionality onto a totally different one (recreate merges, serving \n> > a different purpose), making them both needlessly dependent on each \n> > other, further complicating user interface, making it more confusing \n> > and less tunable as per each separate functionality needs (rebase vs. \n> > recreate).\n> >\n> > I guess I`m the one to pretty much blame here, too, as I really \n> > wanted `--recreate-merges` to handle \"rebase merges\" better, only to \n> > later realize it might not be the best tool for the job, and that a \n> > more separate approach would be better (at least not through the same \n> > `merge` todo list command)...\n> >\n> > [1] https://public-inbox.org/git/f3872fb9-01bc-b2f1-aee9-cfc0e4db77d6@gmail.com/\n> \n> Well, the `-R` option is no worse than `git merge`'s `-s <strategy>`\n> option (which *also* changes the strategies rather drastically).\n\nWhat I wrote above, -R seems unfitting for `merge`, as we are not \nreally merging, but rebasing (conceptually, not implementation wise).\n\nAnd it makes even less sense in the light of that previous comment \nwhere \"rebasing a merge\" shouldn`t even allow selecting a specific \nstrategy, as that would imply (re)creating the merge instead.\n\nSo using `merge` for rebasing existing (merge) commit seems as rather \nmisusing the concept of `merging`.\n\nI don`t know, I`m thinking if we are looking at todo list from \ndifferent perspectives - to you, it seems to be a sequence of \ncommands to create something new (yes, from something that already \nexists, but that`s implementation detail). In that context, using \n`merge` might have sense (even if still being a very special merge).\n\nBut to me, as we already have `pick` and not `commit` to rebase \ncommits, it means we are not creating but rather reusing what we have \n(being an important concept to reason about), thus `pick` would still \nfit in for picking a merge commit just nicely, and more naturally, too.\n\n*Maybe if* `-R` would be turned into a full fledged \"rebase\" (or \n\"rebasing\") merge strategy, written as:\n\n\tmerge -s rebase -C <original--merge-commit> <merge-head>\n\n..., might be it would make more sense to me (aligned with what \n`merge` is expected to do). But even then, I might prefer having \n`pick` as a syntactic sugar over `merge -s rebase`, at least.\n\nIn the light of this, I _could_ even see `-R` as short for `-s \nrebase`, but it still seems a bit awkward and forced.\n\nRegards, Buga\n"},{"id":"341515","messageId":"39327070-f13a-f7e5-6c8c-cd204530f051@gmail.com","threadId":"47864","inReplyTo":"87h8plh2qd.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-13T00:01:38Z","receivedAt":"2018-03-13T00:02:03Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 12/03/2018 13:56, Sergey Organov wrote:\n> \n> > > I agree with both of you that `pick <merge-commit>` is inflexible \n> > > (not to say just plain wrong), but I never thought about it like that.\n> > >\n> > > If we are to extract further mentioned explicit old:new merge \n> > > parameter mapping to a separate discussion point, what we`re \n> > > eventually left with is just replacing this:\n> > >\n> > > \tmerge -R -C <original--merge-commit> <merge-head>\n> > >\n> > > ... with this:\n> > >\n> > > \tpick <original--merge-commit> <merge-head>\n> >\n> > I see where you are coming from.\n> >\n> > I also see where users will be coming from. Reading a todo list in the\n> > editor is as much documentation as it is a \"program to execute\". And I am\n> > afraid that reading a command without even mentioning the term \"merge\"\n> > once is pretty misleading in this setting.\n> >\n> > And even from the theoretical point of view: cherry-picking non-merge\n> > commits is *so much different* from \"rebasing merge commits\" as discussed\n> > here, so much so that using the same command would be even more\n> > misleading.\n> \n> This last statement is plain wrong when applied to the method in the\n> [RFC] you are replying to. Using the method in [RFC], \"cherry-pick\n> non-merge\" is nothing more or less than reduced version of generic\n> \"cherry-pick merge\", exactly as it should be.\n> \n> Or, in other words, \"cherry-pick merge\" is generalization of\n> \"cherry-pick non-merge\" to multiple parents.\n\nI think Sergey does have a point here, his approach showing it.\n\nPhillip`s simplification might be further from it, though, but we`re \ntalking implementation again - important mental model should just be \n\"rebasing a commit\" (merge or non-merge), how we`re doing it is \nirrelevant for the user, the point (goal) is the same.\n"},{"id":"341517","messageId":"243ca23d-77a9-4ae1-a120-de6c6b195cdc@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803121142550.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-13T00:16:20Z","receivedAt":"2018-03-13T00:16:44Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 12/03/2018 11:46, Johannes Schindelin wrote:\n> \n> > Sometimes one just needs to read the manual, and I don`t really think\n> > this is a ton complicated, but just something we didn`t really have\n> > before (real merge rebasing), so it requires a moment to grasp the\n> > concept.\n> \n> If that were the case, we would not keep getting bug reports about\n> --preserve-merges failing to reorder patches.\n\nNot sure where that is heading to, but what I`m arguing about is that \nintroducing new commands and concepts (`merge`, and with `-R`) just \nmakes the situation even worse (more stuff to grasp).\n\nReusing existing concepts where possible doesn`t have this problem.\n\n> > Saying in favor of `--rebase-merges`, you mean as a separate option,\n> > alongside `--recreate-merges` (once that series lands)?\n> \n> No. I am against yet another option. The only reason I pollute the option\n> name space further with --recreate-merges is that it would be confusing to\n> users if the new mode was called --preserve-merges=v2 (but work *totally\n> differently*).\n\nI see. So I take you`re thinking about renaming `--recreate-merges` \nto `--rebase-merges` instead?\n\nThat would seem sensible, too, I think, being the default usage mode \nin the first place. Being able to actually (re)create merges, too, \nonce user goes interactive, would be \"just\" an additional (nice and \npowerful) feature on top of it.\n\nRegards, Buga\n"},{"id":"341518","messageId":"45d05a89-b10e-5035-7c5b-2981dba27d42@gmail.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803121056400.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-13T00:29:21Z","receivedAt":"2018-03-13T00:29:46Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Dscho,\n\nOn 12/03/2018 11:20, Johannes Schindelin wrote:\n> \n> > > [...] and cannot introduce ambiguities when rebasing the\n> > > changes introduced by M (i.e. the \"amendmendts\" we talked about).\n> >\n> > Hmm, not following here, which ambiguities are we talking about?\n> \n> U1' vs U2' of course. Those are two things that can be different, even if\n> they ideally would have identical trees.\n> \n> Phillip's strategy does not leave that room for ambiguity.\n\nEhm, in Sergey`s approach, this is not an issue, but a feature :)\n\nIf U1' != U2', it just means a more complex rebase happened, but it \ndoesn`t compromise the result (rebased merge) in any way.\n\nOn the other hand, if U1' == U2', we can be pretty sure that merge \nrebasing went as clean as possible.\n\nThat`s the idea, at least.\n\nRegards, Buga\n"},{"id":"341524","messageId":"87r2oocx0l.fsf@javad.com","threadId":"47864","inReplyTo":"77b695d0-7564-80d7-d9e6-70a531e66eda@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-13T06:25:30Z","receivedAt":"2018-03-13T06:25:37Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n[...]\n\n> I don`t know, I`m thinking if we are looking at todo list from\n> different perspectives - to you, it seems to be a sequence of\n> commands to create something new (yes, from something that already\n> exists, but that`s implementation detail). In that context, using\n> `merge` might have sense (even if still being a very special merge).\n>\n> But to me, as we already have `pick` and not `commit` to rebase\n> commits, it means we are not creating but rather reusing what we have\n> (being an important concept to reason about), thus `pick` would still\n> fit in for picking a merge commit just nicely, and more naturally,\n> too.\n\nExactly.\n\nFundamentally, a good editing tool should first be able to just safely\nreproduce back what it got, only then everything else goes.\n\nFrom this follows that git history-editing tool should start from sound\nhistory representation, i.e., some text representation of the DAG that\nallows to re-create the DAG back.\n\nThe simplest way is to just list all the nodes in some topological\norder, along with references to the parents. Then, to simplify the list,\nfirst parent, unless explicitly specified, could be assumed to be the\npreceding item in the list.\n\nNext, we actually need _to do_ something with this, so we convert this\nto a _todo_ list by prepending action to each element of the list (isn't\nit Lisp once again?). Let the action be called 'pick'. Then, e.g., the\npiece of history:\n\n           B1-------B2\n          /           \\\n S--M0---M1---- M2 ----M3 -- M4\n\nfrom M0 to M4 will be represented like this:\n\nskip S          # Just to have a handy reference\npick M0         # Implicit first parent (S)\npick M1         # Implicit first parent (M0)\npick M2         # Implicit first parent (M1)\npick B1 M1      # Explicit first parent\npick B2         # Implicit first parent (B1)\npick M3 M2 B2   # Explicit first and second parents\npick M4\n\nWhich basically gets us back to what you are advocating.\n\nHere is another variant, using command options to specify parents (I\nalso exchanged order of branch and mainline):\n\nskip S          # To have the base reference handy\npick M0         # Implicit first parent (S)\npick B1         # Implicit first parent (M0)\npick B2         # Implicit first parent (B1)\npick M1 -1 M0   # Explicit first parent M0\npick M2         # Implicit first parent (M1)\npick M3 -2 B2   # Implicit first parent (M2) and\n                # explicit second parent B2\npick M4         # Implicit first parent (M3)\n\nI like this one even better.\n\nIMHO, this is indeed a good starting point. No special treatment for\nmerges is needed so far.\n\n-- Sergey\n"},{"id":"341544","messageId":"877eqgardi.fsf@javad.com","threadId":"47864","inReplyTo":"6c8749ca-ec5d-b4b7-f1a0-50d9ad2949a5@talktalk.net","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-13T16:10:17Z","receivedAt":"2018-03-13T16:10:42Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Phillip,\n\nPhillip Wood <phillip.wood@talktalk.net> writes:\n\n[...]\n\n> Hi Sergey, I've been following this discussion from the sidelines,\n> though I haven't had time to study all the posts in this thread in\n> detail. I wonder if it would be helpful to think of rebasing a merge as\n> merging the changes in the parents due to the rebase back into the\n> original merge. So for a merge M with parents A B C that are rebased to\n> A' B' C' the rebased merge M' would be constructed by (ignoring shell\n> quoting issues)\n>\n> git checkout --detach M\n> git merge-recursive A -- M A'\n> tree=$(git write-tree)\n> git merge-recursive B -- $tree B'\n> tree=$(git write-tree)\n> git merge-recursive C -- $tree C'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n\nI wonder if it's OK to exchange the order of heads in the first merge\n(also dropped C for brevity):\n\ngit checkout --detach A'\ngit merge-recursive A -- A' M\ntree=$(git write-tree)\ngit merge-recursive B -- $tree B'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n\nIf so, don't the first 2 lines now read: \"rebase (first parent of) M on\ntop of A'\"?\n\nIf so, then it could be implemented so that it reduces back to regular\nrebase of non-merges when applied to a single-parent commit, similar to\nthe method in the RFC, striking out one of advantages of the RFC.\n\n-- Sergey\n"},{"id":"341563","messageId":"xmqqk1uf3kcd.fsf@gitster-ct.c.googlers.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803111248200.20700@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-03-13T18:24:02Z","receivedAt":"2018-03-13T18:24:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> So essentially, what your cherry-pick'able commits are is a way to store\n> what rerere would have stored (i.e. the set of merge conflicts together\n> with their resolution)?\n\nIf rerere would have stored, I wouldn't have separate band-aid\nsystem on top.  These fix-up commits are usually on parts that do\nnot get involved in textual conflicts; \"rerere\" which relies on\nhaving textual conflicts (the \"shape\" of the text in the conflicted\nregion is what lets \"rerere\" index into its database to find the\nrecorded resolution) wouldn't have stored them and that is\nfundamental.\n\n> If so, what tooling do you have to identify quickly what to cherry-pick,\n> given merge conflicts?\n\nIt exactly is the issue I've been trying to find ideal solution for\nquite a while and not successfully.  Here is a sample thread\n\n  https://public-inbox.org/git/xmqqeft3u0u5.fsf@gitster.mtv.corp.google.com/#t\n\nand every message I mention \"merge-fix\" is relevant.\n\nThe current band-aid system punts and indexes the merge-fix changes\nby merely a branch name.  When refs/merge-fix/X exists, what it\nmeans is \"When branch X is merged to an integration branch, it is\nlikely that the integration branch _already_ has merged an unnamed\ntopic that causes semantic conflicts and requires this fix-up\".\nThis needs occasional manual adjustment---e.g. when the topic X\nturns out to be a lot more stable than the other topic Y that was\ncausing us trouble with semantic conflicts, I may at some point\nreorder the topics and have topic X advance to 'next' before topic Y\ndoes.  And when that happens, when I merge X to 'next', because Y is\nnot yet in 'next', I shouldn't apply refs/merge-fix/X (often, an\nattempt to cherry-pick it on top of a merge of X into 'next' would\nfail, which would be a bit of safety, but not always).  What I\nshould do instead is to rename refs/merge-fix/X to refs/merge-fix/Y\nimmediately before merging X to 'next', so that the cherry-pick is\nnot applied.  When rebuilding 'master'->'jch'->'pu' chain, X (now in\n'next') will be merged before Y (not in 'next') gets merged, and\nwhen it is Y's turn to be merged, the merge-fix I used to apply when\nmerging topic X will be applied.\n\nIn the ideal world (I think I'm repeating the ideas raised in the\nthread quoted), the merge-fix database should be indexed with a pair\nof commit object names (e.g. a step in branch X that adds a new\ncallsite for function frotz() and a step in branch Y that changes\nthe function signature of frotz()), and teach the system to\ncherry-pick refs/merge-fix/A-B to resolve semantic conflicts, when\nboth commits A and B appears in the integration branch for the first\ntime.  And make sure these are kept up-to-date across rebasing of\ncommits A and B.  After rebasing the topics X and Y that contained\nthe commits A and B, if they became C and D, the system somehow\nneeds to be able to locate the previous merge-fix that was valid for\nA-B pair when C-D pair gets merged.\n\n"},{"id":"341610","messageId":"3f2209e0-c560-5384-c589-3aa83615d688@gmail.com","threadId":"47864","inReplyTo":"877eqgardi.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-14T01:12:28Z","receivedAt":"2018-03-14T01:12:54Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 13/03/2018 17:10, Sergey Organov wrote:\n> \n> > Hi Sergey, I've been following this discussion from the sidelines,\n> > though I haven't had time to study all the posts in this thread in\n> > detail. I wonder if it would be helpful to think of rebasing a merge as\n> > merging the changes in the parents due to the rebase back into the\n> > original merge. So for a merge M with parents A B C that are rebased to\n> > A' B' C' the rebased merge M' would be constructed by (ignoring shell\n> > quoting issues)\n> >\n> > git checkout --detach M\n> > git merge-recursive A -- M A'\n> > tree=$(git write-tree)\n> > git merge-recursive B -- $tree B'\n> > tree=$(git write-tree)\n> > git merge-recursive C -- $tree C'\n> > tree=$(git write-tree)\n> > M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n> \n> I wonder if it's OK to exchange the order of heads in the first merge\n> (also dropped C for brevity):\n\nIt should be, being \"left\" or \"right\" hand side (\"theirs\" or \"ours\") \nof the three-way merge shouldn`t matter, they`re still both equally \ncompared to the merge-base.\n\n> git checkout --detach A'\n> git merge-recursive A -- A' M\n> tree=$(git write-tree)\n> git merge-recursive B -- $tree B'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n> \n> If so, don't the first 2 lines now read: \"rebase (first parent of) M on\n> top of A'\"?\n\nHmm, lol, yes...? :) So basically, this:\n\n(1)\tgit checkout --detach M\n\tgit merge-recursive A -- M A'\n\ttree=$(git write-tree)\n\t...\n\n... is equivalent to this:\n\n(2)\tgit checkout --detach A'\n\tgit merge-recursive A -- A' M\n\ttree=$(git write-tree)\n\t...\n\n..., being equivalent to this:\n\n(3)\tgit checkout --detach A'\n\tgit cherry-pick -m 1 M\n\ttree=$(git write-tree)\n\t...\n\n..., where in all three cases that `$tree` is equivalent to U1' we \ndiscussed about so much already :)\n\nI tested it like this as well, slightly modifying previously sent out \nscript (like this one[1]), and it still seems to be working ;) Nice!\n\n> If so, then it could be implemented so that it reduces back to regular\n> rebase of non-merges when applied to a single-parent commit, similar to\n> the method in the RFC, striking out one of advantages of the RFC.\n\nI guess so, but I think it now boils down only to what one finds \neasier to reason about even more.\n\nI`m just glad we got to U1' from this perspective as well, hopefully \nadding even more faith in the overall concept, being beaten from both \nends and dropping out to be the same (minus minor implementation details).\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/872944c4-ca97-9f55-a424-86d1e3299a22@gmail.com/\n"},{"id":"341619","messageId":"87efkn6s1h.fsf@javad.com","threadId":"47864","inReplyTo":"3f2209e0-c560-5384-c589-3aa83615d688@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-14T07:21:46Z","receivedAt":"2018-03-14T07:21:57Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 13/03/2018 17:10, Sergey Organov wrote:\n>> \n>> > Hi Sergey, I've been following this discussion from the sidelines,\n>> > though I haven't had time to study all the posts in this thread in\n>> > detail. I wonder if it would be helpful to think of rebasing a merge as\n>> > merging the changes in the parents due to the rebase back into the\n>> > original merge. So for a merge M with parents A B C that are rebased to\n>> > A' B' C' the rebased merge M' would be constructed by (ignoring shell\n>> > quoting issues)\n>> >\n>> > git checkout --detach M\n>> > git merge-recursive A -- M A'\n>> > tree=$(git write-tree)\n>> > git merge-recursive B -- $tree B'\n>> > tree=$(git write-tree)\n>> > git merge-recursive C -- $tree C'\n>> > tree=$(git write-tree)\n>> > M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB' -pC')\n>> \n>> I wonder if it's OK to exchange the order of heads in the first merge\n>> (also dropped C for brevity):\n>\n> It should be, being \"left\" or \"right\" hand side (\"theirs\" or \"ours\") \n> of the three-way merge shouldn`t matter, they`re still both equally \n> compared to the merge-base.\n>\n>> git checkout --detach A'\n>> git merge-recursive A -- A' M\n>> tree=$(git write-tree)\n>> git merge-recursive B -- $tree B'\n>> tree=$(git write-tree)\n>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n>> \n>> If so, don't the first 2 lines now read: \"rebase (first parent of) M on\n>> top of A'\"?\n>\n> Hmm, lol, yes...? :) So basically, this:\n>\n> (1)\tgit checkout --detach M\n> \tgit merge-recursive A -- M A'\n> \ttree=$(git write-tree)\n> \t...\n>\n> ... is equivalent to this:\n>\n> (2)\tgit checkout --detach A'\n> \tgit merge-recursive A -- A' M\n> \ttree=$(git write-tree)\n> \t...\n>\n> ..., being equivalent to this:\n>\n> (3)\tgit checkout --detach A'\n> \tgit cherry-pick -m 1 M\n> \ttree=$(git write-tree)\n> \t...\n>\n> ..., where in all three cases that `$tree` is equivalent to U1' we \n> discussed about so much already :)\n\nExactly, and thanks for noticing that it's actually U1', that happens to\nsoon become rather handy, see below.\n\n> I tested it like this as well, slightly modifying previously sent out \n> script (like this one[1]), and it still seems to be working ;) Nice!\n\nVery nice of you, thanks!\n\nYet another outcome of this transformation is that the fist step is now\nfree to (and probably should) utilize all the options (-s, -X, etc.)\nthat usual rebase has:\n\ngit-rebase-first-parent --onto A' M\ntree=$(git write-tree)\n\nwhere 'git-rebase-first-parent' is whatever machinery is currently being\nused to rebase simple non-merge commit.\n\n[\n\nMoreover, Phillip's method could further be transformed to what is in\nRFC, not that I think it should, see below. Just for the sake of\ncompleteness though, here is the essential missing transformation that\nmakes Phillip's method symmetric, after which it becomes true special\ncase of the RFC with particular rebase-first-parent implementation:\n\ngit checkout --detach A'\ngit merge-recursive A -- A' M\ntree_U1'=$(git write-tree)\ngit checkout --detach B'\ngit merge-recursive B -- B' M\ntree_U2'=$(git write-tree)\ngit merge-recursive M -- $tree_U1' $tree_U2'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n\n]\n\n>\n>> If so, then it could be implemented so that it reduces back to regular\n>> rebase of non-merges when applied to a single-parent commit, similar to\n>> the method in the RFC, striking out one of advantages of the RFC.\n>\n> I guess so, but I think it now boils down only to what one finds \n> easier to reason about even more.\n\nI actually think there is more to it. It's incremental asymmetric nature\nof the Phillip's approach that I now find rather appealing and worth to\nbe used in practice.\n\nWhile the RFC approach, being entirely symmetric, is nice from the POV\nof theory and reasoning, yet simple to implement, the actual user\ninterface of Git is inherently asymmetric with respect to merges (one\nmerges side-branch(es) to mainline), so asymmetric approach of the\nPhillip's method should give smoother user experience, even if only\nbecause of 1 less merge.\n\nThere are still 2 issues about the implementation that need to be\ndiscussed though:\n\n1. Still inverted order of the second merge compared to RFC.\n\nIt'd be simple to \"fix\" again, except I'm not sure it'd be better, and\nas there is no existing experiences with this step to follow, it\nprobably should be left as in the original, where it means \"merge the\nchanges made in B' (w.r.t B) into our intermediate version of the\nresulting merge\".\n\nThe original Phillip's version seems to better fit the asymmetry between\nmainline and side-branch handling.\n\nThe actual difference will be only in the order of ours vs theirs in\nconflicts though, and thus it's not that critical.\n\n2. The U1' == U2' consistency check in RFC that I still think is worth\nto be implemented.\n\nIn application to the method being discussed, we only need the check if\nthe final merge went without conflicts, so the user was not already\ninvolved, and the check itself is then pretty simple:\n\n \"proceed without stop only if $tree = $tree_U1'\"\n\nIts equivalence to the U1' == U2' test in the RFC follows from the fact\nthat if M' is non-conflicting merge of U1' and U2', then M' == U1' if\nand only if U2' == U1'.\n\nFinally, here is a sketch of the implementation that I'd suggest to\nuse:\n\ngit-rebase-first-parent --onto A' M\ntree_U1'=$(git write-tree)\ngit merge-recursive B -- $tree_U1' B'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n[ $conflicted_last_merge = \"yes\" ] ||\n  trees-match $tree_U1' $tree || \n  stop-for-user-amendment\n\nwhere 'git-rebase-first-parent' denotes whatever machinery is currently\nbeing used to rebase simple non-merge commit. Handy approximation of\nwhich for stand-alone scripting is:\n\ngit checkout --detach A' && git cherry-pick -m 1 M\n\n[As an interesting note, observe how, after all, that original Johannes\nSixt's idea of rebasing of merge commit by cherry-picking its first\nparent is back there.]\n\n-- Sergey\n"},{"id":"341633","messageId":"87vadyd9az.fsf@javad.com","threadId":"47864","inReplyTo":"2749ce78-8917-c821-6116-0c8d67b5e16e@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-14T14:24:36Z","receivedAt":"2018-03-14T14:24:44Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Dscho,\n>\n> On 07/03/2018 08:26, Johannes Schindelin wrote:\n\n[...]\n\n>> Second side note: if we can fast-forward, currently we prefer that, and I\n>> think we should keep that behavior with -R, too.\n>\n> I agree.\n\nI'm admittedly somewhat lost in the discussion, but are you talking\nfast-forward on _rebasing_ existing merge? Where would it go in any of\nthe suggested algorithms of rebasing and why?\n\nI readily see how it can break merges. E.g., any \"git merge --ff-only\n--no-ff\" merge will magically disappear. So, even if somehow supported,\nfast-forward should not be performed by default during _rebasing_ of a\nmerge.\n\n>> If the user wants to force a new merge, they simply remove that -R\n>> flag.\n\nAlternatively, they'd replace 'pick' with 'merge', as they already do\nfor other actions. \"A plurality is not to be posited without necessity\".\n\nPlease, _please_, don't use 'merge' command to 'pick' merge commits!\nIt's utterly confusing!\n\nThinking about it I've got an idea that what we actually need is\n--no-flatten flag that, when used alone, will just tell \"git rebase\" to\nstop flattening history, and which will be implicitly imposed by\n--recreate-merges (and --preserve-merges).\n\nThen the only thing the --recreate-merges will tune is to put 'merge'\ndirectives into the todo list for merge commits, exactly according to\nwhat its name suggests, while the default behavior will be to put 'pick'\nwith suitable syntax into the todo. And arguments to the\n--recreate-merge will specify additional options for the 'merge'\ndirective, obviously.\n\n-- Sergey\n"},{"id":"341727","messageId":"d5e68db4-8006-2c0e-bc21-0b136503edd9@gmail.com","threadId":"47864","inReplyTo":"87vadyd9az.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-14T23:11:09Z","receivedAt":"2018-03-14T23:11:35Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 14/03/2018 15:24, Sergey Organov wrote:\n> \n> > > Second side note: if we can fast-forward, currently we prefer that, and I\n> > > think we should keep that behavior with -R, too.\n> >\n> > I agree.\n> \n> I'm admittedly somewhat lost in the discussion, but are you talking\n> fast-forward on _rebasing_ existing merge? Where would it go in any of\n> the suggested algorithms of rebasing and why?\n> \n> I readily see how it can break merges. E.g., any \"git merge --ff-only\n> --no-ff\" merge will magically disappear. So, even if somehow supported,\n> fast-forward should not be performed by default during _rebasing_ of a\n> merge.\n\nHmm, now that you brought this up, I can only agree, of course.\n\nWhat I had in my mind was more similar to \"no-rebase-cousins\", like \nif we can get away without actually rebasing the merge but still \nusing the original one, do it. But I guess that`s not what Johannes \noriginally asked about.\n\nThis is another definitive difference between rebasing (`pick`?) and \nrecreating (`merge`) a merge commit - in the case where we`re rebasing, \nof course it doesn`t make sense to drop commit this time (due to \nfast-forward). This does make sense in recreating the merge (only).\n\n> > > If the user wants to force a new merge, they simply remove that -R\n> > > flag.\n\nAnd this sounds wrong now, too, because we actually have _three_\npossible behaviors here - (1) rebase merge commit, which should \nalways do what its told (so no fast-forwarding, otherwise the whole \nconcept of rebasing a merge commit doesn`t make sense), and recreate \nmerge commit, which should (2) by default use fast-forward where \npossible (or whatever the settings say), but (3) also be possible to \nforce a new merge as well (through standard `--no-ff`, I guess, or \nsomething).\n\n> Alternatively, they'd replace 'pick' with 'merge', as they already do\n> for other actions. \"A plurality is not to be posited without necessity\".\n> \n> Please, _please_, don't use 'merge' command to 'pick' merge commits!\n> It's utterly confusing!\n\nI agree here, as previously discussed[1], but let`s hear Johannes.\n\n> Thinking about it I've got an idea that what we actually need is\n> --no-flatten flag that, when used alone, will just tell \"git rebase\" to\n> stop flattening history, and which will be implicitly imposed by\n> --recreate-merges (and --preserve-merges).\n> \n> Then the only thing the --recreate-merges will tune is to put 'merge'\n> directives into the todo list for merge commits, exactly according to\n> what its name suggests, while the default behavior will be to put 'pick'\n> with suitable syntax into the todo. And arguments to the\n> --recreate-merge will specify additional options for the 'merge'\n> directive, obviously.\n\nThis seem to basically boil down to what I mentioned previously[2] \nthrough use of new `--rebase-merges` alongside `--recreate-merges`, just \nthat you named it `--no-flatten` here, but the point is the same - and \nnot something Johannes liked, \"polluting\" rebase option space further.\n\nI would agree with him, and settling onto `--rebase-merges` _instead_ of \n`--recreate-merges` seems as a more appropriate name, indeed, now that \ndefault behavior is actually merge commit rebasing and not recreating \n(recreating still being possible through user editing the todo list).\n\nNow, the only thing left seems to be agreeing on actual command to \nuse to rebase the merge commit, to `pick` it, so to say... ;)\n\nRegards, Buga\n\n[1] https://public-inbox.org/git/77b695d0-7564-80d7-d9e6-70a531e66eda@gmail.com/\n[2] https://public-inbox.org/git/b329bb98-f9d6-3d51-2513-465aad2fa37a@gmail.com/\n"},{"id":"341728","messageId":"de063fba-2882-6194-a889-ad3e9b6b02b9@gmail.com","threadId":"47864","inReplyTo":"87efkn6s1h.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-15T00:09:31Z","receivedAt":"2018-03-15T00:09:57Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 14/03/2018 08:21, Sergey Organov wrote:\n> \n> There are still 2 issues about the implementation that need to be\n> discussed though:\n> \n> 1. Still inverted order of the second merge compared to RFC.\n> \n> It'd be simple to \"fix\" again, except I'm not sure it'd be better, and\n> as there is no existing experiences with this step to follow, it\n> probably should be left as in the original, where it means \"merge the\n> changes made in B' (w.r.t B) into our intermediate version of the\n> resulting merge\".\n> \n> The original Phillip's version seems to better fit the asymmetry between\n> mainline and side-branch handling.\n> \n> The actual difference will be only in the order of ours vs theirs in\n> conflicts though, and thus it's not that critical.\n\nShouldn`t this be easy to solve just by changing the order of <head> \nand <remote>, on passing to `git merge-recursive`, if needed? (or \nthat`s what you meant by \"simple to fix\"?)\n\n> 2. The U1' == U2' consistency check in RFC that I still think is worth\n> to be implemented.\n\nAt the moment, I think we`d appreciate test cases where it actually \nproves useful, as the general consensus seems to be leaning towards \nit possibly being annoying (over-paranoid).\n\n> In application to the method being discussed, we only need the check if\n> the final merge went without conflicts, so the user was not already\n> involved, and the check itself is then pretty simple:\n> \n>  \"proceed without stop only if $tree = $tree_U1'\"\n> \n> Its equivalence to the U1' == U2' test in the RFC follows from the fact\n> that if M' is non-conflicting merge of U1' and U2', then M' == U1' if\n> and only if U2' == U1'.\n\nNicely spot! I`m glad there`s still (kind of) former U1' == U2' check \nin this approach, too, in case it proves useful :)\n\n> Finally, here is a sketch of the implementation that I'd suggest to\n> use:\n> \n> git-rebase-first-parent --onto A' M\n> tree_U1'=$(git write-tree)\n> git merge-recursive B -- $tree_U1' B'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n> [ $conflicted_last_merge = \"yes\" ] ||\n>   trees-match $tree_U1' $tree || \n>   stop-for-user-amendment\n\nYes, in case where we would want the \"no-op merge\" check (equivalent \nto U1' == U2' with original approach), this aligns with something I \nwould expect.\n\nNote that all the \"rebase merge commit\" steps leading to the check \nwill/should probably be observed as a single one from user`s perspective \n(in worst case ending with nested conflicts we discussed), thus \n`$conflicted_last_merge` is not related to `merge-recursive` step(s) \nonly, but `rebase-first-parent`, too (just in case this isn`t implied).\n\nMight be easier to reason about simply as `[ $conflicts = \"yes\" ] || `\n\n> where 'git-rebase-first-parent' denotes whatever machinery is currently\n> being used to rebase simple non-merge commit. Handy approximation of\n> which for stand-alone scripting is:\n> \n> git checkout --detach A' && git cherry-pick -m 1 M\n> \n> [As an interesting note, observe how, after all, that original Johannes\n> Sixt's idea of rebasing of merge commit by cherry-picking its first\n> parent is back there.]\n\nHeh ;) It`s always a bit enlightening when people start from different \npositions, opposing ones, even (or so it may seem, at least), but \neventually end up in the same place, through means of open (minded) \ndiscussion.\n\nRegards, Buga\n"},{"id":"341733","messageId":"87zi397uak.fsf@javad.com","threadId":"47864","inReplyTo":"d5e68db4-8006-2c0e-bc21-0b136503edd9@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-15T06:00:03Z","receivedAt":"2018-03-15T06:00:14Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 14/03/2018 15:24, Sergey Organov wrote:\n[...]\n>> Thinking about it I've got an idea that what we actually need is\n>> --no-flatten flag that, when used alone, will just tell \"git rebase\" to\n>> stop flattening history, and which will be implicitly imposed by\n>> --recreate-merges (and --preserve-merges).\n>> \n>> Then the only thing the --recreate-merges will tune is to put 'merge'\n>> directives into the todo list for merge commits, exactly according to\n>> what its name suggests, while the default behavior will be to put 'pick'\n>> with suitable syntax into the todo. And arguments to the\n>> --recreate-merge will specify additional options for the 'merge'\n>> directive, obviously.\n>\n> This seem to basically boil down to what I mentioned previously[2] \n> through use of new `--rebase-merges` alongside `--recreate-merges`, just \n> that you named it `--no-flatten` here, but the point is the same - and \n> not something Johannes liked, \"polluting\" rebase option space further.\n\nNot quite so. The problem with --XXX-merges flags is that they do two\nthings at once: they say _what_ to do and _how_ to do it. Clean UI\ndesigns usually have these things separate, and that's what I propose.\n\nThe --[no-]flatten says _what_ (not) to do, and --recreate-merges says\n_how_ exactly it will be performed. In this model --no-flatten could\nhave been called, say --preserve-shape, but not --rebase-merges.\n\nTo minimize pollution, the _how_ part could rather be made option value:\n\n--no-flatten[=<strategy>]\n\nwhere <strategy> is 'rebase', 'remerge', etc.\n\nIn this case we will need separate option to specify strategy options,\nif required, that will lead us to something similar to the set of merge\nstrategies options.\n\n> I would agree with him, and settling onto `--rebase-merges` _instead_ of \n> `--recreate-merges` seems as a more appropriate name, indeed, now that \n> default behavior is actually merge commit rebasing and not recreating \n> (recreating still being possible through user editing the todo list).\n\nI hope he'd be pleased to be able to say --no-flatten=remerge and get\nback his current mode of operation, that he obviously has a good use\nfor.\n\n-- Sergey\n"},{"id":"341735","messageId":"87lget7p2g.fsf@javad.com","threadId":"47864","inReplyTo":"de063fba-2882-6194-a889-ad3e9b6b02b9@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-15T07:52:55Z","receivedAt":"2018-03-15T07:53:04Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 14/03/2018 08:21, Sergey Organov wrote:\n>> \n>> There are still 2 issues about the implementation that need to be\n>> discussed though:\n>> \n>> 1. Still inverted order of the second merge compared to RFC.\n>> \n>> It'd be simple to \"fix\" again, except I'm not sure it'd be better, and\n>> as there is no existing experiences with this step to follow, it\n>> probably should be left as in the original, where it means \"merge the\n>> changes made in B' (w.r.t B) into our intermediate version of the\n>> resulting merge\".\n>> \n>> The original Phillip's version seems to better fit the asymmetry between\n>> mainline and side-branch handling.\n>> \n>> The actual difference will be only in the order of ours vs theirs in\n>> conflicts though, and thus it's not that critical.\n>\n> Shouldn`t this be easy to solve just by changing the order of <head> \n> and <remote>, on passing to `git merge-recursive`, if needed? (or \n> that`s what you meant by \"simple to fix\"?)\n\nYes, that's exactly what I meant, except it looks cleaner as is, so I\ndon't think the exchange is called for.\n\n>> 2. The U1' == U2' consistency check in RFC that I still think is worth\n>> to be implemented.\n>\n> At the moment, I think we`d appreciate test cases where it actually \n> proves useful, as the general consensus seems to be leaning towards \n> it possibly being annoying (over-paranoid).\n\nAs we now have a simple way to actually check it even in this algorithm,\nI'd suggest command-line option to either relax or enforce the check,\nwhatever the default is. For the default, I'd still opt for safety, as\nwithout it we will gather little experience with this new matter.\n\nHonestly, without this check available, I'd likely vote for at least an\noption for stopping on every rebased merge, on the ground that if\nrebasing a non-merge could be a trouble, rebasing a merge is at least\ndouble-trouble, and it's not that frequent anyway. So the check we\ndiscuss is actually a way to make all the process much less paranoid,\nnot more.\n\nBy the way, nobody yet commented about \"rerere\" behavior that basically\nstops rebasing every time it fires. Do you consider it over-paranoid?\n\nAs for test cases, I have none myself, but \"-s ours\" merge may be an\nexample of an actual trouble.\n\nIf we don't treat it specially, then changes to side branch will be\nsilently propagated over the merge, that's obviously not what is needed,\nprovided user keeps his intention to leave the merge \"-s ours\".\n\nIf we do treat it specially, it could be the case that the merge in\nquestion only looks like \"-s ours\" by pure accident, and thus changes to\nthe side branch should be propagated.\n\nI don't see how we can safely proceed without stop for user assistance.\nHad we already achieved some consensus on this issue?\n\n>\n>> In application to the method being discussed, we only need the check if\n>> the final merge went without conflicts, so the user was not already\n>> involved, and the check itself is then pretty simple:\n>> \n>>  \"proceed without stop only if $tree = $tree_U1'\"\n>> \n>> Its equivalence to the U1' == U2' test in the RFC follows from the fact\n>> that if M' is non-conflicting merge of U1' and U2', then M' == U1' if\n>> and only if U2' == U1'.\n>\n> Nicely spot! I`m glad there`s still (kind of) former U1' == U2' check \n> in this approach, too, in case it proves useful :)\n>\n>> Finally, here is a sketch of the implementation that I'd suggest to\n>> use:\n>> \n>> git-rebase-first-parent --onto A' M\n>> tree_U1'=$(git write-tree)\n>> git merge-recursive B -- $tree_U1' B'\n>> tree=$(git write-tree)\n>> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n>> [ $conflicted_last_merge = \"yes\" ] ||\n>>   trees-match $tree_U1' $tree || \n>>   stop-for-user-amendment\n>\n> Yes, in case where we would want the \"no-op merge\" check (equivalent \n> to U1' == U2' with original approach), this aligns with something I \n> would expect.\n>\n> Note that all the \"rebase merge commit\" steps leading to the check \n> will/should probably be observed as a single one from user`s perspective \n> (in worst case ending with nested conflicts we discussed), thus \n> `$conflicted_last_merge` is not related to `merge-recursive` step(s) \n> only, but `rebase-first-parent`, too (just in case this isn`t implied).\n>\n> Might be easier to reason about simply as `[ $conflicts = \"yes\" ] || `\n\nNo. For this check it's essential to ensure that no tweaking of the\ncontent has been performed under the hood after the user has resolved\nconflicts, i.e., after he has been involved last time.\n\nIf all this is done in one \"huge merge\" step from user point of view,\nthen the check belongs to this merge, as this is the last (and the only)\none. If it's done in steps (and I vote for it), only the last merge\nstatus is essential for the check, preceding merges don't matter.\n\nAs I said, putting myself on the user side, I'd prefer entirely separate\nfirst step of the algorithm, exactly as written, with its own conflict\nresolution, all running entirely the same way as it does with non-merge\ncommits. I'm used to it and don't want to learn something new without\nnecessity. I.e., I'd prefer to actually see it in two separate stages,\nlike this:\n\nRebasing mainline of the merge...\n[.. possible conflicts resolution ..]\nMerging in changes to side branch(es)...\n[.. possible conflicts resolution ..]\n\nAnd if the second stage gives non-trivial conflicts, I'd like to have a\nsimple way to just do \"merge -s ours <heads>\" on top of already rebased\nmainline of the merge and go with it. Note that the latter is\nsignificantly different than re-merging everything from scratch, that\nwould be the only choice with \"all-in-one\" approach, and it essentially\ngives me back those simple \"rebase first parent and just record other\nparents\" semantics when needed.\n\n-- Sergey\n"},{"id":"341836","messageId":"a3d40dca-f508-5853-89bc-1f9ab393416b@gmail.com","threadId":"47864","inReplyTo":"87zi397uak.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-15T21:51:50Z","receivedAt":"2018-03-15T21:52:15Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 15/03/2018 07:00, Sergey Organov wrote:\n> \n> > > Thinking about it I've got an idea that what we actually need is\n> > > --no-flatten flag that, when used alone, will just tell \"git rebase\" to\n> > > stop flattening history, and which will be implicitly imposed by\n> > > --recreate-merges (and --preserve-merges).\n> > >\n> > > Then the only thing the --recreate-merges will tune is to put 'merge'\n> > > directives into the todo list for merge commits, exactly according to\n> > > what its name suggests, while the default behavior will be to put 'pick'\n> > > with suitable syntax into the todo. And arguments to the\n> > > --recreate-merge will specify additional options for the 'merge'\n> > > directive, obviously.\n> >\n> > This seem to basically boil down to what I mentioned previously[2] \n> > through use of new `--rebase-merges` alongside `--recreate-merges`, just \n> > that you named it `--no-flatten` here, but the point is the same - and \n> > not something Johannes liked, \"polluting\" rebase option space further.\n> \n> Not quite so. The problem with --XXX-merges flags is that they do two\n> things at once: they say _what_ to do and _how_ to do it. Clean UI\n> designs usually have these things separate, and that's what I propose.\n> \n> The --[no-]flatten says _what_ (not) to do, and --recreate-merges says\n> _how_ exactly it will be performed. In this model --no-flatten could\n> have been called, say --preserve-shape, but not --rebase-merges.\n> \n> To minimize pollution, the _how_ part could rather be made option value:\n> \n> --no-flatten[=<strategy>]\n> \n> where <strategy> is 'rebase', 'remerge', etc.\n> \n> In this case we will need separate option to specify strategy options,\n> if required, that will lead us to something similar to the set of merge\n> strategies options.\n> \n> > I would agree with him, and settling onto `--rebase-merges` _instead_ of \n> > `--recreate-merges` seems as a more appropriate name, indeed, now that \n> > default behavior is actually merge commit rebasing and not recreating \n> > (recreating still being possible through user editing the todo list).\n> \n> I hope he'd be pleased to be able to say --no-flatten=remerge and get\n> back his current mode of operation, that he obviously has a good use\n> for.\n\nMakes sense, I like it, thanks for elaborating. [ Especially that you \nused \"(no) flatten\" phrasing, where original `--preserve-merges` \ndocumentation says it`s used \"not to flatten the history\", nice touch ;) ]\n\nNot sure if I would prefer original `recreate` instead of `remerge` \nas that particular strategy name, though, but might be I`m just more \nused to the former one at the moment.\n\nBut if I think about it more, \"recreate\" seems straightforward enough - \ncreate something (again), kind of making it more obvious that it is a \nnew thing (that we are now creating, again, based on some old thing).\n\nOn the other hand, \"remerge\" communicates \"merge something again\", \nwhich doesn`t necessarily mean creating a new thing (based on, but \nnot attached to old thing), and could also be interpreted as \"merge \nexisting thing again\" (and leaves me wondering if it would better \nsuite some other strategy possible in the future).\n\nNot sure if that explanation suffices, but it comes to \"recreate a \nmerge\" having more clear meaning than \"remerge a merge\", being \nsomewhat ambiguous, thus confusing (to me, at least).\n\nI don`t know, thinking too much?\n\nRegards, Buga\n"},{"id":"341852","messageId":"3dbf86bc-cae9-8d6c-a206-cac685938f3d@gmail.com","threadId":"47864","inReplyTo":"87lget7p2g.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-15T23:08:07Z","receivedAt":"2018-03-15T23:09:15Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 15/03/2018 08:52, Sergey Organov wrote:\n> \n> > > 2. The U1' == U2' consistency check in RFC that I still think is worth\n> > > to be implemented.\n> >\n> > At the moment, I think we`d appreciate test cases where it actually \n> > proves useful, as the general consensus seems to be leaning towards \n> > it possibly being annoying (over-paranoid).\n> \n> As we now have a simple way to actually check it even in this algorithm,\n> I'd suggest command-line option to either relax or enforce the check,\n> whatever the default is. For the default, I'd still opt for safety, as\n> without it we will gather little experience with this new matter.\n> \n> Honestly, without this check available, I'd likely vote for at least an\n> option for stopping on every rebased merge, on the ground that if\n> rebasing a non-merge could be a trouble, rebasing a merge is at least\n> double-trouble, and it's not that frequent anyway. So the check we\n> discuss is actually a way to make all the process much less paranoid,\n> not more.\n> \n> By the way, nobody yet commented about \"rerere\" behavior that basically\n> stops rebasing every time it fires. Do you consider it over-paranoid?\n\nI wouldn`t really know, my workflows are usually/still rather simple, I \ndon`t think I`ve ever used it on purpose, and I don`t really remember \nI`ve triggered it by accident, not having it stop for amendment, at least.\n\nYou did say you find it annoying yourself, though ;) But also accepting \nit as something that probably has a good reason, though (thus not \nconsidering it over-paranoid, even if annoying).\n\n> As for test cases, I have none myself, but \"-s ours\" merge may be an\n> example of an actual trouble.\n> \n> If we don't treat it specially, then changes to side branch will be\n> silently propagated over the merge, that's obviously not what is needed,\n> provided user keeps his intention to leave the merge \"-s ours\".\n> \n> If we do treat it specially, it could be the case that the merge in\n> question only looks like \"-s ours\" by pure accident, and thus changes to\n> the side branch should be propagated.\n> \n> I don't see how we can safely proceed without stop for user assistance.\n> Had we already achieved some consensus on this issue?\n\nI don`t know, from what Johannes said in the past, I got an \nimpression that this is to be expected (\"by design\"), and not worth \nbothering to stop for. And he is one of the heaviest users of (merge) \nrebasing I know.\n\nPersonally, I still feel it would make sense to stop in case like \nthis, indeed, but it`s just my humble (and not necessarily much \neducated) opinion.\n\n> > > Finally, here is a sketch of the implementation that I'd suggest to\n> > > use:\n> > >\n> > > git-rebase-first-parent --onto A' M\n> > > tree_U1'=$(git write-tree)\n> > > git merge-recursive B -- $tree_U1' B'\n> > > tree=$(git write-tree)\n> > > M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n> > > [ $conflicted_last_merge = \"yes\" ] ||\n> > >   trees-match $tree_U1' $tree || \n> > >   stop-for-user-amendment\n> >\n> > Yes, in case where we would want the \"no-op merge\" check (equivalent \n> > to U1' == U2' with original approach), this aligns with something I \n> > would expect.\n> >\n> > Note that all the \"rebase merge commit\" steps leading to the check \n> > will/should probably be observed as a single one from user`s perspective \n> > (in worst case ending with nested conflicts we discussed), thus \n> > `$conflicted_last_merge` is not related to `merge-recursive` step(s) \n> > only, but `rebase-first-parent`, too (just in case this isn`t implied).\n> >\n> > Might be easier to reason about simply as `[ $conflicts = \"yes\" ] || `\n> \n> No. For this check it's essential to ensure that no tweaking of the\n> content has been performed under the hood after the user has resolved\n> conflicts, i.e., after he has been involved last time.\n> \n> If all this is done in one \"huge merge\" step from user point of view,\n> then the check belongs to this merge, as this is the last (and the only)\n> one. If it's done in steps (and I vote for it), only the last merge\n> status is essential for the check, preceding merges don't matter.\n\n\"Huge merge\" step (from user point of view) is exactly how I perceived \nJohannes` opinion on it, describing it`s already part of Git user \nexperience (with possible nested conflicts), while otherwise possibly \nhard to explain where we are precisely at in the moment of stopping for \n(intermediate) conflict resolution.\n\nThus only `$conflicts`, meaning anything in the \"huge merge\", as no user \naction/tweaking/involvement can happen until the \"huge merge\" is done.\n\n> As I said, putting myself on the user side, I'd prefer entirely separate\n> first step of the algorithm, exactly as written, with its own conflict\n> resolution, all running entirely the same way as it does with non-merge\n> commits. I'm used to it and don't want to learn something new without\n> necessity. I.e., I'd prefer to actually see it in two separate stages,\n> like this:\n> \n> Rebasing mainline of the merge...\n> [.. possible conflicts resolution ..]\n> Merging in changes to side branch(es)...\n> [.. possible conflicts resolution ..]\n> \n> And if the second stage gives non-trivial conflicts, I'd like to have a\n> simple way to just do \"merge -s ours <heads>\" on top of already rebased\n> mainline of the merge and go with it. Note that the latter is\n> significantly different than re-merging everything from scratch, that\n> would be the only choice with \"all-in-one\" approach, and it essentially\n> gives me back those simple \"rebase first parent and just record other\n> parents\" semantics when needed.\n\nI`m undecided here, and while I do see a point in what you`re saying, \nthis being new to general public I dont`t think you being accustomed \nto it is a very strong argument :)\n\nYes, having more steps would mean more power/options to the user, but \nmore complexity to explain to and guide him through as well, not really \nsure where the line should be drawn - for the first time, at least.\n\nAlso note that, for example, in case side branch(es) dropped some \ncommits (interactively or otherwise), first step alone would still \nreintroduce those dropped changes, thus later possible `merge -s ours \n<heads>` would be a pretty bad \"evil merge\" case and a wrong thing to \ndo in general.\n\nRegards, Buga\n"},{"id":"341862","messageId":"87vadw3297.fsf@javad.com","threadId":"47864","inReplyTo":"3dbf86bc-cae9-8d6c-a206-cac685938f3d@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-16T07:31:32Z","receivedAt":"2018-03-16T07:31:43Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n\n[...]\n\n>> As I said, putting myself on the user side, I'd prefer entirely separate\n>> first step of the algorithm, exactly as written, with its own conflict\n>> resolution, all running entirely the same way as it does with non-merge\n>> commits. I'm used to it and don't want to learn something new without\n>> necessity. I.e., I'd prefer to actually see it in two separate stages,\n>> like this:\n>> \n>> Rebasing mainline of the merge...\n>> [.. possible conflicts resolution ..]\n>> Merging in changes to side branch(es)...\n>> [.. possible conflicts resolution ..]\n>> \n>> And if the second stage gives non-trivial conflicts, I'd like to have a\n>> simple way to just do \"merge -s ours <heads>\" on top of already rebased\n>> mainline of the merge and go with it. Note that the latter is\n>> significantly different than re-merging everything from scratch, that\n>> would be the only choice with \"all-in-one\" approach, and it essentially\n>> gives me back those simple \"rebase first parent and just record other\n>> parents\" semantics when needed.\n>\n> I`m undecided here, and while I do see a point in what you`re saying, \n> this being new to general public I dont`t think you being accustomed \n> to it is a very strong argument :)\n\nSure. It's mostly that having already familiar step separate seems to be\na good idea, as well as resulting isolation of the new stuff, where I\nreadily agree not to granulate it further. As if the latter actually\nmakes any difference... Octopus merges? I mean, really?\n\n> Yes, having more steps would mean more power/options to the user, but \n> more complexity to explain to and guide him through as well, not really \n> sure where the line should be drawn - for the first time, at least.\n\nA good thing is that while it runs smoothly it still runs smoothly both\nways.\n\n> Also note that, for example, in case side branch(es) dropped some \n> commits (interactively or otherwise), first step alone would still \n> reintroduce those dropped changes, thus later possible `merge -s ours \n> <heads>` would be a pretty bad \"evil merge\" case and a wrong thing to \n> do in general.\n\nExcept that my presumption is that the second step has been run already\nand has stopped due to conflicts, so I see the conflicting result of\ndropping those commits on side branch(es), check the previous state of\nthe right side of the conflicting merge, and decide those state, being\nthe result of the fist step after possibly demanding conflicts\nresolution, is fine after all. Thus I just re-merge -x ours the\nbranch(es), instead of re-merging everythig from scratch only to finally\nget back to the same result, be it evil or not, the hard way.\n\n-- Sergey\n"},{"id":"341967","messageId":"d50a4099-9b3a-5aa9-c304-160c62330056@gmail.com","threadId":"47864","inReplyTo":"d5e68db4-8006-2c0e-bc21-0b136503edd9@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-17T02:08:54Z","receivedAt":"2018-03-17T02:09:21Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"On 15/03/2018 00:11, Igor Djordjevic wrote:\n> \n> > > > Second side note: if we can fast-forward, currently we prefer\n> > > > that, and I think we should keep that behavior with -R, too.\n> > >\n> > > I agree.\n> > \n> > I'm admittedly somewhat lost in the discussion, but are you\n> > talking fast-forward on _rebasing_ existing merge? Where would it\n> > go in any of the suggested algorithms of rebasing and why?\n> > \n> > I readily see how it can break merges. E.g., any \"git merge\n> > --ff-only --no-ff\" merge will magically disappear. So, even if\n> > somehow supported, fast-forward should not be performed by default\n> > during _rebasing_ of a merge.\n> \n> Hmm, now that you brought this up, I can only agree, of course.\n> \n> What I had in my mind was more similar to \"no-rebase-cousins\", like \n> if we can get away without actually rebasing the merge but still \n> using the original one, do it. But I guess that`s not what Johannes \n> originally asked about.\n> \n> This is another definitive difference between rebasing (`pick`?) and \n> recreating (`merge`) a merge commit - in the case where we`re rebasing, \n> of course it doesn`t make sense to drop commit this time (due to \n> fast-forward). This does make sense in recreating the merge (only).\n\nEh, I might take this back. I think my original interpretation (and \nagreement) to fast-forwarding is correct.\n\nBut the confusion here comes from `--no-ff` as used for merging, as \nopposed to `--no-ff` as used for rebasing. I _think_ Johannes meant \nthe latter one.\n\nIn rebasing, `--no-ff` means that even if a commit inside todo list \nisn`t to be changed, do not reuse it but create a new one. Here`s \nexcerpt from the docs[1]:\n\n  --no-ff\n    With --interactive, cherry-pick all rebased commits instead of \n    fast-forwarding over the unchanged ones. This ensures that the \n    entire history of the rebased branch is composed of new commits.\n\n    Without --interactive, this is a synonym for --force-rebase.\n\n\nSo fast-forwarding in case of rebasing (merge commits as well) is \nsomething you would want by default, as it wouldn`t drop/lose \nanything, but merely reuse existing commit (if unchanged), instead of \ncherry-picking (rebasing) it into a new (merge) commit anyway.\n\nThe same goes for this part:\n\n> > > > If the user wants to force a new merge, they simply remove that\n> > > > -R flag.\n\nThis means that using `-R` flag is sensitive to `--no-ff` rebase \noption, original merge commit _reused_ (fast-forwarded) when possible \n(unchanged, and `--no-ff` not provided), or original merge commit \n_rebased_ (when changed, or `--no-ff` provided).\n\nIf `-R` flag is removed, then merge commit is always _recreated_, no \nmatter if `--no-ff` option is used or not.\n\np.s. I`m still a bit opposed to `-R` flag in the first place, as \ndiscussed elsewhere[2][3], but that`s unrelated to this fast-forward \ndiscussion.\n\nRelated to it, though, if `pick` command would be used instead of \n`merge -R` to signal merge commit _rebasing_, it would fit into \nexisting logic nicely, where `pick` is already sensitive to `--no-ff` \noption (for rebasing regular commits). Then `merge` alone could be \nnaturally (and only) used for _recreating_ merge commits, as \noriginally intended (and intuitively expected).\n\nRegards, Buga\n\n[1] https://git-scm.com/docs/git-rebase#git-rebase---no-ff\n[2] https://public-inbox.org/git/77b695d0-7564-80d7-d9e6-70a531e66eda@gmail.com/\n[3] https://public-inbox.org/git/a3d40dca-f508-5853-89bc-1f9ab393416b@gmail.com/\n"},{"id":"341968","messageId":"095bbfe2-e095-a4b6-d337-740553acd9ec@gmail.com","threadId":"47864","inReplyTo":"87vadw3297.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-17T03:04:27Z","receivedAt":"2018-03-17T03:04:54Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 16/03/2018 08:31, Sergey Organov wrote:\n> \n> > > As I said, putting myself on the user side, I'd prefer entirely\n> > > separate first step of the algorithm, exactly as written, with\n> > > its own conflict resolution, all running entirely the same way as\n> > > it does with non-merge commits. I'm used to it and don't want to\n> > > learn something new without necessity. I.e., I'd prefer to\n> > > actually see it in two separate stages, like this:\n> > >\n> > > Rebasing mainline of the merge...\n> > > [.. possible conflicts resolution ..]\n> > > Merging in changes to side branch(es)...\n> > > [.. possible conflicts resolution ..]\n> > >\n> > > And if the second stage gives non-trivial conflicts, I'd like to\n> > > have a simple way to just do \"merge -s ours <heads>\" on top of\n> > > already rebased mainline of the merge and go with it. Note that\n> > > the latter is significantly different than re-merging everything\n> > > from scratch, that would be the only choice with \"all-in-one\"\n> > > approach, and it essentially gives me back those simple \"rebase\n> > > first parent and just record other parents\" semantics when\n> > > needed.\n> > \n> > [...]\n> > \n> > Also note that, for example, in case side branch(es) dropped some \n> > commits (interactively or otherwise), first step alone would still \n> > reintroduce those dropped changes, thus later possible `merge -s ours \n> > <heads>` would be a pretty bad \"evil merge\" case and a wrong thing to \n> > do in general.\n> \n> Except that my presumption is that the second step has been run already\n> and has stopped due to conflicts, so I see the conflicting result of\n> dropping those commits on side branch(es), check the previous state of\n> the right side of the conflicting merge, and decide those state, being\n> the result of the fist step after possibly demanding conflicts\n> resolution, is fine after all. Thus I just re-merge -x ours the\n> branch(es), instead of re-merging everythig from scratch only to finally\n> get back to the same result, be it evil or not, the hard way.\n\nMight be my comment missed the point here, it should have been more \nabout what you said regarding \"first step having its own conflict \nresolution\" - in case of dropped commits on side branch(es), you would \nbe trying to resolve conflicts using one tree that doesn`t/shouldn`t \neven exist anymore (rebased merge commit first parent changes), which \nmight be pretty confusing, only to find the \"second stage\" later \nremoving changes that you might have actually picked as \"first stage\" \nconflict resolution, making it all even worse.\n\nOnly once \"huge merge\" is done completely (meaning all steps involved \nin merge commit rebasing), user can have a more realistic overview of \n(possibly nested, even) conflicts to resolve (and knowing his resolution \nwill actually stick).\n\nRegarding `merge -s ours <heads>` you mention, as you say it would \nhappen only after \"huge merge\" is complete (with possible conflicts), \nI guess it`s unrelated to having \"merge commit rebasing\" happen in \none go (\"huge merge\"), or iteratively, in stages (from user`s \nperspective, unrelated to underlying implementation)...?\n\nThus I`m questioning use-case for step-by-step merge commit rebasing \nwhere each stage has its own conflict resolution, in the face of it \npossibly being more confusing than helpful.\n\nOtherwise, I see the point in what you would like to accomplish with \nthat `merge -s ours <heads>` (not from scratch), but I`m not sure \nwhat would be the most sane way to allow it, and if it would be worth \nit in the first place, seeming to be a pretty exotic use case.\n\nRegards, Buga\n"},{"id":"342129","messageId":"87h8pc1uxr.fsf@javad.com","threadId":"47864","inReplyTo":"d50a4099-9b3a-5aa9-c304-160c62330056@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-19T05:44:00Z","receivedAt":"2018-03-19T05:44:11Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> On 15/03/2018 00:11, Igor Djordjevic wrote:\n>> \n>> > > > Second side note: if we can fast-forward, currently we prefer\n>> > > > that, and I think we should keep that behavior with -R, too.\n>> > >\n>> > > I agree.\n>> > \n>> > I'm admittedly somewhat lost in the discussion, but are you\n>> > talking fast-forward on _rebasing_ existing merge? Where would it\n>> > go in any of the suggested algorithms of rebasing and why?\n>> > \n>> > I readily see how it can break merges. E.g., any \"git merge\n>> > --ff-only --no-ff\" merge will magically disappear. So, even if\n>> > somehow supported, fast-forward should not be performed by default\n>> > during _rebasing_ of a merge.\n>> \n>> Hmm, now that you brought this up, I can only agree, of course.\n>> \n>> What I had in my mind was more similar to \"no-rebase-cousins\", like \n>> if we can get away without actually rebasing the merge but still \n>> using the original one, do it. But I guess that`s not what Johannes \n>> originally asked about.\n>> \n>> This is another definitive difference between rebasing (`pick`?) and \n>> recreating (`merge`) a merge commit - in the case where we`re rebasing, \n>> of course it doesn`t make sense to drop commit this time (due to \n>> fast-forward). This does make sense in recreating the merge (only).\n>\n> Eh, I might take this back. I think my original interpretation (and \n> agreement) to fast-forwarding is correct.\n>\n> But the confusion here comes from `--no-ff` as used for merging, as \n> opposed to `--no-ff` as used for rebasing. I _think_ Johannes meant \n> the latter one.\n>\n> In rebasing, `--no-ff` means that even if a commit inside todo list \n> isn`t to be changed, do not reuse it but create a new one. Here`s \n> excerpt from the docs[1]:\n>\n>   --no-ff\n>     With --interactive, cherry-pick all rebased commits instead of \n>     fast-forwarding over the unchanged ones. This ensures that the \n>     entire history of the rebased branch is composed of new commits.\n>\n>     Without --interactive, this is a synonym for --force-rebase.\n>\n>\n> So fast-forwarding in case of rebasing (merge commits as well) is \n> something you would want by default, as it wouldn`t drop/lose \n> anything, but merely reuse existing commit (if unchanged), instead of \n> cherry-picking (rebasing) it into a new (merge) commit anyway.\n\nThis sounds like breakage. E.g., it seems to be breaking every \"-x ours\"\nmerge out there.\n\nFast-forwarding existing merge, one way or another, still seems to be\nwrong idea to me, as merge commit is not only about content change, but\nalso about joint point at particular place in the DAG.\n\nAs for fast-forwarding re-merge, explicitly requested, I'm not sure. On\none hand, it's inline with the default \"git merge\" behavior, on the\nother hand, it still feels wrong, somehow.\n\n-- Sergey\n"},{"id":"342130","messageId":"87a7v41u4w.fsf@javad.com","threadId":"47864","inReplyTo":"095bbfe2-e095-a4b6-d337-740553acd9ec@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-19T06:01:19Z","receivedAt":"2018-03-19T06:01:28Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Buga,\n\nIgor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 16/03/2018 08:31, Sergey Organov wrote:\n>> \n>> > > As I said, putting myself on the user side, I'd prefer entirely\n>> > > separate first step of the algorithm, exactly as written, with\n>> > > its own conflict resolution, all running entirely the same way as\n>> > > it does with non-merge commits. I'm used to it and don't want to\n>> > > learn something new without necessity. I.e., I'd prefer to\n>> > > actually see it in two separate stages, like this:\n>> > >\n>> > > Rebasing mainline of the merge...\n>> > > [.. possible conflicts resolution ..]\n>> > > Merging in changes to side branch(es)...\n>> > > [.. possible conflicts resolution ..]\n>> > >\n>> > > And if the second stage gives non-trivial conflicts, I'd like to\n>> > > have a simple way to just do \"merge -s ours <heads>\" on top of\n>> > > already rebased mainline of the merge and go with it. Note that\n>> > > the latter is significantly different than re-merging everything\n>> > > from scratch, that would be the only choice with \"all-in-one\"\n>> > > approach, and it essentially gives me back those simple \"rebase\n>> > > first parent and just record other parents\" semantics when\n>> > > needed.\n>> > \n>> > [...]\n>> > \n>> > Also note that, for example, in case side branch(es) dropped some \n>> > commits (interactively or otherwise), first step alone would still \n>> > reintroduce those dropped changes, thus later possible `merge -s ours \n>> > <heads>` would be a pretty bad \"evil merge\" case and a wrong thing to \n>> > do in general.\n>> \n>> Except that my presumption is that the second step has been run already\n>> and has stopped due to conflicts, so I see the conflicting result of\n>> dropping those commits on side branch(es), check the previous state of\n>> the right side of the conflicting merge, and decide those state, being\n>> the result of the fist step after possibly demanding conflicts\n>> resolution, is fine after all. Thus I just re-merge -x ours the\n>> branch(es), instead of re-merging everythig from scratch only to finally\n>> get back to the same result, be it evil or not, the hard way.\n>\n> Might be my comment missed the point here, it should have been more \n> about what you said regarding \"first step having its own conflict \n> resolution\" - in case of dropped commits on side branch(es), you would \n> be trying to resolve conflicts using one tree that doesn`t/shouldn`t \n> even exist anymore (rebased merge commit first parent changes), which \n> might be pretty confusing, only to find the \"second stage\" later \n> removing changes that you might have actually picked as \"first stage\" \n> conflict resolution, making it all even worse.\n>\n> Only once \"huge merge\" is done completely (meaning all steps involved \n> in merge commit rebasing), user can have a more realistic overview of \n> (possibly nested, even) conflicts to resolve (and knowing his resolution \n> will actually stick).\n>\n> Regarding `merge -s ours <heads>` you mention, as you say it would \n> happen only after \"huge merge\" is complete (with possible conflicts), \n> I guess it`s unrelated to having \"merge commit rebasing\" happen in \n> one go (\"huge merge\"), or iteratively, in stages (from user`s \n> perspective, unrelated to underlying implementation)...?\n>\n> Thus I`m questioning use-case for step-by-step merge commit rebasing \n> where each stage has its own conflict resolution, in the face of it \n> possibly being more confusing than helpful.\n>\n> Otherwise, I see the point in what you would like to accomplish with \n> that `merge -s ours <heads>` (not from scratch), but I`m not sure \n> what would be the most sane way to allow it, and if it would be worth \n> it in the first place, seeming to be a pretty exotic use case.\n\nI find your arguments sound, except that I somehow feel that \"exotic use\ncase\" will solve 90% of conflicting merge rebases, as merges are about\nthe mainline in the first place. It's likely nothing more than personal\nfeeling though, so I'd simply agree to disagree at this point, at least\nuntil some actual experience is gained.\n\n-- Sergey\n"},{"id":"342257","messageId":"34e8d563-a035-b09e-e959-748f2b4f4b99@gmail.com","threadId":"47864","inReplyTo":"87h8pc1uxr.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Igor Djordjevic","fromEmail":"igor.d.djordjevic@gmail.com","sentAt":"2018-03-19T21:35:09Z","receivedAt":"2018-03-19T21:35:41Z","isPatch":false,"sender":{"key":"igor.d.djordjevic@gmail.com","avatar":null},"body":"Hi Sergey,\n\nOn 19/03/2018 06:44, Sergey Organov wrote:\n> \n> > > > > > Second side note: if we can fast-forward, currently we prefer\n> > > > > > that, and I think we should keep that behavior with -R, too.\n> > > > >\n> > > > > I agree.\n> > > >\n> > > > I'm admittedly somewhat lost in the discussion, but are you\n> > > > talking fast-forward on _rebasing_ existing merge? Where would it\n> > > > go in any of the suggested algorithms of rebasing and why?\n> > > >\n> > > > I readily see how it can break merges. E.g., any \"git merge\n> > > > --ff-only --no-ff\" merge will magically disappear. So, even if\n> > > > somehow supported, fast-forward should not be performed by default\n> > > > during _rebasing_ of a merge.\n> > >\n> > > Hmm, now that you brought this up, I can only agree, of course.\n> > >\n> > > What I had in my mind was more similar to \"no-rebase-cousins\", like \n> > > if we can get away without actually rebasing the merge but still \n> > > using the original one, do it. But I guess that`s not what Johannes \n> > > originally asked about.\n> > >\n> > > This is another definitive difference between rebasing (`pick`?) and \n> > > recreating (`merge`) a merge commit - in the case where we`re rebasing, \n> > > of course it doesn`t make sense to drop commit this time (due to \n> > > fast-forward). This does make sense in recreating the merge (only).\n> >\n> > Eh, I might take this back. I think my original interpretation (and \n> > agreement) to fast-forwarding is correct.\n> >\n> > But the confusion here comes from `--no-ff` as used for merging, as \n> > opposed to `--no-ff` as used for rebasing. I _think_ Johannes meant \n> > the latter one.\n> >\n> > In rebasing, `--no-ff` means that even if a commit inside todo list \n> > isn`t to be changed, do not reuse it but create a new one. Here`s \n> > excerpt from the docs[1]:\n> >\n> >   --no-ff\n> >     With --interactive, cherry-pick all rebased commits instead of \n> >     fast-forwarding over the unchanged ones. This ensures that the \n> >     entire history of the rebased branch is composed of new commits.\n> >\n> >     Without --interactive, this is a synonym for --force-rebase.\n> >\n> >\n> > So fast-forwarding in case of rebasing (merge commits as well) is \n> > something you would want by default, as it wouldn`t drop/lose \n> > anything, but merely reuse existing commit (if unchanged), instead of \n> > cherry-picking (rebasing) it into a new (merge) commit anyway.\n> \n> This sounds like breakage. E.g., it seems to be breaking every \"-x ours\"\n> merge out there.\n\nEither you are not understanding how rebase fast-forward works, or \nI`m missing what you are pointing to... Mind explaining how can \nsomething that`s left unchanged suddenly become a breakage?\n\n> Fast-forwarding existing merge, one way or another, still seems to be\n> wrong idea to me, as merge commit is not only about content change, but\n> also about joint point at particular place in the DAG.\n\nNot sure what this has to do with rebase fast-forwarding, either - \nnothing changes for fast-forwarded (merge or non-merge) commit in \nquestion, both content, joint point and everything else stays exactly \nthe same. If anything changed, then it can`t/won`t be fast-forwarded, \nbeing unchanged is a prerequisite.\n\nLet me elaborate a bit. Here`s a starting diagram:\n\n(1) ---X1---X2---X3 (master)\n                 |\\\n                 | A1---A2---A3\n                 |            \\\n                 |             M---C1---C2 (topic)\n                 |            /\n                 \\-B1---B2---B3\n\n\nWith \"topic\" being active branch, we start interactive rebase with \n`git rebase -i master`. Generated todo list will hold commits A1 to \nA3, B1 to B3, M and C1 to C2.\n\nNow, if we decide to `edit` commit C1, leaving everything else the \nsame, fast-forward logic will make the new situation look like this:\n\n(2) ---X1---X2---X3 (master)\n                 |\\\n                 | A1---A2---A3\n                 |            \\\n                 |             M---C1'--C2' (topic)\n                 |            /\n                 \\-B1---B2---B3\n\n\nNotice how only C1 and C2 changed to C1' and C2'? That`s rebase \nfast-forwarding, noticing earlier commits left unchanged, thus \nreusing original ones.\n\nNo matter what, no breakage can happen to M in this case, as it`s \nleft (reused) exactly as it was - it`s fast-forward rebased.\n\nIf we `edit`-ed commit A2, we would have ended in a situation like this:\n\n(3) ---X1---X2---X3 (master)\n                 |\\\n                 | A1---A2'--A3'\n                 |            \\\n                 |             M'--C1'--C2' (topic)\n                 |            /\n                 \\-B1---B2---B3\n\n\nThis time we have new commits A2', A3', M', C1' and C2' - so \neverything influenced by the change that happened will be changed \n(merge commit as well), where all the rest can still be reused \n(fast-forwarded).\n\nIf we had started rebasing with `git rebase -i --no-ff master`, no \nmatter which commits we `edit` (or none, even), we would end up with \nthis instead:\n\n(4) ---X1---X2---X3 (master)\n                 |\\\n                 | A1'--A2'--A3'\n                 |            \\\n                 |             M'--C1'--C2' (topic)\n                 |            /\n                 \\-B1'--B2'--B3'\n\n\nSo even in case where nothing is changed, no rebase fast-forwarding \nis performed (as requested), and each and every commit is changed (old \ncommit replaced with its rebased version, commit hash changed).\n\nNow, if our starting position looked like this instead:\n\n(5) ---X1---X2---X3---X4---X5 (master)\n                 |\\\n                 | A1---A2---A3\n                 |            \\\n                 |             M---C1---C2 (topic)\n                 |            /\n                 \\-B1---B2---B3\n\n... and we simply do `git rebase -i master` again, causing all side \ncommits to be rebased onto X5, then no fast forwarding can be done, as \nall commits _are_ changed (by having their parent changed, no matter if \nwe additionally edit them or not), so even without `--no-ff` option we \nend up with this:\n\n(6) ---X1---X2---X3---X4---X5 (master)\n                           |\\\n                           | A1'--A2'--A3'\n                           |            \\\n                           |             M'--C1'--C2' (topic)\n                           |            /\n                           \\-B1'--B2'--B3'\n\n\nDoes this settle your concerns, or I`m missing something?\n\n> As for fast-forwarding re-merge, explicitly requested, I'm not sure. On\n> one hand, it's inline with the default \"git merge\" behavior, on the\n> other hand, it still feels wrong, somehow.\n\nRegarding fast-forwarding in context of merging, in case where we are \nrecreating merges (not rebasing them), following existing `git merge` \nlogic might make sense, where I would expect rebasing todo list `merge` \ncommand to pick-up tricks from `git merge` as needed, like learning \nto accept `--no-ff` option, for example, thus not fast-forwarding \nmerges (on request) even when possible.\n\nThough, I do agree that in case you want to recreate an existing merge \n(instead of just rebasing it), `merge` command fast-forwarding might \nprobably not be what you want for the most of the time, but I`m afraid \nhaving rebase todo list `merge` command default behavior different than \n`git merge` default one (in regards to fast-forwarding) would be \nconfusing... or not?\n\nFrom what I could grasp so far, usually Git commands` default \nbehavior is (explained to be) chosen per \"most common use case\", so \nmight be non fast-forwarding would be fine as default for rebase todo \nlist `merge` command, even though different than `git merge` itself...?\n\nRegards, Buga\n"},{"id":"342318","messageId":"87r2oevmdj.fsf@javad.com","threadId":"47864","inReplyTo":"34e8d563-a035-b09e-e959-748f2b4f4b99@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-20T14:43:04Z","receivedAt":"2018-03-20T14:43:13Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n\n> Hi Sergey,\n>\n> On 19/03/2018 06:44, Sergey Organov wrote:\n>> \n>> > > > > > Second side note: if we can fast-forward, currently we prefer\n>> > > > > > that, and I think we should keep that behavior with -R, too.\n>> > > > >\n>> > > > > I agree.\n>> > > >\n>> > > > I'm admittedly somewhat lost in the discussion, but are you\n>> > > > talking fast-forward on _rebasing_ existing merge? Where would it\n>> > > > go in any of the suggested algorithms of rebasing and why?\n>> > > >\n>> > > > I readily see how it can break merges. E.g., any \"git merge\n>> > > > --ff-only --no-ff\" merge will magically disappear. So, even if\n>> > > > somehow supported, fast-forward should not be performed by default\n>> > > > during _rebasing_ of a merge.\n>> > >\n>> > > Hmm, now that you brought this up, I can only agree, of course.\n>> > >\n>> > > What I had in my mind was more similar to \"no-rebase-cousins\", like \n>> > > if we can get away without actually rebasing the merge but still \n>> > > using the original one, do it. But I guess that`s not what Johannes \n>> > > originally asked about.\n>> > >\n>> > > This is another definitive difference between rebasing (`pick`?) and \n>> > > recreating (`merge`) a merge commit - in the case where we`re rebasing, \n>> > > of course it doesn`t make sense to drop commit this time (due to \n>> > > fast-forward). This does make sense in recreating the merge (only).\n>> >\n>> > Eh, I might take this back. I think my original interpretation (and \n>> > agreement) to fast-forwarding is correct.\n>> >\n>> > But the confusion here comes from `--no-ff` as used for merging, as \n>> > opposed to `--no-ff` as used for rebasing. I _think_ Johannes meant \n>> > the latter one.\n>> >\n>> > In rebasing, `--no-ff` means that even if a commit inside todo list \n>> > isn`t to be changed, do not reuse it but create a new one. Here`s \n>> > excerpt from the docs[1]:\n>> >\n>> >   --no-ff\n>> >     With --interactive, cherry-pick all rebased commits instead of \n>> >     fast-forwarding over the unchanged ones. This ensures that the \n>> >     entire history of the rebased branch is composed of new commits.\n>> >\n>> >     Without --interactive, this is a synonym for --force-rebase.\n>> >\n>> >\n>> > So fast-forwarding in case of rebasing (merge commits as well) is \n>> > something you would want by default, as it wouldn`t drop/lose \n>> > anything, but merely reuse existing commit (if unchanged), instead of \n>> > cherry-picking (rebasing) it into a new (merge) commit anyway.\n>> \n>> This sounds like breakage. E.g., it seems to be breaking every \"-x ours\"\n>> merge out there.\n>\n> Either you are not understanding how rebase fast-forward works, or \n> I`m missing what you are pointing to... Mind explaining how can \n> something that`s left unchanged suddenly become a breakage?\n\nIt was misunderstanding on my side indeed, sorry.\n\n>\n>> Fast-forwarding existing merge, one way or another, still seems to be\n>> wrong idea to me, as merge commit is not only about content change, but\n>> also about joint point at particular place in the DAG.\n>\n> Not sure what this has to do with rebase fast-forwarding, either - \n> nothing changes for fast-forwarded (merge or non-merge) commit in \n> question, both content, joint point and everything else stays exactly \n> the same. If anything changed, then it can`t/won`t be fast-forwarded, \n> being unchanged is a prerequisite.\n>\n> Let me elaborate a bit. Here`s a starting diagram:\n\n[... detailed explanation skipped for brevity ...]\n\n> Does this settle your concerns, or I`m missing something?\n\nYes, it does, thank you! Leaving as many leading commits as possible\nunchanged during rebase is what fast-forward mean in this case then, and\nit's pretty OK with me.\n\n>> As for fast-forwarding re-merge, explicitly requested, I'm not sure. On\n>> one hand, it's inline with the default \"git merge\" behavior, on the\n>> other hand, it still feels wrong, somehow.\n>\n> Regarding fast-forwarding in context of merging, in case where we are \n> recreating merges (not rebasing them), following existing `git merge` \n> logic might make sense, where I would expect rebasing todo list `merge` \n> command to pick-up tricks from `git merge` as needed, like learning \n> to accept `--no-ff` option, for example, thus not fast-forwarding \n> merges (on request) even when possible.\n>\n> Though, I do agree that in case you want to recreate an existing merge \n> (instead of just rebasing it), `merge` command fast-forwarding might \n> probably not be what you want for the most of the time, but I`m afraid \n> having rebase todo list `merge` command default behavior different than \n> `git merge` default one (in regards to fast-forwarding) would be \n> confusing... or not?\n>\n> From what I could grasp so far, usually Git commands` default \n> behavior is (explained to be) chosen per \"most common use case\", so \n> might be non fast-forwarding would be fine as default for rebase todo \n> list `merge` command, even though different than `git merge`\n> itself...?\n\nAs far as I can tell, fast-forward as default for \"git merge\" has been\nchosen to avoid excessive unintended merges in typical workflows, and\ntherefore this decision is not actually applicable to rebasing, I think.\nI'm inclined to disable merges to fast-forward during history rebasing,\nat least by default.\n\nAs far as I can tell, current \"--preserve-merges\" does fast-forward and\nbreaks \"git merge --ff-only --no-ff\" merges, among other things it\nbreaks, and that was my primary concern here. Didn't check\nwhat \"--recreate-merges\" does though.\n\n-- Sergey\n"},{"id":"342986","messageId":"nycvar.QRO.7.76.6.1803261331340.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87zi3dh53k.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T11:33:20Z","receivedAt":"2018-03-26T11:33:17Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Mon, 12 Mar 2018, Sergey Organov wrote:\n\n> [...]\n> \n> Yet another consequence is that my approach will likely result in better\n> code reuse.\n\nThis is a purely academic speculation. At least until somebody implements\nPhillip's method. Oh wait, I already started to implement it, and it was\nnot exactly hard to implement:\n\nhttps://github.com/dscho/git/commit/26d2858800a4e0d3cc6313ddb54dd4d2ce516f31\n\nCiao,\nJohannes\n"},{"id":"342987","messageId":"nycvar.QRO.7.76.6.1803261333500.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87vae1h3uo.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T11:37:57Z","receivedAt":"2018-03-26T11:37:52Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Mon, 12 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >\n> > On Wed, 7 Mar 2018, Sergey Organov wrote:\n> >\n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> \n> >> > How can your approach -- which relies *very much* on having the\n> >> > original parent commits -- not *require* that consistency check?\n> >> \n> >> I don't understand what you mean, sorry. Could you please point me to\n> >> the *require* you talk about in the original proposal?\n> >\n> > Imagine a todo list that contains this line\n> >\n> > \tmerge -C abcdef 123456\n> >\n> > and now the user edits it (this is an interactive rebase, after all),\n> > adding another merge head:\n> >\n> > \tmerge -C abcdef 987654 123456\n> >\n> > Now your strategy would have a serious problem: to find the original\n> > version of 987654. If there was one.\n> \n> We are talking about different checks then. My method has a built-in\n> check that Pillip's one doesn't.\n\nSince you did not bother to elaborate, I have to assume that your\n\"built-in check\" is that thing where intermediate merges can give you\nconflicts?\n\nIf so, there is a possibility in Phillip's method for such conflicts, too:\nwe have to perform as many 3-way merges as there are parent commits.\n\nIt does make me uncomfortable to have to speculate what you meant, though.\n\n> >> > What would your approach (that still has no satisfyingly trivial\n> >> > explanation, in my mind)\n> >> \n> >> Here is one-liner: rebase sides of the merge commit and then 3-way\n> >> merge them, using original merge commit as merge base.\n> >\n> > But I already pointed out how that would undo a commit having been\n> > dropped.\n> \n> No. Not for this version. You did it for originally flawed version of\n> the method, that has been already fixed by addition of \"using original\n> merge commit as merge base\" in the above sentence, and that was the\n> exact reason for [RFC v2], that in turn is explicitly stated at the\n> beginning of [RFC v2].\n\nSince there is no \"interdiff\" between your versions, it is unreasonably\nhard to deduce this, and since you seem to be unwilling to explain... I'll\njust leave it at that.\n\nCiao,\nJohannes\n"},{"id":"342988","messageId":"nycvar.QRO.7.76.6.1803261348410.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87r2oph3cj.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T11:50:31Z","receivedAt":"2018-03-26T11:50:24Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Mon, 12 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> > Hi Sergey,\n> \n> [...]\n> \n> > That is misrepresenting what happened.\n> \n> No, it's you who are spreading misinformation, probably unintentional,\n> but still.\n\nWay to go, Sergey. Way to go.\n\n> [... more of the same...]\n>\n> > Let's focus on that strategy rather than going back to the strategy\n> > which has known flaws and only an unsatisfyingly complex explanation.\n> \n> Not that fast, as it now has no known flaws and still has surprisingly\n> simple explanation. It also has its own niceties that are currently\n> being discussed elsewhere in the thread.\n\nI find it surprisingly complicated. Of course, that may be just me, but I\nam not exactly a noob when it comes to interactive rebases.\n\nCiao,\nJohannes\n"},{"id":"342991","messageId":"nycvar.QRO.7.76.6.1803261351070.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"39327070-f13a-f7e5-6c8c-cd204530f051@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T12:03:42Z","receivedAt":"2018-03-26T12:03:37Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Tue, 13 Mar 2018, Igor Djordjevic wrote:\n\n> On 12/03/2018 13:56, Sergey Organov wrote:\n> > \n> > > > I agree with both of you that `pick <merge-commit>` is inflexible\n> > > > (not to say just plain wrong), but I never thought about it like\n> > > > that.\n> > > >\n> > > > If we are to extract further mentioned explicit old:new merge\n> > > > parameter mapping to a separate discussion point, what we`re\n> > > > eventually left with is just replacing this:\n> > > >\n> > > > \tmerge -R -C <original--merge-commit> <merge-head>\n> > > >\n> > > > ... with this:\n> > > >\n> > > > \tpick <original--merge-commit> <merge-head>\n> > >\n> > > I see where you are coming from.\n> > >\n> > > I also see where users will be coming from. Reading a todo list in\n> > > the editor is as much documentation as it is a \"program to execute\".\n> > > And I am afraid that reading a command without even mentioning the\n> > > term \"merge\" once is pretty misleading in this setting.\n> > >\n> > > And even from the theoretical point of view: cherry-picking\n> > > non-merge commits is *so much different* from \"rebasing merge\n> > > commits\" as discussed here, so much so that using the same command\n> > > would be even more misleading.\n> > \n> > This last statement is plain wrong when applied to the method in the\n> > [RFC] you are replying to.\n\nThat is only because the RFC seems to go out of its way to break down a\nsingle merge commit into as many commits as there are merge commit\nparents.\n\nThis is a pretty convoluted way to think about it: if you have three\nparent commits, for example, that way of thinking would introduce three\nintermediate commits, one with the changes of parent 2 & 3 combined, one\nwith the changes of parent 1 & 3 combined, and one with the changes of\nparent 1 & 2 combined.\n\nTo rebase those commits, you essentially have to rebase *every parent's\nchanges twice*.\n\nIt gets worse with merge commits that have 4 parents. In that case, you\nhave to rebase every parent's changes *three times*.\n\nAnd so on.\n\n> > Using the method in [RFC], \"cherry-pick non-merge\" is nothing more or\n> > less than reduced version of generic \"cherry-pick merge\", exactly as\n> > it should be.\n\nI really get the impression that you reject Phillip's proposal on the\nground of not being yours. In other words, the purpose of this here\nargument is to praise one proposal because of its heritage, rather than\ntrying to come up with the best solution.\n\nOn that basis, I will go with the proposal that is clearly the simplest\nand does the job and gets away with avoiding unnecessary work.\n\n> > Or, in other words, \"cherry-pick merge\" is generalization of\n> > \"cherry-pick non-merge\" to multiple parents.\n> \n> I think Sergey does have a point here, his approach showing it.\n\nHis approach is showing that he wants to shoehorn the \"rebase a merge\ncommit\" idea into a form where you can cherry-pick *something*.\n\nIt does not have to make sense. And to me, it really does not.\n\n> Phillip`s simplification might be further from it, though, but we`re \n> talking implementation again - important mental model should just be \n> \"rebasing a commit\" (merge or non-merge), how we`re doing it is \n> irrelevant for the user, the point (goal) is the same.\n\nExcept that Phillip's simplification is not a simplification. It comes\nfrom a different point of view: trying to reconcile the diverging changes.\n\nPhillip's is a true generalization of the \"rebase vs merge\" story: it is\nno longer about merging, or about rebasing, but about reconciling\ndivergent commit histories, with whatever tool is appropriate.\n\nCiao,\nDscho\n"},{"id":"342995","messageId":"nycvar.QRO.7.76.6.1803261405170.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"874lllh09b.fsf@javad.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T12:44:40Z","receivedAt":"2018-03-26T12:44:54Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Mon, 12 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > [...]\n> >\n> > Where \"easy\" meant that I had to spend 1h still to figure out why\n> > using the unrebased merge parents as merge bases.\n> \n> That's because you try to figure out something that is not there in the\n> [RFC v2]. I suggest to forget everything you've already imagined and\n> just read the [RFC v2] proposal afresh. It should take about 10 minutes\n> or less to get it. Really.\n> \n> > The same amount of time did not allow me to wrap my head around\n> > Sergey's verbose explanations.\n> \n> Honestly, I don't believe it, sorry, but I'm willing to explain anything\n> you wish to be explained in _[RFC v2]_.\n\nNo, really. If you cannot bring yourself to believe my words, then I hate\nto break it to you: I am not lying.\n\nAs to \"I'm willing to explain anything you wish to be explained in RFC\nv2\": I was asking, and asking, and asking again, for a simple summary of\nthe idea behind your proposal. Nothing. That was the answer.\n\nI had to figure it out myself: the idea is to *create* fake commits,\nnon-merge ones, for every single merge commit parent. Those fake commits\ncombine the changes of *all* merge commit parents *but one*. And then\nthose commits are rebased, individually, with tons of opportunities for\nmerge conflicts. Repeated ones. And then that result is merged.\n\nExcept that there is something more convoluted going on because of that\ndumb, annoying requirement that this also has to work interactively. Where\nsomebody like myself might have done something really annoying such as\ndropping commits, or even amending them with changes that had not been in\nthe previous version of the merge commit parents.\n\nSo then, after doing a ton of work to rebase the original merge commit's\nchanges, we perform three-way merges with the already-rebased parents (or\nactually, the new tips, because as I pointed out, the parent commit may\nhave been dropped or reordered) to *undo* those painfully rebased changes.\n\nNo matter how much you are married to RFC v2: it *does* do unnecessary\nwork, it *does* result in a *lot* more opportunity for merge conflicts,\nand as a bonus: it even introduces the opportunity to come up with\ntwo versions of the rebased merge commit that disagree with one another.\n\n> > But I'll take your word for it that the strategies are equivalent, and\n> > go with the one that has both a simpler explanation (in my mind, at\n> > least), and an more robust implementation.\n> \n> It's up to you, and it'd still be much better than what we have now, but\n> you will need to face the (I think unfortunate) consequences I just\n> summarized elsewhere in the thread.\n\nNo, it was not up to me. It was up to you to convince me (or for that\nmatter, anybody else on the Git mailing list), that your approaches are\nessentially the same.\n\nBut they are not, as your RFC v2 includes a detour of unnecessary work.\nEven if the end result is theoretically the same, *practically* your\napproach forces a lot of work on the user, work that is often just thrown\naway!\n\nLet's take a concrete example. Like, an example that really came up. On\nthe Git mailing list. A tangible example that shapes my experience, and\nmore importantly: other Git users' experience as well.\n\nI introduced a change to the funny construct `void *data = data;` that was\nmeant to fool GCC versions that could not figure out that data would not\nbe used uninitialized. While that shut up GCC, it upset other compilers\nthat now said that this new construct does not make sense. My approach was\nto introduce the macro `FAKE_INIT(type, name, value)` which would be\nexpanded to `type name = name;` for GCC, and to `type name = (type)value`\nfor all other compilers.\n\nThis was a change I wanted to cook in Git for Windows for a couple of\niterations until I am sure it works as expected, also on non-Windows\nplatforms, and with other compilers than MSVC, GCC and Clang.\n\nRecently Ramsay Jones spent the time to research this issue a lot deeper\nthan it was done before, and found out *which* GCC versions are affected,\nand introduced a patch series that fixes this problem for real, *undoing*\nthe `void *data = data;` mess.\n\nObviously, this fix conflicts with my work-around.\n\nOkay, good, so what would happen, hypothetically, if the Git garden shears\nI use (and which you probably still haven't studied, even if I pointed you\nto it several times, but expecting me to read RFC v2 at the same time\ninstead of answering my questions about it) were adjusted to use RFC v2 to\nrebase merges?\n\nTo answer that, I first have to tell you that Git for Windows' branch\nthicket consists of roughly 70 topic branches that are partially\ncriss-cross-merged. There are roughly 40 merge commits (44 if I counted\ncorrectly) on the commit graph between HEAD and that work-around that\nconflicts with Ramsay's fix.\n\nSo the first thing that would happen when rebasing the branch thicket is\nthis: I would encounter the merge conflict when my workaround is\ncherry-picked, realize that my work-around is no longer necessary, and\ncall `git rebase --skip` and that's that.\n\nThe Git garden shears currently do not even try to rebase merge commits,\nso that really would be that. I might encounter unrelated conflicts, but\nnothing about the `void *data = data;` issue again.\n\nWith Phillip's approach, the same is true, as the 40+ merge commits would\nbe rebased with my work-around being undone by the first three-way merge,\nthe second three-way merge being unaffected (and no further 3-way merge\nnecessary because I do not do octopus merges in Git for Windows branch\nthicket) and that's that.\n\n(There is a chance, of course, that I misunderstood, or that I missed\nsomething. The proof lies in the pudding. Somebody will have to try this,\nand this somebody is probably me.)\n\nWith your RFC v2 approach, however, the original tips of all of those 40+\nmerges would be \"cherry-picked\" (via those intermediate fake commits).\nConflicting every single time. And of course the subsequent three-way\nmerge to undo the changes (because I dropped the change via `git rebase\n--skip`) would conflict *again*.\n\nThat's an awful lot of merge conflicts. One might be tempted to suggest\ncomplexifying the entire procedure by requiring `rerere`, and my initial\nanswer would be that this still conflicts when the context lines of the\nmerge conflict changed, but the truth is: this level of complexity, this\namount of merge conflicts, is not even necessary, as seen by looking at\nPhillip's strategy.\n\nThis is what I referred to as \"unecessary work\". And to me, as a power\n(read: frequent) user of the closest thing we have to --recreate-merges in\nthe wild, it is not funny. Not funny at all.\n\nBTW this is the level of detail I would have wished your answers to my\nrepeated questions for clarification of your RFC v2 to be. And that is\nwhat I expect in response to my valid questions in the future.\n\nCiao,\nJohannes\n"},{"id":"342999","messageId":"nycvar.QRO.7.76.6.1803261455130.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"243ca23d-77a9-4ae1-a120-de6c6b195cdc@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T13:07:32Z","receivedAt":"2018-03-26T13:07:47Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Tue, 13 Mar 2018, Igor Djordjevic wrote:\n\n> On 12/03/2018 11:46, Johannes Schindelin wrote:\n> > \n> > > Sometimes one just needs to read the manual, and I don`t really\n> > > think this is a ton complicated, but just something we didn`t really\n> > > have before (real merge rebasing), so it requires a moment to grasp\n> > > the concept.\n> > \n> > If that were the case, we would not keep getting bug reports about\n> > --preserve-merges failing to reorder patches.\n> \n> Not sure where that is heading to, but what I`m arguing about is that \n> introducing new commands and concepts (`merge`, and with `-R`) just \n> makes the situation even worse (more stuff to grasp).\n\nThe problem with re-using `pick` is that its concept does not apply to\nmerges. The cherry-pick of a non-merge commit is well-defined: the current\nHEAD is implicitly chosen as the cherry-picked commit's (single) parent\ncommit. There is no ambiguity here.\n\nBut for merge commits, we need to specify the parent commits (apart from\nthe first one) *explicitly*. There was no need for that in the `pick`\ncommand, nor in the concept of a cherry-pick.\n\n> Reusing existing concepts where possible doesn`t have this problem.\n\nExisting concepts are great. As long as they fit the requirements of the\nnew scenarios. In this case, `pick` does *not* fit the requirement of\n\"rebase a merge commit\".\n\nIf you really want to force the `pick` concept onto the use case where you\nneed to \"reapply\" merges, then the closest you get really is Sergey's\nidea, which I came to reject when considering its practical implications.\n\nEven so, you would have to make the `pick` command more complicated to\nsupport merge commits. And whatever you would do to extend the `pick`\ncommand would *not make any sense* to the current use case of the `pick`\ncommand.\n\nThe real problem, of course, is that a non-merge commit, when viewed from\nthe perspective of the changes it introduced, is a very different beast\nthan a merge commit: it does not need to reconcile changes, ever, because\nthere is really only one \"patch\" to one revision. That is very different\nfrom a merge commit, whose changes can even disagree with one another (and\nin fact be resolved with changes disagreeing *yet again*)!\n\n> > > Saying in favor of `--rebase-merges`, you mean as a separate option,\n> > > alongside `--recreate-merges` (once that series lands)?\n> > \n> > No. I am against yet another option. The only reason I pollute the\n> > option name space further with --recreate-merges is that it would be\n> > confusing to users if the new mode was called --preserve-merges=v2\n> > (but work *totally differently*).\n> \n> I see. So I take you`re thinking about renaming `--recreate-merges` to\n> `--rebase-merges` instead?\n\nThinking about it. Nothing will happen before v2.17.0 on that front,\nthough, because -- unlike you gentle people -- I have to focus on\nstabilizing Git's code base now.\n\n> That would seem sensible, too, I think, being the default usage mode in\n> the first place. Being able to actually (re)create merges, too, once\n> user goes interactive, would be \"just\" an additional (nice and powerful)\n> feature on top of it.\n\nThe implementation detail is, of course, that I will introduce this with\nthe technically-simpler strategy: always recreating merge commits with the\nrecursive strategy. A follow-up patch series will add support for rebasing\nmerge commits, and then use it by default.\n\nThis latter part will need a lot of experimentation, though. That's why I\nwant the --recreate-merges patch series cooking in `next` first.\n\nCiao,\nDscho\n"},{"id":"343003","messageId":"nycvar.QRO.7.76.6.1803261508540.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"xmqqk1uf3kcd.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T13:17:24Z","receivedAt":"2018-03-26T13:17:38Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 13 Mar 2018, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > If so, what tooling do you have to identify quickly what to\n> > cherry-pick, given merge conflicts?\n> \n> It exactly is the issue I've been trying to find ideal solution for\n> quite a while and not successfully.  Here is a sample thread\n> \n>   https://public-inbox.org/git/xmqqeft3u0u5.fsf@gitster.mtv.corp.google.com/#t\n> \n> and every message I mention \"merge-fix\" is relevant.\n>\n> [... detailed explanation of the current \"band-aid\" system...]\n\nThank you for the very thorough account. I have been struggling with this,\ntoo, even chatting to Michael Haggerty about this at the Contributors'\nSummit (where I missed you a lot). He pointed me to a blog post of his\nabout the very interesting concept of \"obsolete markers\" in Hg:\n\nhttp://softwareswirl.blogspot.de/2013/05/obsolete-markers-in-mercurial.html\n\nGranted, that concept really makes most sense for rebase, but I wonder\nwhether the concept could be extended to help your (and my) use case of\nfrequently-changing targets (for me, it is more rebase targets, for you it\nis merge targets). It would probably be implemented using commit notes, to\nallow for bidirectional mappings.\n\nCiao,\nDscho\n> \n> The current band-aid system punts and indexes the merge-fix changes\n> by merely a branch name.  When refs/merge-fix/X exists, what it\n> means is \"When branch X is merged to an integration branch, it is\n> likely that the integration branch _already_ has merged an unnamed\n> topic that causes semantic conflicts and requires this fix-up\".\n> This needs occasional manual adjustment---e.g. when the topic X\n> turns out to be a lot more stable than the other topic Y that was\n> causing us trouble with semantic conflicts, I may at some point\n> reorder the topics and have topic X advance to 'next' before topic Y\n> does.  And when that happens, when I merge X to 'next', because Y is\n> not yet in 'next', I shouldn't apply refs/merge-fix/X (often, an\n> attempt to cherry-pick it on top of a merge of X into 'next' would\n> fail, which would be a bit of safety, but not always).  What I\n> should do instead is to rename refs/merge-fix/X to refs/merge-fix/Y\n> immediately before merging X to 'next', so that the cherry-pick is\n> not applied.  When rebuilding 'master'->'jch'->'pu' chain, X (now in\n> 'next') will be merged before Y (not in 'next') gets merged, and\n> when it is Y's turn to be merged, the merge-fix I used to apply when\n> merging topic X will be applied.\n> \n> In the ideal world (I think I'm repeating the ideas raised in the\n> thread quoted), the merge-fix database should be indexed with a pair\n> of commit object names (e.g. a step in branch X that adds a new\n> callsite for function frotz() and a step in branch Y that changes\n> the function signature of frotz()), and teach the system to\n> cherry-pick refs/merge-fix/A-B to resolve semantic conflicts, when\n> both commits A and B appears in the integration branch for the first\n> time.  And make sure these are kept up-to-date across rebasing of\n> commits A and B.  After rebasing the topics X and Y that contained\n> the commits A and B, if they became C and D, the system somehow\n> needs to be able to locate the previous merge-fix that was valid for\n> A-B pair when C-D pair gets merged.\n> \n> \n"},{"id":"343004","messageId":"nycvar.QRO.7.76.6.1803261518390.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87vadyd9az.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T13:47:09Z","receivedAt":"2018-03-26T13:47:22Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 14 Mar 2018, Sergey Organov wrote:\n\n> Igor Djordjevic <igor.d.djordjevic@gmail.com> writes:\n> \n> > On 07/03/2018 08:26, Johannes Schindelin wrote:\n> \n> [...]\n> \n> >> Second side note: if we can fast-forward, currently we prefer that,\n> >> and I think we should keep that behavior with -R, too.\n> >\n> > I agree.\n> \n> I'm admittedly somewhat lost in the discussion,\n\n... and cutting so much context does not help...\n\nThe \"fast-forward\" here refers to the thing `git rebase` does unless you\ncall it with `--force-rebase`: if we are about to `pick` a commit, and\nHEAD already points to its parent commit, we do not evey cherry-pick: we\njust fast-forward to the original commit.\n\nLikewise, `merge -C <commit>` will simply fast-forward to the specified\ncommit if HEAD is pointing to its first parent and the specified merge\nheads are also identical to the respective original parent commits.\n\nWhat I said with my comment was that `merge -R -C <commit>` will behave in\nexactly the same way.\n\n> but are you talking fast-forward on _rebasing_ existing merge? Where\n> would it go in any of the suggested algorithms of rebasing and why?\n\nAnd this is something I did not talk about yet, but it does come up in\npractice: the main use case of rebasing branches is to follow an\n\"upstream\", of course. And guess what? From time to time, some of the\nbranches get merged upstream (or, in Git's own source code, applied). In\nthis case, the Git garden shears *do* skip the merge (as the new merge\nhead is already an ancestor of HEAD). In --recreate-merges, it *will*\ncreate a new merge commit, though, which is a bit annoying.\n\nThe best way to handle this would *probably* look similar to how \"empty\"\ncommits (i.e. commits whose patch is empty) are handled by rebase. But it\nis not yet clear to me how that would look in practice, as `pick <commit>`\nis a single operation that can be easily commented out in the todo list\ndepending on `--allow-empty`, while the `merge -C <commit>` command is not\nthe entire operation, as there may be `pick` commands in the merge head\nthat could potentially be skipped due to merge conflicts with\nalready-applied versions of the same patches.\n\nIf this sounds unclear to you, please do ask for clarification. Although\nthis is currently not my highest priority in the `sequencer-shears` branch\nthicket (where `--recreate-merges` is the first part).\n\n> I readily see how it can break merges. E.g., any \"git merge --ff-only\n> --no-ff\" merge will magically disappear.\n\nDid you mean `git merge --no-ff`? Combining `--ff-only` with `--no-ff`\ndoes not make sense.\n\n> So, even if somehow supported, fast-forward should not be performed by\n> default during _rebasing_ of a merge.\n\nThat statement is too general to be correct.\n\n*If* we detect that the original merge could have been fast-forwarded\ninstead (and it is very easy to detect that in --make-list), we would have\nto handle that similar to afore-mentioned empty commits in conjunction\nwith `--allow-empty`.\n\nIf the original merge could not have been fast-forwarded, but during the\nrebase it *can*, we should skip it, as the reason for the merge commit\nis clearly no longer there.\n\nThis, by the way, is an insight you can really only win by using\n--recreate-merges (or the Git garden shears). And using it a *lot*.\nBecause otherwise, you will not even guess correctly what will, and what\nwon't, come up in practice.\n\n> >> If the user wants to force a new merge, they simply remove that -R\n> >> flag.\n> \n> Alternatively, they'd replace 'pick' with 'merge', as they already do\n> for other actions. \"A plurality is not to be posited without necessity\".\n\nNo, no, no and no again!\n\nWe learned how *wrong* the `pick` approach was with --preserve-merges!\nHave you *ever* used --preserve-merges in any real way? If so, you *have*\nencountered the problems, and probably directed several lengthy curses my\nway for that lousy design.\n\nA pick is a pick is a pick. Of a single patch with metadata such as the\nauthor, commit message and the date.\n\nA merge is not a patch. While a pick introduces a specific change on top\nof a single revision, the changes introduced by a merge are ideally\nalready there. It is conceptually *very* different.\n\nSure, a merge commit sometimes needs to introduce extra changes on top of\nthe merged changes, sure, that happens (and is called \"evil merge\" in Git\nparlance). Those *additional* changes should be kept as minimal as\npossible, in particular there should only be changes *necessitated* by the\nreconciled changes.\n\nSo no, a `pick` is not a `merge`. Not at all.\n\n> Please, _please_, don't use 'merge' command to 'pick' merge commits!\n> It's utterly confusing!\n\nPlease, please, please *work* with branch thickets for a while. And you\nwill see that it makes a *huge* difference!\n\nFor example, within a block of `pick` lines, it is relatively safe to\nreorder. You see more or less what changes interact with one another.\n\nBe *very* careful when reordering `merge` lines, in particular when you\nhave a real-world branch thicket, not just a toy example.\n\nDo *not* use `pick` for merges. Not. Ever.\n\nBy the way, let this here discussion serve as Yet Another Example why it\nis important to not only consider new features theoretically. Only in\npractice do you find out where your theory sounded too good to be actually\ntrue.\n\n> Thinking about it I've got an idea that what we actually need is\n> --no-flatten flag that, when used alone, will just tell \"git rebase\" to\n> stop flattening history, and which will be implicitly imposed by\n> --recreate-merges (and --preserve-merges).\n\n... and this flag would only make sense if every `git rebase` involved a\ntodo list.\n\nWhich it does not.\n\nCiao,\nJohannes\n"},{"id":"343005","messageId":"nycvar.QRO.7.76.6.1803261553190.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"45d05a89-b10e-5035-7c5b-2981dba27d42@gmail.com","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T13:58:42Z","receivedAt":"2018-03-26T13:58:58Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Tue, 13 Mar 2018, Igor Djordjevic wrote:\n\n> On 12/03/2018 11:20, Johannes Schindelin wrote:\n> > \n> > > > [...] and cannot introduce ambiguities when rebasing the\n> > > > changes introduced by M (i.e. the \"amendmendts\" we talked about).\n> > >\n> > > Hmm, not following here, which ambiguities are we talking about?\n> > \n> > U1' vs U2' of course. Those are two things that can be different, even if\n> > they ideally would have identical trees.\n> > \n> > Phillip's strategy does not leave that room for ambiguity.\n> \n> Ehm, in Sergey`s approach, this is not an issue, but a feature :)\n\nWell, in my use cases, this would not be a good feature. It would be\nhighly annoying, confusing, and cost me tons of time.\n\n> If U1' != U2', it just means a more complex rebase happened, but it \n> doesn`t compromise the result (rebased merge) in any way.\n\nNo, it just means that your strategy failed to give a consistent answer to\nthe question \"what would the rebased merge commit's tree look like\".\n\n> On the other hand, if U1' == U2', we can be pretty sure that merge\n> rebasing went as clean as possible.\n\nWith the backsplanation I gave for Phillip's strategy, I can be as sure\nthat rebasing went as clean as possible if it does not produce merge\nconflicts: it reconciles the changes introduced by 1) rebasing the merge\ntips with the changes introduced by 2) the original merge commit relative\nto its parents.\n\nAnd even if it produces merge conflicts, I know at least that those are\nconflicts between those two sets of changes.\n\nCiao,\nDscho\n"},{"id":"343007","messageId":"nycvar.QRO.7.76.6.1803261602360.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"3dbf86bc-cae9-8d6c-a206-cac685938f3d@gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-26T14:11:33Z","receivedAt":"2018-03-26T14:11:46Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Buga,\n\nOn Fri, 16 Mar 2018, Igor Djordjevic wrote:\n\n> [...]\n>\n> Yes, having more steps would mean more power/options to the user, but\n> more complexity to explain to and guide him through as well, not really\n> sure where the line should be drawn - for the first time, at least.\n\nIf you want to avoid having a huge discussion with me about bias, male\nprivilege and how unaware most men are of it, and how it excludes half the\npotential usership/talented developers, and how representation matters --\nand believe me, you do want to avoid this discussion -- you will want to\navoid referring to the user as a \"he\".\n\nIt might be true in your case. But it is also true in your case that you\nare Russian. Yet you write English here, probably to avoid excluding\npeople from the discussion. And you should demonstrate the same courtesy\nto people who do not happen to identify with the same gender as you do.\n\nIn short: every time you think of a user or a developer as \"he\", take a\nstep back and reflect how excluded *you* would feel if someone forced you\nto change that to \"she\". That is exactly how much you exclude non-males if\nyou think of them as \"he\". Just don't.\n\nThe remedy is easy: use the gender-neutral \"they\". Which is, by the way,\nnot a modern invention as of late (in contrast to the \"he\" you use):\nhttps://en.wikipedia.org/wiki/Singular_they#Older_usage\n\nCiao,\nDscho\n"},{"id":"343097","messageId":"87muyugl60.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803261351070.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-27T05:08:39Z","receivedAt":"2018-03-27T05:08:47Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Buga,\n>\n> On Tue, 13 Mar 2018, Igor Djordjevic wrote:\n>\n>> On 12/03/2018 13:56, Sergey Organov wrote:\n>> > \n>> > > > I agree with both of you that `pick <merge-commit>` is inflexible\n>> > > > (not to say just plain wrong), but I never thought about it like\n>> > > > that.\n>> > > >\n>> > > > If we are to extract further mentioned explicit old:new merge\n>> > > > parameter mapping to a separate discussion point, what we`re\n>> > > > eventually left with is just replacing this:\n>> > > >\n>> > > > \tmerge -R -C <original--merge-commit> <merge-head>\n>> > > >\n>> > > > ... with this:\n>> > > >\n>> > > > \tpick <original--merge-commit> <merge-head>\n>> > >\n>> > > I see where you are coming from.\n>> > >\n>> > > I also see where users will be coming from. Reading a todo list in\n>> > > the editor is as much documentation as it is a \"program to execute\".\n>> > > And I am afraid that reading a command without even mentioning the\n>> > > term \"merge\" once is pretty misleading in this setting.\n>> > >\n>> > > And even from the theoretical point of view: cherry-picking\n>> > > non-merge commits is *so much different* from \"rebasing merge\n>> > > commits\" as discussed here, so much so that using the same command\n>> > > would be even more misleading.\n>> > \n>> > This last statement is plain wrong when applied to the method in the\n>> > [RFC] you are replying to.\n>\n> That is only because the RFC seems to go out of its way to break down a\n> single merge commit into as many commits as there are merge commit\n> parents.\n\nComplex entity is being split for ease of reasoning. People tend to use\nthis often.\n\n> This is a pretty convoluted way to think about it: if you have three\n> parent commits, for example, that way of thinking would introduce three\n> intermediate commits, one with the changes of parent 2 & 3 combined, one\n> with the changes of parent 1 & 3 combined, and one with the changes of\n> parent 1 & 2 combined.\n\nNo.\n\n> To rebase those commits, you essentially have to rebase *every parent's\n> changes twice*.\n\nNo.\n\n> It gets worse with merge commits that have 4 parents. In that case, you\n> have to rebase every parent's changes *three times*.\n\nSorry, the [RFC] has nothing of the above. Once again, it's still just\nas simple is: rebase every side of the merge then merge the results\nusing the original merge commit as a merge base.\n\nAnd if you can't or don't want to grok the explanation in the RFC, just\nforget the explanation, no problem.\n\n> And so on.\n>\n>> > Using the method in [RFC], \"cherry-pick non-merge\" is nothing more or\n>> > less than reduced version of generic \"cherry-pick merge\", exactly as\n>> > it should be.\n>\n> I really get the impression that you reject Phillip's proposal on the\n> ground of not being yours. In other words, the purpose of this here\n> argument is to praise one proposal because of its heritage, rather than\n> trying to come up with the best solution.\n\nNo. As the discussion evolved, I inclined to conclusion that modified\nPhillip's algorithm is actually better suited for the implementation\n[1].\n\n> On that basis, I will go with the proposal that is clearly the simplest\n> and does the job and gets away with avoiding unnecessary work.\n\nThese algorithms are actually the same one, as has already been shown\nelsewhere in the discussion. Asymmetric incremental nature of the\nPhillip's one is apparently better suited for naturally asymmetrical way\nGit already handles merging. FYI, here is the latest proposal that came\nout of discussion [1]:\n\ngit-rebase-first-parent --onto A' M\ntree_U1'=$(git write-tree)\ngit merge-recursive B -- $tree_U1' B'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n[ $conflicted_last_merge = \"yes\" ] ||\n  trees-match $tree_U1' $tree || \n  stop-for-user-amendment\n\nwhere 'git-rebase-first-parent' denotes whatever machinery is currently\nbeing used to rebase simple non-merge commit.\n\n>\n>> > Or, in other words, \"cherry-pick merge\" is generalization of\n>> > \"cherry-pick non-merge\" to multiple parents.\n>> \n>> I think Sergey does have a point here, his approach showing it.\n>\n> His approach is showing that he wants to shoehorn the \"rebase a merge\n> commit\" idea into a form where you can cherry-pick *something*.\n>\n> It does not have to make sense. And to me, it really does not.\n\nExcept that Phillip's one does exactly this as well, only in incremental\nmanner, as shown in [1].\n\n>\n>> Phillip`s simplification might be further from it, though, but we`re \n>> talking implementation again - important mental model should just be \n>> \"rebasing a commit\" (merge or non-merge), how we`re doing it is \n>> irrelevant for the user, the point (goal) is the same.\n>\n> Except that Phillip's simplification is not a simplification. It comes\n> from a different point of view: trying to reconcile the diverging\n> changes.\n\nThey are essentially the same as one easily converts to another and back\n[1]. They will only bring different user experience in case of\nconflicts.\n\n> Phillip's is a true generalization of the \"rebase vs merge\" story: it is\n> no longer about merging, or about rebasing, but about reconciling\n> divergent commit histories, with whatever tool is appropriate.\n\nWhatever. They are essentially the same thing. The only difference is\nincremental vs parallel [1].\n\nReferences:\n\n[1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com/\n\n-- Sergey\n"},{"id":"343098","messageId":"87in9igl0s.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803261333500.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-27T05:11:47Z","receivedAt":"2018-03-27T05:11:54Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Mon, 12 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> >\n>> > On Wed, 7 Mar 2018, Sergey Organov wrote:\n>> >\n>> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> >> \n>> >> > How can your approach -- which relies *very much* on having the\n>> >> > original parent commits -- not *require* that consistency check?\n>> >> \n>> >> I don't understand what you mean, sorry. Could you please point me to\n>> >> the *require* you talk about in the original proposal?\n>> >\n>> > Imagine a todo list that contains this line\n>> >\n>> > \tmerge -C abcdef 123456\n>> >\n>> > and now the user edits it (this is an interactive rebase, after all),\n>> > adding another merge head:\n>> >\n>> > \tmerge -C abcdef 987654 123456\n>> >\n>> > Now your strategy would have a serious problem: to find the original\n>> > version of 987654. If there was one.\n>> \n>> We are talking about different checks then. My method has a built-in\n>> check that Pillip's one doesn't.\n>\n> Since you did not bother to elaborate, I have to assume that your\n> \"built-in check\" is that thing where intermediate merges can give you\n> conflicts?\n>\n> If so, there is a possibility in Phillip's method for such conflicts, too:\n> we have to perform as many 3-way merges as there are parent commits.\n>\n> It does make me uncomfortable to have to speculate what you meant,\n> though.\n\nIt doesn't matter anymore as this check could easily be added to\nPhillip's algorithm as well, see [1].\n\n[1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com\n"},{"id":"343099","messageId":"87bmfagk2u.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803261405170.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-27T05:32:09Z","receivedAt":"2018-03-27T05:32:20Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Dear Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Mon, 12 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > [...]\n>> >\n>> > Where \"easy\" meant that I had to spend 1h still to figure out why\n>> > using the unrebased merge parents as merge bases.\n>> \n>> That's because you try to figure out something that is not there in the\n>> [RFC v2]. I suggest to forget everything you've already imagined and\n>> just read the [RFC v2] proposal afresh. It should take about 10 minutes\n>> or less to get it. Really.\n>> \n>> > The same amount of time did not allow me to wrap my head around\n>> > Sergey's verbose explanations.\n>> \n>> Honestly, I don't believe it, sorry, but I'm willing to explain anything\n>> you wish to be explained in _[RFC v2]_.\n>\n> No, really. If you cannot bring yourself to believe my words, then I hate\n> to break it to you: I am not lying.\n>\n> As to \"I'm willing to explain anything you wish to be explained in RFC\n> v2\": I was asking, and asking, and asking again, for a simple summary of\n> the idea behind your proposal. Nothing. That was the answer.\n\nNo. The answer rather was this simple explanation that I gave you\nmultiple times already \"rebase each side of the merge, then merge the\nresults back using original merge commit as the merge base\". Yet you say\nthere was none. I'm confused.\n\nWell, as it seems you grok Phillip's notation just fine, here is RFC\nalgorithm in this notation [1]:\n\ngit checkout --detach A'\ngit merge-recursive A -- A' M\ntree_U1'=$(git write-tree)\ngit checkout --detach B'\ngit merge-recursive B -- B' M\ntree_U2'=$(git write-tree)\ngit merge-recursive M -- $tree_U1' $tree_U2'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n\n> I had to figure it out myself: the idea is to *create* fake commits,\n> non-merge ones, for every single merge commit parent. Those fake commits\n> combine the changes of *all* merge commit parents *but one*. And then\n> those commits are rebased, individually, with tons of opportunities for\n> merge conflicts. Repeated ones. And then that result is merged.\n\nWrong. See above.\n\nAnyway, it doesn't matter anymore, see [1].\n\nReferences:\n\n[1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com\n\n-- Sergey\n"},{"id":"343100","messageId":"874ll2gjzp.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803261331340.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC v2] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-27T05:34:02Z","receivedAt":"2018-03-27T05:34:35Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Mon, 12 Mar 2018, Sergey Organov wrote:\n>\n>> [...]\n>> \n>> Yet another consequence is that my approach will likely result in better\n>> code reuse.\n>\n> This is a purely academic speculation. At least until somebody implements\n> Phillip's method. Oh wait, I already started to implement it, and it was\n> not exactly hard to implement:\n>\n> https://github.com/dscho/git/commit/26d2858800a4e0d3cc6313ddb54dd4d2ce516f31\n\nNice! Please see [1] for some recent relevant discussion.\n\n[1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com/\n\n-- Sergey\n"},{"id":"343107","messageId":"87woxyf4lk.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803261455130.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-27T05:51:51Z","receivedAt":"2018-03-27T05:51:58Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Buga,\n>\n> On Tue, 13 Mar 2018, Igor Djordjevic wrote:\n>\n>> On 12/03/2018 11:46, Johannes Schindelin wrote:\n>> > \n>> > > Sometimes one just needs to read the manual, and I don`t really\n>> > > think this is a ton complicated, but just something we didn`t really\n>> > > have before (real merge rebasing), so it requires a moment to grasp\n>> > > the concept.\n>> > \n>> > If that were the case, we would not keep getting bug reports about\n>> > --preserve-merges failing to reorder patches.\n>> \n>> Not sure where that is heading to, but what I`m arguing about is that \n>> introducing new commands and concepts (`merge`, and with `-R`) just \n>> makes the situation even worse (more stuff to grasp).\n>\n> The problem with re-using `pick` is that its concept does not apply to\n> merges. The cherry-pick of a non-merge commit is well-defined: the current\n> HEAD is implicitly chosen as the cherry-picked commit's (single) parent\n> commit. There is no ambiguity here.\n>\n> But for merge commits, we need to specify the parent commits (apart from\n> the first one) *explicitly*. There was no need for that in the `pick`\n> command, nor in the concept of a cherry-pick.\n>\n>> Reusing existing concepts where possible doesn`t have this problem.\n>\n> Existing concepts are great. As long as they fit the requirements of the\n> new scenarios. In this case, `pick` does *not* fit the requirement of\n> \"rebase a merge commit\".\n\nIt does, provided you use suitable syntax.\n\n> If you really want to force the `pick` concept onto the use case where\n> you need to \"reapply\" merges, then the closest you get really is\n> Sergey's idea, which I came to reject when considering its practical\n> implications.\n\nWhich one, and what are the implications that are bad, I wonder?\n\n> Even so, you would have to make the `pick` command more complicated to\n> support merge commits. And whatever you would do to extend the `pick`\n> command would *not make any sense* to the current use case of the `pick`\n> command.\n\nIt would rather make a lot of sense. Please don't use 'merge' to pick\ncommits, merge ones or not!\n\n> The real problem, of course, is that a non-merge commit, when viewed from\n> the perspective of the changes it introduced, is a very different beast\n> than a merge commit: it does not need to reconcile changes, ever, because\n> there is really only one \"patch\" to one revision. That is very different\n> from a merge commit, whose changes can even disagree with one another (and\n> in fact be resolved with changes disagreeing *yet again*)!\n\nYou'd still 'pick' it though, not 'merge'. You don't merge \"merge\ncommit\", it makes no sense. It only makes perfect sense when you get rid\nof original \"merge commit\" and re-merge from scratch, as you were doing\ntill now.\n\n>> > > Saying in favor of `--rebase-merges`, you mean as a separate option,\n>> > > alongside `--recreate-merges` (once that series lands)?\n>> > \n>> > No. I am against yet another option. The only reason I pollute the\n>> > option name space further with --recreate-merges is that it would be\n>> > confusing to users if the new mode was called --preserve-merges=v2\n>> > (but work *totally differently*).\n>> \n>> I see. So I take you`re thinking about renaming `--recreate-merges` to\n>> `--rebase-merges` instead?\n>\n> Thinking about it. Nothing will happen before v2.17.0 on that front,\n> though, because -- unlike you gentle people -- I have to focus on\n> stabilizing Git's code base now.\n>\n>> That would seem sensible, too, I think, being the default usage mode in\n>> the first place. Being able to actually (re)create merges, too, once\n>> user goes interactive, would be \"just\" an additional (nice and powerful)\n>> feature on top of it.\n>\n> The implementation detail is, of course, that I will introduce this with\n> the technically-simpler strategy: always recreating merge commits with the\n> recursive strategy. A follow-up patch series will add support for rebasing\n> merge commits, and then use it by default.\n\nSwitching to use it by default would be backward incompatible again? Yet\nanother option to obsolete? Sigh. \n\n-- Sergey\n"},{"id":"343122","messageId":"nycvar.QRO.7.76.6.1803271454010.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87in9igl0s.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-27T12:55:43Z","receivedAt":"2018-03-27T12:55:58Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Tue, 27 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Mon, 12 Mar 2018, Sergey Organov wrote:\n> >\n> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> >\n> >> > On Wed, 7 Mar 2018, Sergey Organov wrote:\n> >> >\n> >> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >> >> \n> >> >> > How can your approach -- which relies *very much* on having the\n> >> >> > original parent commits -- not *require* that consistency check?\n> >> >> \n> >> >> I don't understand what you mean, sorry. Could you please point me\n> >> >> to the *require* you talk about in the original proposal?\n> >> >\n> >> > Imagine a todo list that contains this line\n> >> >\n> >> > \tmerge -C abcdef 123456\n> >> >\n> >> > and now the user edits it (this is an interactive rebase, after\n> >> > all), adding another merge head:\n> >> >\n> >> > \tmerge -C abcdef 987654 123456\n> >> >\n> >> > Now your strategy would have a serious problem: to find the\n> >> > original version of 987654. If there was one.\n> >> \n> >> We are talking about different checks then. My method has a built-in\n> >> check that Pillip's one doesn't.\n> >\n> > Since you did not bother to elaborate, I have to assume that your\n> > \"built-in check\" is that thing where intermediate merges can give you\n> > conflicts?\n> >\n> > If so, there is a possibility in Phillip's method for such conflicts,\n> > too: we have to perform as many 3-way merges as there are parent\n> > commits.\n> >\n> > It does make me uncomfortable to have to speculate what you meant,\n> > though.\n> \n> It doesn't matter anymore as this check could easily be added to\n> Phillip's algorithm as well, see [1].\n> \n> [1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com\n\nAh, and there I was, thinking that finally you would answer my questions\ndirectly, instead you keep directing me elsewhere (\"read that! Somewhere\nin there you will find the answer you are looking for\").\n\nMy time is a bit too valuable, and I will not continue a discussion where\nmy questions are constantly deflected that way.\n\nCiao,\nJohannes\n"},{"id":"343123","messageId":"nycvar.QRO.7.76.6.1803271456050.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87muyugl60.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-27T13:35:38Z","receivedAt":"2018-03-27T13:35:52Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Tue, 27 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> >\n> > On Tue, 13 Mar 2018, Igor Djordjevic wrote:\n> >\n> >> On 12/03/2018 13:56, Sergey Organov wrote:\n> >> > \n> >> > > > I agree with both of you that `pick <merge-commit>` is inflexible\n> >> > > > (not to say just plain wrong), but I never thought about it like\n> >> > > > that.\n> >> > > >\n> >> > > > If we are to extract further mentioned explicit old:new merge\n> >> > > > parameter mapping to a separate discussion point, what we`re\n> >> > > > eventually left with is just replacing this:\n> >> > > >\n> >> > > > \tmerge -R -C <original--merge-commit> <merge-head>\n> >> > > >\n> >> > > > ... with this:\n> >> > > >\n> >> > > > \tpick <original--merge-commit> <merge-head>\n> >> > >\n> >> > > I see where you are coming from.\n> >> > >\n> >> > > I also see where users will be coming from. Reading a todo list in\n> >> > > the editor is as much documentation as it is a \"program to execute\".\n> >> > > And I am afraid that reading a command without even mentioning the\n> >> > > term \"merge\" once is pretty misleading in this setting.\n> >> > >\n> >> > > And even from the theoretical point of view: cherry-picking\n> >> > > non-merge commits is *so much different* from \"rebasing merge\n> >> > > commits\" as discussed here, so much so that using the same command\n> >> > > would be even more misleading.\n> >> > \n> >> > This last statement is plain wrong when applied to the method in the\n> >> > [RFC] you are replying to.\n> >\n> > That is only because the RFC seems to go out of its way to break down a\n> > single merge commit into as many commits as there are merge commit\n> > parents.\n> \n> Complex entity is being split for ease of reasoning. People tend to use\n> this often.\n\nSure. Divide and conquer. Not duplicate and complicate, though.\n\n> > This is a pretty convoluted way to think about it: if you have three\n> > parent commits, for example, that way of thinking would introduce three\n> > intermediate commits, one with the changes of parent 2 & 3 combined, one\n> > with the changes of parent 1 & 3 combined, and one with the changes of\n> > parent 1 & 2 combined.\n> \n> No.\n\nSorry. This is unacceptable. If you disagree, sure, you are free to do\nthat. If you want to contribute to a fruitful discussion, just saying \"No\"\nwithout explaining why you *think* that my statement is wrong is just...\nunconstructive.\n\n> > To rebase those commits, you essentially have to rebase *every\n> > parent's changes twice*.\n> \n> No.\n\nSame here.\n\n> > It gets worse with merge commits that have 4 parents. In that case, you\n> > have to rebase every parent's changes *three times*.\n> \n> Sorry, the [RFC] has nothing of the above. Once again, it's still just\n> as simple is: rebase every side of the merge then merge the results\n> using the original merge commit as a merge base.\n> \n> And if you can't or don't want to grok the explanation in the RFC, just\n> forget the explanation, no problem.\n\nYour RFC talks about U1 and U2, for the two merge parents.\n\nObviously this strategy can be generalized to n parents. I thought you had\nthought of that and simply did not bother to talk about it.\n\nSorry, my mistake. I should not assume so much.\n\n> > And so on.\n> >\n> >> > Using the method in [RFC], \"cherry-pick non-merge\" is nothing more or\n> >> > less than reduced version of generic \"cherry-pick merge\", exactly as\n> >> > it should be.\n> >\n> > I really get the impression that you reject Phillip's proposal on the\n> > ground of not being yours. In other words, the purpose of this here\n> > argument is to praise one proposal because of its heritage, rather than\n> > trying to come up with the best solution.\n> \n> No. As the discussion evolved, I inclined to conclusion that modified\n> Phillip's algorithm is actually better suited for the implementation\n> [1].\n\nAgain a link.\n\nIf that's what you are looking for, I will throw a hundred links your way\nand see how constructive a discussion you find that.\n\n> > On that basis, I will go with the proposal that is clearly the simplest\n> > and does the job and gets away with avoiding unnecessary work.\n> \n> These algorithms are actually the same one, as has already been shown\n> elsewhere in the discussion.\n\nI disproved that already. My example showed that instead of reconciling\nthe diverging changes starting from the original merge parents, RFC v2\ntries to rebase those parents first, and then use the original merge\ncommit as base of \"diverging changes\" that never started from that\noriginal merge commit.\n\nEssentially, where Phillip's strategy imitates a cherry-pick's 3-way\nmerge, your strategy tries to rebase the merge tips independently from the\nuser (who already rebased them, thank you very much), and then runs a\n*revert*: while a cherry-pick uses the picked commit's parent as merge\nbase, a revert uses the to-be-reverted commit itself as merge base.\n\nIn short: Phillip's strategy is only equivalent to yours if you ignore the\nfact that you perform unnecessary work only to undo it in the end.\n\n> Asymmetric incremental nature of the Phillip's one is apparently better\n> suited for naturally asymmetrical way Git already handles merging. FYI,\n> here is the latest proposal that came out of discussion [1]:\n\nAnd another link.\n\n> git-rebase-first-parent --onto A' M\n> tree_U1'=$(git write-tree)\n> git merge-recursive B -- $tree_U1' B'\n> tree=$(git write-tree)\n> M'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n> [ $conflicted_last_merge = \"yes\" ] ||\n>   trees-match $tree_U1' $tree || \n>   stop-for-user-amendment\n\nAnd a bunch of commands from which the reader is expected to deduce the\nidea.\n\n> >> > Or, in other words, \"cherry-pick merge\" is generalization of\n> >> > \"cherry-pick non-merge\" to multiple parents.\n> >> \n> >> I think Sergey does have a point here, his approach showing it.\n> >\n> > His approach is showing that he wants to shoehorn the \"rebase a merge\n> > commit\" idea into a form where you can cherry-pick *something*.\n> >\n> > It does not have to make sense. And to me, it really does not.\n> \n> Except that Phillip's one does exactly this as well, only in incremental\n> manner, as shown in [1].\n\nAnd yet another link.\n\n> >> Phillip`s simplification might be further from it, though, but we`re \n> >> talking implementation again - important mental model should just be \n> >> \"rebasing a commit\" (merge or non-merge), how we`re doing it is \n> >> irrelevant for the user, the point (goal) is the same.\n> >\n> > Except that Phillip's simplification is not a simplification. It comes\n> > from a different point of view: trying to reconcile the diverging\n> > changes.\n> \n> They are essentially the same as one easily converts to another and back\n> [1].\n\nRepeating this does not make it more true.\n\nWith your method, this branch structure:\n\n- A - B\n    \\   \\\n      C - D\n\nwould be rebased by first cherry-picking B, then C, then doing it *again*\nbecause you need to construct U1 (which is kind of C) and U2 (which is\nkind of B) and rebase those, and if the user resolved merge conflicts\nwhile rebasing B, those merge conflicts will have to be resolved *again*\nwhen rebasing U2, and if the user dropped part of B, U2 will still have to\nrebase them, and the final merge with the original D as merge base will\nhave to undo those changes.\n\nYour strategy involves *a lot* more work, and *a lot* more opportunities\nfor merge conflicts, and it also allows for giving incongruent answers\nto the question \"what should the tree of the rebased merge commit look\nlike?\".\n\n> They will only bring different user experience in case of conflicts.\n\nOh yes, they do. The amount, to begin with.\n\n> > Phillip's is a true generalization of the \"rebase vs merge\" story: it is\n> > no longer about merging, or about rebasing, but about reconciling\n> > divergent commit histories, with whatever tool is appropriate.\n> \n> Whatever. They are essentially the same thing. The only difference is\n> incremental vs parallel [1].\n\nYou know, if you promise to answer whatever questions I have, just simply\nstop throwing around links. Answer my questions. To the point. Not\ndeflecting. This is getting ridiculous.\n\n> [1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com/\n\nI will allow myself the joke and answer the concerns you had in this mail\nthusly:\n\nhttps://public-inbox.org/git/nycvar.QRO.7.76.6.1803261405170.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz/\n\nSo that you cannot miss it: there is a really good, real-world example\nshowing why Phillip's strategy is so much more practical than yours,\nproving that they are not equivalent (except in a very narrow, purely\ntheoretical sense that ignores the possibility of merge conflicts). Look\nfor \"concrete example\" in that mail.\n\nAnother most important thing from that mail is really, really important.\nSo I will stress it instead of expecting you to pick up on it, by\nrepeating it here:\n\n\tBTW this is the level of detail I would have wished your answers\n\tto my repeated questions for clarification of your RFC v2 to be.\n\tAnd that is what I expect in response to my valid questions in the\n\tfuture.\n\nInstead, you chose to fling a link in my direction again.\n\nAnd yes, I read your mail, and no, it does not clarify anything, or even\naddresses my objections.\n\nIf you contest my understanding of your strategy (where I say that U1 is\nessentially the changes of the *other* merged branch), you will have to do\na much better job at explaining yourself. \"No\" is definitely not adequate.\n\nAnd don't promise to answer my questions if you plan only on throwing a\nlink at me. That is no good.\n\nSo to repeat my point (that you contested without any argument, by a rude\nand totally unmeritedly terse \"No\"):\n\n> > To rebase those commits, you essentially have to rebase *every\n> > parent's changes twice*.\n> \n> No.\n\nIn the parlance of your RFC v2, where you start with this history (which I\ntranslated into the left-to-right notation that is used in pretty much all\nof Git's own documentation about interactive rebases, which you apparently\neither did not read, or chose *not* to imitate, creating yet another\nunnecessary diversion):\n\n- B1\n     \\\n- B2 - M\n\nYou now insert U1 and U2 with trees identical to M:\n\n- B1 - U1\n          \\\n- B2 - U2 - M\n\nSo U1 is essentially B2 cherry-picked on top of B1, and U2 is essentially\nB1 cherry-picked on top of B2.\n\nThese U1/U2 commits are now to be cherry-picked on top of the rebased B1'\nand B2'. I spare you more diagrams, you get the idea.\n\nNow, the changes in U1/U2 *are* the changes of the merge parents, that's\nhow they were constructed.\n\nSince they repeat what B1 and B2 are about, and since B1'/B2' means they\nare rebased, and since U1'/U2' are *also* rebased, but independently...\n\n\t...  you essentially have to rebase *every parent's changes twice*.\n\nThe answer \"No\" to this is... astonishing.\n\nCiao,\nJohannes\n"},{"id":"343124","messageId":"nycvar.QRO.7.76.6.1803271536020.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","threadId":"47864","inReplyTo":"87woxyf4lk.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-27T13:49:17Z","receivedAt":"2018-03-27T13:49:33Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Tue, 27 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > On Tue, 13 Mar 2018, Igor Djordjevic wrote:\n> >\n> >> On 12/03/2018 11:46, Johannes Schindelin wrote:\n> >> > \n> >> > > Sometimes one just needs to read the manual, and I don`t really\n> >> > > think this is a ton complicated, but just something we didn`t\n> >> > > really have before (real merge rebasing), so it requires a moment\n> >> > > to grasp the concept.\n> >> > \n> >> > If that were the case, we would not keep getting bug reports about\n> >> > --preserve-merges failing to reorder patches.\n> >> \n> >> Not sure where that is heading to, but what I`m arguing about is that\n> >> introducing new commands and concepts (`merge`, and with `-R`) just\n> >> makes the situation even worse (more stuff to grasp).\n> >\n> > The problem with re-using `pick` is that its concept does not apply to\n> > merges. The cherry-pick of a non-merge commit is well-defined: the\n> > current HEAD is implicitly chosen as the cherry-picked commit's\n> > (single) parent commit. There is no ambiguity here.\n> >\n> > But for merge commits, we need to specify the parent commits (apart\n> > from the first one) *explicitly*. There was no need for that in the\n> > `pick` command, nor in the concept of a cherry-pick.\n> >\n> >> Reusing existing concepts where possible doesn`t have this problem.\n> >\n> > Existing concepts are great. As long as they fit the requirements of\n> > the new scenarios. In this case, `pick` does *not* fit the requirement\n> > of \"rebase a merge commit\".\n> \n> It does, provided you use suitable syntax.\n\nYou know what `pick` would also do, provided you use suitable syntax? Pick\nyour nose.\n\nDon't blame me for this ridiculous turn the discussion took.\n\nOf course, using the suitable syntax you can do anything. Unless there is\n*already* a syntax and you cannot break it for backwards-compatibility\nreasons, as is the case here.\n\nBut I'll stop here. Even my account how there are conceptual differences\nbetween the changes in merge vs non-merge commits (the non-merge commit\n*introduces* changes, the merge commit *reconciles existing* changes)\nseems to fly by without convincing you.\n\nI use rebase every day. I use the Git garden shears every week. If you do\nnot trust my experience with these things, nothing will convince you. You\nare just stuck with your pre-existing opinion.\n\n> > If you really want to force the `pick` concept onto the use case where\n> > you need to \"reapply\" merges, then the closest you get really is\n> > Sergey's idea, which I came to reject when considering its practical\n> > implications.\n> \n> Which one, and what are the implications that are bad, I wonder?\n\nThe strategy described in RFC v2, which does too much work, forces the\nuser to potentially address the same merge conflicts multiple times, and\nworst of all: risks merge conflicts with changes the user *already*\ndropped.\n\n> > Even so, you would have to make the `pick` command more complicated to\n> > support merge commits. And whatever you would do to extend the `pick`\n> > command would *not make any sense* to the current use case of the `pick`\n> > command.\n> \n> It would rather make a lot of sense. Please don't use 'merge' to pick\n> commits, merge ones or not!\n\nIt would rather make a lot of sense. If you completely ignored everything\nI said about preserve-merges. If you ignored what I said about problems\nmoving regular `pick` lines across merge commits. If you ignored all the\nexperience I have with Git garden shears and that I tried really patiently\nfor an impatient man to impart on you.\n\n> > The real problem, of course, is that a non-merge commit, when viewed\n> > from the perspective of the changes it introduced, is a very different\n> > beast than a merge commit: it does not need to reconcile changes,\n> > ever, because there is really only one \"patch\" to one revision. That\n> > is very different from a merge commit, whose changes can even disagree\n> > with one another (and in fact be resolved with changes disagreeing\n> > *yet again*)!\n> \n> You'd still 'pick' it though, not 'merge'. You don't merge \"merge\n> commit\", it makes no sense. It only makes perfect sense when you get rid\n> of original \"merge commit\" and re-merge from scratch, as you were doing\n> till now.\n\nNo, you merge \"merge head\". And you use \"merge commit\"'s commit message.\n*That* makes sense.\n\nPicking a merge commit? Not so. What do you merge? The original merge\ncommit's second parent? Or a rebased version thereof? What if that commit\nhas been `pick`ed *twice*?\n\nNo, you can repeat it all you want, it still does not make sense. Now that\nI think of the possiblity of picking the original parents multiple times,\nit does not even make theoretical sense.\n\n> > The implementation detail is, of course, that I will introduce this with\n> > the technically-simpler strategy: always recreating merge commits with the\n> > recursive strategy. A follow-up patch series will add support for rebasing\n> > merge commits, and then use it by default.\n> \n> Switching to use it by default would be backward incompatible again? Yet\n> another option to obsolete? Sigh. \n\nOh wow.\n\nBackwards compatibility of a feature that existed only as a topic branch\nin `next` before being worked on more? Any other splendid ideas?\n\nAnd what's that about another option to obsolete? Who said that I would\nobsolete any newly-introduced option?\n\nI would introduce either --recreate-merges or --rebase-merges, and then\njust stick with it.\n\nI guess it is my turn to sigh.\n\nCiao,\nJohannes\n"},{"id":"343204","messageId":"87po3oddl1.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803271454010.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution (Road Clear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-28T04:32:58Z","receivedAt":"2018-03-28T04:33:08Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Sergey,\n>\n> On Tue, 27 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > On Mon, 12 Mar 2018, Sergey Organov wrote:\n>> >\n>> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> >> >\n>> >> > On Wed, 7 Mar 2018, Sergey Organov wrote:\n>> >> >\n>> >> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> >> >> \n>> >> >> > How can your approach -- which relies *very much* on having the\n>> >> >> > original parent commits -- not *require* that consistency check?\n>> >> >> \n>> >> >> I don't understand what you mean, sorry. Could you please point me\n>> >> >> to the *require* you talk about in the original proposal?\n>> >> >\n>> >> > Imagine a todo list that contains this line\n>> >> >\n>> >> > \tmerge -C abcdef 123456\n>> >> >\n>> >> > and now the user edits it (this is an interactive rebase, after\n>> >> > all), adding another merge head:\n>> >> >\n>> >> > \tmerge -C abcdef 987654 123456\n>> >> >\n>> >> > Now your strategy would have a serious problem: to find the\n>> >> > original version of 987654. If there was one.\n>> >> \n>> >> We are talking about different checks then. My method has a built-in\n>> >> check that Pillip's one doesn't.\n>> >\n>> > Since you did not bother to elaborate, I have to assume that your\n>> > \"built-in check\" is that thing where intermediate merges can give you\n>> > conflicts?\n>> >\n>> > If so, there is a possibility in Phillip's method for such conflicts,\n>> > too: we have to perform as many 3-way merges as there are parent\n>> > commits.\n>> >\n>> > It does make me uncomfortable to have to speculate what you meant,\n>> > though.\n>> \n>> It doesn't matter anymore as this check could easily be added to\n>> Phillip's algorithm as well, see [1].\n>> \n>> [1] https://public-inbox.org/git/87efkn6s1h.fsf@javad.com\n>\n> Ah, and there I was, thinking that finally you would answer my questions\n> directly, instead you keep directing me elsewhere (\"read that! Somewhere\n> in there you will find the answer you are looking for\").\n\nExcept I've copy-pasted it for /you/ from that reference in another\nanswer to /you/, and /you/ denied it there as being unexplained. As it\nactually happens to be discussed and explained in the referenced\nmaterial, should I rather copy-paste the entire reference to fulfill\nyour requirements?\n\nHere I repeat, directly again, that essential quote from that reference,\nin case you forgot it:\n\n<QUOTE>\ngit-rebase-first-parent --onto A' M\ntree_U1'=$(git write-tree)\ngit merge-recursive B -- $tree_U1' B'\ntree=$(git write-tree)\nM'=$(git log --pretty=%B -1 M | git commit-tree -pA' -pB')\n[ $conflicted_last_merge = \"yes\" ] ||\n  trees-match $tree_U1' $tree || \n  stop-for-user-amendment\n  \nwhere 'git-rebase-first-parent' denotes whatever machinery is currently\nbeing used to rebase simple non-merge commit.\n</QUOTE>\n\n> My time is a bit too valuable, and I will not continue a discussion where\n> my questions are constantly deflected that way.\n\nNo deflection on my side was ever intended. The referenced discussion\nactually has explanations. Maybe one whole page of reading, and it is to\nbe read in context, and then a few follow-ups in that discussion could\nalso be of interest, provided you are interested. I'm sorry should you\nhave no time for that.\n\n-- Sergey\n"},{"id":"343209","messageId":"87605gd9oy.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803271536020.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-28T05:57:01Z","receivedAt":"2018-03-28T05:57:09Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n\n[...]\n\n> But I'll stop here. Even my account how there are conceptual differences\n> between the changes in merge vs non-merge commits (the non-merge commit\n> *introduces* changes, the merge commit *reconciles existing* changes)\n> seems to fly by without convincing you.\n\nGood for you, but Git should keep caring about content, it should care\nnot about meaning. Please leave it to the user to assign meaning to\ntheir content.\n\nIf you rather want a SCM that focuses on meaning, I'd suggest to look at\nBzr and see how it goes.\n\n> I use rebase every day. I use the Git garden shears every week. If you do\n> not trust my experience with these things, nothing will convince you. \n\nUnfortunately you have exactly zero experience with rebasing merges as\nyou've never actually rebased them till now, and it's rebasing merges\nthat matters in this particular discussion.\n\n> You are just stuck with your pre-existing opinion.\n\nI'm afraid that it's rather your huge experience with re-creating merges\nthat makes you stuck to your pre-existing opinion and carefully shields\nyou from experiencing actual paradigm shift.\n\n-- Sergey\n"},{"id":"343210","messageId":"874ll0d9nt.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803271536020.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-28T05:57:42Z","receivedAt":"2018-03-28T05:57:50Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi Sergey,\n>\n\n[...]\n\n>> >> Reusing existing concepts where possible doesn`t have this problem.\n>> >\n>> > Existing concepts are great. As long as they fit the requirements of\n>> > the new scenarios. In this case, `pick` does *not* fit the requirement\n>> > of \"rebase a merge commit\".\n>> \n>> It does, provided you use suitable syntax.\n>\n> You know what `pick` would also do, provided you use suitable syntax? Pick\n> your nose.\n>\n> Don't blame me for this ridiculous turn the discussion took.\n>\n> Of course, using the suitable syntax you can do anything. Unless there is\n> *already* a syntax and you cannot break it for backwards-compatibility\n> reasons, as is the case here.\n\nBackward compatibility to what? To a broken '--preserve-merges'? I had a\nfeel you've invented '--recreate-merges' exactly to break that\ncompatibility. No?\n\nOr is it \"Backwards compatibility of a feature that existed only as a\ntopic branch in `next` before being worked on more?\", as you say\nyourself below?\n\n[...]\n\n>> > The implementation detail is, of course, that I will introduce this with\n>> > the technically-simpler strategy: always recreating merge commits with the\n>> > recursive strategy. A follow-up patch series will add support for rebasing\n>> > merge commits, and then use it by default.\n>> \n>> Switching to use it by default would be backward incompatible again? Yet\n>> another option to obsolete? Sigh. \n>\n> Oh wow.\n>\n> Backwards compatibility of a feature that existed only as a topic branch\n> in `next` before being worked on more? Any other splendid ideas?\n\nEither you care about compatibility or not. You can't have it both ways,\nsorry.\n\nAnd \"technically-simpler strategy: always recreating merge commits with\nthe recursive strategy\" vs. \"rebasing merge commits\" is not just a minor\nstrategy change, it's entire paradigm shift in handling merge commits\nwhile rebasing. I'm afraid you will still come up with a wrong design\nunless you finally accept this fact.\n\n-- Sergey\n"},{"id":"343219","messageId":"87r2o48mm2.fsf@javad.com","threadId":"47864","inReplyTo":"CA+P7+xoDQ2mzhxeZPFhaY+TaSoKkQm=5AtoduHH06-VggOJ2jg@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-28T11:29:09Z","receivedAt":"2018-03-28T11:29:18Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Jacob Keller <jacob.keller@gmail.com> writes:\n\n> On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Hi Johannes,\n>>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> > Hi Sergey,\n>> >\n>>\n>> [...]\n>>\n>> >> >> Reusing existing concepts where possible doesn`t have this problem.\n>> >> >\n>> >> > Existing concepts are great. As long as they fit the requirements of\n>> >> > the new scenarios. In this case, `pick` does *not* fit the\n> requirement\n>> >> > of \"rebase a merge commit\".\n>> >>\n>> >> It does, provided you use suitable syntax.\n>> >\n>> > You know what `pick` would also do, provided you use suitable syntax?\n> Pick\n>> > your nose.\n>> >\n>> > Don't blame me for this ridiculous turn the discussion took.\n>> >\n>> > Of course, using the suitable syntax you can do anything. Unless there\n> is\n>> > *already* a syntax and you cannot break it for backwards-compatibility\n>> > reasons, as is the case here.\n>>\n>> Backward compatibility to what? To a broken '--preserve-merges'? I had a\n>> feel you've invented '--recreate-merges' exactly to break that\n>> compatibility. No?\n>>\n>> Or is it \"Backwards compatibility of a feature that existed only as a\n>> topic branch in `next` before being worked on more?\", as you say\n>> yourself below?\n>>\n>\n> I'm pretty sure he meant that changing the meaning and behavior of \"pick\"\n> is incompatible, as people use scripts which check the edit lists, and\n> these scripts would expect pick to behave in a certain way.\n\nAre we still speaking about that new --recreate-merges feature? You\nalready care for compatibility for it? You expect there are already\nscripts that use it?\n\nOnce again, it seems like you care and don't care about backward\ncompatibility at the same time, here is your phrase below:\n\n\"He absolutely cares about compatibility, but in this case, the feature\nhas not yet been merged into an official release.\"\n\nAre we still speaking about that new --recreate-merges feature?\n\nDo you guys care for compatibility for this particular --recreate-merges\nfeature or not? I'm lost. \"Yes\" or \"No\" answer, if you please!\n\n-- Sergey\n"},{"id":"343220","messageId":"87k1tw8kok.fsf@javad.com","threadId":"47864","inReplyTo":"CA+P7+xoDQ2mzhxeZPFhaY+TaSoKkQm=5AtoduHH06-VggOJ2jg@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-28T12:10:51Z","receivedAt":"2018-03-28T12:10:59Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Jacob Keller <jacob.keller@gmail.com> writes:\n\n> On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorganov@gmail.com> wrote:\n>>\n>> Hi Johannes,\n>>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n[...]\n\n> I'm pretty sure the fact has already been accepted, as he did indeed\n> implement and develop a strategy for rebasing the merges (Phillip's\n> strategy). He hasn't chosen to re-write all the code such that it was\n> \"always\" this method, but rather kept it as an incremental patch on top as\n> it makes it easier to review the changes since we've already spent time\n> looking at and reviewing the --recreate-merges patches.\n\nThat's perfectly OK with me, except that he apparently still can't\naccept the fact that rebasing a non-merge is not fundamentally different\nfrom rebasing a merge.\n\n\"Rebase non-merge\" is just a special case of generic \"rebase commit\",\nprovided we do have generic method that is capable to rebase any commit,\nand we do have it, Phillip's or not.\n\n> Having watched from the sidelines, I've been unable to completely\n> understand and parse the strategies completely, but I've also found\n> Phillip's method to be easier to understand.\n\nIt doesn't matter at all for this particular discussion. Let's call the\nmethod \"rebase a commit\", a black-box, that is capable to rebase any\ncommit. I don't care what implementation is inside. Rebasing a commit is\nstill rebasing a commit, and it should not be called \"merge\" in the todo\nlist.\n\n> As someone who's read the discussion on the sidelines, it certainly\n> does feel like there is some misunderstanding on both sides. Neither\n> of you have been able to get the other to see what you clearly both\n> believe strongly.\n\nCalling \"rebase\" operation \"merge\" is wrong no matter what method is\nused to rebase a commit. Isn't it obvious? It's currently called \"pick\"\nin the todo and it seems natural to continue to use that name for\npicking a commit, whatever number of parents it happens to have.\n\n> Unfortunately I do not have any suggestion as to how to resolve the\n> misunderstanding.\n\nThis sub-thread is not about method at all, so no resolution on that\nmatter is required here. This sub-thread is about todo format only.\n\n> Sergey's method appears to me to be more complex, and I agree that the\n> extra steps could cause more merge conflicts, at least in how it was\n> originally conceptualized and implemented. It is possible that we are\n> mis-understanding the terminology for U1 and U2? It sure seems like it\n> introduces more changes for merge conflicts than the strategy proposed by\n> Phillip. However, the latest editions also sound a lot closer to Phillip's\n> strategy in general, so maybe I have mis-understood how it works and what\n> is fundamentally different about the two strategies.\n\nThere is nothing fundamentally different between them and thus I don't\ncare in this discussion what exact method is being used.\n\n-- Sergey\n"},{"id":"343311","messageId":"87zi2r5swc.fsf@javad.com","threadId":"47864","inReplyTo":"CA+P7+xo19mHrWz9Fy-ifgCcVJM2xwzcLj7F2NvFe2LwGbaJiDQ@mail.gmail.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-29T05:53:55Z","receivedAt":"2018-03-29T05:54:05Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Jacob Keller <jacob.keller@gmail.com> writes:\n\n> On Wed, Mar 28, 2018 at 4:29 AM, Sergey Organov <sorganov@gmail.com> wrote:\n>\n>> Jacob Keller <jacob.keller@gmail.com> writes:\n>>\n>> > On Tue, Mar 27, 2018 at 10:57 PM, Sergey Organov <sorganov@gmail.com>\n>> wrote:\n>> >>\n>> >> Hi Johannes,\n>> >>\n>> >> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> >> > Hi Sergey,\n>> >> >\n>> >>\n>> >> [...]\n>> >>\n>> >> >> >> Reusing existing concepts where possible doesn`t have this\n>> problem.\n>> >> >> >\n>> >> >> > Existing concepts are great. As long as they fit the requirements\n>> of\n>> >> >> > the new scenarios. In this case, `pick` does *not* fit the\n>> > requirement\n>> >> >> > of \"rebase a merge commit\".\n>> >> >>\n>> >> >> It does, provided you use suitable syntax.\n>> >> >\n>> >> > You know what `pick` would also do, provided you use suitable syntax?\n>> > Pick\n>> >> > your nose.\n>> >> >\n>> >> > Don't blame me for this ridiculous turn the discussion took.\n>> >> >\n>> >> > Of course, using the suitable syntax you can do anything. Unless there\n>> > is\n>> >> > *already* a syntax and you cannot break it for backwards-compatibility\n>> >> > reasons, as is the case here.\n>> >>\n>> >> Backward compatibility to what? To a broken '--preserve-merges'? I had a\n>> >> feel you've invented '--recreate-merges' exactly to break that\n>> >> compatibility. No?\n>> >>\n>> >> Or is it \"Backwards compatibility of a feature that existed only as a\n>> >> topic branch in `next` before being worked on more?\", as you say\n>> >> yourself below?\n>> >>\n>> >\n>> > I'm pretty sure he meant that changing the meaning and behavior of \"pick\"\n>> > is incompatible, as people use scripts which check the edit lists, and\n>> > these scripts would expect pick to behave in a certain way.\n>>\n>> Are we still speaking about that new --recreate-merges feature? You\n>> already care for compatibility for it? You expect there are already\n>> scripts that use it?\n>>\n>> Once again, it seems like you care and don't care about backward\n>> compatibility at the same time, here is your phrase below:\n>>\n>> \"He absolutely cares about compatibility, but in this case, the feature\n>> has not yet been merged into an official release.\"\n>>\n>> Are we still speaking about that new --recreate-merges feature?\n>>\n>> Do you guys care for compatibility for this particular --recreate-merges\n>> feature or not? I'm lost. \"Yes\" or \"No\" answer, if you please!\n>>\n>> -- Sergey\n>>\n>\n> I care about the general compatibility of the rebase todo list regardless\n> of which options you enabled on the command line to generate it.\n\nIt's a good thing in general, yes. However, I recall I was told by the\nauthor that --recreate-merges was introduced exactly to break backward\ncompatibility of the todo list. If so, could we please agree to stop\nusing backward compatibility as an objection in the discussion of this\nparticular feature?\n\n> Yes this has a bit of problem because *any* new todo command will\n> break the todo list, but it's better to only add new commands rather\n> than change semantics of existing ones.\n\nI'm not against new commands in general. I'm against inventing new\nentities without necessity, so, provided we did agree not to care about\ncompatibility, there should be some other necessity to invent yet\nanother command. I don't see such a necessity. Do you?\n\nThe main principle I stand for in this discussion though is that all the\ncommits should be treated equally as much as possible, new command or no\nnew command. Doing otherwise will lead to all kinds of troubles and\nconfusion, both in implementation and in user experience.\n\nOverall, what I think is needed is extending the syntax of existing todo\ncommands to handle merge commits. This will give a provision to get it\nright this time. Otherwise it will likely end up being yet another\nsubject of deprecation in the future.\n\n-- Sergey\n"},{"id":"343401","messageId":"nycvar.QRO.7.76.6.1803301235560.5026@qfpub.tvgsbejvaqbjf.bet","threadId":"47864","inReplyTo":"87zi2r5swc.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-30T10:38:55Z","receivedAt":"2018-03-30T10:39:11Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 29 Mar 2018, Sergey Organov wrote:\n\n> Jacob Keller <jacob.keller@gmail.com> writes:\n> \n> > I care about the general compatibility of the rebase todo list\n> > regardless of which options you enabled on the command line to\n> > generate it.\n> \n> It's a good thing in general, yes. However, I recall I was told by the\n> author that --recreate-merges was introduced exactly to break backward\n> compatibility of the todo list. If so, could we please agree to stop\n> using backward compatibility as an objection in the discussion of this\n> particular feature?\n\nThat is a serious misrepresentation of what I said.\n\nIf I had changed --preserve-merges to the new format, *that* would have\nbroken backwards-compatibility.\n\nSo the entire reason of introducing --recreate-merges was to *not have to\nbreak backwards-compatibility*.\n\nI definitely did not say the *exact opposite*.\n\nHopefully this clarifies your confusion,\nJohannes\n"},{"id":"343408","messageId":"87bmf5zqn3.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803301235560.5026@qfpub.tvgsbejvaqbjf.bet","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-30T12:36:48Z","receivedAt":"2018-03-30T12:36:56Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Hi,\n>\n> On Thu, 29 Mar 2018, Sergey Organov wrote:\n>\n>> Jacob Keller <jacob.keller@gmail.com> writes:\n>> \n>> > I care about the general compatibility of the rebase todo list\n>> > regardless of which options you enabled on the command line to\n>> > generate it.\n>> \n>> It's a good thing in general, yes. However, I recall I was told by the\n>> author that --recreate-merges was introduced exactly to break backward\n>> compatibility of the todo list. If so, could we please agree to stop\n>> using backward compatibility as an objection in the discussion of this\n>> particular feature?\n>\n> That is a serious misrepresentation of what I said.\n>\n> If I had changed --preserve-merges to the new format, *that* would have\n> broken backwards-compatibility.\n>\n> So the entire reason of introducing --recreate-merges was to *not have to\n> break backwards-compatibility*.\n>\n> I definitely did not say the *exact opposite*.\n\nI'm sorry I committed ambiguity in my wording that allowed it to be\nmisinterpreted. I actually intended to say roughly the same thing you\nare saying, as what matters for the discussion is that new todo list\nformat does not need to be (backward-)compatible to that of\n--preserve-merges. \n\n> Hopefully this clarifies your confusion,\n\nThere was actually no confusion on my side, and I like your wording\nbetter.\n\nExcept that you've managed to clarify your intentions without actually\naddressing the primary concern:\n\nCould we please agree to stop using backward compatibility as an\nobjection in the discussion of the  --recreate-merges feature?\n\nCould we?\n\nI understand you are still resistant to change 'pick' syntax, but it's\nnot because of backward-compatibility, right?\n\n-- Sergey\n"},{"id":"343418","messageId":"nycvar.QRO.7.76.6.1803301523060.5026@qfpub.tvgsbejvaqbjf.bet","threadId":"47864","inReplyTo":"87bmf5zqn3.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-30T13:33:46Z","receivedAt":"2018-03-30T13:33:59Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Fri, 30 Mar 2018, Sergey Organov wrote:\n\n> Could we please agree to stop using backward compatibility as an\n> objection in the discussion of the  --recreate-merges feature?\n\nNo.\n\nThe expectation of users as to what a `pick` is has not changed just\nbecause you wish it would.\n\nThat is a matter of backwards-compatibility.\n\nYou see, if you are driving a car for a hundred years already, and then\nswitch to a different car, and it has a lever in the same place as your\nprevious car's windshield wiper, but in the new car it has a button that\nactivates the emergency driver seat ejection OMG *it has a seat ejection\nlike in the James Bond movies! Where can I get that car?* Sorry for\ndisgressing.\n\nI am really concerned about that willingness to put an innocuous button,\nso to speak, onto something users got really used to, over the course of a\ndecade or so, when that button should really be made red and blinking and\nOMG where can I get that car?\n\nSo to reiterate, I am really interested in a practical solution that won't\ncause nasty surprises. Meaning: `pick` != merge. That was a mistake in\npreserve-merges, as I have only mentioned like a hundred times, and we\nwon't repeat it.\n\nNow back to that important question: where can I get such a James Bond\ncar? Ideally also with Turbo Boost. Oh wait, that was somebody else's car.\n\nCiao,\nJohannes\n"},{"id":"343419","messageId":"nycvar.QRO.7.76.6.1803301537250.5026@qfpub.tvgsbejvaqbjf.bet","threadId":"47864","inReplyTo":"87605gd9oy.fsf@javad.com","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-03-30T13:41:16Z","receivedAt":"2018-03-30T13:41:28Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Sergey,\n\nOn Wed, 28 Mar 2018, Sergey Organov wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > I use rebase every day. I use the Git garden shears every week. If you\n> > do not trust my experience with these things, nothing will convince\n> > you. \n> \n> Unfortunately you have exactly zero experience with rebasing merges as\n> you've never actually rebased them till now, and it's rebasing merges\n> that matters in this particular discussion.\n\nWho says that I have 0 experience with that? Oh yes, you do. Like, as if\nyou know.\n\nGuess what I do with those Git garden shears' merges? Can you guess? Of\ncourse you can. But you'll never know until I tell you. It is a little\nsilly to try to tell me that I do not have any experience with rebasing\nmerges when you have no idea what strategies I tried in the past.\n\nNow, Phillip's strategy is clearly the best strategy I ever heard about,\nand I am in the process of doing Actual Work to Put It To The Test.\n\n> > You are just stuck with your pre-existing opinion.\n> \n> I'm afraid that it's rather your huge experience with re-creating merges\n> that makes you stuck to your pre-existing opinion and carefully shields\n> you from experiencing actual paradigm shift.\n\nYou know what? Whatevs.\n\nCiao,\nJohannes\n"},{"id":"343431","messageId":"87tvsxwq9s.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803301523060.5026@qfpub.tvgsbejvaqbjf.bet","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-30T15:13:03Z","receivedAt":"2018-03-30T15:13:12Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Fri, 30 Mar 2018, Sergey Organov wrote:\n>\n>> Could we please agree to stop using backward compatibility as an\n>> objection in the discussion of the  --recreate-merges feature?\n>\n> No.\n>\n> The expectation of users as to what a `pick` is has not changed just\n> because you wish it would.\n\nAs if I ever suggested to change user expectations. Could you please\nstop putting words into my mouth?\n\nI _am_ a user, and I expect 'pick' to pick commits, no matter how many\nparents they might have.\n\nAnd no, --preserve-merges did not ever pick commits with number of\nparents more than one, it rather threw them away and re-merged the\nheads. Calling it 'pick' was a huge mistake indeed! Fixing that mistake\nis what I expect, as a user.\n\nJust teach the 'pick' to correctly pick any commit, please!\n\n>\n> That is a matter of backwards-compatibility.\n\nOK, fine, at least its only about user expectations and not about some\nscripting incompatibility.\n\n> You see, if you are driving a car for a hundred years already, and then\n> switch to a different car, and it has a lever in the same place as your\n> previous car's windshield wiper, but in the new car it has a button that\n> activates the emergency driver seat ejection OMG *it has a seat ejection\n> like in the James Bond movies! Where can I get that car?* Sorry for\n> disgressing.\n\nExcept it's irrelevant as the 'pick' will still pick commits.\n\n> I am really concerned about that willingness to put an innocuous button,\n> so to speak, onto something users got really used to, over the course of a\n> decade or so, when that button should really be made red and blinking and\n> OMG where can I get that car?\n\nIt's irrelevant as the 'pick' will still pick commits.\n\n> So to reiterate, I am really interested in a practical solution that won't\n> cause nasty surprises.\n\nI rather don't see how it possibly could cause any surprises, especially\ncompared to using 'merge' to pick commits.\n\n> Meaning: `pick` != merge.\n\nExactly! Use 'merge' when you merge, as you are already doing. Use 'pick'\nwhen you are picking. You don't merge \"merge commit\" when you are\npicking it!\n\n> That was a mistake in preserve-merges, as I have only mentioned like a\n> hundred times, and we won't repeat it.\n\nThe mistake was that it used 'pick' to denote re-merge. You already\nfixed that mistake by introducing 'merge' to re-merge, thanks God.\n\nPlease don't commit yet another mistake by now using 'merge' to pick!\n\n-- Sergey\n"},{"id":"343436","messageId":"87h8oxwmfg.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803301537250.5026@qfpub.tvgsbejvaqbjf.bet","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-03-30T16:36:03Z","receivedAt":"2018-03-30T16:36:11Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n> On Wed, 28 Mar 2018, Sergey Organov wrote:\n>\n>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> \n>> > I use rebase every day. I use the Git garden shears every week. If you\n>> > do not trust my experience with these things, nothing will convince\n>> > you. \n>> \n>> Unfortunately you have exactly zero experience with rebasing merges as\n>> you've never actually rebased them till now, and it's rebasing merges\n>> that matters in this particular discussion.\n>\n> Who says that I have 0 experience with that? Oh yes, you do. Like, as if\n> you know.\n\nI just didn't see even single symptom of it in the discussion, still I\nsaid nothing about it until you started to use your presumed experience\nin place of true arguments.\n\n> Guess what I do with those Git garden shears' merges? Can you guess? Of\n> course you can. But you'll never know until I tell you. It is a little\n> silly to try to tell me that I do not have any experience with rebasing\n> merges when you have no idea what strategies I tried in the past.\n\nPlease notice that I never even started to discuss your 'merge'\ndirective, exactly because I believe you have huge experience both\nimplementing and using it that could be relied upon. Just don't mix-in\nrebasing merge commits into it, as that is fundamentally different\noperation.\n\nAnd the other unspoken strategies you tried are irrelevant here, as you\ndeclined the whole idea of replaying merge-the-commit instead of\nreplaying merge-the-operation until recently, and it seems you still do,\nat least to some level, by attempting to use 'merge' operation to replay\n\"the (merge) _commit_\". I'm afraid that whatever you've tried in the\npast likely suffered from the same conceptual confusion, and thus did\nnot work indeed.\n\nThat said, negative experience is still an experience, often helpful,\nbut what is relevant here is that it likely was not about rebasing merge\ncommits at all, so trying to use this irrelevant experience in the\ndiscussion to support your arguments, or rather lack of them, seems even\nmore unfair to me then using relevant experience for that purpose.\n\n> Now, Phillip's strategy is clearly the best strategy I ever heard\n> about,\n\nFor 'pick' vs 'merge', it's not about strategy, it's about concept. It\nlooks like you still believe that you somehow \"merge\" a merge commit\nwhen you actually rebase it (with Phillip's strategy if you wish). You\ndon't merge it anywhere, period.\n\n> and I am in the process of doing Actual Work to Put It To The Test.\n\nThat's the best outcome of the discussion I ever hoped for, seriously,\nand I'll be all ears to listen to the outcomes of the experience you\nwill gain with it.\n\nBTW, when you have it working, use the strategy you've implemented for\nnon-merge commits as well, as a good one should still work fine.\nMoreover, it should better bring exactly the same results as the default\nexisting strategy being used for non-merge commits, even in conflicting\nsituations.\n\nHopefully /that/ experience will finally push you strong enough to get\nthe concept right, and you will finally understand that what you've \nimplemented is nothing else but a _cherry-pick_ of a _merge commit_,\nthat reads simply _pick_, for brevity.\n\n-- Sergey\n"},{"id":"343569","messageId":"87y3i6ta4a.fsf@javad.com","threadId":"47864","inReplyTo":"nycvar.QRO.7.76.6.1803271456050.77@ZVAVAG-6OXH6DA.rhebcr.pbec.zvpebfbsg.pbz","subject":"Re: [RFC] Rebasing merges: a jorney to the ultimate solution(RoadClear)","fromName":"Sergey Organov","fromEmail":"sorganov@gmail.com","sentAt":"2018-04-02T06:07:01Z","receivedAt":"2018-04-02T06:07:10Z","isPatch":false,"sender":{"key":"sorganov@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8501568?v=4"},"body":"Hi Johannes,\n\nJohannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi Sergey,\n>\n\n[...]\n\n> In the parlance of your RFC v2, where you start with this history (which I\n> translated into the left-to-right notation that is used in pretty much all\n> of Git's own documentation about interactive rebases, which you apparently\n> either did not read, or chose *not* to imitate, creating yet another\n> unnecessary diversion):\n>\n>\n> - B1\n>      \\\n> - B2 - M\n\nFirst, it should rather be:\n\n- B1\n    \\\n     M\n    / \n- B2\n\nas RFC presents essentially symmetric approach and I'd like it to be\nexplicit. Representation in RFC simply saves some vertical\nspace: \n\n  M\n / \\\nB1  B2\n\nAnother reason to use it is that I liked to somehow indicate that this\nis about abstract DAG representation of Git history, not to be confused\nwith some actual practical Git history. So that, for example, the reader\ncan't be tempted to even try to assume that M has been necessarily\ncreated by \"git merge\" operation in the first place.\n\nThat said, I'm sorry if it upsets you. I'll stick to your preferred\nnotation below.\n\n>\n> You now insert U1 and U2 with trees identical to M:\n>\n> - B1 - U1\n>           \\\n> - B2 - U2 - M\n\n - B1 - U1 \n          \\\n           UM\n          / \n - B2 - U2\n\n_YES_. You've slightly screwed RFC as UM is not M anymore, having\ndifferent parents, but otherwise it's still right.\n\n> So U1 is essentially B2 cherry-picked on top of B1, and U2 is essentially\n> B1 cherry-picked on top of B2.\n\n_NO_. No any cherry-picking has been involved, and I see absolutely no\nreason to pretend there has, except to intentionally make otherwise\nsimple thing look tricky.\n\nU1 tree is still M tree, and U2 tree is still M tree, and UM tree is\nstill M tree. That's what actually matters from RFC POV.\n\n> These U1/U2 commits are now to be cherry-picked on top of the rebased B1'\n> and B2'. I spare you more diagrams, you get the idea.\n\n_YES_. Exactly 2 cherry-picks.\n\n> Now, the changes in U1/U2 *are* the changes of the merge parents, that's\n> how they were constructed.\n\nEither _YES_, or _NO_, depending on the exact meaning of the term \"the\nchanges of the merge parents\" you've used, but I suspect it's _NO_,\ntaking into account your further inferences.\n\nThe U1/U2 are constructed by simply duplicating the tree of the original\nmerge commit M and thus they represent the changes _to_ the merge\nparents B1/B2 introduced by M, and not the changes \"_of_ the merge\nparents\" B1/B2, provided the latter meant to have some relation to the\nchanges introduced by the merge parents B1/B2 themselves.\n\n>\n> Since they repeat what B1 and B2 are about,\n\n_NO_, they do not repeat what B1 and B2 are about at all. They rather\nrepresent what M is about. In other words, whatever B1 and B2 are about,\nthe RFC method doesn't care.\n\nAnd as this is fundamental misinterpretation of the RFC on your side, it\nstarts to be big _NO_ from now on...\n\n> and since B1'/B2' means they are rebased, and since U1'/U2' are *also*\n> rebased, but independently...\n>\n> \t...  you essentially have to rebase *every parent's changes\n> \ttwice*.\n\n_NO_. U1' is rebase of U1 (on top of B1'), and U2' is rebase of U2 (on\ntop of B2'). Each of U1/U2 is rebased only once.\n\n> The answer \"No\" to this is... astonishing.\n\nIt's still _NO_, sorry.\n\nIn fact, I could have said _NO_ the first time you started to assign\nsome arbitrary \"meaning\" to the commits, as RFC is about somewhat formal\nproof of the method, using already well-known operations on the DAG, and\nto criticize the RFC, you need to either find and show a _formal_\nmistake somewhere in the proof logic, or to show a use-case where it\nfails, as you did for RFC v1. Assigning arbitrary \"meaning\" to the DAG\nnodes and operations on them won't do the trick, sorry.\n\nI'd like to reach some agreement on formal correctness of the RFC first,\nand then discuss the meanings, the implementations, and other\nconsequences based on well-established formal base.\n\n-- Sergey\n"}]}