Skip to content

Commit

Permalink
xdl_merge(): introduce XDL_MERGE_ZEALOUS_ALNUM
Browse files Browse the repository at this point in the history
When a merge conflicts, there are often common lines that are not really
common, such as empty lines or lines containing a single curly bracket.

With XDL_MERGE_ZEALOUS_ALNUM, we use the following heuristics: when a
hunk does not contain any letters or digits, it is treated as conflicting.

In other words, a conflict which used to look like this:

	<<<<<<<
					a = 1;
	=======
					output();
	>>>>>>>
				}
			}
		}

	<<<<<<<
		output();
	=======
		b = 1;
	>>>>>>>

will look like this with ZEALOUS_ALNUM:

	<<<<<<<
					a = 1;
				}
			}
		}

		output();
	=======
					output();
				}
			}
		}

		b = 1;
	>>>>>>>

To demonstrate this, git-merge-file has been switched from
XDL_MERGE_ZEALOUS to XDL_MERGE_ZEALOUS_ALNUM.

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 f407f14 commit ee95ec5
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 5 deletions.
2 changes: 1 addition & 1 deletion builtin-merge-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
}

ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
&xpp, XDL_MERGE_ZEALOUS, &result);
&xpp, XDL_MERGE_ZEALOUS_ALNUM, &result);

for (i = 0; i < 3; i++)
free(mmfs[i].ptr);
Expand Down
10 changes: 10 additions & 0 deletions t/t6023-merge-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,14 @@ test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' '
'

sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit;/" < new6.txt > new8.txt
sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit --/" < new7.txt > new9.txt

test_expect_success 'ZEALOUS_ALNUM' '
! git merge-file -p new8.txt new5.txt new9.txt > merge.out &&
test 1 = $(grep ======= < merge.out | wc -l)
'

test_done
1 change: 1 addition & 0 deletions xdiff/xdiff.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ extern "C" {
#define XDL_MERGE_MINIMAL 0
#define XDL_MERGE_EAGER 1
#define XDL_MERGE_ZEALOUS 2
#define XDL_MERGE_ZEALOUS_ALNUM 3

typedef struct s_mmfile {
char *ptr;
Expand Down
31 changes: 27 additions & 4 deletions xdiff/xmerge.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,23 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
return 0;
}

static int line_contains_alnum(const char *ptr, long size)
{
while (size--)
if (isalnum(*(ptr++)))
return 1;
return 0;
}

static int lines_contain_alnum(xdfenv_t *xe, int i, int chg)
{
for (; chg; chg--, i++)
if (line_contains_alnum(xe->xdf2.recs[i]->ptr,
xe->xdf2.recs[i]->size))
return 1;
return 0;
}

/*
* This function merges m and m->next, marking everything between those hunks
* as conflicting, too.
Expand All @@ -266,7 +283,8 @@ static void xdl_merge_two_conflicts(xdmerge_t *m)
* 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)
static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m,
int simplify_if_no_alnum)
{
int result = 0;

Expand All @@ -282,9 +300,12 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *m)
begin = m->i1 + m->chg1;
end = next_m->i1;

if (m->mode != 0 || next_m->mode != 0 || end - begin > 3)
if (m->mode != 0 || next_m->mode != 0 ||
(end - begin > 3 &&
(!simplify_if_no_alnum ||
lines_contain_alnum(xe1, begin, end - begin)))) {
m = next_m;
else {
} else {
result++;
xdl_merge_two_conflicts(m);
}
Expand All @@ -295,6 +316,8 @@ static int xdl_simplify_non_conflicts(xdfenv_t *xe1, xdmerge_t *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
* level == 3: analyze non-identical changes for minimal conflict set, but
* treat hunks not containing any letter or number as conflicting
*
* returns < 0 on error, == 0 for no conflicts, else number of conflicts
*/
Expand Down Expand Up @@ -400,7 +423,7 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1, const char *name1,
/* refine conflicts */
if (level > 1 &&
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
xdl_simplify_non_conflicts(xe1, changes) < 0)) {
xdl_simplify_non_conflicts(xe1, changes, level > 2) < 0)) {
xdl_cleanup_merge(changes);
return -1;
}
Expand Down

0 comments on commit ee95ec5

Please sign in to comment.