{"thread":{"id":"2987","subject":"RE: needs merge","startedAt":"2006-01-07T10:33:06Z","lastAt":"2006-01-10T05:21:08Z","messageCount":3,"participants":["Brown, Len","Junio C Hamano","Daniel Barkalow"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"14241","messageId":"F7DC2337C7631D4386A2DF6E8FB22B3005A1336F@hdsmsx401.amr.corp.intel.com","threadId":"2987","inReplyTo":null,"subject":"RE: needs merge","fromName":"Brown, Len","fromEmail":"len.brown@intel.com","sentAt":"2006-01-07T10:33:06Z","receivedAt":"2006-01-07T10:33:06Z","isPatch":false,"sender":{"key":"len.brown@intel.com","avatar":"https://gravatar.com/avatar/a091f34f66caadb51d85a8a496800c6ccae73737e2f45762373e6b8c55fa5dd6?d=mp&s=160"},"body":"yes, it did the right thing to the source.\n\nas a user, \"cute\" isn't the first word that comes to mind:-)\n\nthanks,\n-Len \n\n>-----Original Message-----\n>From: git-owner@vger.kernel.org \n>[mailto:git-owner@vger.kernel.org] On Behalf Of Junio C Hamano\n>Sent: Saturday, January 07, 2006 5:29 AM\n>To: Brown, Len\n>Cc: git@vger.kernel.org\n>Subject: Re: needs merge\n>\n>Len Brown <len.brown@intel.com> writes:\n>\n>> however, when i then merged that branch into another there seem to\n>> be some phantom conflicts on the very same files.\n>\n>First of all, does the final merge result look correct, without\n>conflict markers?  I've slurped from your tree and tried the\n>merge myself and it seems that both branches and the merge\n>result of these branches have the conflicting path the same way,\n>so I think it did the right thing for you, but I am just trying\n>to make sure.\n>\n>> Do I understand all this output to mean that git attempted two\n>> different merges, and discarded the 1st attempt in favor of \n>the second?\n>\n>Not really.  This is Fredrik's \"recursive\" merge in action.\n>\n>acpica (ed03f4) is merged into test (e3627f), but these two\n>branches have criss-cross merge history and there are two\n>equally valid common ancestors, 0aec63 and ed349a.\n>\n>What it did was first to find a merge between these two common\n>ancestors, during which it found conflicting merge on those\n>paths.\n>\n>It then used this merge result (with conflict markers still in\n>them!) as the \"virtual common ancestor\" to merge the ed03f4 and\n>e3627f commits; because both branches have resolved the\n>conflicting part the same way earlier, this three-way merge\n>cancels out the part that are marked with conflict markers in\n>the virtual common ancestor (this is the cutest part of Fredrik\n>merge algorithm).\n>\n>-\n>To unsubscribe from this list: send the line \"unsubscribe git\" in\n>the body of a message to majordomo@vger.kernel.org\n>More majordomo info at  http://vger.kernel.org/majordomo-info.html\n>\n"},{"id":"14263","messageId":"7vy81reoie.fsf@assigned-by-dhcp.cox.net","threadId":"2987","inReplyTo":"F7DC2337C7631D4386A2DF6E8FB22B3005A1336F@hdsmsx401.amr.corp.intel.com","subject":"Re: needs merge","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-07T21:06:49Z","receivedAt":"2006-01-07T21:06:49Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Brown, Len\" <len.brown@intel.com> writes:\n\n> yes, it did the right thing to the source.\n>\n> as a user, \"cute\" isn't the first word that comes to mind:-)\n\nFair enough.  I agree that it is rather unnerving from the\nuser's point of view, especially because the \"recursive merging\nof the ancestors\" part is not trivially obvious why it works.\n\nThe issue it tries to address (and the other merge strategy,\n\"resolve\", addresses a bit differently) is to detect when two\nsides of criss-cross merged branches resolved the same conflicts\ndifferently in the past.  When merging E and F in this ancestry\ngraph:\n\n             A----C---E----?\n            / \\  /        /\n           /   \\/        /\n          /    /\\       /\n         /    /  \\     /\n        O----B----D---F\n\nsuppose that A and B made conflicting modifications on path P, C\nand D resolved the conflicts by taking its own side, and E and F\nfurther made independent changes to the path.  \n\nWhen we try to merge E and F, if we happen to pick B as the\nmerge base, normal three-way merge between E and F using B as\nbase would say that E has change between B and C while F's\nversion stayed the same in the area that change touches, and you\nwould end up with merge result that is diff(D,F) on top of E.\nIf we used A, then the result would be diff(C,E) on top of F.\nDoing either of these silently is not desirable [*1*].\n\nWhen we use a tree that is an automerge (with conflict markers)\nbetween A and B as the merge base for E and F, what happens is\nthat the three-way merge notices the part with conflict markers\nas a whole is rewritten to one version in E and to another in F,\nremoves the original (which is the conflicting merge between A\nand B) and replaces that with conflicts between E and F with its\nown conflict markers, so decision to resolve the conflicting\nmerge between A and B which C and D resolved differently is\ngiven to the user who tries to merge E and F.\n\nIf C and D resolved the conflicting merge the same way, the\n\"phantom conflict\" you observed still happens while merging A\nand B to come up with the merge base tree, but the part will be\nrewritten the same way in both E and F, so the result will merge\ncleanly.\n\n[Footnote]\n\n*1* While I was trying out the above scenario, I noticed that\nresolve strategy does not notice this and ended up picking one\nancestor at random.  I think this is because case #16 covers\nonly the case where the path P is not changed between C and E\nand D and F, and case #11 must pick an ancestor and picks one at\nrandom.  Daniel, any thoughts on this?\n\n-- >8 --\n#!/bin/sh\n\nunset GIT_DIR GIT_OBJECT_DIRECTORY\ntest -d .git || {\n\techo Run this in a newly created empty directory please.\n\texit 1\n}\n\n: <<\\EOF\n\n\tCriss Cross Merge\n\n             A----C---E----?\n            / \\  /        /\n           /   \\/        /\n          /    /\\       /\n         /    /  \\     /\n        O----B----D---F\n\nEOF\n\ngit init-db\n\nfor l in a b c d e f g h i j k l m n o p q r s t u v w x y z\ndo\n\techo $l\ndone >testfile\ngit add testfile\ngit commit -m 'Initial'\ngit tag O\ngit branch bottom\ngit checkout -b top\ncp testfile testfile.orig\ntr 'm-p' 'M-P' <testfile.orig >testfile\ngit update-index testfile\ngit commit -m A\ngit tag A\ngit checkout bottom\ntr 'm-p' 'A-D' <testfile.orig >testfile\ngit update-index testfile\ngit commit -m B\ngit tag B\ngit merge -s ours 'D=A+B=B' HEAD A\ngit tag D\ngit checkout top\ngit merge -s ours 'C=A+B=A' HEAD B\ngit tag C\nmv testfile j; tr 'a' 'A' <j >testfile; rm -f j\ngit update-index testfile\ngit commit -m E\ngit tag E\ngit checkout bottom\nmv testfile j; tr 'z' 'Z' <j >testfile; rm -f j\ngit update-index testfile\ngit commit -m F\ngit tag F\n\nrm -f testfile.orig\n\ngit checkout master\ngit reset --hard A\ngit merge -s resolve V HEAD B\ngit update-index testfile\ngit commit -m 'V'\ngit tag V\n\ngit show-branch\n\ngit checkout top\necho \"** RECURSIVE **\"\ngit merge -s recursive recursive HEAD F\necho theirs\ngit diff --theirs\necho ours\ngit diff --ours\n\ngit reset --hard\necho \"** RESOLVE **\"\ngit merge -s resolve resolve HEAD F\n\necho theirs\ngit diff HEAD^2\necho ours\ngit diff HEAD^\n"},{"id":"14393","messageId":"Pine.LNX.4.64.0601092356400.25300@iabervon.org","threadId":"2987","inReplyTo":"7vy81reoie.fsf@assigned-by-dhcp.cox.net","subject":"Re: needs merge","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2006-01-10T05:21:08Z","receivedAt":"2006-01-10T05:21:08Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sat, 7 Jan 2006, Junio C Hamano wrote:\n\n> *1* While I was trying out the above scenario, I noticed that\n> resolve strategy does not notice this and ended up picking one\n> ancestor at random.  I think this is because case #16 covers\n> only the case where the path P is not changed between C and E\n> and D and F, and case #11 must pick an ancestor and picks one at\n> random.  Daniel, any thoughts on this?\n\nRight; in this case, we really want to use a merge program that takes \nmultiple ancestors and handles the equivalent to case #16 at the hunk \nlevel, but we don't have such a program available. Such a program would be \nable to identify whether case #16 ever actually occurs for a hunk, which \nis important because there will generally be a bunch of case #11s at the \nfile level, even if there aren't any reverts (if the common ancestors \ndisagreed before, and the two branches both changed the file to something \nentirely new, with no reverts, either ancestor is correct to use and the \nmerge result will be useful; we only need to be careful if there were \nreverts somewhere, which leads to the possibility of false sharing between \na branch and an ancestor, and thereby to ignoring the revert, and my \nfeeling is that rejecting case #11 with divergant ancestors would lead to \ntoo many conflicts to make crossing merges useable).\n\nOne possibility, actually, is to steal a trick from the recursive \nstrategy, and have a multi-ancestor merge program which merges all of the \nancestors with a merge-style diff (i.e., merge output, but on diff instead \nof diff3, with all differences being conflicts), and then uses the result \nas the ancestor for the three-way merge. It seems to me that this would \ncapture the central advantage of the recursive strategy without quite so \nmuch work. Or I might be completely wrong; I'm kind of worn out, and may \nnot be thinking clearly.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"}]}