path: root/xdiff
diff options
authorJohannes Schindelin <>2006-12-31 01:07:41 (GMT)
committerJunio C Hamano <>2006-12-31 02:05:05 (GMT)
commit22b6abcd0872c50f4bff47e96819a86db4bb6e61 (patch)
tree67db67e23722908f41b9816a094bc660c36adefe /xdiff
parent53af9816bcb1d441fef76c3adaf0c4cb858768ac (diff)
Fix yet another subtle xdl_merge() bug
In very obscure cases, a merge can hit an unexpected code path (where the original code went as far as saying that this was a bug). This failing merge was noticed by Alexandre Juillard. The problem is that the original file contains something like this: -- snip -- two non-empty lines before two empty lines after two empty lines -- snap -- and this snippet is reduced to _one_ empty line in _both_ new files. However, it is ambiguous as to which hunk takes the empty line: the first or the second one? Indeed in Alexandre's example files, the xdiff algorithm attributes the empty line to the first hunk in one case, and to the second hunk in the other case. (Trimming down the example files _changes_ that behaviour!) Thus, the call to xdl_merge_cmp_lines() has no chance to realize that the change is actually identical in both new files. Therefore, xdl_refine_conflicts() finds an empty diff script, which was not expected there, because (the original author of xdl_merge() thought) xdl_merge_cmp_lines() would catch that case earlier. Signed-off-by: Johannes Schindelin <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'xdiff')
1 files changed, 5 insertions, 2 deletions
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 294450b..b83b334 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -166,6 +166,8 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
size += xdl_recs_copy(xe2, m->i2 - m->i1 + i1,
m->i1 + m->chg2 - i1, 0,
dest ? dest + size : NULL);
+ else
+ continue;
i1 = m->i1 + m->chg1;
size += xdl_recs_copy(xe1, i1, xe1->xdf2.nrec - i1, 0,
@@ -213,9 +215,10 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
return -1;
if (!xscr) {
- /* If this happens, it's a bug. */
+ /* If this happens, the changes are identical. */
- return -2;
+ m->mode = 4;
+ continue;
x = xscr;
m->i1 = xscr->i1 + i1;