{"thread":{"id":"12063","subject":"Merge-Recursive Improvements","startedAt":"2008-02-12T22:16:33Z","lastAt":"2008-02-18T11:33:36Z","messageCount":23,"participants":["Voltage Spike","Stefan Monnier","Junio C Hamano","Linus Torvalds","Johannes Schindelin","Johannes Sixt","Steffen Prohaska"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"68560","messageId":"A21B3CA8-6240-434F-87A9-C6F76DA15265@gmail.com","threadId":"12063","inReplyTo":null,"subject":"Merge-Recursive Improvements","fromName":"Voltage Spike","fromEmail":"voltspike@gmail.com","sentAt":"2008-02-12T22:16:33Z","receivedAt":"2008-02-12T22:16:33Z","isPatch":false,"sender":{"key":"voltspike@gmail.com","avatar":null},"body":"I would like to make a series of significant improvements to the\nmerge-recursive mechanism in git, but I was hoping to solicit some early\nfeedback before submitting patches.\n\nFirst, git is overly zealous at merging differences and two functions  \nadded\nat the same point in a file become intertwined during the merge. A  \ntrivial\nexample of this behavior:\n\n   <<<<<<< HEAD:file.txt\n   void newfunc1()\n   =======\n   void newfunc2()\n   >>>>>>> merge:file.txt\n   {\n     int err;\n   <<<<<<< HEAD:file.txt\n     err = doSomething();\n   =======\n     err = doSomethingElse();\n   >>>>>>> merge:file.txt\n\nSecond, git doesn't tell me the original code inside the conflict  \nmarkers so\nI almost always resort to \"MERGE_HEAD...ORIG_HEAD\" and\n\"ORIG_HEAD...MERGE_HEAD\" diffs to see what was going on. I could use an\nexternal diff tool (yuck), but I would like to modify the conflict  \nmarkers\nto resemble those of Perforce:\n\n   >>>>>>> merge-base:file.txt\n   Original code.\n   ======= HEAD:file.txt\n   Head code.\n   ======= merge:file.txt\n   Merged code.\n   <<<<<<<\n\nThird, git doesn't appear to have any sense of context when performing a\nmerge. Another contrived example which wouldn't be flagged as a merge\nconflict:\n\n   ptr = malloc(len); // Added in HEAD.\n   init();            // Included in merge-base.\n   ptr = malloc(len); // Added in \"merge\".\n\nFourth, git doesn't provide a mechanism for merges to ignore whitespace\nchanges.\n\nI resolved issues the first and the fourth through the introduction  \nof new\nconfiguration variables and trivial modifications to the manner in  \nwhich we\ncall xdl_merge. I suspect the second and third issue may also be  \nsimple to\nsolve but would require that I modify libxdiff directly.\n\nAre these changes something other people might be interested in? (It  \nseems\nodd that nobody is complaining about these really irritating flaws.)  \nShould\nI concern myself with writing a custom merge driver rather than  \nmodify core\nbehavior (even if the change is configurable)?  If I should focus on an\nexternal driver, under what circumstances would merge.*.recursive  \ncome into\nplay (i.e., when do I have to worry about poor behavior for an \"internal\nmerge\")?\n\nThank you in advance for the feedback.\n"},{"id":"68565","messageId":"jwv3arxairx.fsf-monnier+gmane.comp.version-control.git@gnu.org","threadId":"12063","inReplyTo":"A21B3CA8-6240-434F-87A9-C6F76DA15265@gmail.com","subject":"Re: Merge-Recursive Improvements","fromName":"Stefan Monnier","fromEmail":"monnier@iro.umontreal.ca","sentAt":"2008-02-12T23:03:00Z","receivedAt":"2008-02-12T23:03:00Z","isPatch":false,"sender":{"key":"monnier@iro.umontreal.ca","avatar":null},"body":"> \"ORIG_HEAD...MERGE_HEAD\" diffs to see what was going on. I could use an\n> external diff tool (yuck), but I would like to modify the conflict markers\n> to resemble those of Perforce:\n\n>>>>>>>> merge-base:file.txt\n>   Original code.\n>   ======= HEAD:file.txt\n>   Head code.\n>   ======= merge:file.txt\n>   Merged code.\n>   <<<<<<<\n\nHaving such 3-parts conflicts helps tremendously when you have to do\nthe merge by hand, so I'm 100% in favor of such a change.\n\nBUT Please, please, pretty please, don't follow Perforce who blindly\ndisregards previous standards.  Instead use the format used by diff3\nwhich has been there for ages:\n\n   <<<<<<< foo\n   original text\n   ||||||| bar\n   ancestor\n   =======\n   new text\n   >>>>>>> baz\n\n> Third, git doesn't appear to have any sense of context when performing a\n> merge. Another contrived example which wouldn't be flagged as a merge\n> conflict:\n\n>   ptr = malloc(len); // Added in HEAD.\n>   init();            // Included in merge-base.\n>   ptr = malloc(len); // Added in \"merge\".\n\nYes, that's nasty.\n\n> Fourth, git doesn't provide a mechanism for merges to ignore whitespace\n> changes.\n\nI can live with that.  As long as the conflict is clearly marked with\nall 3 parts, I can use any external tool I want to resolve the conflict.\n\n\n        Stefan\n"},{"id":"68567","messageId":"7vodal22js.fsf@gitster.siamese.dyndns.org","threadId":"12063","inReplyTo":"A21B3CA8-6240-434F-87A9-C6F76DA15265@gmail.com","subject":"Re: Merge-Recursive Improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-12T23:11:19Z","receivedAt":"2008-02-12T23:11:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Voltage Spike <voltspike@gmail.com> writes:\n\n> I would like to make a series of significant improvements to the\n> merge-recursive mechanism in git, but I was hoping to solicit some early\n> feedback before submitting patches.\n>\n> First, git is overly zealous at merging differences and two functions\n> added\n> at the same point in a file become intertwined during the merge. A\n> trivial\n> example of this behavior:\n>\n>   <<<<<<< HEAD:file.txt\n>   void newfunc1()\n>   =======\n>   void newfunc2()\n>   >>>>>>> merge:file.txt\n>   {\n>     int err;\n>   <<<<<<< HEAD:file.txt\n>     err = doSomething();\n>   =======\n>     err = doSomethingElse();\n>   >>>>>>> merge:file.txt\n\nThis lacks illustration of what you change that example to, which\nmakes the proposal harder to judge.\n\nI suspect you are saying that you would want to coalesce\nadjacent hunks that have too small number of lines between '>>>'\nof the previous hunk and '<<<' of the current hunk by duplicate\nthe common hunks, like this:\n\n   <<<<<<< HEAD:file.txt\n   void newfunc1()\n   {\n     int err;\n     err = doSomething();\n   =======\n   void newfunc2()\n   {\n     int err;\n     err = doSomethingElse();\n   >>>>>>> merge:file.txt\n\n(here, two lines that are \"{\" and \"int err;\" are taken as \"too small\").\n\nI think it makes sense.\n\n> Second, git doesn't tell me the original code inside the conflict\n>\n>   >>>>>>> merge-base:file.txt\n>   Original code.\n>   ======= HEAD:file.txt\n>   Head code.\n>   ======= merge:file.txt\n>   Merged code.\n>   <<<<<<<\n\nThis is a much harder sell, as external tool like git-mergetool\nthat inspect the result depend on the current output.\n\nAnd it is not as useful as an alternative.\n\nIn case you did not know, you can get a much better picture by:\n\n    $ git log --left-right -p --merge\n\nbecause you would then see not just the merge base version but\nthe changes _and the reasons for the changes_ in between.\n\n> Third, git doesn't appear to have any sense of context when performing a\n> merge. Another contrived example which wouldn't be flagged as a merge\n> conflict:\n>\n>   ptr = malloc(len); // Added in HEAD.\n>   init();            // Included in merge-base.\n>   ptr = malloc(len); // Added in \"merge\".\n\nAre you saying it a problem to report or not to report?  In\neither case, I decline to comment on this one, as I do not have\na strong opinion either way.\n\n> Fourth, git doesn't provide a mechanism for merges to ignore whitespace\n> changes.\n\nThat would be a good change.\n\nI can immediately say that 1 and 4 are worthwhile things to do,\nas long as they are contained to xdl_merge().  It would help\nother users of the merge logic.\n\nI've started working on rewriting revert to directly use\nxdl_merge(), bypassing major parts of merge-recursive, and I\nimagine such a change you propose would be useful without\naffecting the callers.\n"},{"id":"68571","messageId":"alpine.LFD.1.00.0802121544370.2920@woody.linux-foundation.org","threadId":"12063","inReplyTo":"A21B3CA8-6240-434F-87A9-C6F76DA15265@gmail.com","subject":"Re: Merge-Recursive Improvements","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-02-12T23:48:06Z","receivedAt":"2008-02-12T23:48:06Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Tue, 12 Feb 2008, Voltage Spike wrote:\n> \n> First, git is overly zealous at merging differences and two functions added\n> at the same point in a file become intertwined during the merge. A trivial\n> example of this behavior:\n\nHmm. Have you tested what happens if you use XDL_MERGE_EAGER instead of \nXDL_MERGE_ZEALOUS in the \"level\" argument to xdl_merge() in \nmerge-recursive.c?\n\n(No, I didn't test it myself, but it may get you the behaviour you want, \nand we could make it a config option for people who want a less aggressive \nmerge)\n\n\t\t\tLinus\n"},{"id":"68573","messageId":"alpine.LSU.1.00.0802130003370.3870@racer.site","threadId":"12063","inReplyTo":"alpine.LFD.1.00.0802121544370.2920@woody.linux-foundation.org","subject":"Re: Merge-Recursive Improvements","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-13T00:05:41Z","receivedAt":"2008-02-13T00:05:41Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 12 Feb 2008, Linus Torvalds wrote:\n\n> On Tue, 12 Feb 2008, Voltage Spike wrote:\n> > \n> > First, git is overly zealous at merging differences and two functions \n> > added at the same point in a file become intertwined during the merge. \n> > A trivial example of this behavior:\n> \n> Hmm. Have you tested what happens if you use XDL_MERGE_EAGER instead of \n> XDL_MERGE_ZEALOUS in the \"level\" argument to xdl_merge() in \n> merge-recursive.c?\n> \n> (No, I didn't test it myself, but it may get you the behaviour you want, \n> and we could make it a config option for people who want a less \n> aggressive merge)\n\nActually, I have this in my ever-growing TODO:\n\nXDL_MERGE_ZEALOUS_ALNUM: require an alnum in the common code; otherwise do \nnot de-conflict it.\n\nIn other words, if there is a hunk consisting of conflicting lines, which \nare identical, but have no letter and no number in it, then keep them as \nconflicts.\n\nBut I never got around to try it.\n\nCiao,\nDscho\n"},{"id":"68585","messageId":"alpine.LSU.1.00.0802130108060.3870@racer.site","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802130003370.3870@racer.site","subject":"[PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-13T01:10:04Z","receivedAt":"2008-02-13T01:10:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen a merge conflicts, there are often common lines that are not really\ncommon, such as empty lines or lines containing a single curly bracket.\n\nWith XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a\nhunk does not contain any letters or digits, it is treated as conflicting.\n\nIn other words, a conflict which used to look like this:\n\n\t<<<<<<<\n\tif (a == 1)\n\t=======\n\tif (a == 2)\n\t>>>>>>>\n\t{\n\t<<<<<<<\n\t\tb = 2;\n\t=======\n\t\tb = 1;\n\t>>>>>>>\n\nwill look like this with ZEALOUS_ALNUM:\n\n\t<<<<<<<\n\tif (a == 1)\n\t{\n\t\tb = 2;\n\t=======\n\tif (a == 2)\n\t{\n\t\tb = 1;\n\t>>>>>>>\n\nTo demonstrate this, git-merge-file has been switched from\nXDL_MERGE_ZEALOUS to XDL_MERGE_ZEALOUS_ALNUM.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tOn Wed, 13 Feb 2008, Johannes Schindelin wrote:\n\n\t> On Tue, 12 Feb 2008, Linus Torvalds wrote:\n\t> \n\t> > On Tue, 12 Feb 2008, Voltage Spike wrote:\n\t> > > \n\t> > > First, git is overly zealous at merging differences and two \n\t> > > functions added at the same point in a file become \n\t> > > intertwined during the merge.  A trivial example of this \n\t> > > behavior:\n\t> > \n\t> > Hmm. Have you tested what happens if you use XDL_MERGE_EAGER \n\t> > instead of XDL_MERGE_ZEALOUS in the \"level\" argument to \n\t> > xdl_merge() in merge-recursive.c?\n\t> > \n\t> > (No, I didn't test it myself, but it may get you the behaviour \n\t> > you want, and we could make it a config option for people who \n\t> > want a less aggressive merge)\n\t> \n\t> Actually, I have this in my ever-growing TODO:\n\t> \n\t> XDL_MERGE_ZEALOUS_ALNUM: require an alnum in the common code; \n\t> otherwise do not de-conflict it.\n\t> \n\t> In other words, if there is a hunk consisting of conflicting \n\t> lines, which are identical, but have no letter and no number in \n\t> it, then keep them as conflicts.\n\t> \n\t> But I never got around to try it.\n\n\tI just could not resist.  But now I HEAD for bed.\n\n builtin-merge-file.c  |    2 +-\n t/t6023-merge-file.sh |   40 ++++++++++++++++++++++++++++++++++\n xdiff/xdiff.h         |    1 +\n xdiff/xmerge.c        |   57 +++++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 99 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-merge-file.c b/builtin-merge-file.c\nindex 58deb62..adce6d4 100644\n--- a/builtin-merge-file.c\n+++ b/builtin-merge-file.c\n@@ -46,7 +46,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t}\n \n \tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xpp, XDL_MERGE_ZEALOUS, &result);\n+\t\t\t&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);\n \n \tfor (i = 0; i < 3; i++)\n \t\tfree(mmfs[i].ptr);\ndiff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh\nindex 8641996..7e72b8d 100755\n--- a/t/t6023-merge-file.sh\n+++ b/t/t6023-merge-file.sh\n@@ -139,4 +139,44 @@ test_expect_success 'binary files cannot be merged' '\n \tgrep \"Cannot merge binary files\" merge.err\n '\n \n+cat > a1.c << EOF\n+int main()\n+{\n+\treturn 1;\n+}\n+EOF\n+\n+cat > a2.c << EOF\n+int main2()\n+{\n+\treturn 0;\n+}\n+EOF\n+\n+cat > a3.c << EOF\n+int main3()\n+{\n+\treturn 2;\n+}\n+EOF\n+\n+cat > expect << EOF\n+<<<<<<< a2.c\n+int main2()\n+{\n+\treturn 0;\n+}\n+=======\n+int main3()\n+{\n+\treturn 2;\n+}\n+>>>>>>> a3.c\n+EOF\n+\n+test_expect_success 'ZEALOUS_ALNUM' '\n+\t! git merge-file -p a2.c a1.c a3.c > merge.out &&\n+\tgit diff expect merge.out\n+'\n+\n test_done\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex c00ddaa..413082e 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -53,6 +53,7 @@ extern \"C\" {\n #define XDL_MERGE_MINIMAL 0\n #define XDL_MERGE_EAGER 1\n #define XDL_MERGE_ZEALOUS 2\n+#define XDL_MERGE_ZEALOUS_ALNUM 3\n \n typedef struct s_mmfile {\n \tchar *ptr;\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex b83b334..330121b 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -248,10 +248,63 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,\n \treturn 0;\n }\n \n+static int line_contains_alnum(const char *ptr, long size)\n+{\n+\twhile (size--)\n+\t\tif (isalnum(*(ptr++)))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n+static int lines_contain_alnum(xdfenv_t *xe, int i, int chg)\n+{\n+\tfor (; chg; chg--, i++)\n+\t\tif (line_contains_alnum(xe->xdf2.recs[i]->ptr,\n+\t\t\t\txe->xdf2.recs[i]->size))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n+/*\n+ * This function merges m and m->next, marking everything between those hunks\n+ * as conflicting, too.\n+ */\n+static void xdl_merge_two_conflicts(xdmerge_t *m)\n+{\n+\txdmerge_t *next_m = m->next;\n+\tm->chg1 += next_m->i1 + next_m->chg1 - m->i1;\n+\tm->chg2 += next_m->i2 + next_m->chg2 - m->i2;\n+\tm->next = next_m->next;\n+\tfree(next_m);\n+}\n+\n+static int xdl_non_alnum_conflicts(xdfenv_t *xe1, xdmerge_t *m)\n+{\n+\tint result = 0;\n+\n+\tfor (;;) {\n+\t\txdmerge_t *next_m = m->next;\n+\n+\t\tif (!next_m)\n+\t\t\treturn result;\n+\n+\t\tif (lines_contain_alnum(xe1, m->i1 + m->chg1,\n+\t\t\t\tnext_m->i1 + next_m->chg1 - 1\n+\t\t\t\t- m->i1 - m->chg1))\n+\t\t\tm = next_m;\n+\t\telse {\n+\t\t\tresult++;\n+\t\t\txdl_merge_two_conflicts(m);\n+\t\t}\n+\t}\n+}\n+\n /*\n  * level == 0: mark all overlapping changes as conflict\n  * level == 1: mark overlapping changes as conflict only if not identical\n  * level == 2: analyze non-identical changes for minimal conflict set\n+ * level == 3: analyze non-identical changes for minimal conflict set, but\n+ *             treat hunks not containing any letter or number as conflicting\n  *\n  * returns < 0 on error, == 0 for no conflicts, else number of conflicts\n  */\n@@ -359,6 +412,10 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t\txdl_cleanup_merge(changes);\n \t\treturn -1;\n \t}\n+\tif (level > 2 && xdl_non_alnum_conflicts(xe1, changes) < 0) {\n+\t\txdl_cleanup_merge(changes);\n+\t\treturn -1;\n+\t}\n \t/* output */\n \tif (result) {\n \t\tint size = xdl_fill_merge_buffer(xe1, name1, xe2, name2,\n-- \n1.5.4.1.1321.g633fc8\n"},{"id":"68589","messageId":"7v3arxzlke.fsf@gitster.siamese.dyndns.org","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802130108060.3870@racer.site","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-13T01:34:09Z","receivedAt":"2008-02-13T01:34:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> When a merge conflicts, there are often common lines that are not really\n> common, such as empty lines or lines containing a single curly bracket.\n>\n> With XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a\n> hunk does not contain any letters or digits, it is treated as conflicting.\n\nI like the general direction.\n\nThis might need to be loosened further if we want to cover\nVoltage's case where the inconveniently common hunk had another\nline, \"int err;\", which had alnums.  Perhaps we would want to\nsay \"max N alnums\" instead of \"no alnums\".\n"},{"id":"68594","messageId":"alpine.LFD.1.00.0802121758220.2920@woody.linux-foundation.org","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802130108060.3870@racer.site","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-02-13T02:06:37Z","receivedAt":"2008-02-13T02:06:37Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Wed, 13 Feb 2008, Johannes Schindelin wrote:\n> \n> With XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a\n> hunk does not contain any letters or digits, it is treated as conflicting.\n\nWell, I think this is interesting in itself, but..\n\nTo some degree it would be even more interesting to at least partially \nseparate the issue of \"what conflicts\" with the issue of \"how do we \nexpress things when they _do_ conflict\".\n\nIOW, it's quite possible that we want to have the ZEALOUS algorithm for \ndoing conflict resolution (on the assumption that we want aggressively \nmerge), but then when conflicts happen _despite_ being zealous in the \nresolver, print out the resulting conflict with near-by conflicts merged \ninto bigger block.\n\n> In other words, a conflict which used to look like this:\n> \n> \t<<<<<<<\n> \tif (a == 1)\n> \t=======\n> \tif (a == 2)\n> \t>>>>>>>\n> \t{\n> \t<<<<<<<\n> \t\tb = 2;\n> \t=======\n> \t\tb = 1;\n> \t>>>>>>>\n> \n> will look like this with ZEALOUS_ALNUM:\n> \n> \t<<<<<<<\n> \tif (a == 1)\n> \t{\n> \t\tb = 2;\n> \t=======\n> \tif (a == 2)\n> \t{\n> \t\tb = 1;\n> \t>>>>>>>\n\nI think this is an improvement already, but to take the example that \nvoltspike had:\n\n <<<<<<< HEAD:file.txt\n void newfunc1()\n =======\n void newfunc2()\n >>>>>>> merge:file.txt\n {\n   int err;\n <<<<<<< HEAD:file.txt\n   err = doSomething();\n =======\n   err = doSomethingElse();\n >>>>>>> merge:file.txt\n\nthis does have alnum's in the shared region (\"int err\") so it wouldn't \nhave been modified by this, but it would be nice to notice: \"there were \njust two small lines between two conflicts, and we could actually make the \nfinal conflict marker _smaller_ by merging them\", and just doing the \nreverse of xdl_refine_conflicts(), and do a \"xdl_merge_conflicts()\" before \nprintout, and get\n\n <<<<<<< HEAD:file.txt\n void newfunc1()\n {\n   int err;\n   err = doSomething();\n =======\n void newfunc2()\n {\n   int err;\n   err = doSomethingElse();\n >>>>>>> merge:file.txt\n\n(note how this really *is* smaller: it's 11 lines rather than 12 lines, \nbecause while we had to duplicate the two common lines in between the \nconflicts (+2), we got rid of the three marker lines (-3), giving us a net \nwin of one line.\n\nSo the \"merge adjacent conflicts\" logic should actually be pretty simple: \nif there is less than three lines between two conflicts, the conflicts \nshould always be merged, because the end result is smaller.\n\n(And with three lines in between the end result is as many lines, but \narguably simpler, so it's probably better to merge then too).\n\nHmm? What do you think?\n\n\t\t\tLinus\n"},{"id":"68603","messageId":"47B29EBF.7060607@viscovery.net","threadId":"12063","inReplyTo":"A21B3CA8-6240-434F-87A9-C6F76DA15265@gmail.com","subject":"Re: Merge-Recursive Improvements","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-02-13T07:39:43Z","receivedAt":"2008-02-13T07:39:43Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Voltage Spike schrieb:\n> Third, git doesn't appear to have any sense of context when performing a\n> merge. Another contrived example which wouldn't be flagged as a merge\n> conflict:\n> \n>   ptr = malloc(len); // Added in HEAD.\n>   init();            // Included in merge-base.\n>   ptr = malloc(len); // Added in \"merge\".\n\nYou seem to say that you want this to result in a merge conflict.\n\nI'm opposed to this: It means that you would mark a conflict if there is a\nsingle unchanged line between the two changes that come from the merged\nbranches. So far it has happened for me much more frequently that such\nmerges were correct, and I should not be bothered with conflict markers. I\nconciously prefer to pay the price that such a merge is incorrect on occasion.\n\nYou also need to draw a border line: a single unchanged line between the\nchanges? Or better also conflict at 2 lines? Or 3?\n\n-- Hannes\n"},{"id":"68609","messageId":"BE8E2652-6FB7-46F8-ACE7-1F5141F0E504@zib.de","threadId":"12063","inReplyTo":"47B29EBF.7060607@viscovery.net","subject":"Re: Merge-Recursive Improvements","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2008-02-13T08:17:45Z","receivedAt":"2008-02-13T08:17:45Z","isPatch":false,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Feb 13, 2008, at 8:39 AM, Johannes Sixt wrote:\n\n> Voltage Spike schrieb:\n>> Third, git doesn't appear to have any sense of context when  \n>> performing a\n>> merge. Another contrived example which wouldn't be flagged as a merge\n>> conflict:\n>>\n>>   ptr = malloc(len); // Added in HEAD.\n>>   init();            // Included in merge-base.\n>>   ptr = malloc(len); // Added in \"merge\".\n>\n> You seem to say that you want this to result in a merge conflict.\n>\n> I'm opposed to this: It means that you would mark a conflict if  \n> there is a\n> single unchanged line between the two changes that come from the  \n> merged\n> branches. So far it has happened for me much more frequently that such\n> merges were correct, and I should not be bothered with conflict  \n> markers. I\n> conciously prefer to pay the price that such a merge is incorrect  \n> on occasion.\n>\n> You also need to draw a border line: a single unchanged line  \n> between the\n> changes? Or better also conflict at 2 lines? Or 3?\n\nMaybe git could try various numbers and print a certainty\nmeasure that tells the user how far appart non-conflicting\nchanges are.  If changes are near git would print a low\ncertainty and the user could decide to review the merge in\nmore detail than he would usually do.\n\n\tSteffen\n"},{"id":"68610","messageId":"E105587B-9E61-4A21-91F5-6310A83C3F41@gmail.com","threadId":"12063","inReplyTo":"47B29EBF.7060607@viscovery.net","subject":"Re: Merge-Recursive Improvements","fromName":"Voltage Spike","fromEmail":"voltspike@gmail.com","sentAt":"2008-02-13T08:21:36Z","receivedAt":"2008-02-13T08:21:36Z","isPatch":false,"sender":{"key":"voltspike@gmail.com","avatar":null},"body":"On Feb 13, 2008, at 12:39 AM, Johannes Sixt wrote:\n\n> Voltage Spike schrieb:\n>> Third, git doesn't appear to have any sense of context when  \n>> performing a\n>> merge. Another contrived example which wouldn't be flagged as a merge\n>> conflict:\n>>\n>>   ptr = malloc(len); // Added in HEAD.\n>>   init();            // Included in merge-base.\n>>   ptr = malloc(len); // Added in \"merge\".\n>\n> You seem to say that you want this to result in a merge conflict.\n\nYes, it appears that I wasn't clear that I see the above as a conflict.\n\n> I'm opposed to this: It means that you would mark a conflict if  \n> there is a\n> single unchanged line between the two changes that come from the  \n> merged\n> branches. So far it has happened for me much more frequently that such\n> merges were correct, and I should not be bothered with conflict  \n> markers. I\n> conciously prefer to pay the price that such a merge is incorrect  \n> on occasion.\n\nThat is why I'm hoping to make it configurable. I know that we have  \nmore information than during a simple patch, but it seems odd that  \nchanges can be occurring all around your local modifications and  \nyou'll never be notified.\n\nWhich leads to a different point: does this lessen the value of  \nfalling back to a 3-way merge during a rebase?\n\n> You also need to draw a border line: a single unchanged line  \n> between the\n> changes? Or better also conflict at 2 lines? Or 3?\n\nI naturally assumed the default number of context lines: 3. If I  \nrecall correctly, this isn't typically configurable.\n"},{"id":"68614","messageId":"47B2AE6B.2030700@viscovery.net","threadId":"12063","inReplyTo":"E105587B-9E61-4A21-91F5-6310A83C3F41@gmail.com","subject":"Re: Merge-Recursive Improvements","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2008-02-13T08:46:35Z","receivedAt":"2008-02-13T08:46:35Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Voltage Spike schrieb:\n> On Feb 13, 2008, at 12:39 AM, Johannes Sixt wrote:\n> \n>> Voltage Spike schrieb:\n>>> Third, git doesn't appear to have any sense of context when performing a\n>>> merge. Another contrived example which wouldn't be flagged as a merge\n>>> conflict:\n>>>\n>>>   ptr = malloc(len); // Added in HEAD.\n>>>   init();            // Included in merge-base.\n>>>   ptr = malloc(len); // Added in \"merge\".\n>>\n>> You seem to say that you want this to result in a merge conflict.\n> \n> Yes, it appears that I wasn't clear that I see the above as a conflict.\n> \n>> I'm opposed to this: It means that you would mark a conflict if there\n>> is a\n>> single unchanged line between the two changes that come from the merged\n>> branches. So far it has happened for me much more frequently that such\n>> merges were correct, and I should not be bothered with conflict\n>> markers. I\n>> conciously prefer to pay the price that such a merge is incorrect on\n>> occasion.\n> \n> That is why I'm hoping to make it configurable. I know that we have more\n> information than during a simple patch, but it seems odd that changes\n> can be occurring all around your local modifications and you'll never be\n> notified.\n> \n> Which leads to a different point: does this lessen the value of falling\n> back to a 3-way merge during a rebase?\n\nThe current non-conflicting merges are invaluable for my workflow, which\ninvolves lots and lots of rebasing and cherry-picking.\n\n>> You also need to draw a border line: a single unchanged line between the\n>> changes? Or better also conflict at 2 lines? Or 3?\n> \n> I naturally assumed the default number of context lines: 3. If I recall\n> correctly, this isn't typically configurable.\n\nNawww... Guess how many, many more conflicts this would report?\n\nPractically all merges that I do are during rebase and cherry-pick. During\nthis work I often have changes that are separated by only a single line.\nThe potential merge conflicts that fall in the above category I know in\nadvance because I've made the changes just two minutes ago, and I can fix\nthem even without being reminded by a merge conflict.\n\nIOW: I don't need conflict markers in this case - I need them not to\nconflict at all.\n\n-- Hannes\n"},{"id":"68630","messageId":"alpine.LSU.1.00.0802131113360.30505@racer.site","threadId":"12063","inReplyTo":"7v3arxzlke.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-13T11:16:20Z","receivedAt":"2008-02-13T11:16:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 12 Feb 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > When a merge conflicts, there are often common lines that are not \n> > really common, such as empty lines or lines containing a single curly \n> > bracket.\n> >\n> > With XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a \n> > hunk does not contain any letters or digits, it is treated as \n> > conflicting.\n> \n> I like the general direction.\n> \n> This might need to be loosened further if we want to cover Voltage's \n> case where the inconveniently common hunk had another line, \"int err;\", \n> which had alnums.  Perhaps we would want to say \"max N alnums\" instead \n> of \"no alnums\".\n\nMaybe even both.  \n\nAs Linus has stated in the other reply, up to three lines between two \nconflicts could be \"merged\" with the conflicts by default, because less or \nequally much screen estate would used.\n\nSo I am thinking about an interface that is not too painful.\n\nCiao,\nDscho\n"},{"id":"68631","messageId":"alpine.LSU.1.00.0802131116370.30505@racer.site","threadId":"12063","inReplyTo":"alpine.LFD.1.00.0802121758220.2920@woody.linux-foundation.org","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-13T11:22:04Z","receivedAt":"2008-02-13T11:22:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 12 Feb 2008, Linus Torvalds wrote:\n\n> On Wed, 13 Feb 2008, Johannes Schindelin wrote:\n> > \n> > With XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a \n> > hunk does not contain any letters or digits, it is treated as \n> > conflicting.\n> \n> [...]\n> \n> So the \"merge adjacent conflicts\" logic should actually be pretty \n> simple: if there is less than three lines between two conflicts, the \n> conflicts should always be merged, because the end result is smaller.\n> \n> (And with three lines in between the end result is as many lines, but \n> arguably simpler, so it's probably better to merge then too).\n> \n> Hmm? What do you think?\n\nMakes sense.  As I said to Junio, I'll think about an interface to do \nthis.  The obvious choice is to have a struct, but that has to be memset() \nto 0 for future compatibility.\n\nOTOH there's xpparam_t already, and we could just have that as a member of \nthe new struct, something like\n\ntypedef struct s_xmergeparam {\n\txpparam_t xpp;\n\tenum {\n\t\tXDL_MERGE_MINIMAL = 0,\n\t\tXDL_MERGE_EAGER,\n\t\tXDL_MERGE_ZEALOUS,\n\t\tXDL_MERGE_ZEALOUS_ALNUM\n\t} mode;\n\t/* minimum number of inter-conflict lines goes here */\n} xmergeparam_t;\n\nHmm.  This has to simmer in my head a bit.\n\nCiao,\nDscho\n"},{"id":"68822","messageId":"7vlk5mgm5y.fsf@gitster.siamese.dyndns.org","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802131113360.30505@racer.site","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-15T17:32:57Z","receivedAt":"2008-02-15T17:32:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Maybe even both.  \n>\n> As Linus has stated in the other reply, up to three lines between two \n> conflicts could be \"merged\" with the conflicts by default, because less or \n> equally much screen estate would used.\n>\n> So I am thinking about an interface that is not too painful.\n\nI think there is no excuse not to coalesce hunks separated by\nthree lines or less, so we can first get immediate improvement\nwithout any configuration or tweaking.  My \"less than N alnums\"\nwas ill thought out overengineering, and Linus's improvement is\nmuch cleaner.\n"},{"id":"68826","messageId":"alpine.LFD.1.00.0802151012380.3066@woody.linux-foundation.org","threadId":"12063","inReplyTo":"7vlk5mgm5y.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Linus Torvalds","fromEmail":"torvalds@linux-foundation.org","sentAt":"2008-02-15T18:17:06Z","receivedAt":"2008-02-15T18:17:06Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Fri, 15 Feb 2008, Junio C Hamano wrote:\n> \n> I think there is no excuse not to coalesce hunks separated by\n> three lines or less\n\nWell, I think the two line limit is the \"unquestionable\" one, since that's \nthe one that actually results in fewer lines over-all. \n\nThe three-line case gets a bit less obvious since the line count doesn't \nchange, and if the unchanged lines are complex, it might well be better to \nleave them as shared. What's not uncommon at all is that you have a small \nchange that results in a new variable or similar, and then it's quite \npossible that the first conflict comes from a new variable declaration, \nand the second conflict is the \"real code\" change, and if there are three \ncomplex lines in between, it probably makes sense to keep them unmodified, \nand have two much simpler choices.\n\nIn fact, in many ways, maybe we'd be better off counting (non-space) bytes \nrather than lines. That gets the \"complexity\" argument mostly right.\n\n\t\t\tLinus\n"},{"id":"68827","messageId":"alpine.LSU.1.00.0802151823110.30505@racer.site","threadId":"12063","inReplyTo":"alpine.LFD.1.00.0802151012380.3066@woody.linux-foundation.org","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-15T18:23:42Z","receivedAt":"2008-02-15T18:23:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 15 Feb 2008, Linus Torvalds wrote:\n\n> In fact, in many ways, maybe we'd be better off counting (non-space) \n> bytes rather than lines. That gets the \"complexity\" argument mostly \n> right.\n\nI don't like it.  It's not simple enough.  Let's stay with 3 lines, and if \nit turns out to be a bad choice, change it to two.\n\nCiao,\nDscho\n"},{"id":"68834","messageId":"7v63wqgh5i.fsf@gitster.siamese.dyndns.org","threadId":"12063","inReplyTo":"47B29EBF.7060607@viscovery.net","subject":"Re: Merge-Recursive Improvements","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-15T19:21:13Z","receivedAt":"2008-02-15T19:21:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Sixt <j.sixt@viscovery.net> writes:\n\n> Voltage Spike schrieb:\n>> Third, git doesn't appear to have any sense of context when performing a\n>> merge. Another contrived example which wouldn't be flagged as a merge\n>> conflict:\n>> \n>>   ptr = malloc(len); // Added in HEAD.\n>>   init();            // Included in merge-base.\n>>   ptr = malloc(len); // Added in \"merge\".\n>\n> You seem to say that you want this to result in a merge conflict.\n>\n> I'm opposed to this: It means that you would mark a conflict if there is a\n> single unchanged line between the two changes that come from the merged\n> branches. So far it has happened for me much more frequently that such\n> merges were correct, and I should not be bothered with conflict markers. I\n> conciously prefer to pay the price that such a merge is incorrect on occasion.\n\nActually I think we really should mark this as conflict.  The\ntool should resolve only the most unquestionable cases and keep\nhumans in the loop to validate the result if there is any\nuncertainty.  Resolving the above example automatically without\nwarning is most likely a problem waiting to happen.\n\nSuch a merge being more often correct than not is not an\nargument for resolving them silently.  It's rare mismerge cases\nthat will bite you later, and we should really be careful,\nespecially when a mismerge is less common.\n"},{"id":"69023","messageId":"alpine.LSU.1.00.0802171816150.30505@racer.site","threadId":"12063","inReplyTo":"alpine.LFD.1.00.0802151012380.3066@woody.linux-foundation.org","subject":"Re: [PATCH] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-17T19:06:41Z","receivedAt":"2008-02-17T19:06:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 15 Feb 2008, Linus Torvalds wrote:\n\n> On Fri, 15 Feb 2008, Junio C Hamano wrote:\n> > \n> > I think there is no excuse not to coalesce hunks separated by three \n> > lines or less\n> \n> Well, I think the two line limit is the \"unquestionable\" one, since \n> that's the one that actually results in fewer lines over-all.\n\nWell, I hit a problem.  It is visible in t7201-co.sh:\n\nSuppose you have these files\n\nnew1\torig\tnew2\n1\t1\t1\n2\t2\t3\n3\t3\t4\n4\t4\t5\n5\t5\t6\n7\t6\t7\n8\t7\t8\n\t8\n\nIn other words: if the \"6\" was removed in the first case, and the \"2\" in \nthe second case, all of a sudden changes which were not really conflicting \n(if one side was unchanged, it is considered a resolvable \"conflict\") now \n_will_ conflict.\n\nIn the upcoming patch, I now restrict this merging of conflicts to \nnon-resolvable conflicts only.\n\nWill send it out shortly.\n\nCiao,\nDscho\n"},{"id":"69024","messageId":"alpine.LSU.1.00.0802171906590.30505@racer.site","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802171816150.30505@racer.site","subject":"[PATCH 1/2] xdl_merge(): make XDL_MERGE_ZEALOUS output simpler","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-17T19:07:19Z","receivedAt":"2008-02-17T19:07:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen a merge conflicts, there are often less than three common lines\nbetween two conflicting regions.\n\nSince a conflict takes up as many lines as are conflicting, plus three\nlines for the commit markers,  the output will be shorter (and thus,\nsimpler) in this case, if the common lines will be merged into the\nconflicting regions.\n\nThis patch merges up to three common lines into the conflicts.\n\nFor example, what looked like this before this patch:\n\n\t<<<<<<<\n\tif (a == 1)\n\t=======\n\tif (a != 0)\n\t>>>>>>>\n\t{\n\t\tint i;\n\t<<<<<<<\n\t\ta = 0;\n\t=======\n\t\ta = !a;\n\t>>>>>>>\n\nwill now look like this:\n\n\t<<<<<<<\n\tif (a == 1)\n\t{\n\t\tint i;\n\t\ta = 0;\n\t=======\n\tif (a != 0)\n\t{\n\t\tint i;\n\t\ta = !a;\n\t>>>>>>>\n\nSuggested Linus (based on ideas by \"Voltage Spike\" -- if that name is\nreal, it is mighty cool).\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6023-merge-file.sh |   10 ++++++++++\n xdiff/xmerge.c        |   47 ++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 56 insertions(+), 1 deletions(-)\n\ndiff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh\nindex 8641996..869e8d5 100755\n--- a/t/t6023-merge-file.sh\n+++ b/t/t6023-merge-file.sh\n@@ -139,4 +139,14 @@ test_expect_success 'binary files cannot be merged' '\n \tgrep \"Cannot merge binary files\" merge.err\n '\n \n+sed -e \"s/deerit.$/deerit;/\" -e \"s/me;$/me./\" < new5.txt > new6.txt\n+sed -e \"s/deerit.$/deerit,/\" -e \"s/me;$/me,/\" < new5.txt > new7.txt\n+\n+test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '\n+\n+\t! git merge-file -p new6.txt new5.txt new7.txt > output &&\n+\ttest 1 = $(grep ======= < output | wc -l)\n+\n+'\n+\n test_done\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex b83b334..9cd448c 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -249,6 +249,49 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,\n }\n \n /*\n+ * This function merges m and m->next, marking everything between those hunks\n+ * as conflicting, too.\n+ */\n+static void xdl_merge_two_conflicts(xdmerge_t *m)\n+{\n+\txdmerge_t *next_m = m->next;\n+\tm->chg1 = next_m->i1 + next_m->chg1 - m->i1;\n+\tm->chg2 = next_m->i2 + next_m->chg2 - m->i2;\n+\tm->next = next_m->next;\n+\tfree(next_m);\n+}\n+\n+/*\n+ * If there are less than 3 non-conflicting lines between conflicts,\n+ * it appears simpler -- because it takes up less (or as many) lines --\n+ * if the lines are moved into the conflicts.\n+ */\n+static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)\n+{\n+\tint result = 0;\n+\n+\tif (!m)\n+\t\treturn result;\n+\tfor (;;) {\n+\t\txdmerge_t *next_m = m->next;\n+\t\tint begin, end;\n+\n+\t\tif (!next_m)\n+\t\t\treturn result;\n+\n+\t\tbegin = m->i1 + m->chg1;\n+\t\tend = next_m->i1;\n+\n+\t\tif (m->mode != 0 || next_m->mode != 0 || end - begin > 3)\n+\t\t\tm = next_m;\n+\t\telse {\n+\t\t\tresult++;\n+\t\t\txdl_merge_two_conflicts(m);\n+\t\t}\n+\t}\n+}\n+\n+/*\n  * level == 0: mark all overlapping changes as conflict\n  * level == 1: mark overlapping changes as conflict only if not identical\n  * level == 2: analyze non-identical changes for minimal conflict set\n@@ -355,7 +398,9 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \tif (!changes)\n \t\tchanges = c;\n \t/* refine conflicts */\n-\tif (level > 1 && xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0) {\n+\tif (level > 1 &&\n+\t\t\t(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||\n+\t\t\t xdl_simplify_non_conflicts(xe1, changes) < 0)) {\n \t\txdl_cleanup_merge(changes);\n \t\treturn -1;\n \t}\n-- \n1.5.4.1.1396.g177d-dirty\n"},{"id":"69025","messageId":"alpine.LSU.1.00.0802171907310.30505@racer.site","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802171906590.30505@racer.site","subject":"[PATCH(RFC) 2/2] xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-17T19:07:40Z","receivedAt":"2008-02-17T19:07:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nWhen a merge conflicts, there are often common lines that are not really\ncommon, such as empty lines or lines containing a single curly bracket.\n\nWith XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a\nhunk does not contain any letters or digits, it is treated as conflicting.\n\nIn other words, a conflict which used to look like this:\n\n\t<<<<<<<\n\t\t\t\t\ta = 1;\n\t=======\n\t\t\t\t\toutput();\n\t>>>>>>>\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t<<<<<<<\n\t\toutput();\n\t=======\n\t\tb = 1;\n\t>>>>>>>\n\nwill look like this with ZEALOUS_ALNUM:\n\n\t<<<<<<<\n\t\t\t\t\ta = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\toutput();\n\t=======\n\t\t\t\t\toutput();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tb = 1;\n\t>>>>>>>\n\nTo demonstrate this, git-merge-file has been switched from\nXDL_MERGE_ZEALOUS to XDL_MERGE_ZEALOUS_ALNUM.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nConflicts:\n\n\tt/t6023-merge-file.sh\n---\n builtin-merge-file.c  |    2 +-\n t/t6023-merge-file.sh |   10 ++++++++++\n xdiff/xdiff.h         |    1 +\n xdiff/xmerge.c        |   31 ++++++++++++++++++++++++++++---\n 4 files changed, 40 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-merge-file.c b/builtin-merge-file.c\nindex 58deb62..adce6d4 100644\n--- a/builtin-merge-file.c\n+++ b/builtin-merge-file.c\n@@ -46,7 +46,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)\n \t}\n \n \tret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],\n-\t\t\t&xpp, XDL_MERGE_ZEALOUS, &result);\n+\t\t\t&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);\n \n \tfor (i = 0; i < 3; i++)\n \t\tfree(mmfs[i].ptr);\ndiff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh\nindex 869e8d5..79dc58b 100755\n--- a/t/t6023-merge-file.sh\n+++ b/t/t6023-merge-file.sh\n@@ -149,4 +149,14 @@ test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '\n \n '\n \n+sed -e 's/deerit./&\\n\\n\\n\\n/' -e \"s/locavit,/locavit;/\" < new6.txt > new8.txt\n+sed -e 's/deerit./&\\n\\n\\n\\n/' -e \"s/locavit,/locavit --/\" < new7.txt > new9.txt\n+\n+test_expect_success 'ZEALOUS_ALNUM' '\n+\n+\t! git merge-file -p new8.txt new5.txt new9.txt > merge.out &&\n+\ttest 1 = $(grep ======= < merge.out | wc -l)\n+\n+'\n+\n test_done\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex c00ddaa..413082e 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -53,6 +53,7 @@ extern \"C\" {\n #define XDL_MERGE_MINIMAL 0\n #define XDL_MERGE_EAGER 1\n #define XDL_MERGE_ZEALOUS 2\n+#define XDL_MERGE_ZEALOUS_ALNUM 3\n \n typedef struct s_mmfile {\n \tchar *ptr;\ndiff --git a/xdiff/xmerge.c b/xdiff/xmerge.c\nindex 9cd448c..2128eaf 100644\n--- a/xdiff/xmerge.c\n+++ b/xdiff/xmerge.c\n@@ -248,6 +248,23 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,\n \treturn 0;\n }\n \n+static int line_contains_alnum(const char *ptr, long size)\n+{\n+\twhile (size--)\n+\t\tif (isalnum(*(ptr++)))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n+static int lines_contain_alnum(xdfenv_t *xe, int i, int chg)\n+{\n+\tfor (; chg; chg--, i++)\n+\t\tif (line_contains_alnum(xe->xdf2.recs[i]->ptr,\n+\t\t\t\txe->xdf2.recs[i]->size))\n+\t\t\treturn 1;\n+\treturn 0;\n+}\n+\n /*\n  * This function merges m and m->next, marking everything between those hunks\n  * as conflicting, too.\n@@ -266,7 +283,8 @@ static void xdl_merge_two_conflicts(xdmerge_t *m)\n  * it appears simpler -- because it takes up less (or as many) lines --\n  * if the lines are moved into the conflicts.\n  */\n-static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)\n+static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,\n+\t\tint simplify_if_no_alnum)\n {\n \tint result = 0;\n \n@@ -282,7 +300,11 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)\n \t\tbegin = m->i1 + m->chg1;\n \t\tend = next_m->i1;\n \n-\t\tif (m->mode != 0 || next_m->mode != 0 || end - begin > 3)\n+\t\tif (m->mode != 0 || next_m->mode != 0 ||\n+\t\t\t\t(end - begin > 3 &&\n+\t\t\t\t (!simplify_if_no_alnum ||\n+\t\t\t\t  lines_contain_alnum(xe1, begin,\n+\t\t\t\t\t  end - begin))))\n \t\t\tm = next_m;\n \t\telse {\n \t\t\tresult++;\n@@ -295,6 +317,8 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)\n  * level == 0: mark all overlapping changes as conflict\n  * level == 1: mark overlapping changes as conflict only if not identical\n  * level == 2: analyze non-identical changes for minimal conflict set\n+ * level == 3: analyze non-identical changes for minimal conflict set, but\n+ *             treat hunks not containing any letter or number as conflicting\n  *\n  * returns < 0 on error, == 0 for no conflicts, else number of conflicts\n  */\n@@ -400,7 +424,8 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,\n \t/* refine conflicts */\n \tif (level > 1 &&\n \t\t\t(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||\n-\t\t\t xdl_simplify_non_conflicts(xe1, changes) < 0)) {\n+\t\t\t xdl_simplify_non_conflicts(xe1, changes,\n+\t\t\t\tlevel > 2) < 0)) {\n \t\txdl_cleanup_merge(changes);\n \t\treturn -1;\n \t}\n-- \n1.5.4.1.1396.g177d-dirty\n"},{"id":"69100","messageId":"7vy79ir79u.fsf@gitster.siamese.dyndns.org","threadId":"12063","inReplyTo":"alpine.LSU.1.00.0802171906590.30505@racer.site","subject":"Re: [PATCH 1/2] xdl_merge(): make XDL_MERGE_ZEALOUS output simpler","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-18T08:35:57Z","receivedAt":"2008-02-18T08:35:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> When a merge conflicts, there are often less than three common lines\n> between two conflicting regions.\n>\n> Since a conflict takes up as many lines as are conflicting, plus three\n> lines for the commit markers,  the output will be shorter (and thus,\n> simpler) in this case, if the common lines will be merged into the\n> conflicting regions.\n>\n> This patch merges up to three common lines into the conflicts.\n\nI can give immediate positive feedback to this.\n\nWhen I rebuilt \"next\" last night, I considered rebasing its\nconstituent branches while I was at it (I ended up not doing\nthat as I felt it was too much).\n\nThe tip of js/reflog-delete used to be at cb97cc9.  Rebasing\nthis on top of any recent master will give you unreadable\nconflicts in t/t1410-reflog.sh, but with these two patches (but\nthe second one does not have chance to kick in for this\nparticular case) the result is quite obvious and much cleaner.\n"},{"id":"69123","messageId":"alpine.LSU.1.00.0802181132050.30505@racer.site","threadId":"12063","inReplyTo":"7vy79ir79u.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 1/2] xdl_merge(): make XDL_MERGE_ZEALOUS output simpler","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-18T11:33:36Z","receivedAt":"2008-02-18T11:33:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 18 Feb 2008, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> > When a merge conflicts, there are often less than three common lines \n> > between two conflicting regions.\n> >\n> > Since a conflict takes up as many lines as are conflicting, plus three \n> > lines for the commit markers, the output will be shorter (and thus, \n> > simpler) in this case, if the common lines will be merged into the \n> > conflicting regions.\n> >\n> > This patch merges up to three common lines into the conflicts.\n> \n> I can give immediate positive feedback to this.\n> \n> When I rebuilt \"next\" last night, I considered rebasing its constituent \n> branches while I was at it (I ended up not doing that as I felt it was \n> too much).\n> \n> The tip of js/reflog-delete used to be at cb97cc9.  Rebasing this on top \n> of any recent master will give you unreadable conflicts in \n> t/t1410-reflog.sh, but with these two patches (but the second one does \n> not have chance to kick in for this particular case) the result is quite \n> obvious and much cleaner.\n\nGreat!\n\nNote that the _ALNUM stuff was meant more for discussion, as it only is \nactivated for merge-file, not for merge-recursive or blame or all the \nother (indirect) users of xdl_merge().\n\nI am a bit hesitant on activating it, since merging is pretty important, \nafter all, and if I break things with it...\n\nCiao,\nDscho\n"}]}