diff options
author | Christian Halstrick <christian.halstrick@sap.com> | 2010-12-02 13:11:21 +0100 |
---|---|---|
committer | Christian Halstrick <christian.halstrick@sap.com> | 2010-12-02 13:15:59 +0100 |
commit | deabacc420bd009a2bbecceeb9f1c432ec3dfc0a (patch) | |
tree | fef0c04441bb5bab42a6598c1c251c68ba36c0d5 | |
parent | d29b5db695225ed9629b028f99070bd182320b0f (diff) | |
download | jgit-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>
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)); |