Skip to content

Commit f407f14

Browse files
dschogitster
authored andcommitted
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>
1 parent cf5c51e commit f407f14

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

t/t6023-merge-file.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,14 @@ test_expect_success 'binary files cannot be merged' '
139139
grep "Cannot merge binary files" merge.err
140140
'
141141

142+
sed -e "s/deerit.$/deerit;/" -e "s/me;$/me./" < new5.txt > new6.txt
143+
sed -e "s/deerit.$/deerit,/" -e "s/me;$/me,/" < new5.txt > new7.txt
144+
145+
test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
146+
147+
! git merge-file -p new6.txt new5.txt new7.txt > output &&
148+
test 1 = $(grep ======= < output | wc -l)
149+
150+
'
151+
142152
test_done

xdiff/xmerge.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,49 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
248248
return 0;
249249
}
250250

251+
/*
252+
* This function merges m and m->next, marking everything between those hunks
253+
* as conflicting, too.
254+
*/
255+
static void xdl_merge_two_conflicts(xdmerge_t *m)
256+
{
257+
xdmerge_t *next_m = m->next;
258+
m->chg1 = next_m->i1 + next_m->chg1 - m->i1;
259+
m->chg2 = next_m->i2 + next_m->chg2 - m->i2;
260+
m->next = next_m->next;
261+
free(next_m);
262+
}
263+
264+
/*
265+
* If there are less than 3 non-conflicting lines between conflicts,
266+
* it appears simpler -- because it takes up less (or as many) lines --
267+
* if the lines are moved into the conflicts.
268+
*/
269+
static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)
270+
{
271+
int result = 0;
272+
273+
if (!m)
274+
return result;
275+
for (;;) {
276+
xdmerge_t *next_m = m->next;
277+
int begin, end;
278+
279+
if (!next_m)
280+
return result;
281+
282+
begin = m->i1 + m->chg1;
283+
end = next_m->i1;
284+
285+
if (m->mode != 0 || next_m->mode != 0 || end - begin > 3)
286+
m = next_m;
287+
else {
288+
result++;
289+
xdl_merge_two_conflicts(m);
290+
}
291+
}
292+
}
293+
251294
/*
252295
* level == 0: mark all overlapping changes as conflict
253296
* 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,
355398
if (!changes)
356399
changes = c;
357400
/* refine conflicts */
358-
if (level > 1 && xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0) {
401+
if (level > 1 &&
402+
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
403+
xdl_simplify_non_conflicts(xe1, changes) < 0)) {
359404
xdl_cleanup_merge(changes);
360405
return -1;
361406
}

0 commit comments

Comments
 (0)