summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java5
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java4
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java180
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java6
4 files changed, 194 insertions, 1 deletions
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
index 1079d98439..136c64726f 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java
@@ -229,6 +229,11 @@ public abstract class JGitTestUtil {
return read(file);
}
+ public static boolean check(final Repository db, final String name) {
+ File file = new File(db.getWorkTree(), name);
+ return file.exists();
+ }
+
public static void deleteTrashFile(final Repository db,
final String name) throws IOException {
File path = new File(db.getWorkTree(), name);
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index c1e0a2dcf3..bc225cc017 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -119,6 +119,10 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase {
return JGitTestUtil.read(db, name);
}
+ protected boolean check(final String name) {
+ return JGitTestUtil.check(db, name);
+ }
+
protected void deleteTrashFile(final String name) throws IOException {
JGitTestUtil.deleteTrashFile(db, name);
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
index 8f43f7f868..4e39daaf4f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/RecursiveMergerTest.java
@@ -44,6 +44,7 @@ package org.eclipse.jgit.merge;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.File;
@@ -178,7 +179,7 @@ public class RecursiveMergerTest extends RepositoryTestCase {
/**
* Merging m2,s2 from the following topology. The same file is modified
* in both branches. The modifications should be mergeable. m2 and s2
- * contain branch specific conflict resolutions. Therefore m2 and don't contain the same content.
+ * contain branch specific conflict resolutions. Therefore m2 and s2 don't contain the same content.
*
* <pre>
* m0--m1--m2
@@ -260,6 +261,183 @@ public class RecursiveMergerTest extends RepositoryTestCase {
@Theory
/**
* Merging m2,s2 from the following topology. The same file is modified
+ * in both branches. The modifications should be mergeable but only if the automerge of m1 and s1
+ * is choosen as parent. Choosing m0 as parent would not be sufficient (in contrast to the merge in
+ * crissCrossMerge_mergeable). m2 and s2 contain branch specific conflict resolutions. Therefore m2
+ * and s2 don't contain the same content.
+ *
+ * <pre>
+ * m0--m1--m2
+ * \ \/
+ * \ /\
+ * s1--s2
+ * </pre>
+ */
+ public void crissCrossMerge_mergeable2(MergeStrategy strategy,
+ IndexState indexState, WorktreeState worktreeState)
+ throws Exception {
+ if (!validateStates(indexState, worktreeState))
+ return;
+
+ BranchBuilder master = db_t.branch("master");
+ RevCommit m0 = master.commit().add("f", "1\n2\n3\n")
+ .message("m0")
+ .create();
+ RevCommit m1 = master.commit().add("f", "1-master\n2\n3\n")
+ .message("m1").create();
+ db_t.getRevWalk().parseCommit(m1);
+
+ BranchBuilder side = db_t.branch("side");
+ RevCommit s1 = side.commit().parent(m0).add("f", "1\n2\n3-side\n")
+ .message("s1").create();
+ RevCommit s2 = side.commit().parent(m1)
+ .add("f", "1-master\n2\n3-side-r\n")
+ .message("s2(merge)")
+ .create();
+ RevCommit m2 = master.commit().parent(s1)
+ .add("f", "1-master-r\n2\n3-side\n")
+ .message("m2(merge)")
+ .create();
+
+ Git git = Git.wrap(db);
+ git.checkout().setName("master").call();
+ modifyWorktree(worktreeState, "f", "side");
+ modifyIndex(indexState, "f", "side");
+
+ ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
+ worktreeState == WorktreeState.Bare);
+ if (worktreeState != WorktreeState.Bare)
+ merger.setWorkingTreeIterator(new FileTreeIterator(db));
+ try {
+ boolean expectSuccess = true;
+ if (!(indexState == IndexState.Bare
+ || indexState == IndexState.Missing || indexState == IndexState.SameAsHead))
+ // index is dirty
+ expectSuccess = false;
+ else if (worktreeState == WorktreeState.DifferentFromHeadAndOther
+ || worktreeState == WorktreeState.SameAsOther)
+ expectSuccess = false;
+ assertEquals(Boolean.valueOf(expectSuccess),
+ Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
+ assertEquals(MergeStrategy.RECURSIVE, strategy);
+ if (!expectSuccess)
+ // if the merge was not successful skip testing the state of
+ // index and workingtree
+ return;
+ assertEquals(
+ "1-master-r\n2\n3-side-r",
+ contentAsString(db, merger.getResultTreeId(), "f"));
+ if (indexState != IndexState.Bare)
+ assertEquals(
+ "[f, mode:100644, content:1-master-r\n2\n3-side-r\n]",
+ indexState(RepositoryTestCase.CONTENT));
+ if (worktreeState != WorktreeState.Bare
+ && worktreeState != WorktreeState.Missing)
+ assertEquals(
+ "1-master-r\n2\n3-side-r\n",
+ read("f"));
+ } catch (NoMergeBaseException e) {
+ assertEquals(MergeStrategy.RESOLVE, strategy);
+ assertEquals(e.getReason(),
+ MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
+ }
+ }
+
+ @Theory
+ /**
+ * Merging m2,s2 from the following topology. The same file is modified
+ * in both branches. The modifications should be mergeable but only if the automerge of m1 and s1
+ * is choosen as parent. On both branches delete and modify files untouched on the other branch.
+ * On both branches create new files. Make sure these files are correctly merged and
+ * exist in the workingtree.
+ *
+ * <pre>
+ * m0--m1--m2
+ * \ \/
+ * \ /\
+ * s1--s2
+ * </pre>
+ */
+ public void crissCrossMerge_checkOtherFiles(MergeStrategy strategy,
+ IndexState indexState, WorktreeState worktreeState)
+ throws Exception {
+ if (!validateStates(indexState, worktreeState))
+ return;
+
+ BranchBuilder master = db_t.branch("master");
+ RevCommit m0 = master.commit().add("f", "1\n2\n3\n").add("m.m", "0")
+ .add("m.d", "0").add("s.m", "0").add("s.d", "0").message("m0")
+ .create();
+ RevCommit m1 = master.commit().add("f", "1-master\n2\n3\n")
+ .add("m.c", "0").add("m.m", "1").rm("m.d").message("m1")
+ .create();
+ db_t.getRevWalk().parseCommit(m1);
+
+ BranchBuilder side = db_t.branch("side");
+ RevCommit s1 = side.commit().parent(m0).add("f", "1\n2\n3-side\n")
+ .add("s.c", "0").add("s.m", "1").rm("s.d").message("s1")
+ .create();
+ RevCommit s2 = side.commit().parent(m1)
+ .add("f", "1-master\n2\n3-side-r\n").add("m.m", "1")
+ .add("m.c", "0").rm("m.d").message("s2(merge)").create();
+ RevCommit m2 = master.commit().parent(s1)
+ .add("f", "1-master-r\n2\n3-side\n").add("s.m", "1")
+ .add("s.c", "0").rm("s.d").message("m2(merge)").create();
+
+ Git git = Git.wrap(db);
+ git.checkout().setName("master").call();
+ modifyWorktree(worktreeState, "f", "side");
+ modifyIndex(indexState, "f", "side");
+
+ ResolveMerger merger = (ResolveMerger) strategy.newMerger(db,
+ worktreeState == WorktreeState.Bare);
+ if (worktreeState != WorktreeState.Bare)
+ merger.setWorkingTreeIterator(new FileTreeIterator(db));
+ try {
+ boolean expectSuccess = true;
+ if (!(indexState == IndexState.Bare
+ || indexState == IndexState.Missing || indexState == IndexState.SameAsHead))
+ // index is dirty
+ expectSuccess = false;
+ else if (worktreeState == WorktreeState.DifferentFromHeadAndOther
+ || worktreeState == WorktreeState.SameAsOther)
+ expectSuccess = false;
+ assertEquals(Boolean.valueOf(expectSuccess),
+ Boolean.valueOf(merger.merge(new RevCommit[] { m2, s2 })));
+ assertEquals(MergeStrategy.RECURSIVE, strategy);
+ if (!expectSuccess)
+ // if the merge was not successful skip testing the state of
+ // index and workingtree
+ return;
+ assertEquals(
+ "1-master-r\n2\n3-side-r",
+ contentAsString(db, merger.getResultTreeId(), "f"));
+ if (indexState != IndexState.Bare)
+ assertEquals(
+ "[f, mode:100644, content:1-master-r\n2\n3-side-r\n][m.c, mode:100644, content:0][m.m, mode:100644, content:1][s.c, mode:100644, content:0][s.m, mode:100644, content:1]",
+ indexState(RepositoryTestCase.CONTENT));
+ if (worktreeState != WorktreeState.Bare
+ && worktreeState != WorktreeState.Missing) {
+ assertEquals(
+ "1-master-r\n2\n3-side-r\n",
+ read("f"));
+ assertTrue(check("s.c"));
+ assertFalse(check("s.d"));
+ assertTrue(check("s.m"));
+ assertTrue(check("m.c"));
+ assertFalse(check("m.d"));
+ assertTrue(check("m.m"));
+ }
+ } catch (NoMergeBaseException e) {
+ assertEquals(MergeStrategy.RESOLVE, strategy);
+ assertEquals(e.getReason(),
+ MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
+ }
+ }
+
+ @Theory
+ /**
+ * Merging m2,s2 from the following topology. The same file is modified
* in both branches. The modifications are not automatically
* mergeable. m2 and s2 contain branch specific conflict resolutions.
* Therefore m2 and s2 don't contain the same content.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
index 5802850a30..cce3de9b2d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -212,6 +212,12 @@ public class RecursiveMerger extends ResolveMerger {
inCore = oldIncore;
dircache = oldDircache;
workingTreeIterator = oldWTreeIt;
+ toBeCheckedOut.clear();
+ toBeDeleted.clear();
+ modifiedFiles.clear();
+ unmergedPaths.clear();
+ mergeResults.clear();
+ failingPaths.clear();
}
return currentBase;
}