Fix Severe Bug in Merge Algorithm

As described in Bug 328551 there was a bug that the merge algorithm
was not always reporting conflicts when the same line was deleted
and modified. This problem was introduced during commit
0c017188b4 when reported conflicts have
been checked for common pre- and suffixes.

This was fixed here by better determining whether after stripping
off common prefixes and suffixes from a conflicting region there
is still some conflicting part left.
I also added a unit test to test this situation.

Bug: 328551
Change-Id: Iec6c9055d00e5049938484a27ab98dda2577afc4
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
This commit is contained in:
Christian Halstrick 2010-10-27 22:12:46 +02:00
parent 07cae6e6c1
commit beeb1f6d08
2 changed files with 30 additions and 8 deletions

View File

@ -98,6 +98,7 @@ public class MergeAlgorithmTest extends TestCase {
String replace_BCDEGI_by_ZZZZZZ=A+Z+Z+Z+Z+F+Z+H+Z+J;
String replace_CEFGHJ_by_YYYYYY=A+B+Y+D+Y+Y+Y+Y+I+Y;
String replace_BDE_by_ZZY=A+Z+C+Z+Y+F+G+H+I+J;
String delete_C=A+B+D+E+F+G+H+I+J;
/**
* Check for a conflict where the second text was changed similar to the
@ -190,6 +191,16 @@ public void testSameModification() throws IOException {
merge(base, replace_C_by_Z, replace_C_by_Z));
}
/**
* Check that a deleted vs. a modified line shows up as conflict (see Bug
* 328551)
*
* @throws IOException
*/
public void testDeleteVsModify() throws IOException {
assertEquals(A+B+XXX_0+XXX_1+Z+XXX_2+D+E+F+G+H+I+J, merge(base, delete_C, replace_C_by_Z));
}
private String merge(String commonBase, String ours, String theirs) throws IOException {
MergeResult r=MergeAlgorithm.merge(RawTextComparator.DEFAULT, new RawText(Constants.encode(commonBase)), new RawText(Constants.encode(ours)), new RawText(Constants.encode(theirs)));
ByteArrayOutputStream bo=new ByteArrayOutputStream(50);

View File

@ -201,28 +201,39 @@ public static <S extends Sequence> MergeResult<S> merge(
// A conflicting region is found. Strip off common lines in
// in the beginning and the end of the conflicting region
int conflictLen = Math.min(oursEndB - oursBeginB, theirsEndB
- theirsBeginB);
// Determine the minimum length of the conflicting areas in OURS
// and THEIRS. Also determine how much bigger the conflicting
// area in THEIRS is compared to OURS. All that is needed to
// limit the search for common areas at the beginning or end
// (the common areas cannot be bigger then the smaller
// conflicting area. The delta is needed to know whether the
// complete conflicting area is common in OURS and THEIRS.
int minBSize = oursEndB - oursBeginB;
int BSizeDelta = minBSize - (theirsEndB - theirsBeginB);
if (BSizeDelta > 0)
minBSize -= BSizeDelta;
int commonPrefix = 0;
while (commonPrefix < conflictLen
while (commonPrefix < minBSize
&& cmp.equals(ours, oursBeginB + commonPrefix, theirs,
theirsBeginB + commonPrefix))
commonPrefix++;
conflictLen -= commonPrefix;
minBSize -= commonPrefix;
int commonSuffix = 0;
while (commonSuffix < conflictLen
while (commonSuffix < minBSize
&& cmp.equals(ours, oursEndB - commonSuffix - 1, theirs,
theirsEndB - commonSuffix - 1))
commonSuffix++;
conflictLen -= commonSuffix;
minBSize -= commonSuffix;
// Add the common lines at start of conflict
if (commonPrefix > 0)
result.add(1, oursBeginB, oursBeginB + commonPrefix,
ConflictState.NO_CONFLICT);
// Add the conflict
if (conflictLen > 0) {
// Add the conflict (Only if there is a conflict left to report)
if (minBSize > 0 || BSizeDelta != 0) {
result.add(1, oursBeginB + commonPrefix, oursEndB
- commonSuffix,
ConflictState.FIRST_CONFLICTING_RANGE);