Code

xdl_merge(): make XDL_MERGE_ZEALOUS output simpler
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Sun, 17 Feb 2008 19:07:19 +0000 (19:07 +0000)
committerJunio C Hamano <gitster@pobox.com>
Mon, 18 Feb 2008 08:08:40 +0000 (00:08 -0800)
When a merge conflicts, there are often less than three common lines
between two conflicting regions.

Since a conflict takes up as many lines as are conflicting, plus three
lines for the commit markers,  the output will be shorter (and thus,
simpler) in this case, if the common lines will be merged into the
conflicting regions.

This patch merges up to three common lines into the conflicts.

For example, what looked like this before this patch:

<<<<<<<
if (a == 1)
=======
if (a != 0)
>>>>>>>
{
int i;
<<<<<<<
a = 0;
=======
a = !a;
>>>>>>>

will now look like this:

<<<<<<<
if (a == 1)
{
int i;
a = 0;
=======
if (a != 0)
{
int i;
a = !a;
>>>>>>>

Suggested Linus (based on ideas by "Voltage Spike" -- if that name is
real, it is mighty cool).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t6023-merge-file.sh
xdiff/xmerge.c

index 86419964b441ebcc15592b872933915472c463d2..869e8d559e82b6015999e3967ce6cf77761481b3 100755 (executable)
@@ -139,4 +139,14 @@ test_expect_success 'binary files cannot be merged' '
        grep "Cannot merge binary files" merge.err
 '
 
+sed -e "s/deerit.$/deerit;/" -e "s/me;$/me./" < new5.txt > new6.txt
+sed -e "s/deerit.$/deerit,/" -e "s/me;$/me,/" < new5.txt > new7.txt
+
+test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
+
+       ! git merge-file -p new6.txt new5.txt new7.txt > output &&
+       test 1 = $(grep ======= < output | wc -l)
+
+'
+
 test_done
index b83b3348cc3aab66b13cb565a0a0fabaef4b689b..ecbdae502c7109f0bc46e00322ae95e8815e90c3 100644 (file)
@@ -248,6 +248,49 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
        return 0;
 }
 
+/*
+ * This function merges m and m->next, marking everything between those hunks
+ * as conflicting, too.
+ */
+static void xdl_merge_two_conflicts(xdmerge_t *m)
+{
+       xdmerge_t *next_m = m->next;
+       m->chg1 = next_m->i1 + next_m->chg1 - m->i1;
+       m->chg2 = next_m->i2 + next_m->chg2 - m->i2;
+       m->next = next_m->next;
+       free(next_m);
+}
+
+/*
+ * If there are less than 3 non-conflicting lines between conflicts,
+ * it appears simpler -- because it takes up less (or as many) lines --
+ * if the lines are moved into the conflicts.
+ */
+static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)
+{
+       int result = 0;
+
+       if (!m)
+               return result;
+       for (;;) {
+               xdmerge_t *next_m = m->next;
+               int begin, end;
+
+               if (!next_m)
+                       return result;
+
+               begin = m->i1 + m->chg1;
+               end = next_m->i1;
+
+               if (m->mode != 0 || next_m->mode != 0 || end - begin > 3)
+                       m = next_m;
+               else {
+                       result++;
+                       xdl_merge_two_conflicts(m);
+               }
+       }
+}
+
 /*
  * level == 0: mark all overlapping changes as conflict
  * level == 1: mark overlapping changes as conflict only if not identical
@@ -355,7 +398,9 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
        if (!changes)
                changes = c;
        /* refine conflicts */
-       if (level > 1 && xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0) {
+       if (level > 1 &&
+           (xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
+            xdl_simplify_non_conflicts(xe1, changes) < 0)) {
                xdl_cleanup_merge(changes);
                return -1;
        }