Skip to content

Commit

Permalink
xdl_merge(): make XDL_MERGE_ZEALOUS output simpler
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Johannes Schindelin authored and Junio C Hamano committed Feb 18, 2008
1 parent cf5c51e commit f407f14
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 1 deletion.
10 changes: 10 additions & 0 deletions t/t6023-merge-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
47 changes: 46 additions & 1 deletion xdiff/xmerge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down

0 comments on commit f407f14

Please sign in to comment.