From 0461ff4f0c7ef505c818dac95286fa852f16eef7 Mon Sep 17 00:00:00 2001 From: Christian Halstrick Date: Tue, 17 May 2011 10:59:17 +0200 Subject: [PATCH] Optimize MergeAlgorithm if ours or theirs is empty Previously when merging two contents with a non-empty base and one of the contents was empty (size == 0) and the other was modified there was a potentially expensive calculation until we finally always come to the same result -> the complete non-deleted content should collide with the empty content. This proposal adds an optimization to detect empty input content and to produce the appropriate result immediatly. Change-Id: Ie6a837260c19d808f0e99173f570ff96dd22acd3 Signed-off-by: Christian Halstrick --- .../jgit/merge/MergeAlgorithmTest.java | 20 +++++++++++- .../eclipse/jgit/merge/MergeAlgorithm.java | 31 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java index aa8f8281e..8a33425b1 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java @@ -198,6 +198,25 @@ public void testTwoSimilarModsAndOneInsert() throws IOException { } + /** + * Test situations where (at least) one input value is the empty text + * + * @throws IOException + */ + @Test + public void testEmptyTexts() throws IOException { + // test modification against deletion + assertEquals(t(""), merge("A", "AB", "")); + assertEquals(t("<=AB>"), merge("A", "", "AB")); + + // test unmodified against deletion + assertEquals(t(""), merge("AB", "AB", "")); + assertEquals(t(""), merge("AB", "", "AB")); + + // test deletion against deletion + assertEquals(t(""), merge("AB", "", "")); + } + private String merge(String commonBase, String ours, String theirs) throws IOException { MergeResult r = new MergeAlgorithm().merge(RawTextComparator.DEFAULT, T(commonBase), T(ours), T(theirs)); @@ -231,5 +250,4 @@ public static String t(String text) { public static RawText T(String text) { return new RawText(Constants.encode(t(text))); } - } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java index e6688f5bc..112550a1d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeAlgorithm.java @@ -103,6 +103,37 @@ public MergeResult merge( sequences.add(ours); sequences.add(theirs); MergeResult result = new MergeResult(sequences); + + if (ours.size() == 0) { + if (theirs.size() != 0) { + EditList theirsEdits = diffAlg.diff(cmp, base, theirs); + if (!theirsEdits.isEmpty()) { + // we deleted, they modified -> Let their complete content + // conflict with empty text + result.add(1, 0, 0, ConflictState.FIRST_CONFLICTING_RANGE); + result.add(2, 0, theirs.size(), + ConflictState.NEXT_CONFLICTING_RANGE); + } else + // we deleted, they didn't modify -> Let our deletion win + result.add(1, 0, 0, ConflictState.NO_CONFLICT); + } else + // we and they deleted -> return a single chunk of nothing + result.add(1, 0, 0, ConflictState.NO_CONFLICT); + return result; + } else if (theirs.size() == 0) { + EditList oursEdits = diffAlg.diff(cmp, base, ours); + if (!oursEdits.isEmpty()) { + // we modified, they deleted -> Let our complete content + // conflict with empty text + result.add(1, 0, ours.size(), + ConflictState.FIRST_CONFLICTING_RANGE); + result.add(2, 0, 0, ConflictState.NEXT_CONFLICTING_RANGE); + } else + // they deleted, we didn't modify -> Let their deletion win + result.add(2, 0, 0, ConflictState.NO_CONFLICT); + return result; + } + EditList oursEdits = diffAlg.diff(cmp, base, ours); Iterator baseToOurs = oursEdits.iterator(); EditList theirsEdits = diffAlg.diff(cmp, base, theirs);