]> source.dussan.org Git - jgit.git/commitdiff
Fixed Merge Algorithm regarding concurrent file creations 39/1939/3
authorChristian Halstrick <christian.halstrick@sap.com>
Thu, 2 Dec 2010 12:11:21 +0000 (13:11 +0100)
committerChristian Halstrick <christian.halstrick@sap.com>
Thu, 2 Dec 2010 12:15:59 +0000 (13:15 +0100)
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>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/diff/RawText.java
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java

index 141f330bfa7275bfccb9957ce2fa73f7d5f81832..d75ec32f0b71b132c0f764c590c95051d001d6f4 100644 (file)
@@ -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);
 
index 06b01e9d06439e9cc3caa7aec133f9d9e86953f4..f83df6b53d889fc5dcc31bfe31d7cbe3b8367381 100644 (file)
@@ -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;
 
index a1bda4128490309f1ff3c8cdea09202862475b75..cf716cbf400af8915fa5b49c13e8a60e189d8573 100644 (file)
@@ -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));