{"thread":{"id":"10196","subject":"confused about a conflict during octopus merging","startedAt":"2007-10-09T00:31:56Z","lastAt":"2007-10-09T09:47:48Z","messageCount":3,"participants":["martin f krafft","Linus Torvalds"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"55215","messageId":"20071009003156.GA30498@lapse.madduck.net","threadId":"10196","inReplyTo":null,"subject":"confused about a conflict during octopus merging","fromName":"martin f krafft","fromEmail":"madduck@madduck.net","sentAt":"2007-10-09T00:31:56Z","receivedAt":"2007-10-09T00:31:56Z","isPatch":false,"sender":{"key":"madduck@madduck.net","avatar":null},"body":"Dear list,\n\nI am a little confused why the following yields a conflict:\n\n$ git init\n$ touch a; git add a; git commit -ma\nCreated initial commit 0ba90cc: a\n 0 files changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 a\n\n  # create merger branch for later\n$ git branch merger\n\n  # create a file\n$ date > d; git add d; git commit -md1\nCreated commit 89d22eb: d\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 d\n\n  # branch off a second branch and populate it\n$ git checkout -b second\nSwitched to a new branch \"second\"\n$ touch b; git add b; git commit -mb\nCreated commit 7370737: b\n 0 files changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 b\n\n  # modify file changed in previous commit\n$ git checkout master\nSwitched to branch \"master\"\n$ date >> d; git add d; git commit -md2\nCreated commit bb5f1b4: d2\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\n\n\nNow the tree structure is\n\n  x -- master: d2\n  | x -- second: b\n  |/\n  x d1\n  |\n  x -- merger: a\n\n  # now octopus-merge master+second into merger\n$ git checkout merger\nSwitched to branch \"merger\"\n\n$ git merge master second\nTrying simple merge with bb5f1b4f3a8cbfcbc9dbc97cc823f3ca05db2db1\nTrying simple merge with 7370737ff3aa6540a425db015e194766d2cbda2e\nSimple merge did not work, trying automatic merge.\nAdded d in both, but differently.\nerror: Could not read .merge_file_mCwa4W\nERROR: Merge conflict in d\nfatal: merge program failed\nAutomatic merge failed; fix conflicts and then commit the result.\n\n\nI don't understand why these conflict. I mean, sure, it makes sense:\nafter merging master, file d is at d2. Now when merging second, it\ntries to replace d by its ancestor, d1.\n\nWhat I don't understand is why Git does not understand that commit\nd is part of the path of arriving at d2, so when 'second' is merged,\nGit *should* really see that the change to file d in 'second' (d1)\nis an ancestor of the already present d2 commit, and *not* conflict.\n\nWhat am I misunderstanding here?\n\nThanks,\n\n-- \nmartin;              (greetings from the heart of the sun.)\n  \\____ echo mailto: !#^.\"<*>\"|tr \"<*> mailto:\" net@madduck\n \n\"distrust all those who love you extremely\n upon a very slight acquaintance and without any visible reason.\"\n                                                  -- lord chesterfield\n \nspamtraps: madduck.bogus@madduck.net\n"},{"id":"55218","messageId":"alpine.LFD.0.999.0710081812200.4964@woody.linux-foundation.org","threadId":"10196","inReplyTo":"20071009003156.GA30498@lapse.madduck.net","subject":"Re: confused about a conflict during octopus merging","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2007-10-09T01:21:50Z","receivedAt":"2007-10-09T01:21:50Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 9 Oct 2007, martin f krafft wrote:\n> \n> I am a little confused why the following yields a conflict:\n\nOctopus merges are special. Don't use them unless you really know what \nyou're doing. And generally not even then ;)\n\n> $ git merge master second\n> Trying simple merge with bb5f1b4f3a8cbfcbc9dbc97cc823f3ca05db2db1\n> Trying simple merge with 7370737ff3aa6540a425db015e194766d2cbda2e\n> Simple merge did not work, trying automatic merge.\n> Added d in both, but differently.\n> error: Could not read .merge_file_mCwa4W\n> ERROR: Merge conflict in d\n> fatal: merge program failed\n> Automatic merge failed; fix conflicts and then commit the result.\n> \n> I don't understand why these conflict. I mean, sure, it makes sense:\n> after merging master, file d is at d2. Now when merging second, it\n> tries to replace d by its ancestor, d1.\n\nRight. It makes total sense, because an octopus merge is simply always \ngoing to create a whole new merge commit that goes through the sources one \nby one, and merges them in - and if you do that, then you get a conflict \nin \"d\".\n\n> What I don't understand is why Git does not understand that commit\n> d is part of the path of arriving at d2, so when 'second' is merged,\n> Git *should* really see that the change to file d in 'second' (d1)\n> is an ancestor of the already present d2 commit, and *not* conflict.\n> \n> What am I misunderstanding here?\n\nOctopus merges do *not* fast-forward. Maybe they should. But they don't.\n\nSo when the octopus merge starts merging in \"master\" into the \"merger\" \nbranch, it will *not* just fast-forward the branch to \"master\". Instead, \nif will generate a new tree that is basically the merged state: but that \nnew tree is *not* the same as the master commit, it's literally a merge of \nthe two branches - which in practice means that it has the same *content* \nas master, but it's not at that commit.\n\nSo that first stage of the octopus merge has gone fine, but it didn't \nreally do what you expected.\n\nAnd so now we have a half-way done octopus merge, with the first branch \nadded. Now it merges in the second branch (\"second\"), and it *still* has \nthe merge base being the original merge base, namely \"merger\".\n\nAnd from that standpoint, it really *is* a conflict. \n\nI do think that \n - octopus merges should probably refuse to happen when a branch isn't a \n   \"merge\" at all, but a fast-forward.\n*or*\n - we should make octopus-merges smarter, and for each branch that is a \n   fast-forward, it really just fast-forwards.\n\nbut I don't think the current behaviour is \"wrong\", it's just not what you \nexpected.\n\nIf you think of octopus merges as a really stupid thing where git will \nmindlessly do a three-way merge based on the *current* state with all the \nbranches you name, then you get the current octopus merge. You just \nexpected it to be smarter than it is, probably because you compare it to \nthe *real* merge.\n\n\t\tLinus\n"},{"id":"55246","messageId":"20071009094748.GA1158@lapse.madduck.net","threadId":"10196","inReplyTo":"alpine.LFD.0.999.0710081812200.4964@woody.linux-foundation.org","subject":"Re: confused about a conflict during octopus merging","fromName":"martin f krafft","fromEmail":"madduck@madduck.net","sentAt":"2007-10-09T09:47:48Z","receivedAt":"2007-10-09T09:47:48Z","isPatch":false,"sender":{"key":"madduck@madduck.net","avatar":null},"body":"Thanks, Linus, for taking your time to answer me. I truly appreciate\nit.\n\nalso sprach Linus Torvalds <torvalds@linux-foundation.org> [2007.10.09.0221 +0100]:\n> So when the octopus merge starts merging in \"master\" into the\n> \"merger\" branch, it will *not* just fast-forward the branch to\n> \"master\". Instead, if will generate a new tree that is basically\n> the merged state: but that new tree is *not* the same as the\n> master commit, it's literally a merge of the two branches - which\n> in practice means that it has the same *content* as master, but\n> it's not at that commit.\n\nOkay, this makes perfect sense.\n\n> And so now we have a half-way done octopus merge, with the first\n> branch added. Now it merges in the second branch (\"second\"), and\n> it *still* has the merge base being the original merge base,\n> namely \"merger\".\n> \n> And from that standpoint, it really *is* a conflict. \n\nI would have to agree with you: this is pretty exactly what's going\non.\n\nNow, I think Git could do better though. Fast-forwarding\noctopus merges, as you suggest, is one possible enhancement, but is\nthat the solution to my problem? Yes, but could we do better?\n\nCouldn't Git just ignore any commit it has already seen in this\noctopus merge? I think this is perfectly okay in terms of the\nresulting ancestry, it's really all about applying a commit to the\nworktree or not.\n\nRecall the original tree:\n\n  x -- master: d2\n  | x -- second: b\n  |/\n  x  d1\n  |\n  x -- merger: a\n\nNow after merging master, the tree is at the same state as it is at\nthe tip of master. The asterisk denotes that the commit is half-way\ndone:\n\n  x  c* (a+d1+d2)\n  |\\\n  | x -- master: d2\n  | | x -- second: b\n  | |/\n  | x  d1\n  |/\n  x  a\n\nNext, we merge second to create c2\n\n  x_ c2*  ((a+d1+d2)+(d1+b))\n  |\\ \\\n  | | |\n  | x-|- master: d2\n  | | |\n  | | x -- second: b\n  | |/\n  | x  d1\n  |/\n  x  a\n\n(yay ASCII art!)\n\nAt this point, the conflict happens, when Git tries to re-apply d1\nto the work tree. But since d1 is already in the ancestry of the\nnode into which we are merging, couldn't it just skip applying the\ncommit to the worktree?\n\n  x_ c  (a+d1+d2+b)\n  |\\ \\\n  | | |\n  | x-|- master: d2\n  | | |\n  | | x -- second: b\n  | |/\n  | x  d1\n  |/\n  x  a\n\nIf it does, then I think ordering of merges for an octopus becomes\nrelevant, but I'd say that's already the case.\n\nAnd I guess this is identical to fast-forwarding the branches...\njust seems like approaching it from another angle to me.\n\n> If you think of octopus merges as a really stupid thing where git\n> will mindlessly do a three-way merge based on the *current* state\n> with all the branches you name, then you get the current octopus\n> merge. You just expected it to be smarter than it is, probably\n> because you compare it to the *real* merge.\n\nNo, Git just raised the bar for expectations half-way up to the\nmoon In other words: you spoiled me so far; now I won't settle for\nless than perfection. :)\n\n-- \nmartin;              (greetings from the heart of the sun.)\n  \\____ echo mailto: !#^.\"<*>\"|tr \"<*> mailto:\" net@madduck\n \n\"however jewel-like the good will may be in its own right, there is\n a morally significant difference between rescuing someone from\n a burning building and dropping him from a twelfth-storey window\n while trying to rescue him.\"\n                                                       -- thomas nagel\n \nspamtraps: madduck.bogus@madduck.net\n"}]}