{"thread":{"id":"17447","subject":"Newbie question regarding 3way merge order.","startedAt":"2009-01-29T22:25:00Z","lastAt":"2009-02-03T07:21:24Z","messageCount":16,"participants":["Raimund Berger","Sitaram Chamarty","Nanako Shiraishi","Junio C Hamano","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"102510","messageId":"871vulda2r.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":null,"subject":"Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-01-29T22:25:00Z","receivedAt":"2009-01-29T22:25:00Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"\nHi guys\n\nI got a dumb question for you to wholeheartedly laugh at, and to which\nthe answer seems to be so self evident. I'd still like a possibly\nauthoritative statement though, just for the books.\n\nThe question is whether a (3way) merge is commutative, purely in terms\nof content (i.e. disregarding commit history for now). Iow if no matter\nin which order I merge A and B, i.e. A into B or B into A, I'd be\nguaranteed to arrive at the same content.\n\nIf yes, a followup question would be if the merge machinery sitting\nbeneath rebase is exactly the same as that of a standard merge.\n\nThe reason I ask is obvious I guess. What basically interests me is if I\ngave a bunch of topic branches exposure on a test branch and, after\nresolving issues, applied them to stable, that I could be 100% sure to\nnot introduce new issues content wise just by applying merges in a\ndifferent order or form (rebase, patch set).\n\nThanks for feedback, Raimund.\n"},{"id":"102573","messageId":"87wscdaut9.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"871vulda2r.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-01-30T11:37:38Z","receivedAt":"2009-01-30T11:37:38Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"\n> The question is whether a (3way) merge is commutative, purely in terms\n> of content \n\nYes / No / Unknown ? \n"},{"id":"102630","messageId":"slrngo6eat.s1d.sitaramc@sitaramc.homelinux.net","threadId":"17447","inReplyTo":"871vulda2r.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Sitaram Chamarty","fromEmail":"sitaramc@gmail.com","sentAt":"2009-01-30T17:31:09Z","receivedAt":"2009-01-30T17:31:09Z","isPatch":false,"sender":{"key":"sitaramc@gmail.com","avatar":"https://avatars.githubusercontent.com/u/43316?v=4"},"body":"[replying only because no one else did; caveat reader!]\n\nOn 2009-01-29, Raimund Berger <raimund.berger@gmail.com> wrote:\n\n> The question is whether a (3way) merge is commutative, purely in terms\n> of content (i.e. disregarding commit history for now). Iow if no matter\n> in which order I merge A and B, i.e. A into B or B into A, I'd be\n> guaranteed to arrive at the same content.\n\nI'd say yes.  Finding the common ancestor and then applying\nthe differences from both sides are operations that do not\nappear to be order dependent.\n\n> If yes, a followup question would be if the merge machinery sitting\n> beneath rebase is exactly the same as that of a standard merge.\n\nThe merge \"machinery\" can be explicitly chosen using the\n\"-s\" (strategy) option, but for the same chosen strategy, I\nthink yes it would be the same for a merge as for a rebase.\n\n> The reason I ask is obvious I guess. What basically interests me is if I\n> gave a bunch of topic branches exposure on a test branch and, after\n> resolving issues, applied them to stable, that I could be 100% sure to\n> not introduce new issues content wise just by applying merges in a\n> different order or form (rebase, patch set).\n\nThat appears to be a different question than the one you\nstarted with.\n\nReversing A and B is one thing, applying a sequence of\nmerges in a different order is quite something else.\n"},{"id":"102638","messageId":"87vdrwbofv.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"slrngo6eat.s1d.sitaramc@sitaramc.homelinux.net","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-01-30T19:09:56Z","receivedAt":"2009-01-30T19:09:56Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"\nSitaram Chamarty <sitaramc@gmail.com> writes:\n\n> [replying only because no one else did; caveat reader!]\n>\n> On 2009-01-29, Raimund Berger <raimund.berger@gmail.com> wrote:\n>\n>> The question is whether a (3way) merge is commutative, purely in terms\n>> of content (i.e. disregarding commit history for now). Iow if no matter\n>> in which order I merge A and B, i.e. A into B or B into A, I'd be\n>> guaranteed to arrive at the same content.\n>\n> I'd say yes.  Finding the common ancestor and then applying\n> the differences from both sides are operations that do not\n> appear to be order dependent.\n\nThat's exactly the point which I'd like to have clarified.\n\nE.g. with A, B and ancestor C, the merging and conflict resolution\nalgorithm had to be completely symmetric if diff(A,C)+diff(B,C) applied\nto C should always be the same as diff(B,C)+diff(A,C) applied to C.\n\nSo I'm really asking if that is a fact upon which I can rely.\n\n>\n>> If yes, a followup question would be if the merge machinery sitting\n>> beneath rebase is exactly the same as that of a standard merge.\n>\n> The merge \"machinery\" can be explicitly chosen using the\n> \"-s\" (strategy) option, but for the same chosen strategy, I\n> think yes it would be the same for a merge as for a rebase.\n\nAn interesting hint. Up to now, I assumed that rebase would always\nperform implicit merging strategies. I mean what else would one expect\nin the above picture to happen when rebasing A on B? I'd assume it'd\nproduce the same tree as a merge of A into B, by employing exactly the\nsame machinery. E.g. fast forward of C to B, then merge A in. So that,\neffectively, the only difference between rebase and merge is just commit\nhistory but not (tree) content.\n\n>From reading the rebase man page though it seems that merging machinery\nhas to be explicitly requested via '-m'. Which makes me wonder how the\ndefault rebase actually works.\n\n>\n>> The reason I ask is obvious I guess. What basically interests me is if I\n>> gave a bunch of topic branches exposure on a test branch and, after\n>> resolving issues, applied them to stable, that I could be 100% sure to\n>> not introduce new issues content wise just by applying merges in a\n>> different order or form (rebase, patch set).\n>\n> That appears to be a different question than the one you\n> started with.\n>\n> Reversing A and B is one thing, applying a sequence of\n> merges in a different order is quite something else.\n\nMathematically speaking, if A1 and A2 commute with regard to a binary\noperation, A1 ... An do as well. So I'd still think the latter question\nboils down to the commutativity question above *iff* rebase actually\ndoes an implicit merge by default. Which I'm now led to question.\n\nThanks for you answer, much appreciated.\n"},{"id":"102665","messageId":"slrngo771p.b1i.sitaramc@sitaramc.homelinux.net","threadId":"17447","inReplyTo":"87vdrwbofv.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Sitaram Chamarty","fromEmail":"sitaramc@gmail.com","sentAt":"2009-01-31T00:32:57Z","receivedAt":"2009-01-31T00:32:57Z","isPatch":false,"sender":{"key":"sitaramc@gmail.com","avatar":"https://avatars.githubusercontent.com/u/43316?v=4"},"body":"On 2009-01-30, Raimund Berger <raimund.berger@gmail.com> wrote:\n\n> E.g. with A, B and ancestor C, the merging and conflict resolution\n> algorithm had to be completely symmetric if diff(A,C)+diff(B,C) applied\n> to C should always be the same as diff(B,C)+diff(A,C) applied to C.\n\n> So I'm really asking if that is a fact upon which I can rely.\n\nI've always relied on it :-)  Or, to put it another way,\nI've never come been bitten by this issue.\n\n> An interesting hint. Up to now, I assumed that rebase would always\n> perform implicit merging strategies. I mean what else would one expect\n\nIt does.\n\n> in the above picture to happen when rebasing A on B? I'd assume it'd\n> produce the same tree as a merge of A into B, by employing exactly the\n> same machinery. E.g. fast forward of C to B, then merge A in. So that,\n> effectively, the only difference between rebase and merge is just commit\n> history but not (tree) content.\n\nThis is also true.  For example, \"git help pull\" offers an\noption to use rebase instead of merge.\n\n> From reading the rebase man page though it seems that merging machinery\n> has to be explicitly requested via '-m'. Which makes me wonder how the\n> default rebase actually works.\n\nNo.  I think the documentation is not sufficiently clear.\nEverything else in \"git help rebase\" (look for the string\n\"strateg\") tells me that the default, if you don't specify\nanything at all, is the recursive merge strategy.  Since\n\"-s\" implies \"-m\", I'm not sure what -- if anything -- is\nachived by \"-m\" all by itself.\n\nWhen I get some time I'm planning to look at the test\nscripts and simulate them without \"-m\" to see what\ndifferences there are; I'd assume a test script set up to\ntest the proper operation of rebase --merge should be using\na test case whose result differs if you dont use --merge!\n\n> Mathematically speaking, if A1 and A2 commute with regard to a binary\n> operation, A1 ... An do as well. So I'd still think the latter question\n> boils down to the commutativity question above *iff* rebase actually\n> does an implicit merge by default. Which I'm now led to question.\n\nRebase *does* do an implicit merge by default (as far as the\ntree that results is concerned, which you mentioned right at\nthe start), I'm pretty sure of it.\n\nPerhaps someone with more git smarts will chip in with\nsomething more concrete.\n"},{"id":"102668","messageId":"20090131095724.6117@nanako3.lavabit.com","threadId":"17447","inReplyTo":"871vulda2r.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Nanako Shiraishi","fromEmail":"nanako3@lavabit.com","sentAt":"2009-01-31T00:57:24Z","receivedAt":"2009-01-31T00:57:24Z","isPatch":false,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting \"Raimund Berger\" <raimund.berger@gmail.com>:\n\n> The question is whether a (3way) merge is commutative, purely in terms\n> of content (i.e. disregarding commit history for now). Iow if no matter\n> in which order I merge A and B, i.e. A into B or B into A, I'd be\n> guaranteed to arrive at the same content.\n\nI think three-way merge of A into B and B into A will produce the same\nresult when the merge doesn't conflict (when it does, you will get the\nconflict markers and text from A and B in a different order depending on\nthe direction of the merge).\n\n> The reason I ask is obvious I guess. What basically interests me is if I\n> gave a bunch of topic branches exposure on a test branch and, after\n> resolving issues, applied them to stable, that I could be 100% sure to\n> not introduce new issues content wise just by applying merges in a\n> different order or form (rebase, patch set).\n\nI don't think you can make a blanket conclusion like that by only knowing\nthat merging A into B and merging B into A would produce the same result.\n\nIf you merge topics A, B, and C in this order into your current state O,\nthere may not be any conflict, but if you merge the same topics to the\nsame current state in different order, C, B and then A for example, you\nmay get conflicts that breaks the merge. The commutativeness only says\nthat merge of A into O will produce the same result as merge of O into A.\nIt doesn't say anything about what would happen when you merge B to O.\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"102693","messageId":"87r62jboth.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"20090131095724.6117@nanako3.lavabit.com","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-01-31T13:14:02Z","receivedAt":"2009-01-31T13:14:02Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"Nanako Shiraishi <nanako3@lavabit.com> writes:\n\n> Quoting \"Raimund Berger\" <raimund.berger@gmail.com>:\n>\n>> The question is whether a (3way) merge is commutative, purely in terms\n>> of content (i.e. disregarding commit history for now). Iow if no matter\n>> in which order I merge A and B, i.e. A into B or B into A, I'd be\n>> guaranteed to arrive at the same content.\n>\n> I think three-way merge of A into B and B into A will produce the same\n> result when the merge doesn't conflict (when it does, you will get the\n> conflict markers and text from A and B in a different order depending on\n> the direction of the merge).\n>\n>> The reason I ask is obvious I guess. What basically interests me is if I\n>> gave a bunch of topic branches exposure on a test branch and, after\n>> resolving issues, applied them to stable, that I could be 100% sure to\n>> not introduce new issues content wise just by applying merges in a\n>> different order or form (rebase, patch set).\n>\n> I don't think you can make a blanket conclusion like that by only knowing\n> that merging A into B and merging B into A would produce the same result.\n>\n> If you merge topics A, B, and C in this order into your current state O,\n> there may not be any conflict, but if you merge the same topics to the\n> same current state in different order, C, B and then A for example, you\n> may get conflicts that breaks the merge. The commutativeness only says\n> that merge of A into O will produce the same result as merge of O into A.\n> It doesn't say anything about what would happen when you merge B to O.\n\nThat's correct. Strictly speaking one would also have to verify\nassociativity. I.e. whether merge(merge(A,B),C) == merge(A,merge(B,C))\nfor all A,B,C.\n\nThanks for making an implicit point explicit. So a followup question\nwould be: is git's 3way merge associative?\n\n>From my pov people seem to assume it.\n"},{"id":"102695","messageId":"87myd7bo8f.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"slrngo771p.b1i.sitaramc@sitaramc.homelinux.net","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-01-31T13:26:40Z","receivedAt":"2009-01-31T13:26:40Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"Sitaram Chamarty <sitaramc@gmail.com> writes:\n\n[snip] ...\n\n> Rebase *does* do an implicit merge by default (as far as the\n> tree that results is concerned, which you mentioned right at\n> the start), I'm pretty sure of it.\n\nI'm myself, especially since a conflicting rebase leaves the index in an\n\"unmerged\" state. Much like a regular merge does. It's still all\nassumptions though, or maybe I'm missing documentation .... (?)\n\n> Perhaps someone with more git smarts will chip in with\n> something more concrete.\n\nThat'd really be awesome. I mean, it's ok for me to dig through source\ncode and find answers myself, but it would really save time if somebody\nwho knows for sure dropped a word or two.\n"},{"id":"102717","messageId":"20090201064543.6117@nanako3.lavabit.com","threadId":"17447","inReplyTo":"87myd7bo8f.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Nanako Shiraishi","fromEmail":"nanako3@lavabit.com","sentAt":"2009-01-31T21:45:43Z","receivedAt":"2009-01-31T21:45:43Z","isPatch":false,"sender":{"key":"nanako3@lavabit.com","avatar":"https://gravatar.com/avatar/3777b9e201c5883a62b1a6fdf7c53f2d712d1d80989146063ea861e33aad72a8?d=mp&s=160"},"body":"Quoting \"Raimund Berger\" <raimund.berger@gmail.com> writes:\n\n> I'm myself, especially since a conflicting rebase leaves the index in an\n> \"unmerged\" state. Much like a regular merge does. It's still all\n> assumptions though, or maybe I'm missing documentation .... (?)\n\nThe rebase command you run with neither -m nor -i option replays\nyour work on top of the upstream by running git-am with the --3way\noption.\n\nThis commit introduced the feature.\n\ncommit 7f59dbbb8f8d479c1d31453eac06ec765436a780\nAuthor: Junio C Hamano <junkio@cox.net>\nDate:   Mon Nov 14 00:41:53 2005 -0800\n\n    Rewrite rebase to use git-format-patch piped to git-am.\n    \n    The current rebase implementation finds commits in our tree but\n    not in the upstream tree using git-cherry, and tries to apply\n    them using git-cherry-pick (i.e. always use 3-way) one by one.\n    \n    Which is fine, but when some of the changes do not apply\n    cleanly, it punts, and punts badly.\n\n    [omitting the rest]\n\nThe message talks about what was wrong with the original, what\nbenefit it gives the users, and how to use it, but it doesn't\ndiscuss how the magic works in detail.\n\nJunio much later describes how it works, taking a real-world example\nin this message:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/46569/focus=46609\n\nIn short, it works by applying your changes as patches but when a\npatch doesn't apply it falls back to a simplified three-way merge.\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/100579/focus=100602\n\nI think Junio misremembered the history in his last message in the thread.\nHe says that rebase was originally a format-patch piped to am, but\nbefore the commit 7f59dbbb8f8d479c1d31453eac06ec765436a780 it was\ndone by a series of cherry-pick.\n\n-- \nNanako Shiraishi\nhttp://ivory.ap.teacup.com/nanako3/\n"},{"id":"102754","messageId":"87eiyib5y8.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"20090201064543.6117@nanako3.lavabit.com","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-02-01T14:13:51Z","receivedAt":"2009-02-01T14:13:51Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"Nanako Shiraishi <nanako3@lavabit.com> writes:\n\n> Quoting \"Raimund Berger\" <raimund.berger@gmail.com> writes:\n>\n>> I'm myself, especially since a conflicting rebase leaves the index in an\n>> \"unmerged\" state. Much like a regular merge does. It's still all\n>> assumptions though, or maybe I'm missing documentation .... (?)\n>\n> The rebase command you run with neither -m nor -i option replays\n> your work on top of the upstream by running git-am with the --3way\n> option.\n>\n> This commit introduced the feature.\n>\n> commit 7f59dbbb8f8d479c1d31453eac06ec765436a780\n> Author: Junio C Hamano <junkio@cox.net>\n> Date:   Mon Nov 14 00:41:53 2005 -0800\n>\n>     Rewrite rebase to use git-format-patch piped to git-am.\n>     \n>     The current rebase implementation finds commits in our tree but\n>     not in the upstream tree using git-cherry, and tries to apply\n>     them using git-cherry-pick (i.e. always use 3-way) one by one.\n>     \n>     Which is fine, but when some of the changes do not apply\n>     cleanly, it punts, and punts badly.\n>\n>     [omitting the rest]\n>\n> The message talks about what was wrong with the original, what\n> benefit it gives the users, and how to use it, but it doesn't\n> discuss how the magic works in detail.\n>\n> Junio much later describes how it works, taking a real-world example\n> in this message:\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/46569/focus=46609\n>\n> In short, it works by applying your changes as patches but when a\n> patch doesn't apply it falls back to a simplified three-way merge.\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/100579/focus=100602\n>\n> I think Junio misremembered the history in his last message in the thread.\n> He says that rebase was originally a format-patch piped to am, but\n> before the commit 7f59dbbb8f8d479c1d31453eac06ec765436a780 it was\n> done by a series of cherry-pick.\n\n\nUgh. OK, that really explains a lot alright. Especially that fundamental\nchange in rebase behavior makes it quite clear that the various\ntechniques for \"merging\" content might not be as consistent as I had\nhoped. In my ideal world they'd only differ in how they map out commit\nhistory, but obviously that's not the case.\n\nTo me, this really leaves questions open regarding a hassle free\nworkflow. Since one apparently can't be confident that conflict\nresolutions obtained in some testing or early integration branch will\neasily carry over to stable it looks like special measures need to be\ntaken, like strict observation of merge order/technique and employment\nof replay tools.\n\nSo serialization apparently can't entirely be lost, and where e.g. CVS\nkind of enforces it at an early stage through expensive branching it\nseems git still requires some of the same coordination just at a\ndifferent level resp. point in time.\n\nHey, thanks a bunch for taking the time carrying those links\ntogether. They've been very informative.\n"},{"id":"102762","messageId":"7vskmyt127.fsf@gitster.siamese.dyndns.org","threadId":"17447","inReplyTo":"slrngo6eat.s1d.sitaramc@sitaramc.homelinux.net","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-01T19:22:08Z","receivedAt":"2009-02-01T19:22:08Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Sitaram Chamarty <sitaramc@gmail.com> writes:\n\n> Reversing A and B is one thing, applying a sequence of\n> merges in a different order is quite something else.\n\nThis point is true in theory but I haven't found it to cause problems in\npractice.  Textual conflicts between topics do happen, but it does not\nhappen so often in overlapping areas across more than two topics that\nearlier resolutions to them cannot be reused by the rerere mechanism.\n\nSemantic conflicts and dependencies are harder to deal with.\n\nSuppose you have a topic to introduce feature A.  You propose an\nenhancement, validate what it does logically makes sense, queue it to the\ntesting integration branch and unleash it to the world for real world\ntesting.\n\n    ---o-------*     test integration branch\n      /       /\n     /       o       feature A\n    /       /\n   o---o---o---o---o mainline\n\nLater, you find out that there is a bug B, and your enhancement to\nimplement A does not work as intended when B triggers.\n\nYou could do two things.\n\n (1) You extend feature A topic and queue the fix there.\n\n    ---o-------*---*  test integration branch\n      /       /   /\n     /       o---o    feature A + bugfix B\n    /       /\n   o---o---o---o---o  mainline\n\n (2) Because B is an independent bug, you can have its own topic to fix it\n     and merge ot to test integration, planning to merge it later to\n     mainline independently from feature A topic.\n\n      ---o-------*---*   test integration branch\n        /       /   / \n       /       /   o     bugfix B\n      /       /   /\n     /       o   /       feature A\n    /       /   /\n   o---o---o---o---o     mainline\n\n\nNeither is satisfactory.\n\nThe former is bad because it takes hostage of a useful bugfix to the\nfeature.  Without adding the feature A, which may or may not be what\npeople want to have, you cannot merge the fix to the mainline.\n\nThe latter is better because bugfix B could independently be merged to\nmainline, but it risks you forgetting to merge it when you merge feature A\nto the mainline.  By the time you decide to merge feature A to the\nmainline, the test integration branch has had both for some time, and you\ndidn't seen the problem bug B causes to feature A there, but if you merge\nonly feature A but not fix B to the mainline, suddenly you have a buggy\nfeature on the mainline.\n\nThis is where you need to use the tool right to get the most out of it.\n\nYou could do this in addition to (2).\n\n (3) Because B is an independent bug, you can have its own topic to fix it\n     and merge it to the test integration, planning to merge it later to\n     mainline independently from feature A topic.  But you already know\n     feature A depends on bugfix B to work correctly, so you merge the fix\n     to the feature as well in advance.\n\n      ---o-------*---*   test integration branch\n        /       /   / \n       /       /   o     bugfix B\n      /       /   / \\\n     /       o-------*   feature A\n    /       /   /\n   o---o---o---o---o     mainline\n\nThis way, even if you later choose to merge feature A, forgetting that you\nhave to have bugfix B for it to work, to the mainline, the merge will\nbring in the necessary fix with it automatically.\n\n      ---o-------*---*   test integration branch\n        /       /   / \n       /       /   o     bugfix B\n      /       /   / \\\n     /       o-------*   feature A\n    /       /   /     \\\n   o---o---o---o---o---* mainline\n\nThis technique to resolve conflicts and dependencies early between topics\nto force a merge order to the mainline can be used not only to deal with\nsemantic conflicts but textual ones, too.  If two branches textually\ninteract badly, you prepare a consolidated topic between the two, so that\nyou can merge A alone, B alone, or A+B together to the mainline.\n\nIf you end up merging A first and then want to merge B later (or the other\nway around, merge B and then A), and if the second merge to the mainline\ncauses huge textual conflicts, you can instead merge the conslidated topic\nA+B to the mainline.\n"},{"id":"102806","messageId":"slrngockbi.vsa.sitaramc@sitaramc.homelinux.net","threadId":"17447","inReplyTo":"7vskmyt127.fsf@gitster.siamese.dyndns.org","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Sitaram Chamarty","fromEmail":"sitaramc@gmail.com","sentAt":"2009-02-02T01:50:42Z","receivedAt":"2009-02-02T01:50:42Z","isPatch":false,"sender":{"key":"sitaramc@gmail.com","avatar":"https://avatars.githubusercontent.com/u/43316?v=4"},"body":"On 2009-02-01, Junio C Hamano <gitster@pobox.com> wrote:\n> Sitaram Chamarty <sitaramc@gmail.com> writes:\n>\n>> Reversing A and B is one thing, applying a sequence of\n>> merges in a different order is quite something else.\n>\n> This point is true in theory but I haven't found it to cause problems in\n> practice.  Textual conflicts between topics do happen, but it does not\n> happen so often in overlapping areas across more than two topics that\n> earlier resolutions to them cannot be reused by the rerere mechanism.\n\n[snip]\n\n> to force a merge order to the mainline can be used not only to deal with\n> semantic conflicts but textual ones, too.  If two branches textually\n> interact badly, you prepare a consolidated topic between the two, so that\n> you can merge A alone, B alone, or A+B together to the mainline.\n>\n> If you end up merging A first and then want to merge B later (or the other\n> way around, merge B and then A), and if the second merge to the mainline\n> causes huge textual conflicts, you can instead merge the conslidated topic\n> A+B to the mainline.\n\nThanks; great explanation.  I notice you blogged it too, and\nsimilar to the \"Never merging back\" post, the message is: if\nsomething is (or is likely to be) an independent feature, it\nshould have its own branch and be merged into others as soon\nas it is known they need it.  (In that post, it was a random\ncrazy feature that one might normally dump into a customer\nbranch, here it's a bugfix B that you might naively dump\ninto feature A, but the basic logic is the same)\n"},{"id":"102868","messageId":"871vugc2c8.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"7vskmyt127.fsf@gitster.siamese.dyndns.org","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-02-02T14:58:47Z","receivedAt":"2009-02-02T14:58:47Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n[snip]\n\n> This is where you need to use the tool right to get the most out of it.\n>\n> You could do this in addition to (2).\n>\n>  (3) Because B is an independent bug, you can have its own topic to fix it\n>      and merge it to the test integration, planning to merge it later to\n>      mainline independently from feature A topic.  But you already know\n>      feature A depends on bugfix B to work correctly, so you merge the fix\n>      to the feature as well in advance.\n>\n>       ---o-------*---*   test integration branch\n>         /       /   / \n>        /       /   o     bugfix B\n>       /       /   / \\\n>      /       o-------*   feature A\n>     /       /   /\n>    o---o---o---o---o     mainline\n\nYou seem to suggest that juggling merges is possible in the exact way I\nwas inquiring about. So let me ask again:\n\nif M1 and M2 are merges and I define equality of merges (M1==M2) to be\n\n- M1 resolves automatically (on the textual level) iff (if and only if)\n  M2 does\n- if either resolves automatically, the tree produced by M1 is the same\n  as that of M2 (the tree SHAs are the same)\n\ndo the following conditions hold\n\n(i)  A+B == B+A for all commits A,B\n(ii) (A+B)+C == A+(B+C) for all A,B,C\n\nwhere \"+\" designates the standard git 3way merge?\n\n\n[snip]\n\n> If you end up merging A first and then want to merge B later (or the other\n> way around, merge B and then A), and if the second merge to the mainline\n> causes huge textual conflicts, you can instead merge the conslidated topic\n> A+B to the mainline.\n\nOne could imagine (corporate) policies though which might try to map\norganizational \"entities\" (tasks, teams, according responsibilities) to\nbranches. I.e. contexts where conflict resolution through merging might\nnot always be desired and they'd rather be sought on a branch, i.e. by\nproducing a commit on either branch which resolves a possible\nconflict. That's why I asked how rebase compares to merge and whether\nthe merge machinery underlying the former is exactly the same. I seem to\nunderstand by now though that it is not.\n"},{"id":"102871","messageId":"49871ADA.4080905@viscovery.net","threadId":"17447","inReplyTo":"871vugc2c8.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-02-02T16:10:02Z","receivedAt":"2009-02-02T16:10:02Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Please don't set Mail-Followup-To: here, and keep the Cc: list.\n\nRaimund Berger schrieb:\n> do the following conditions hold\n> \n> (i)  A+B == B+A for all commits A,B\n> (ii) (A+B)+C == A+(B+C) for all A,B,C\n> \n> where \"+\" designates the standard git 3way merge?\n\nI don't think that (ii) does holds in general.\n\n[ In the examples consider each letter/symbol on a line by itself; this\nsaves vertical space. ]\n\nStart with this (the merge base):\n\n\tf(a)\n\nand there are three topic branches growing from here:\nA makes this (rename f->g):\n\n\tg(a)\n\nB makes this (add another f):\n\n\tf(a)f(b)\n\nC makes this (renames a->c):\n\n\tf(c)\n\nThen A+B is\n\n\tg(a)f(b)\n\nA+C is\n\n\tg(c)\n\nB+C is\n\n\tf(c)f(b)\n\n(A+B)+C is\n\n\tg(c)f(b)\n\nbut A+(B+C) is ambiguous:\n\n\tg(c)f(b)\nor\n\tf(c)g(b)\n\n-- Hannes\n"},{"id":"102875","messageId":"87wsc8aenx.fsf@gigli.quasi.internal","threadId":"17447","inReplyTo":"49871ADA.4080905@viscovery.net","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Raimund Berger","fromEmail":"raimund.berger@gmail.com","sentAt":"2009-02-02T18:15:30Z","receivedAt":"2009-02-02T18:15:30Z","isPatch":false,"sender":{"key":"raimund.berger@gmail.com","avatar":null},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> Please don't set Mail-Followup-To: here, and keep the Cc: list.\n>\n> Raimund Berger schrieb:\n>> do the following conditions hold\n>> \n>> (i)  A+B == B+A for all commits A,B\n>> (ii) (A+B)+C == A+(B+C) for all A,B,C\n>> \n>> where \"+\" designates the standard git 3way merge?\n>\n> I don't think that (ii) does holds in general.\n>\n> [ In the examples consider each letter/symbol on a line by itself; this\n> saves vertical space. ]\n>\n> Start with this (the merge base):\n>\n> \tf(a)\n>\n> and there are three topic branches growing from here:\n> A makes this (rename f->g):\n>\n> \tg(a)\n>\n> B makes this (add another f):\n>\n> \tf(a)f(b)\n>\n> C makes this (renames a->c):\n>\n> \tf(c)\n>\n> Then A+B is\n>\n> \tg(a)f(b)\n>\n> A+C is\n>\n> \tg(c)\n>\n> B+C is\n>\n> \tf(c)f(b)\n>\n> (A+B)+C is\n>\n> \tg(c)f(b)\n>\n> but A+(B+C) is ambiguous:\n>\n> \tg(c)f(b)\n> or\n> \tf(c)g(b)\n>\n> -- Hannes\n\n\nAre you sure you're not making assumptions about \"obvious\" manual\nresolutions? E.g. I can't quite see how A+B, which is\n\n      g(a)----\n     /        \\\n f(a)          g(a)f(b) or f(a)f(b) ???\n     \\        /\n      f(a)f(b)\n\nwould not be flagged as a conflict regarding f(a) vs. g(a).\n\nNow, you may assume that because B leaves f(a) as it is while A changes\nf(a) into g(a) that both, that change and the addition of f(b) in B,\nshould survive the merge. But the actual algorithm couldn't possibly\nknow and decide that. Same goes for other merges you do there. In fact,\nin strict terms of how I defined equality, you didn't give a counter\nexample because neither (A+B)+C or A+(B+C) automatically resolve. It\nwould have been if one of them did.\n\nAnd that's why I specifically \"limited\" my equality relation to\nautomatic resolutions, to simplify the discussion and deal with kind of\nminimum requirements first. I didn't even mention that originally\nbecause I felt it was so obvious.\n\nSo only the next step would be looking at how manual resolutions play\ninto this, and while that might be fairly intuitive in the A+B == B+A\ncommutativity case, associativity of course is kind of a different\nballpark. Although I'd expect somebody intimately acquainted with\nmerging techniques capable of maybe giving a hint or two even in that\ncase.\n"},{"id":"102932","messageId":"4987F074.9040506@viscovery.net","threadId":"17447","inReplyTo":"87wsc8aenx.fsf@gigli.quasi.internal","subject":"Re: Newbie question regarding 3way merge order.","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-02-03T07:21:24Z","receivedAt":"2009-02-03T07:21:24Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Again: Don't set Mail-Followup-To and keep the Cc list if you want to\ncommunicate efficiently on this list.\n\nRaimund Berger schrieb:\n> Are you sure you're not making assumptions about \"obvious\" manual\n> resolutions? E.g. I can't quite see how A+B, which is\n> \n>       g(a)----\n>      /        \\\n>  f(a)          g(a)f(b) or f(a)f(b) ???\n>      \\        /\n>       f(a)f(b)\n> \n> would not be flagged as a conflict regarding f(a) vs. g(a).\n\nMy introductory sentence was probably not clear enough. I meant:\n\n  mergebase\tA\tB\tA+B\n\tf\tg\tf\tg\n\t(\t(\t(\t(\n\ta\ta\ta\ta\n\t)\t)\t)\t)\n\t\t\tf\tf\n\t\t\t(\t(\n\t\t\tb\tb\n\t\t\t)\t)\n\nThere is no conflict in A+B. But strctly speaking, this could be regarded\nas an ambiguous merge since the change f->g could be applied to two\nplaces. But if context is taken into consideration, then there is no\nconflict in practice.\n\n> And that's why I specifically \"limited\" my equality relation to\n> automatic resolutions, to simplify the discussion and deal with kind of\n> minimum requirements first. I didn't even mention that originally\n> because I felt it was so obvious.\n\nYes, it was so obvious, that I thought my statement about \"colums are\nlines\" and \"saving vertical space\" were obvious, too.\n\n-- Hannes\n"}]}