summaryrefslogtreecommitdiff
path: root/xdiff
diff options
context:
space:
mode:
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>2008-02-17 19:07:19 (GMT)
committerJunio C Hamano <gitster@pobox.com>2008-02-18 08:08:40 (GMT)
commitf407f14deaa14ebddd0d27238523ced8eca74393 (patch)
tree6250028e000ffb0bdb2b0096aec7f0aa45130601 /xdiff
parentcf5c51efc9fe3b0ef93c7b78005c57b71acaf959 (diff)
downloadgit-f407f14deaa14ebddd0d27238523ced8eca74393.zip
git-f407f14deaa14ebddd0d27238523ced8eca74393.tar.gz
git-f407f14deaa14ebddd0d27238523ced8eca74393.tar.bz2
xdl_merge(): make XDL_MERGE_ZEALOUS output simpler
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>
Diffstat (limited to 'xdiff')
-rw-r--r--xdiff/xmerge.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index b83b334..ecbdae5 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -249,6 +249,49 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
}
/*
+ * 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
* level == 2: analyze non-identical changes for minimal conflict set
@@ -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;
}