aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Halstrick <christian.halstrick@sap.com>2010-12-02 13:11:21 +0100
committerChristian Halstrick <christian.halstrick@sap.com>2010-12-02 13:15:59 +0100
commitdeabacc420bd009a2bbecceeb9f1c432ec3dfc0a (patch)
treefef0c04441bb5bab42a6598c1c251c68ba36c0d5
parentd29b5db695225ed9629b028f99070bd182320b0f (diff)
downloadjgit-deabacc420bd009a2bbecceeb9f1c432ec3dfc0a.tar.gz
jgit-deabacc420bd009a2bbecceeb9f1c432ec3dfc0a.zip
Fixed Merge Algorithm regarding concurrent file creations
When in OURS and THEIRS a new file is created we want a conflict when the two contents differ. If on two branches the same file with the same content is created this should not be a conflict. But: the current merge algorithm is throwing NPEs in this case. Fix this by choosing an empty RawText as common base if the base is empty. Change-Id: I21cb23f852965b82fb82ccd66ec961c7edb3ac3d Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java79
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java3
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java8
3 files changed, 87 insertions, 3 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
index 141f330bfa..d75ec32f0b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
@@ -247,6 +247,57 @@ public class MergeCommandTest extends RepositoryTestCase {
assertEquals(RepositoryState.MERGING, db.getRepositoryState());
}
+ public void testMultipleCreations() throws Exception {
+ Git git = new Git(db);
+
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("b", "1\nb(side)\n3\n");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("b", "1\nb(main)\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("main").call();
+
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
+ }
+
+ public void testMultipleCreationsSameContent() throws Exception {
+ Git git = new Git(db);
+
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ writeTrashFile("b", "1\nb(1)\n3\n");
+ git.add().addFilepattern("b").call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+
+ checkoutBranch("refs/heads/master");
+
+ writeTrashFile("b", "1\nb(1)\n3\n");
+ git.add().addFilepattern("b").call();
+ git.commit().setMessage("main").call();
+
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b")));
+ }
+
public void testSuccessfulContentMerge() throws Exception {
Git git = new Git(db);
@@ -415,6 +466,34 @@ public class MergeCommandTest extends RepositoryTestCase {
read(new File(db.getWorkTree(), "c/c/c")));
}
+ public void testMultipleDeletions() throws Exception {
+ Git git = new Git(db);
+
+ writeTrashFile("a", "1\na\n3\n");
+ git.add().addFilepattern("a").call();
+ RevCommit initialCommit = git.commit().setMessage("initial").call();
+
+ createBranch(initialCommit, "refs/heads/side");
+ checkoutBranch("refs/heads/side");
+
+ assertTrue(new File(db.getWorkTree(), "a").delete());
+ git.add().addFilepattern("a").setUpdate(true).call();
+ RevCommit secondCommit = git.commit().setMessage("side").call();
+
+ assertFalse(new File(db.getWorkTree(), "a").exists());
+ checkoutBranch("refs/heads/master");
+ assertTrue(new File(db.getWorkTree(), "a").exists());
+
+ assertTrue(new File(db.getWorkTree(), "a").delete());
+ git.add().addFilepattern("a").setUpdate(true).call();
+ git.commit().setMessage("main").call();
+
+ // We are merging a deletion into our branch
+ MergeResult result = git.merge().include(secondCommit.getId())
+ .setStrategy(MergeStrategy.RESOLVE).call();
+ assertEquals(MergeStatus.MERGED, result.getMergeStatus());
+ }
+
public void testDeletionAndConflict() throws Exception {
Git git = new Git(db);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
index 06b01e9d06..f83df6b53d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
@@ -66,6 +66,9 @@ import org.eclipse.jgit.util.RawParseUtils;
* they are converting from "line number" to "element index".
*/
public class RawText extends Sequence {
+ /** A Rawtext of length 0 */
+ public static final RawText EMPTY_TEXT = new RawText(new byte[0]);
+
/** Number of bytes to check for heuristics in {@link #isBinary(byte[])} */
private static final int FIRST_FEW_BYTES = 8000;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
index a1bda41284..cf716cbf40 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java
@@ -467,10 +467,12 @@ public class ResolveMerger extends ThreeWayMerger {
throws FileNotFoundException, IllegalStateException, IOException {
MergeFormatter fmt = new MergeFormatter();
+ RawText baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
+ base.getEntryObjectId(), db);
+
// do the merge
- MergeResult<RawText> result = mergeAlgorithm.merge(
- RawTextComparator.DEFAULT,
- getRawText(base.getEntryObjectId(), db),
+ MergeResult<RawText> result = MergeAlgorithm.merge(
+ RawTextComparator.DEFAULT, baseText,
getRawText(ours.getEntryObjectId(), db),
getRawText(theirs.getEntryObjectId(), db));