{"thread":{"id":"29742","subject":"4-way diff (base,ours,theirs,merged) to review merge results","startedAt":"2012-02-26T03:55:37Z","lastAt":"2012-02-26T09:05:14Z","messageCount":3,"participants":["Neal Kreitzinger","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"185447","messageId":"jicafn$gnj$1@dough.gmane.org","threadId":"29742","inReplyTo":null,"subject":"4-way diff (base,ours,theirs,merged) to review merge results","fromName":"Neal Kreitzinger","fromEmail":"neal@rsss.com","sentAt":"2012-02-26T03:55:37Z","receivedAt":"2012-02-26T03:55:37Z","isPatch":false,"sender":{"key":"neal@rsss.com","avatar":null},"body":"Combined diff only tells you what the merge result auto-resolved (with \nrerere turned off and no merge-conflicts) in comparison to \"ours\" and \n\"theirs\".  That only tells you what \"ours\" and \"theirs\" *had*, not what they \n*did* (or were trying to do).  You need the merge-base version to see what \n\"ours\" and \"theirs\" did.  Seeing what \"ours\" and \"theirs\" did will \nmuch-better tell you if \"merged\" did-the-right-thing or not.  What is the \nbest way to display a 4-way diff of merge-base, \"ours\", \"theirs\", and \n\"merged\" after a merge completes so you can review the \"merged\" results for \ncorrectness?\n\nBefore I try writing a script to dump the object-contents of the merge-base, \n\"ours\", \"theirs\", and \"merged\" versions of the-file-in-question to \nwork-files and then feed them to a 4-way diff for review, I would like to \nsee if someone already has a script or better-idea for this, or if git has \nsomething more straight-forward that already does-this-for-you.\n\nReason for this:\nIf \"ours\" has line-x and \"theirs\" does not have line-x, and \"merged\" does \nhave line-x you still have a mystery on your hands:\n\n(Combined diff)\nours:  has line-x\ntheirs (master):  does not have line-x\nmerged:  has line-x\nmerge-base (older master):  *may-or-may-not* have line-x\nconclusion:  I'm not very sure if \"merged\" should have line-x or not...\n\nBased on the combined-diff only, I don't know if \"merged\" should have line-x \nor not because I don't know if \"ours\" *added* line-x to the merge-base or if \n\"theirs\" *removed* line-x from the merge-base.  IOW, if \"theirs\" is master \nand \"ours\" is way-behind master then I pretty-much know I probably need to \ntake \"theirs\" because it has the latest-stuff.  However, I don't know if \n\"theirs\" took line-x out of master (and \"ours\" just has line-x because its \nold), or if line-x was never in master and \"ours\" really-needed to add it. \nHaving merge-base context allows for more accurate conclusions like this:\n\nours:  has line-x\ntheirs (master):  does not have line-x\nmerged:  has line-x\nmerge-base (older master):  has line-x\nconclusion:  I should probably take line-x out of \"merged\"\n\nours:  has line-x\ntheirs (master):  does not have line-x\nmerged:  has line-x\nmerge-base:  does not have line-x\nconclusion:  I should probably keep line-x in \"merged\"\n\nThanks in advance for you feedback.\n\nv/r,\nneal \n"},{"id":"185449","messageId":"7vpqd2f1yg.fsf@alter.siamese.dyndns.org","threadId":"29742","inReplyTo":"jicafn$gnj$1@dough.gmane.org","subject":"Re: 4-way diff (base,ours,theirs,merged) to review merge results","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-02-26T08:12:07Z","receivedAt":"2012-02-26T08:12:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Neal Kreitzinger\" <neal@rsss.com> writes:\n\n> (Combined diff)\n> ours:  has line-x\n> theirs (master):  does not have line-x\n> merged:  has line-x\n> merge-base (older master):  *may-or-may-not* have line-x\n> conclusion:  I'm not very sure if \"merged\" should have line-x or not...\n\nWhen I need this information to resolve a merge in an area of the code\nthat I am not very familiar with, the first thing I do is this:\n\n  $ git merge $other\n  $ git diff\n  ... yikes, that is a complex conflict!\n\n  $ git checkout --conflict=diff3 $the_path_with_difficult_conflict\n  $ git diff\n\nThe output will also show the lines from the merge base.\n\nThe default style of showing the conflict we use is called the \"merge\"\nstyle (it originally came from the \"merge\" program of the RCS suite), and\nit only gives the two sides without the base version.  It is sufficient\nwhen the person who is making the merge is familiar with the baseline\nhistory of the code (e.g. in a contributor-to-integrator pull based\nworkflow, especially when contributors are encouraged to keep their topics\nfocused and short). The \"diff3\" style that also gives the base version is\nneeded less often in such a setting. That, and also the resulting output\nis much shorter, is the reason why \"merge\" style is the default.\n\nWhen the person who is making the merge is not very familiar with the\nbaseline history (e.g. when using Git as an improved CVS and a contributor\npulls the updated upstream into his history), however, \"diff3\" style may\nbe more often helpful---as you mentioned, \"merge\" style requires that you\nknow your code well enough to either already know or be able to guess how\nthe version in the merge base looked like, but by definition, pulling the\nupdated upstream into your work will pull more stuff (because many other\npeople are working on the code on the other side) than pulling one topic\nfrom a contributor into the integrator tree, so there may be more need to\nsee the version from the merge base in such a workflow.\n\nBy setting the configuration variable \"merge.conflictstyle\" to \"diff3\",\nyou would get the base version by default whenever there is a conflict.\n"},{"id":"185451","messageId":"7vd392ezhx.fsf@alter.siamese.dyndns.org","threadId":"29742","inReplyTo":"jicafn$gnj$1@dough.gmane.org","subject":"Re: 4-way diff (base,ours,theirs,merged) to review merge results","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-02-26T09:05:14Z","receivedAt":"2012-02-26T09:05:14Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Neal Kreitzinger\" <neal@rsss.com> writes:\n\n> ....  What is the \n> best way to display a 4-way diff of merge-base, \"ours\", \"theirs\", and \n> \"merged\" after a merge completes so you can review the \"merged\" results for \n> correctness?\n\nAhh, sorry.  While everything I wrote in my previous reply is correct with\nrespect to what happens _during_ a merge until you resolve it, I did not\nrealize that you were asking how to view a merge _after_ it is made.\n\nFor a two-parent merge $M, \"git show --cc $M\" runs a three-way diff\nbetween $M (merge result), $M^1 (the first parent) and $M^2 (the other\nparent) and the combined diff it shows is equivalent to:\n\n  $ git diff --cc $M $M^1 $M^2\n\nNotice the order of parameters. Unlike a normal \"diff A B\" to ask the\ncommand to explain how the state B is reached from state A, you give the\nresult $M and ask the command to explain how it was reached from other\nstates.\n\nSo in a similar way, running\n\n  $ git diff --cc $M $M^1 $M^2 $(git merge-base $M^1 $M^2)\n\nshould show a combined patch that explains the state at $M relative to the\nstates recorded in its parents and the merge base.\n\nI've never tried it myself, though, as I never needed such an operation.\n\nYou can try a trivial example with 4d9e079, which merges 583c389 ec7ff5b\nand has conflicts in cache.h\n\n$ git show 4d9e079 -- cache.h\nOutput omitted; you can see it is the same as the next one for yourself.\n\n$ git diff --cc 4d9e079 583c389 ec7ff5b -- cache.h\ndiff --cc cache.h\nindex 3a8e125,24732e6..422c5cf\n--- a/cache.h\n+++ b/cache.h\n@@@ -1177,7 -1176,7 +1177,8 @@@ extern void setup_pager(void)\n  extern const char *pager_program;\n  extern int pager_in_use(void);\n  extern int pager_use_color;\n +extern int term_columns(void);\n+ extern int decimal_width(int);\n  \n  extern const char *editor_program;\n  extern const char *askpass_program;\n\nOne side adds term_columns, the other side adds decimal_width.\n\n$ git diff --cc 4d9e079 583c389 ec7ff5b \\\n    $(git merge-base 583c389 ec7ff5b) -- cache.h\ndiff --cc cache.h\nindex 3a8e125,24732e6,9bd8c2d..422c5cf\n--- a/cache.h\n+++ b/cache.h\n@@@@ -1177,7 -1176,7 -1176,6 +1177,8 @@@@ extern void setup_pager(void)\n   extern const char *pager_program;\n   extern int pager_in_use(void);\n   extern int pager_use_color;\n ++extern int term_columns(void);\n+ +extern int decimal_width(int);\n   \n   extern const char *editor_program;\n   extern const char *askpass_program;\n\nThe third column is a diff between $M and $(git merge-base $M^1 $M^2); the\nresulting two new lines are indeed shown as additions against the merge\nbase.\n"}]}