diff options
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java')
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/MergeCommandTest.java | 3068 |
1 files changed, 1816 insertions, 1252 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 761aafa3f9..1ec506798c 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 @@ -1,67 +1,47 @@ /* * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> - * Copyright (C) 2010-2014, Christian Halstrick <christian.halstrick@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010-2014, Christian Halstrick <christian.halstrick@sap.com> and others * - * This program and the accompanying materials are made available - * under the terms of the Eclipse Distribution License v1.0 which - * accompanies this distribution, is reproduced below, and is - * available at http://www.eclipse.org/org/documents/edl-v10.php + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * - Neither the name of the Eclipse Foundation, Inc. nor the - * names of its contributors may be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.api; +import static org.eclipse.jgit.lib.Constants.MASTER; +import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import java.io.File; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Iterator; +import java.util.regex.Pattern; import org.eclipse.jgit.api.MergeCommand.FastForwardMode; import org.eclipse.jgit.api.MergeResult.MergeStatus; +import org.eclipse.jgit.api.ResetCommand.ResetType; import org.eclipse.jgit.api.errors.InvalidMergeHeadsException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.TestRepository.BranchBuilder; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; +import org.eclipse.jgit.lib.Sets; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.merge.ContentMergeStrategy; import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; import org.eclipse.jgit.revwalk.RevCommit; @@ -69,6 +49,7 @@ import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.GitDateFormatter; import org.eclipse.jgit.util.GitDateFormatter.Format; +import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.experimental.theories.DataPoints; @@ -93,773 +74,1144 @@ public class MergeCommandTest extends RepositoryTestCase { @Test public void testMergeInItself() throws Exception { - Git git = new Git(db); - git.commit().setMessage("initial commit").call(); + try (Git git = new Git(db)) { + git.commit().setMessage("initial commit").call(); - MergeResult result = git.merge().include(db.getRef(Constants.HEAD)).call(); - assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); + MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call(); + assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); + } // no reflog entry written by merge - assertEquals("commit (initial): initial commit", - db + RefDatabase refDb = db.getRefDatabase(); + assertEquals("commit (initial): initial commit", refDb .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("commit (initial): initial commit", - db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("commit (initial): initial commit", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test public void testAlreadyUpToDate() throws Exception { - Git git = new Git(db); - RevCommit first = git.commit().setMessage("initial commit").call(); - createBranch(first, "refs/heads/branch1"); - - RevCommit second = git.commit().setMessage("second commit").call(); - MergeResult result = git.merge().include(db.getRef("refs/heads/branch1")).call(); - assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); - assertEquals(second, result.getNewHead()); + try (Git git = new Git(db)) { + RevCommit first = git.commit().setMessage("initial commit").call(); + createBranch(first, "refs/heads/branch1"); + + RevCommit second = git.commit().setMessage("second commit").call(); + MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call(); + assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus()); + assertEquals(second, result.getNewHead()); + } // no reflog entry written by merge - assertEquals("commit: second commit", db + assertEquals("commit: second commit", db.getRefDatabase() .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("commit: second commit", db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("commit: second commit", db.getRefDatabase() + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test public void testFastForward() throws Exception { - Git git = new Git(db); - RevCommit first = git.commit().setMessage("initial commit").call(); - createBranch(first, "refs/heads/branch1"); + try (Git git = new Git(db)) { + RevCommit first = git.commit().setMessage("initial commit").call(); + createBranch(first, "refs/heads/branch1"); - RevCommit second = git.commit().setMessage("second commit").call(); + RevCommit second = git.commit().setMessage("second commit").call(); - checkoutBranch("refs/heads/branch1"); + checkoutBranch("refs/heads/branch1"); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call(); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); - assertEquals(second, result.getNewHead()); + assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); + assertEquals(second, result.getNewHead()); + } + RefDatabase refDb = db.getRefDatabase(); assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); + refDb.getReflogReader(Constants.HEAD) + .getLastEntry().getComment()); assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + refDb.getReflogReader(db.getFullBranch()) + .getLastEntry().getComment()); } @Test public void testFastForwardNoCommit() throws Exception { - Git git = new Git(db); - RevCommit first = git.commit().setMessage("initial commit").call(); - createBranch(first, "refs/heads/branch1"); + try (Git git = new Git(db)) { + RevCommit first = git.commit().setMessage("initial commit").call(); + createBranch(first, "refs/heads/branch1"); - RevCommit second = git.commit().setMessage("second commit").call(); + RevCommit second = git.commit().setMessage("second commit").call(); - checkoutBranch("refs/heads/branch1"); + checkoutBranch("refs/heads/branch1"); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)) - .setCommit(false).call(); + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)) + .setCommit(false).call(); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD, - result.getMergeStatus()); - assertEquals(second, result.getNewHead()); - assertEquals("merge refs/heads/master: Fast-forward", db + assertEquals(MergeResult.MergeStatus.FAST_FORWARD, + result.getMergeStatus()); + assertEquals(second, result.getNewHead()); + } + RefDatabase refDb = db.getRefDatabase(); + assertEquals("merge refs/heads/master: Fast-forward", refDb .getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("merge refs/heads/master: Fast-forward", db - .getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test public void testFastForwardWithFiles() throws Exception { - Git git = new Git(db); - - writeTrashFile("file1", "file1"); - git.add().addFilepattern("file1").call(); - RevCommit first = git.commit().setMessage("initial commit").call(); + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit first = git.commit().setMessage("initial commit").call(); - assertTrue(new File(db.getWorkTree(), "file1").exists()); - createBranch(first, "refs/heads/branch1"); + assertTrue(new File(db.getWorkTree(), "file1").exists()); + createBranch(first, "refs/heads/branch1"); - writeTrashFile("file2", "file2"); - git.add().addFilepattern("file2").call(); - RevCommit second = git.commit().setMessage("second commit").call(); - assertTrue(new File(db.getWorkTree(), "file2").exists()); + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + RevCommit second = git.commit().setMessage("second commit").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); - checkoutBranch("refs/heads/branch1"); - assertFalse(new File(db.getWorkTree(), "file2").exists()); + checkoutBranch("refs/heads/branch1"); + assertFalse(new File(db.getWorkTree(), "file2").exists()); - MergeResult result = git.merge().include(db.getRef(Constants.MASTER)).call(); + MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call(); - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); - assertEquals(second, result.getNewHead()); - assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); - assertEquals("merge refs/heads/master: Fast-forward", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus()); + assertEquals(second, result.getNewHead()); + } + RefDatabase refDb = db.getRefDatabase(); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(Constants.HEAD).getLastEntry().getComment()); + assertEquals("merge refs/heads/master: Fast-forward", refDb + .getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Test public void testMultipleHeads() throws Exception { - Git git = new Git(db); - - writeTrashFile("file1", "file1"); - git.add().addFilepattern("file1").call(); - RevCommit first = git.commit().setMessage("initial commit").call(); - createBranch(first, "refs/heads/branch1"); - - writeTrashFile("file2", "file2"); - git.add().addFilepattern("file2").call(); - RevCommit second = git.commit().setMessage("second commit").call(); - - writeTrashFile("file3", "file3"); - git.add().addFilepattern("file3").call(); - git.commit().setMessage("third commit").call(); - - checkoutBranch("refs/heads/branch1"); - assertFalse(new File(db.getWorkTree(), "file2").exists()); - assertFalse(new File(db.getWorkTree(), "file3").exists()); - - MergeCommand merge = git.merge(); - merge.include(second.getId()); - merge.include(db.getRef(Constants.MASTER)); - try { - merge.call(); - fail("Expected exception not thrown when merging multiple heads"); - } catch (InvalidMergeHeadsException e) { - // expected this exception + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit first = git.commit().setMessage("initial commit").call(); + createBranch(first, "refs/heads/branch1"); + + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + RevCommit second = git.commit().setMessage("second commit").call(); + + writeTrashFile("file3", "file3"); + git.add().addFilepattern("file3").call(); + git.commit().setMessage("third commit").call(); + + checkoutBranch("refs/heads/branch1"); + assertFalse(new File(db.getWorkTree(), "file2").exists()); + assertFalse(new File(db.getWorkTree(), "file3").exists()); + + MergeCommand merge = git.merge(); + merge.include(second.getId()); + merge.include(db.exactRef(R_HEADS + MASTER)); + try { + merge.call(); + fail("Expected exception not thrown when merging multiple heads"); + } catch (InvalidMergeHeadsException e) { + // expected this exception + } } } @Theory public void testMergeSuccessAllStrategies(MergeStrategy mergeStrategy) throws Exception { - Git git = new Git(db); - - RevCommit first = git.commit().setMessage("first").call(); - createBranch(first, "refs/heads/side"); - - writeTrashFile("a", "a"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("second").call(); - - checkoutBranch("refs/heads/side"); - writeTrashFile("b", "b"); - git.add().addFilepattern("b").call(); - git.commit().setMessage("third").call(); - - MergeResult result = git.merge().setStrategy(mergeStrategy) - .include(db.getRef(Constants.MASTER)).call(); - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + try (Git git = new Git(db)) { + RevCommit first = git.commit().setMessage("first").call(); + createBranch(first, "refs/heads/side"); + + writeTrashFile("a", "a"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("second").call(); + + checkoutBranch("refs/heads/side"); + writeTrashFile("b", "b"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("third").call(); + + MergeResult result = git.merge().setStrategy(mergeStrategy) + .include(db.exactRef(R_HEADS + MASTER)).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + } + RefDatabase refDb = db.getRefDatabase(); assertEquals( "merge refs/heads/master: Merge made by " + mergeStrategy.getName() + ".", - db.getReflogReader(Constants.HEAD).getLastEntry().getComment()); + refDb.getReflogReader(Constants.HEAD).getLastEntry() + .getComment()); assertEquals( "merge refs/heads/master: Merge made by " + mergeStrategy.getName() + ".", - db.getReflogReader(db.getBranch()).getLastEntry().getComment()); + refDb.getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); } @Theory public void testMergeSuccessAllStrategiesNoCommit( MergeStrategy mergeStrategy) throws Exception { - Git git = new Git(db); - - RevCommit first = git.commit().setMessage("first").call(); - createBranch(first, "refs/heads/side"); - - writeTrashFile("a", "a"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("second").call(); + try (Git git = new Git(db)) { + RevCommit first = git.commit().setMessage("first").call(); + createBranch(first, "refs/heads/side"); + + writeTrashFile("a", "a"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("second").call(); + + checkoutBranch("refs/heads/side"); + writeTrashFile("b", "b"); + git.add().addFilepattern("b").call(); + RevCommit thirdCommit = git.commit().setMessage("third").call(); + + MergeResult result = git.merge().setStrategy(mergeStrategy) + .setCommit(false) + .include(db.exactRef(R_HEADS + MASTER)).call(); + assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); + assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(), + thirdCommit.getId()); + } + } - checkoutBranch("refs/heads/side"); - writeTrashFile("b", "b"); - git.add().addFilepattern("b").call(); - RevCommit thirdCommit = git.commit().setMessage("third").call(); + @Test + public void testContentMerge() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na(main)\n3\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + git.commit().setMessage("main").call(); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + + assertEquals( + "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + + assertEquals(1, result.getConflicts().size()); + assertEquals(3, result.getConflicts().get("a")[0].length); + + assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + } + } - MergeResult result = git.merge().setStrategy(mergeStrategy) - .setCommit(false) - .include(db.getRef(Constants.MASTER)).call(); - assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); - assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), - thirdCommit.getId()); + @Test + public void testContentMergeXtheirs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n4\n"); + writeTrashFile("b", "1\nb(side)\n3\n4\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n4\n", + read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na(main)\n3\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + git.commit().setMessage("main").call(); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(ContentMergeStrategy.THEIRS) + .call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertEquals("1\na(side)\n3\n4\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb(side)\n3\n4\n", + read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + + assertNull(result.getConflicts()); + + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test - public void testContentMerge() throws Exception { - Git git = new Git(db); + public void testContentMergeXours() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n4\n"); + writeTrashFile("b", "1\nb(side)\n3\n4\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n4\n", + read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na(main)\n3\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + git.commit().setMessage("main").call(); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(ContentMergeStrategy.OURS).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertEquals("1\na(main)\n3\n4\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb(side)\n3\n4\n", + read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + + assertNull(result.getConflicts()); + + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } + } - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); + @Test + public void testBinaryContentMerge() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile(".gitattributes", "a binary"); + writeTrashFile("a", "initial"); + git.add().addFilepattern(".").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - writeTrashFile("a", "1\na(side)\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); + writeTrashFile("a", "side"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); - writeTrashFile("a", "1\na(main)\n3\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - git.commit().setMessage("main").call(); + writeTrashFile("a", "main"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); - assertEquals( - "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n", - read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); + assertEquals("main", read(new File(db.getWorkTree(), "a"))); - assertEquals(1, result.getConflicts().size()); - assertEquals(3, result.getConflicts().get("a")[0].length); + // Hmmm... there doesn't seem to be a way to figure out which files + // had a binary conflict from a MergeResult... - assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + } } @Test - public void testMergeTag() throws Exception { - Git git = new Git(db); + public void testBinaryContentMergeXtheirs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile(".gitattributes", "a binary"); + writeTrashFile("a", "initial"); + git.add().addFilepattern(".").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - writeTrashFile("a", "a"); - git.add().addFilepattern("a").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + writeTrashFile("a", "side"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); - writeTrashFile("b", "b"); - git.add().addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01") - .setName("tag01").setObjectId(secondCommit).call(); + checkoutBranch("refs/heads/master"); - checkoutBranch("refs/heads/master"); + writeTrashFile("a", "main"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - writeTrashFile("a", "a2"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("main").call(); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(ContentMergeStrategy.THEIRS) + .call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); - MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + assertEquals("side", read(new File(db.getWorkTree(), "a"))); + + assertNull(result.getConflicts()); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test - public void testMergeMessage() throws Exception { - Git git = new Git(db); + public void testBinaryContentMergeXours() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile(".gitattributes", "a binary"); + writeTrashFile("a", "initial"); + git.add().addFilepattern(".").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - 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"); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + writeTrashFile("a", "side"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); - writeTrashFile("a", "1\na(side)\n3\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("side").call(); + checkoutBranch("refs/heads/master"); - checkoutBranch("refs/heads/master"); + writeTrashFile("a", "main"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - writeTrashFile("a", "1\na(main)\n3\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("main").call(); - - Ref sideBranch = db.getRef("side"); - - git.merge().include(sideBranch) - .setStrategy(MergeStrategy.RESOLVE).call(); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(ContentMergeStrategy.OURS).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); - assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n", - db.readMergeCommitMsg()); + assertEquals("main", read(new File(db.getWorkTree(), "a"))); + assertNull(result.getConflicts()); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test - public void testMergeNonVersionedPaths() throws Exception { - Git git = new Git(db); + public void testMergeTag() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "a"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + writeTrashFile("b", "b"); + git.add().addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01") + .setName("tag01").setObjectId(secondCommit).call(); - writeTrashFile("a", "1\na(side)\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); + checkoutBranch("refs/heads/master"); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + writeTrashFile("a", "a2"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - writeTrashFile("a", "1\na(main)\n3\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - git.commit().setMessage("main").call(); + MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + } + } - writeTrashFile("d", "1\nd\n3\n"); - assertTrue(new File(db.getWorkTree(), "e").mkdir()); + @Test + public void testMergeMessage() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - assertEquals( - "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n", - read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); - assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); - File dir = new File(db.getWorkTree(), "e"); - assertTrue(dir.isDirectory()); + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); - assertEquals(1, result.getConflicts().size()); - assertEquals(3, result.getConflicts().get("a")[0].length); + checkoutBranch("refs/heads/master"); - assertEquals(RepositoryState.MERGING, db.getRepositoryState()); - } + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - @Test - public void testMultipleCreations() throws Exception { - Git git = new Git(db); + Ref sideBranch = db.exactRef("refs/heads/side"); - 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(); + git.merge().include(sideBranch) + .setStrategy(MergeStrategy.RESOLVE).call(); - checkoutBranch("refs/heads/master"); + assertEquals("Merge branch 'side'\n\n# Conflicts:\n#\ta\n", + db.readMergeCommitMsg()); + } - 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()); + @Test + public void testMergeNonVersionedPaths() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na(main)\n3\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + git.commit().setMessage("main").call(); + + writeTrashFile("d", "1\nd\n3\n"); + assertTrue(new File(db.getWorkTree(), "e").mkdir()); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + + assertEquals( + "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + File dir = new File(db.getWorkTree(), "e"); + assertTrue(dir.isDirectory()); + + assertEquals(1, result.getConflicts().size()); + assertEquals(3, result.getConflicts().get("a")[0].length); + + assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + } } @Test - public void testMultipleCreationsSameContent() throws Exception { - Git git = new Git(db); + public void testMultipleCreations() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - 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"); - 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(); - writeTrashFile("b", "1\nb(1)\n3\n"); - git.add().addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); + checkoutBranch("refs/heads/master"); - checkoutBranch("refs/heads/master"); + writeTrashFile("b", "1\nb(main)\n3\n"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("main").call(); - 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.CONFLICTING, result.getMergeStatus()); + } + } - 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"))); - assertEquals("merge " + secondCommit.getId().getName() - + ": Merge made by resolve.", db - .getReflogReader(Constants.HEAD) - .getLastEntry().getComment()); - assertEquals("merge " + secondCommit.getId().getName() - + ": Merge made by resolve.", db - .getReflogReader(db.getBranch()) - .getLastEntry().getComment()); + @Test + public void testMultipleCreationsSameContent() throws Exception { + try (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"))); + RefDatabase refDb = db.getRefDatabase(); + assertEquals( + "merge " + secondCommit.getId().getName() + + ": Merge made by resolve.", + refDb.getReflogReader(Constants.HEAD).getLastEntry() + .getComment()); + assertEquals( + "merge " + secondCommit.getId().getName() + + ": Merge made by resolve.", + refDb.getReflogReader(db.getFullBranch()).getLastEntry() + .getComment()); + } } @Test public void testSuccessfulContentMerge() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - - writeTrashFile("a", "1(side)\na\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - - writeTrashFile("a", "1\na\n3(main)\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - RevCommit thirdCommit = git.commit().setMessage("main").call(); - - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); - - assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), - "a"))); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), - "c/c/c"))); - - assertEquals(null, result.getConflicts()); - - assertEquals(2, result.getMergedCommits().length); - assertEquals(thirdCommit, result.getMergedCommits()[0]); - assertEquals(secondCommit, result.getMergedCommits()[1]); - - Iterator<RevCommit> it = git.log().call().iterator(); - RevCommit newHead = it.next(); - assertEquals(newHead, result.getNewHead()); - assertEquals(2, newHead.getParentCount()); - assertEquals(thirdCommit, newHead.getParent(0)); - assertEquals(secondCommit, newHead.getParent(1)); - assertEquals( - "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'", - newHead.getFullMessage()); - // @TODO fix me - assertEquals(RepositoryState.SAFE, db.getRepositoryState()); - // test index state + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1(side)\na\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na\n3(main)\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + RevCommit thirdCommit = git.commit().setMessage("main").call(); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), + "a"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), + "c/c/c"))); + + assertEquals(null, result.getConflicts()); + + assertEquals(2, result.getMergedCommits().length); + assertEquals(thirdCommit, result.getMergedCommits()[0]); + assertEquals(secondCommit, result.getMergedCommits()[1]); + + Iterator<RevCommit> it = git.log().call().iterator(); + RevCommit newHead = it.next(); + assertEquals(newHead, result.getNewHead()); + assertEquals(2, newHead.getParentCount()); + assertEquals(thirdCommit, newHead.getParent(0)); + assertEquals(secondCommit, newHead.getParent(1)); + assertEquals( + "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'", + newHead.getFullMessage()); + // @TODO fix me + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + // test index state + } } @Test public void testSuccessfulContentMergeNoCommit() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - - writeTrashFile("a", "1(side)\na\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - - writeTrashFile("a", "1\na\n3(main)\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - RevCommit thirdCommit = git.commit().setMessage("main").call(); - - MergeResult result = git.merge().include(secondCommit.getId()) - .setCommit(false) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); - assertEquals(db.getRef(Constants.HEAD).getTarget().getObjectId(), - thirdCommit.getId()); - - assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), - "a"))); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); - - assertEquals(null, result.getConflicts()); - - assertEquals(2, result.getMergedCommits().length); - assertEquals(thirdCommit, result.getMergedCommits()[0]); - assertEquals(secondCommit, result.getMergedCommits()[1]); - assertNull(result.getNewHead()); - assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1(side)\na\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na\n3(main)\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + RevCommit thirdCommit = git.commit().setMessage("main").call(); + + MergeResult result = git.merge().include(secondCommit.getId()) + .setCommit(false) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); + assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(), + thirdCommit.getId()); + + assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), + "a"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + + assertEquals(null, result.getConflicts()); + + assertEquals(2, result.getMergedCommits().length); + assertEquals(thirdCommit, result.getMergedCommits()[0]); + assertEquals(secondCommit, result.getMergedCommits()[1]); + assertNull(result.getNewHead()); + assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); + } } @Test public void testSuccessfulContentMergeAndDirtyworkingTree() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("d", "1\nd\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").addFilepattern("d").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - - writeTrashFile("a", "1(side)\na\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - - writeTrashFile("a", "1\na\n3(main)\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - RevCommit thirdCommit = git.commit().setMessage("main").call(); - - writeTrashFile("d", "--- dirty ---"); - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); - - assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), - "a"))); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), - "c/c/c"))); - assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d"))); - - assertEquals(null, result.getConflicts()); - - assertEquals(2, result.getMergedCommits().length); - assertEquals(thirdCommit, result.getMergedCommits()[0]); - assertEquals(secondCommit, result.getMergedCommits()[1]); - - Iterator<RevCommit> it = git.log().call().iterator(); - RevCommit newHead = it.next(); - assertEquals(newHead, result.getNewHead()); - assertEquals(2, newHead.getParentCount()); - assertEquals(thirdCommit, newHead.getParent(0)); - assertEquals(secondCommit, newHead.getParent(1)); - assertEquals( - "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'", - newHead.getFullMessage()); - - assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("d", "1\nd\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").addFilepattern("d").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1(side)\na\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + + writeTrashFile("a", "1\na\n3(main)\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + RevCommit thirdCommit = git.commit().setMessage("main").call(); + + writeTrashFile("d", "--- dirty ---"); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(), + "a"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), + "c/c/c"))); + assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d"))); + + assertEquals(null, result.getConflicts()); + + assertEquals(2, result.getMergedCommits().length); + assertEquals(thirdCommit, result.getMergedCommits()[0]); + assertEquals(secondCommit, result.getMergedCommits()[1]); + + Iterator<RevCommit> it = git.log().call().iterator(); + RevCommit newHead = it.next(); + assertEquals(newHead, result.getNewHead()); + assertEquals(2, newHead.getParentCount()); + assertEquals(thirdCommit, newHead.getParent(0)); + assertEquals(secondCommit, newHead.getParent(1)); + assertEquals( + "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'", + newHead.getFullMessage()); + + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test public void testSingleDeletion() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("d", "1\nd\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").addFilepattern("d").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - - assertTrue(new File(db.getWorkTree(), "b").delete()); - git.add().addFilepattern("b").setUpdate(true).call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - assertFalse(new File(db.getWorkTree(), "b").exists()); - checkoutBranch("refs/heads/master"); - assertTrue(new File(db.getWorkTree(), "b").exists()); - - writeTrashFile("a", "1\na\n3(main)\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").call(); - RevCommit thirdCommit = 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()); - - assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a"))); - assertFalse(new File(db.getWorkTree(), "b").exists()); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); - assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); - - // Do the opposite, be on a branch where we have deleted a file and - // merge in a old commit where this file was not deleted - checkoutBranch("refs/heads/side"); - assertFalse(new File(db.getWorkTree(), "b").exists()); - - result = git.merge().include(thirdCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); - - assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a"))); - assertFalse(new File(db.getWorkTree(), "b").exists()); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); - assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("d", "1\nd\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").addFilepattern("d").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + assertTrue(new File(db.getWorkTree(), "b").delete()); + git.add().addFilepattern("b").setUpdate(true).call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertFalse(new File(db.getWorkTree(), "b").exists()); + checkoutBranch("refs/heads/master"); + assertTrue(new File(db.getWorkTree(), "b").exists()); + + writeTrashFile("a", "1\na\n3(main)\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").call(); + RevCommit thirdCommit = 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()); + + assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a"))); + assertFalse(new File(db.getWorkTree(), "b").exists()); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + + // Do the opposite, be on a branch where we have deleted a file and + // merge in a old commit where this file was not deleted + checkoutBranch("refs/heads/side"); + assertFalse(new File(db.getWorkTree(), "b").exists()); + + result = git.merge().include(thirdCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a"))); + assertFalse(new File(db.getWorkTree(), "b").exists()); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + } } @Test 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()); + try (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()); + } } @Test public void testDeletionAndConflict() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - writeTrashFile("d", "1\nd\n3\n"); - writeTrashFile("c/c/c", "1\nc\n3\n"); - git.add().addFilepattern("a").addFilepattern("b") - .addFilepattern("c/c/c").addFilepattern("d").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - - assertTrue(new File(db.getWorkTree(), "b").delete()); - writeTrashFile("a", "1\na\n3(side)\n"); - git.add().addFilepattern("b").setUpdate(true).call(); - git.add().addFilepattern("a").setUpdate(true).call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - assertFalse(new File(db.getWorkTree(), "b").exists()); - checkoutBranch("refs/heads/master"); - assertTrue(new File(db.getWorkTree(), "b").exists()); - - writeTrashFile("a", "1\na\n3(main)\n"); - writeTrashFile("c/c/c", "1\nc(main)\n3\n"); - git.add().addFilepattern("a").addFilepattern("c/c/c").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.CONFLICTING, result.getMergeStatus()); - - assertEquals( - "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n", - read(new File(db.getWorkTree(), "a"))); - assertFalse(new File(db.getWorkTree(), "b").exists()); - assertEquals("1\nc(main)\n3\n", - read(new File(db.getWorkTree(), "c/c/c"))); - assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + writeTrashFile("d", "1\nd\n3\n"); + writeTrashFile("c/c/c", "1\nc\n3\n"); + git.add().addFilepattern("a").addFilepattern("b") + .addFilepattern("c/c/c").addFilepattern("d").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + assertTrue(new File(db.getWorkTree(), "b").delete()); + writeTrashFile("a", "1\na\n3(side)\n"); + git.add().addFilepattern("b").setUpdate(true).call(); + git.add().addFilepattern("a").setUpdate(true).call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + assertFalse(new File(db.getWorkTree(), "b").exists()); + checkoutBranch("refs/heads/master"); + assertTrue(new File(db.getWorkTree(), "b").exists()); + + writeTrashFile("a", "1\na\n3(main)\n"); + writeTrashFile("c/c/c", "1\nc(main)\n3\n"); + git.add().addFilepattern("a").addFilepattern("c/c/c").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.CONFLICTING, result.getMergeStatus()); + + assertEquals( + "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n", + read(new File(db.getWorkTree(), "a"))); + assertFalse(new File(db.getWorkTree(), "b").exists()); + assertEquals("1\nc(main)\n3\n", + read(new File(db.getWorkTree(), "c/c/c"))); + assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d"))); + } } @Test public void testDeletionOnMasterConflict() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - // create side branch and modify "a" - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - writeTrashFile("a", "1\na(side)\n3\n"); - git.add().addFilepattern("a").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - // delete a on master to generate conflict - checkoutBranch("refs/heads/master"); - git.rm().addFilepattern("a").call(); - git.commit().setMessage("main").call(); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and modify "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // delete a on master to generate conflict + checkoutBranch("refs/heads/master"); + git.rm().addFilepattern("a").call(); + RevCommit thirdCommit = git.commit().setMessage("main").call(); + + for (ContentMergeStrategy contentStrategy : ContentMergeStrategy + .values()) { + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(contentStrategy) + .call(); + assertEquals("merge -X " + contentStrategy.name(), + MergeStatus.CONFLICTING, result.getMergeStatus()); + + // result should be 'a' conflicting with workspace content from + // side + assertTrue("merge -X " + contentStrategy.name(), + new File(db.getWorkTree(), "a").exists()); + assertEquals("merge -X " + contentStrategy.name(), + "1\na(side)\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("merge -X " + contentStrategy.name(), "1\nb\n3\n", + read(new File(db.getWorkTree(), "b"))); + git.reset().setMode(ResetType.HARD).setRef(thirdCommit.name()) + .call(); + } + } + } - // merge side with master - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + @Test + public void testDeletionOnMasterTheirs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and modify "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // delete a on master to generate conflict + checkoutBranch("refs/heads/master"); + git.rm().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.THEIRS) + .call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + // result should be 'a' + assertTrue(new File(db.getWorkTree(), "a").exists()); + assertEquals("1\na(side)\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertTrue(git.status().call().isClean()); + } + } - // result should be 'a' conflicting with workspace content from side - assertTrue(new File(db.getWorkTree(), "a").exists()); - assertEquals("1\na(side)\n3\n", read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + @Test + public void testDeletionOnMasterOurs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and modify "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // delete a on master to generate conflict + checkoutBranch("refs/heads/master"); + git.rm().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.OURS).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertFalse(new File(db.getWorkTree(), "a").exists()); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertTrue(git.status().call().isClean()); + } } @Test public void testDeletionOnSideConflict() throws Exception { - Git git = new Git(db); - - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - // create side branch and delete "a" - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - git.rm().addFilepattern("a").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); - - // update a on master to generate conflict - checkoutBranch("refs/heads/master"); - writeTrashFile("a", "1\na(main)\n3\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("main").call(); - - // merge side with master - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and delete "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + git.rm().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // update a on master to generate conflict + checkoutBranch("refs/heads/master"); + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit thirdCommit = git.commit().setMessage("main").call(); + + for (ContentMergeStrategy contentStrategy : ContentMergeStrategy + .values()) { + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE) + .setContentMergeStrategy(contentStrategy) + .call(); + assertEquals("merge -X " + contentStrategy.name(), + MergeStatus.CONFLICTING, result.getMergeStatus()); + + assertTrue("merge -X " + contentStrategy.name(), + new File(db.getWorkTree(), "a").exists()); + assertEquals("merge -X " + contentStrategy.name(), + "1\na(main)\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("merge -X " + contentStrategy.name(), "1\nb\n3\n", + read(new File(db.getWorkTree(), "b"))); + + assertNotNull("merge -X " + contentStrategy.name(), + result.getConflicts()); + assertEquals("merge -X " + contentStrategy.name(), 1, + result.getConflicts().size()); + assertEquals("merge -X " + contentStrategy.name(), 3, + result.getConflicts().get("a")[0].length); + git.reset().setMode(ResetType.HARD).setRef(thirdCommit.name()) + .call(); + } + } + } - assertTrue(new File(db.getWorkTree(), "a").exists()); - assertEquals("1\na(main)\n3\n", read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + @Test + public void testDeletionOnSideTheirs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and delete "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + git.rm().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // update a on master to generate conflict + checkoutBranch("refs/heads/master"); + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.THEIRS).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertFalse(new File(db.getWorkTree(), "a").exists()); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertTrue(git.status().call().isClean()); + } + } - assertEquals(1, result.getConflicts().size()); - assertEquals(3, result.getConflicts().get("a")[0].length); + @Test + public void testDeletionOnSideOurs() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + + // create side branch and delete "a" + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + git.rm().addFilepattern("a").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); + + // update a on master to generate conflict + checkoutBranch("refs/heads/master"); + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + // merge side with master + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.OURS).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + + assertTrue(new File(db.getWorkTree(), "a").exists()); + assertEquals("1\na(main)\n3\n", + read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertTrue(git.status().call().isClean()); + } } @Test @@ -867,262 +1219,262 @@ public class MergeCommandTest extends RepositoryTestCase { // this test is essentially the same as testDeletionOnSideConflict, // however if once rename support is added this test should result in a // successful merge instead of a conflict - Git git = new Git(db); - - writeTrashFile("x", "add x"); - git.add().addFilepattern("x").call(); - RevCommit initial = git.commit().setMessage("add x").call(); - - createBranch(initial, "refs/heads/d1"); - createBranch(initial, "refs/heads/d2"); - - // rename x to y on d1 - checkoutBranch("refs/heads/d1"); - new File(db.getWorkTree(), "x") - .renameTo(new File(db.getWorkTree(), "y")); - git.rm().addFilepattern("x").call(); - git.add().addFilepattern("y").call(); - RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call(); - - checkoutBranch("refs/heads/d2"); - writeTrashFile("x", "d2 change"); - git.add().addFilepattern("x").call(); - RevCommit d2Commit = git.commit().setMessage("d2 change in x").call(); - - checkoutBranch("refs/heads/master"); - MergeResult d1Merge = git.merge().include(d1Commit).call(); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD, - d1Merge.getMergeStatus()); - - MergeResult d2Merge = git.merge().include(d2Commit).call(); - assertEquals(MergeResult.MergeStatus.CONFLICTING, - d2Merge.getMergeStatus()); - assertEquals(1, d2Merge.getConflicts().size()); - assertEquals(3, d2Merge.getConflicts().get("x")[0].length); + try (Git git = new Git(db)) { + writeTrashFile("x", "add x"); + git.add().addFilepattern("x").call(); + RevCommit initial = git.commit().setMessage("add x").call(); + + createBranch(initial, "refs/heads/d1"); + createBranch(initial, "refs/heads/d2"); + + // rename x to y on d1 + checkoutBranch("refs/heads/d1"); + new File(db.getWorkTree(), "x") + .renameTo(new File(db.getWorkTree(), "y")); + git.rm().addFilepattern("x").call(); + git.add().addFilepattern("y").call(); + RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call(); + + checkoutBranch("refs/heads/d2"); + writeTrashFile("x", "d2 change"); + git.add().addFilepattern("x").call(); + RevCommit d2Commit = git.commit().setMessage("d2 change in x").call(); + + checkoutBranch("refs/heads/master"); + MergeResult d1Merge = git.merge().include(d1Commit).call(); + assertEquals(MergeResult.MergeStatus.FAST_FORWARD, + d1Merge.getMergeStatus()); + + MergeResult d2Merge = git.merge().include(d2Commit).call(); + assertEquals(MergeResult.MergeStatus.CONFLICTING, + d2Merge.getMergeStatus()); + assertEquals(1, d2Merge.getConflicts().size()); + assertEquals(3, d2Merge.getConflicts().get("x")[0].length); + } } @Test public void testMergeFailingWithDirtyWorkingTree() throws Exception { - Git git = new Git(db); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); - - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - writeTrashFile("a", "1(side)\na\n3\n"); - writeTrashFile("b", "1\nb(side)\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); + writeTrashFile("a", "1(side)\na\n3\n"); + writeTrashFile("b", "1\nb(side)\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); - assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); - checkoutBranch("refs/heads/master"); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b"))); + checkoutBranch("refs/heads/master"); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - writeTrashFile("a", "1\na\n3(main)\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("main").call(); + writeTrashFile("a", "1\na\n3(main)\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - writeTrashFile("a", "--- dirty ---"); - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); + writeTrashFile("a", "--- dirty ---"); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.FAILED, result.getMergeStatus()); + assertEquals(MergeStatus.FAILED, result.getMergeStatus()); - assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals(null, result.getConflicts()); + assertEquals(null, result.getConflicts()); - assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test public void testMergeConflictFileFolder() throws Exception { - Git git = new Git(db); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + writeTrashFile("b", "1\nb\n3\n"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - writeTrashFile("a", "1\na\n3\n"); - writeTrashFile("b", "1\nb\n3\n"); - git.add().addFilepattern("a").addFilepattern("b").call(); - RevCommit initialCommit = git.commit().setMessage("initial").call(); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + writeTrashFile("c/c/c", "1\nc(side)\n3\n"); + writeTrashFile("d", "1\nd(side)\n3\n"); + git.add().addFilepattern("c/c/c").addFilepattern("d").call(); + RevCommit secondCommit = git.commit().setMessage("side").call(); - writeTrashFile("c/c/c", "1\nc(side)\n3\n"); - writeTrashFile("d", "1\nd(side)\n3\n"); - git.add().addFilepattern("c/c/c").addFilepattern("d").call(); - RevCommit secondCommit = git.commit().setMessage("side").call(); + checkoutBranch("refs/heads/master"); - checkoutBranch("refs/heads/master"); + writeTrashFile("c", "1\nc(main)\n3\n"); + writeTrashFile("d/d/d", "1\nd(main)\n3\n"); + git.add().addFilepattern("c").addFilepattern("d/d/d").call(); + git.commit().setMessage("main").call(); - writeTrashFile("c", "1\nc(main)\n3\n"); - writeTrashFile("d/d/d", "1\nd(main)\n3\n"); - git.add().addFilepattern("c").addFilepattern("d/d/d").call(); - git.commit().setMessage("main").call(); + MergeResult result = git.merge().include(secondCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); - MergeResult result = git.merge().include(secondCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a"))); + assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); + assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c"))); + assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d"))); - assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a"))); - assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b"))); - assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c"))); - assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d"))); + assertEquals(null, result.getConflicts()); - assertEquals(null, result.getConflicts()); - - assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + assertEquals(RepositoryState.MERGING, db.getRepositoryState()); + } } @Test public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception { - Git git = new Git(db); - - File fileA = writeTrashFile("a", "a"); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - // modify file a - write(fileA, "a(side)"); - writeTrashFile("b", "b"); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - checkoutBranch("refs/heads/master"); - writeTrashFile("c", "c"); - addAllAndCommit(git); - - // modify and add file a - write(fileA, "a(modified)"); - git.add().addFilepattern("a").call(); - // do not commit - - // get current index state - String indexState = indexState(CONTENT); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - - checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX, - indexState, fileA); + try (Git git = new Git(db)) { + File fileA = writeTrashFile("a", "a"); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + // modify file a + write(fileA, "a(side)"); + writeTrashFile("b", "b"); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + checkoutBranch("refs/heads/master"); + writeTrashFile("c", "c"); + addAllAndCommit(git); + + // modify and add file a + write(fileA, "a(modified)"); + git.add().addFilepattern("a").call(); + // do not commit + + // get current index state + String indexState = indexState(CONTENT); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + + checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX, + indexState, fileA); + } } @Test public void testConflictingMergeFailsDueToDirtyIndex() throws Exception { - Git git = new Git(db); - - File fileA = writeTrashFile("a", "a"); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - // modify file a - write(fileA, "a(side)"); - writeTrashFile("b", "b"); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - checkoutBranch("refs/heads/master"); - // modify file a - this will cause a conflict during merge - write(fileA, "a(master)"); - writeTrashFile("c", "c"); - addAllAndCommit(git); - - // modify and add file a - write(fileA, "a(modified)"); - git.add().addFilepattern("a").call(); - // do not commit - - // get current index state - String indexState = indexState(CONTENT); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - - checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX, - indexState, fileA); + try (Git git = new Git(db)) { + File fileA = writeTrashFile("a", "a"); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + // modify file a + write(fileA, "a(side)"); + writeTrashFile("b", "b"); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + checkoutBranch("refs/heads/master"); + // modify file a - this will cause a conflict during merge + write(fileA, "a(master)"); + writeTrashFile("c", "c"); + addAllAndCommit(git); + + // modify and add file a + write(fileA, "a(modified)"); + git.add().addFilepattern("a").call(); + // do not commit + + // get current index state + String indexState = indexState(CONTENT); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + + checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX, + indexState, fileA); + } } @Test public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception { - Git git = new Git(db); - - File fileA = writeTrashFile("a", "a"); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - // modify file a - write(fileA, "a(side)"); - writeTrashFile("b", "b"); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - checkoutBranch("refs/heads/master"); - writeTrashFile("c", "c"); - addAllAndCommit(git); - - // modify file a - write(fileA, "a(modified)"); - // do not add and commit - - // get current index state - String indexState = indexState(CONTENT); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - - checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE, - indexState, fileA); + try (Git git = new Git(db)) { + File fileA = writeTrashFile("a", "a"); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + // modify file a + write(fileA, "a(side)"); + writeTrashFile("b", "b"); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + checkoutBranch("refs/heads/master"); + writeTrashFile("c", "c"); + addAllAndCommit(git); + + // modify file a + write(fileA, "a(modified)"); + // do not add and commit + + // get current index state + String indexState = indexState(CONTENT); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + + checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE, + indexState, fileA); + } } @Test public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception { - Git git = new Git(db); - - File fileA = writeTrashFile("a", "a"); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - // modify file a - write(fileA, "a(side)"); - writeTrashFile("b", "b"); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - checkoutBranch("refs/heads/master"); - // modify file a - this will cause a conflict during merge - write(fileA, "a(master)"); - writeTrashFile("c", "c"); - addAllAndCommit(git); - - // modify file a - write(fileA, "a(modified)"); - // do not add and commit - - // get current index state - String indexState = indexState(CONTENT); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - - checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE, - indexState, fileA); + try (Git git = new Git(db)) { + File fileA = writeTrashFile("a", "a"); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + // modify file a + write(fileA, "a(side)"); + writeTrashFile("b", "b"); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + checkoutBranch("refs/heads/master"); + // modify file a - this will cause a conflict during merge + write(fileA, "a(master)"); + writeTrashFile("c", "c"); + addAllAndCommit(git); + + // modify file a + write(fileA, "a(modified)"); + // do not add and commit + + // get current index state + String indexState = indexState(CONTENT); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + + checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE, + indexState, fileA); + } } @Test @@ -1140,29 +1492,30 @@ public class MergeCommandTest extends RepositoryTestCase { file = new File(folder2, "file2.txt"); write(file, "folder2--file2.txt"); - Git git = new Git(db); - git.add().addFilepattern(folder1.getName()) - .addFilepattern(folder2.getName()).call(); - RevCommit commit1 = git.commit().setMessage("adding folders").call(); - - recursiveDelete(folder1); - recursiveDelete(folder2); - git.rm().addFilepattern("folder1/file1.txt") - .addFilepattern("folder1/file2.txt") - .addFilepattern("folder2/file1.txt") - .addFilepattern("folder2/file2.txt").call(); - RevCommit commit2 = git.commit() - .setMessage("removing folders on 'branch'").call(); - - git.checkout().setName(commit1.name()).call(); - - MergeResult result = git.merge().include(commit2.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD, - result.getMergeStatus()); - assertEquals(commit2, result.getNewHead()); - assertFalse(folder1.exists()); - assertFalse(folder2.exists()); + try (Git git = new Git(db)) { + git.add().addFilepattern(folder1.getName()) + .addFilepattern(folder2.getName()).call(); + RevCommit commit1 = git.commit().setMessage("adding folders").call(); + + recursiveDelete(folder1); + recursiveDelete(folder2); + git.rm().addFilepattern("folder1/file1.txt") + .addFilepattern("folder1/file2.txt") + .addFilepattern("folder2/file1.txt") + .addFilepattern("folder2/file2.txt").call(); + RevCommit commit2 = git.commit() + .setMessage("removing folders on 'branch'").call(); + + git.checkout().setName(commit1.name()).call(); + + MergeResult result = git.merge().include(commit2.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeResult.MergeStatus.FAST_FORWARD, + result.getMergeStatus()); + assertEquals(commit2, result.getNewHead()); + assertFalse(folder1.exists()); + assertFalse(folder2.exists()); + } } @Test @@ -1180,396 +1533,408 @@ public class MergeCommandTest extends RepositoryTestCase { file = new File(folder2, "file2.txt"); write(file, "folder2--file2.txt"); - Git git = new Git(db); - git.add().addFilepattern(folder1.getName()) - .addFilepattern(folder2.getName()).call(); - RevCommit base = git.commit().setMessage("adding folders").call(); + try (Git git = new Git(db)) { + git.add().addFilepattern(folder1.getName()) + .addFilepattern(folder2.getName()).call(); + RevCommit base = git.commit().setMessage("adding folders").call(); - recursiveDelete(folder1); - recursiveDelete(folder2); - git.rm().addFilepattern("folder1/file1.txt") - .addFilepattern("folder1/file2.txt") - .addFilepattern("folder2/file1.txt") - .addFilepattern("folder2/file2.txt").call(); - RevCommit other = git.commit() - .setMessage("removing folders on 'branch'").call(); + recursiveDelete(folder1); + recursiveDelete(folder2); + git.rm().addFilepattern("folder1/file1.txt") + .addFilepattern("folder1/file2.txt") + .addFilepattern("folder2/file1.txt") + .addFilepattern("folder2/file2.txt").call(); + RevCommit other = git.commit() + .setMessage("removing folders on 'branch'").call(); - git.checkout().setName(base.name()).call(); + git.checkout().setName(base.name()).call(); - file = new File(folder2, "file3.txt"); - write(file, "folder2--file3.txt"); + file = new File(folder2, "file3.txt"); + write(file, "folder2--file3.txt"); - git.add().addFilepattern(folder2.getName()).call(); - git.commit().setMessage("adding another file").call(); + git.add().addFilepattern(folder2.getName()).call(); + git.commit().setMessage("adding another file").call(); - MergeResult result = git.merge().include(other.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); + MergeResult result = git.merge().include(other.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeResult.MergeStatus.MERGED, - result.getMergeStatus()); - assertFalse(folder1.exists()); + assertEquals(MergeResult.MergeStatus.MERGED, + result.getMergeStatus()); + assertFalse(folder1.exists()); + } } @Test public void testFileModeMerge() throws Exception { - if (!FS.DETECTED.supportsExecute()) - return; // Only Java6 - Git git = new Git(db); - - writeTrashFile("mergeableMode", "a"); - setExecutable(git, "mergeableMode", false); - writeTrashFile("conflictingModeWithBase", "a"); - setExecutable(git, "conflictingModeWithBase", false); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - setExecutable(git, "mergeableMode", true); - writeTrashFile("conflictingModeNoBase", "b"); - setExecutable(git, "conflictingModeNoBase", true); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side2"); - checkoutBranch("refs/heads/side2"); - setExecutable(git, "mergeableMode", false); - assertFalse(new File(git.getRepository().getWorkTree(), - "conflictingModeNoBase").exists()); - writeTrashFile("conflictingModeNoBase", "b"); - setExecutable(git, "conflictingModeNoBase", false); - addAllAndCommit(git); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); - assertTrue(canExecute(git, "mergeableMode")); - assertFalse(canExecute(git, "conflictingModeNoBase")); + assumeTrue(FS.DETECTED.supportsExecute()); + try (Git git = new Git(db)) { + writeTrashFile("mergeableMode", "a"); + setExecutable(git, "mergeableMode", false); + writeTrashFile("conflictingModeWithBase", "a"); + setExecutable(git, "conflictingModeWithBase", false); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + setExecutable(git, "mergeableMode", true); + writeTrashFile("conflictingModeNoBase", "b"); + setExecutable(git, "conflictingModeNoBase", true); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side2"); + checkoutBranch("refs/heads/side2"); + setExecutable(git, "mergeableMode", false); + assertFalse(new File(git.getRepository().getWorkTree(), + "conflictingModeNoBase").exists()); + writeTrashFile("conflictingModeNoBase", "b"); + setExecutable(git, "conflictingModeNoBase", false); + addAllAndCommit(git); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + assertTrue(canExecute(git, "mergeableMode")); + assertFalse(canExecute(git, "conflictingModeNoBase")); + } } @Test public void testFileModeMergeWithDirtyWorkTree() throws Exception { - if (!FS.DETECTED.supportsExecute()) - return; // Only Java6 (or set x bit in index) - - Git git = new Git(db); - - writeTrashFile("mergeableButDirty", "a"); - setExecutable(git, "mergeableButDirty", false); - RevCommit initialCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); - setExecutable(git, "mergeableButDirty", true); - RevCommit sideCommit = addAllAndCommit(git); - - // switch branch - createBranch(initialCommit, "refs/heads/side2"); - checkoutBranch("refs/heads/side2"); - setExecutable(git, "mergeableButDirty", false); - addAllAndCommit(git); - - writeTrashFile("mergeableButDirty", "b"); - - // merge - MergeResult result = git.merge().include(sideCommit.getId()) - .setStrategy(MergeStrategy.RESOLVE).call(); - assertEquals(MergeStatus.FAILED, result.getMergeStatus()); - assertFalse(canExecute(git, "mergeableButDirty")); + assumeTrue(FS.DETECTED.supportsExecute()); + + try (Git git = new Git(db)) { + writeTrashFile("mergeableButDirty", "a"); + setExecutable(git, "mergeableButDirty", false); + RevCommit initialCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + setExecutable(git, "mergeableButDirty", true); + RevCommit sideCommit = addAllAndCommit(git); + + // switch branch + createBranch(initialCommit, "refs/heads/side2"); + checkoutBranch("refs/heads/side2"); + setExecutable(git, "mergeableButDirty", false); + addAllAndCommit(git); + + writeTrashFile("mergeableButDirty", "b"); + + // merge + MergeResult result = git.merge().include(sideCommit.getId()) + .setStrategy(MergeStrategy.RESOLVE).call(); + assertEquals(MergeStatus.FAILED, result.getMergeStatus()); + assertFalse(canExecute(git, "mergeableButDirty")); + } } @Test public void testSquashFastForward() throws Exception { - Git git = new Git(db); - - writeTrashFile("file1", "file1"); - git.add().addFilepattern("file1").call(); - RevCommit first = git.commit().setMessage("initial commit").call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - createBranch(first, "refs/heads/branch1"); - checkoutBranch("refs/heads/branch1"); - - writeTrashFile("file2", "file2"); - git.add().addFilepattern("file2").call(); - RevCommit second = git.commit().setMessage("second commit").call(); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - - writeTrashFile("file3", "file3"); - git.add().addFilepattern("file3").call(); - RevCommit third = git.commit().setMessage("third commit").call(); - assertTrue(new File(db.getWorkTree(), "file3").exists()); - - checkoutBranch("refs/heads/master"); - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertFalse(new File(db.getWorkTree(), "file2").exists()); - assertFalse(new File(db.getWorkTree(), "file3").exists()); - - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - assertTrue(new File(db.getWorkTree(), "file3").exists()); - assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED, - result.getMergeStatus()); - assertEquals(first, result.getNewHead()); // HEAD didn't move - assertEquals(first, db.resolve(Constants.HEAD + "^{commit}")); - - assertEquals( - "Squashed commit of the following:\n\ncommit " - + third.getName() - + "\nAuthor: " - + third.getAuthorIdent().getName() - + " <" - + third.getAuthorIdent().getEmailAddress() - + ">\nDate: " - + dateFormatter.formatDate(third - .getAuthorIdent()) - + "\n\n\tthird commit\n\ncommit " - + second.getName() - + "\nAuthor: " - + second.getAuthorIdent().getName() - + " <" - + second.getAuthorIdent().getEmailAddress() - + ">\nDate: " - + dateFormatter.formatDate(second - .getAuthorIdent()) + "\n\n\tsecond commit\n", - db.readSquashCommitMsg()); - assertNull(db.readMergeCommitMsg()); - - Status stat = git.status().call(); - assertEquals(Sets.of("file2", "file3"), stat.getAdded()); + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit first = git.commit().setMessage("initial commit").call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + createBranch(first, "refs/heads/branch1"); + checkoutBranch("refs/heads/branch1"); + + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + RevCommit second = git.commit().setMessage("second commit").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + writeTrashFile("file3", "file3"); + git.add().addFilepattern("file3").call(); + RevCommit third = git.commit().setMessage("third commit").call(); + assertTrue(new File(db.getWorkTree(), "file3").exists()); + + checkoutBranch("refs/heads/master"); + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertFalse(new File(db.getWorkTree(), "file2").exists()); + assertFalse(new File(db.getWorkTree(), "file3").exists()); + + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertTrue(new File(db.getWorkTree(), "file3").exists()); + assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED, + result.getMergeStatus()); + assertEquals(first, result.getNewHead()); // HEAD didn't move + assertEquals(first, db.resolve(Constants.HEAD + "^{commit}")); + + assertEquals( + "Squashed commit of the following:\n\ncommit " + + third.getName() + + "\nAuthor: " + + third.getAuthorIdent().getName() + + " <" + + third.getAuthorIdent().getEmailAddress() + + ">\nDate: " + + dateFormatter.formatDate(third + .getAuthorIdent()) + + "\n\n\tthird commit\n\ncommit " + + second.getName() + + "\nAuthor: " + + second.getAuthorIdent().getName() + + " <" + + second.getAuthorIdent().getEmailAddress() + + ">\nDate: " + + dateFormatter.formatDate(second + .getAuthorIdent()) + "\n\n\tsecond commit\n", + db.readSquashCommitMsg()); + assertNull(db.readMergeCommitMsg()); + + Status stat = git.status().call(); + assertEquals(Sets.of("file2", "file3"), stat.getAdded()); + } } @Test public void testSquashMerge() throws Exception { - Git git = new Git(db); - - writeTrashFile("file1", "file1"); - git.add().addFilepattern("file1").call(); - RevCommit first = git.commit().setMessage("initial commit").call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - createBranch(first, "refs/heads/branch1"); - - writeTrashFile("file2", "file2"); - git.add().addFilepattern("file2").call(); - RevCommit second = git.commit().setMessage("second commit").call(); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - - checkoutBranch("refs/heads/branch1"); - - writeTrashFile("file3", "file3"); - git.add().addFilepattern("file3").call(); - RevCommit third = git.commit().setMessage("third commit").call(); - assertTrue(new File(db.getWorkTree(), "file3").exists()); - - checkoutBranch("refs/heads/master"); - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - assertFalse(new File(db.getWorkTree(), "file3").exists()); - - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - assertTrue(new File(db.getWorkTree(), "file3").exists()); - assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED, - result.getMergeStatus()); - assertEquals(second, result.getNewHead()); // HEAD didn't move - assertEquals(second, db.resolve(Constants.HEAD + "^{commit}")); - - assertEquals( - "Squashed commit of the following:\n\ncommit " - + third.getName() - + "\nAuthor: " - + third.getAuthorIdent().getName() - + " <" - + third.getAuthorIdent().getEmailAddress() - + ">\nDate: " - + dateFormatter.formatDate(third - .getAuthorIdent()) + "\n\n\tthird commit\n", - db.readSquashCommitMsg()); - assertNull(db.readMergeCommitMsg()); - - Status stat = git.status().call(); - assertEquals(Sets.of("file3"), stat.getAdded()); + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit first = git.commit().setMessage("initial commit").call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + createBranch(first, "refs/heads/branch1"); + + writeTrashFile("file2", "file2"); + git.add().addFilepattern("file2").call(); + RevCommit second = git.commit().setMessage("second commit").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + checkoutBranch("refs/heads/branch1"); + + writeTrashFile("file3", "file3"); + git.add().addFilepattern("file3").call(); + RevCommit third = git.commit().setMessage("third commit").call(); + assertTrue(new File(db.getWorkTree(), "file3").exists()); + + checkoutBranch("refs/heads/master"); + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertFalse(new File(db.getWorkTree(), "file3").exists()); + + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertTrue(new File(db.getWorkTree(), "file3").exists()); + assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED, + result.getMergeStatus()); + assertEquals(second, result.getNewHead()); // HEAD didn't move + assertEquals(second, db.resolve(Constants.HEAD + "^{commit}")); + + assertEquals( + "Squashed commit of the following:\n\ncommit " + + third.getName() + + "\nAuthor: " + + third.getAuthorIdent().getName() + + " <" + + third.getAuthorIdent().getEmailAddress() + + ">\nDate: " + + dateFormatter.formatDate(third + .getAuthorIdent()) + "\n\n\tthird commit\n", + db.readSquashCommitMsg()); + assertNull(db.readMergeCommitMsg()); + + Status stat = git.status().call(); + assertEquals(Sets.of("file3"), stat.getAdded()); + } } @Test public void testSquashMergeConflict() throws Exception { - Git git = new Git(db); - - writeTrashFile("file1", "file1"); - git.add().addFilepattern("file1").call(); - RevCommit first = git.commit().setMessage("initial commit").call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - createBranch(first, "refs/heads/branch1"); - - writeTrashFile("file2", "master"); - git.add().addFilepattern("file2").call(); - RevCommit second = git.commit().setMessage("second commit").call(); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - - checkoutBranch("refs/heads/branch1"); - - writeTrashFile("file2", "branch"); - git.add().addFilepattern("file2").call(); - RevCommit third = git.commit().setMessage("third commit").call(); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - - checkoutBranch("refs/heads/master"); - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - - MergeResult result = git.merge().include(db.getRef("branch1")) - .setSquash(true).call(); - - assertTrue(new File(db.getWorkTree(), "file1").exists()); - assertTrue(new File(db.getWorkTree(), "file2").exists()); - assertEquals(MergeResult.MergeStatus.CONFLICTING, - result.getMergeStatus()); - assertNull(result.getNewHead()); - assertEquals(second, db.resolve(Constants.HEAD + "^{commit}")); - - assertEquals( - "Squashed commit of the following:\n\ncommit " - + third.getName() - + "\nAuthor: " - + third.getAuthorIdent().getName() - + " <" - + third.getAuthorIdent().getEmailAddress() - + ">\nDate: " - + dateFormatter.formatDate(third - .getAuthorIdent()) + "\n\n\tthird commit\n", - db.readSquashCommitMsg()); - assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg()); - - Status stat = git.status().call(); - assertEquals(Sets.of("file2"), stat.getConflicting()); + try (Git git = new Git(db)) { + writeTrashFile("file1", "file1"); + git.add().addFilepattern("file1").call(); + RevCommit first = git.commit().setMessage("initial commit").call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + createBranch(first, "refs/heads/branch1"); + + writeTrashFile("file2", "master"); + git.add().addFilepattern("file2").call(); + RevCommit second = git.commit().setMessage("second commit").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + checkoutBranch("refs/heads/branch1"); + + writeTrashFile("file2", "branch"); + git.add().addFilepattern("file2").call(); + RevCommit third = git.commit().setMessage("third commit").call(); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + checkoutBranch("refs/heads/master"); + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + + MergeResult result = git.merge() + .include(db.exactRef("refs/heads/branch1")) + .setSquash(true) + .call(); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertEquals(MergeResult.MergeStatus.CONFLICTING, + result.getMergeStatus()); + assertNull(result.getNewHead()); + assertEquals(second, db.resolve(Constants.HEAD + "^{commit}")); + + assertEquals( + "Squashed commit of the following:\n\ncommit " + + third.getName() + + "\nAuthor: " + + third.getAuthorIdent().getName() + + " <" + + third.getAuthorIdent().getEmailAddress() + + ">\nDate: " + + dateFormatter.formatDate(third + .getAuthorIdent()) + "\n\n\tthird commit\n", + db.readSquashCommitMsg()); + assertEquals("\n# Conflicts:\n#\tfile2\n", db.readMergeCommitMsg()); + + Status stat = git.status().call(); + assertEquals(Sets.of("file2"), stat.getConflicting()); + } } @Test public void testFastForwardOnly() throws Exception { - Git git = new Git(db); - RevCommit initialCommit = git.commit().setMessage("initial commit") - .call(); - createBranch(initialCommit, "refs/heads/branch1"); - git.commit().setMessage("second commit").call(); - checkoutBranch("refs/heads/branch1"); - - MergeCommand merge = git.merge(); - merge.setFastForward(FastForwardMode.FF_ONLY); - merge.include(db.getRef(Constants.MASTER)); - MergeResult result = merge.call(); - - assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus()); + try (Git git = new Git(db)) { + RevCommit initialCommit = git.commit().setMessage("initial commit") + .call(); + createBranch(initialCommit, "refs/heads/branch1"); + git.commit().setMessage("second commit").call(); + checkoutBranch("refs/heads/branch1"); + + MergeCommand merge = git.merge(); + merge.setFastForward(FastForwardMode.FF_ONLY); + merge.include(db.exactRef(R_HEADS + MASTER)); + MergeResult result = merge.call(); + + assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus()); + } } @Test public void testNoFastForward() throws Exception { - Git git = new Git(db); - RevCommit initialCommit = git.commit().setMessage("initial commit") - .call(); - createBranch(initialCommit, "refs/heads/branch1"); - git.commit().setMessage("second commit").call(); - checkoutBranch("refs/heads/branch1"); - - MergeCommand merge = git.merge(); - merge.setFastForward(FastForwardMode.NO_FF); - merge.include(db.getRef(Constants.MASTER)); - MergeResult result = merge.call(); - - assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + try (Git git = new Git(db)) { + RevCommit initialCommit = git.commit().setMessage("initial commit") + .call(); + createBranch(initialCommit, "refs/heads/branch1"); + git.commit().setMessage("second commit").call(); + checkoutBranch("refs/heads/branch1"); + + MergeCommand merge = git.merge(); + merge.setFastForward(FastForwardMode.NO_FF); + merge.include(db.exactRef(R_HEADS + MASTER)); + MergeResult result = merge.call(); + + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + } } @Test public void testNoFastForwardNoCommit() throws Exception { // given - Git git = new Git(db); - RevCommit initialCommit = git.commit().setMessage("initial commit") - .call(); - createBranch(initialCommit, "refs/heads/branch1"); - RevCommit secondCommit = git.commit().setMessage("second commit") - .call(); - checkoutBranch("refs/heads/branch1"); - - // when - MergeCommand merge = git.merge(); - merge.setFastForward(FastForwardMode.NO_FF); - merge.include(db.getRef(Constants.MASTER)); - merge.setCommit(false); - MergeResult result = merge.call(); - - // then - assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); - assertEquals(2, result.getMergedCommits().length); - assertEquals(initialCommit, result.getMergedCommits()[0]); - assertEquals(secondCommit, result.getMergedCommits()[1]); - assertNull(result.getNewHead()); - assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); + try (Git git = new Git(db)) { + RevCommit initialCommit = git.commit().setMessage("initial commit") + .call(); + createBranch(initialCommit, "refs/heads/branch1"); + RevCommit secondCommit = git.commit().setMessage("second commit") + .call(); + checkoutBranch("refs/heads/branch1"); + + // when + MergeCommand merge = git.merge(); + merge.setFastForward(FastForwardMode.NO_FF); + merge.include(db.exactRef(R_HEADS + MASTER)); + merge.setCommit(false); + MergeResult result = merge.call(); + + // then + assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus()); + assertEquals(2, result.getMergedCommits().length); + assertEquals(initialCommit, result.getMergedCommits()[0]); + assertEquals(secondCommit, result.getMergedCommits()[1]); + assertNull(result.getNewHead()); + assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState()); + } } @Test public void testFastForwardOnlyNotPossible() throws Exception { - Git git = new Git(db); - RevCommit initialCommit = git.commit().setMessage("initial commit") - .call(); - createBranch(initialCommit, "refs/heads/branch1"); - git.commit().setMessage("second commit").call(); - checkoutBranch("refs/heads/branch1"); - writeTrashFile("file1", "branch1"); - git.add().addFilepattern("file").call(); - git.commit().setMessage("second commit on branch1").call(); - MergeCommand merge = git.merge(); - merge.setFastForward(FastForwardMode.FF_ONLY); - merge.include(db.getRef(Constants.MASTER)); - MergeResult result = merge.call(); - - assertEquals(MergeStatus.ABORTED, result.getMergeStatus()); + try (Git git = new Git(db)) { + RevCommit initialCommit = git.commit().setMessage("initial commit") + .call(); + createBranch(initialCommit, "refs/heads/branch1"); + git.commit().setMessage("second commit").call(); + checkoutBranch("refs/heads/branch1"); + writeTrashFile("file1", "branch1"); + git.add().addFilepattern("file").call(); + git.commit().setMessage("second commit on branch1").call(); + MergeCommand merge = git.merge(); + merge.setFastForward(FastForwardMode.FF_ONLY); + merge.include(db.exactRef(R_HEADS + MASTER)); + MergeResult result = merge.call(); + + assertEquals(MergeStatus.ABORTED, result.getMergeStatus()); + } } @Test public void testRecursiveMergeWithConflict() throws Exception { - TestRepository<Repository> db_t = new TestRepository<Repository>(db); - BranchBuilder master = db_t.branch("master"); - RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n") - .message("m0").create(); - RevCommit m1 = master.commit() - .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\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\n4\n5\n6\n7\n8\n9-side\n").message("s1") - .create(); - RevCommit s2 = side.commit().parent(m1) - .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n") - .message("s2(merge)").create(); - master.commit().parent(s1) - .add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n") - .message("m2(merge)").create(); - - Git git = Git.wrap(db); - git.checkout().setName("master").call(); - - MergeResult result = git.merge().setStrategy(MergeStrategy.RECURSIVE) - .include("side", s2).call(); - assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + try (TestRepository<Repository> db_t = new TestRepository<>(db)) { + db.incrementOpen(); + BranchBuilder master = db_t.branch("master"); + RevCommit m0 = master.commit() + .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m0") + .create(); + RevCommit m1 = master.commit() + .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\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\n4\n5\n6\n7\n8\n9-side\n").message("s1") + .create(); + RevCommit s2 = side.commit().parent(m1) + .add("f", + "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n") + .message("s2(merge)").create(); + master.commit().parent(s1) + .add("f", + "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n") + .message("m2(merge)").create(); + + Git git = Git.wrap(db); + git.checkout().setName("master").call(); + + MergeResult result = git.merge() + .setStrategy(MergeStrategy.RECURSIVE).include("side", s2) + .call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + } } - @Test - public void testMergeWithMessageOption() throws Exception { - Git git = new Git(db); - + private Ref prepareSuccessfulMerge(Git git) throws Exception { writeTrashFile("a", "1\na\n3\n"); git.add().addFilepattern("a").call(); RevCommit initialCommit = git.commit().setMessage("initial").call(); @@ -1587,46 +1952,245 @@ public class MergeCommandTest extends RepositoryTestCase { git.add().addFilepattern("c").call(); git.commit().setMessage("main").call(); - Ref sideBranch = db.getRef("side"); + return db.exactRef("refs/heads/side"); + } + + @Test + public void testMergeWithMessageOption() throws Exception { + try (Git git = new Git(db)) { + Ref sideBranch = prepareSuccessfulMerge(git); + + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setMessage("user message").call(); + + assertNull(db.readMergeCommitMsg()); + + Iterator<RevCommit> it = git.log().call().iterator(); + RevCommit newHead = it.next(); + assertEquals("user message", newHead.getFullMessage()); + } + } + + @Test + public void testMergeWithChangeId() throws Exception { + try (Git git = new Git(db)) { + Ref sideBranch = prepareSuccessfulMerge(git); + + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setInsertChangeId(true).call(); + + assertNull(db.readMergeCommitMsg()); + + Iterator<RevCommit> it = git.log().call().iterator(); + RevCommit newHead = it.next(); + String commitMessage = newHead.getFullMessage(); + assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n") + .matcher(commitMessage).find()); + } + } + + @Test + public void testMergeWithMessageAndChangeId() throws Exception { + try (Git git = new Git(db)) { + Ref sideBranch = prepareSuccessfulMerge(git); - git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) - .setMessage("user message").call(); + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setMessage("user message").setInsertChangeId(true).call(); - assertNull(db.readMergeCommitMsg()); + assertNull(db.readMergeCommitMsg()); - Iterator<RevCommit> it = git.log().call().iterator(); - RevCommit newHead = it.next(); - assertEquals("user message", newHead.getFullMessage()); + Iterator<RevCommit> it = git.log().call().iterator(); + RevCommit newHead = it.next(); + String commitMessage = newHead.getFullMessage(); + assertTrue(commitMessage.startsWith("user message\n\n")); + assertTrue(Pattern.compile("\nChange-Id: I[0-9a-fA-F]{40}\n") + .matcher(commitMessage).find()); + } } @Test public void testMergeConflictWithMessageOption() throws Exception { - Git git = new Git(db); + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - 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"); - createBranch(initialCommit, "refs/heads/side"); - checkoutBranch("refs/heads/side"); + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); - writeTrashFile("a", "1\na(side)\n3\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("side").call(); + checkoutBranch("refs/heads/master"); - checkoutBranch("refs/heads/master"); + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); - writeTrashFile("a", "1\na(main)\n3\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("main").call(); + Ref sideBranch = db.exactRef("refs/heads/side"); - Ref sideBranch = db.getRef("side"); + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setMessage("user message").call(); - git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) - .setMessage("user message").call(); + assertEquals("user message\n\n# Conflicts:\n#\ta\n", + db.readMergeCommitMsg()); + } + } + + @Test + public void testMergeConflictWithMessageAndCommentChar() throws Exception { + try (Git git = new Git(db)) { + writeTrashFile("a", "1\na\n3\n"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); - assertEquals("user message\n\nConflicts:\n\ta\n", - db.readMergeCommitMsg()); + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); + + checkoutBranch("refs/heads/master"); + + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + StoredConfig config = db.getConfig(); + config.setString("core", null, "commentChar", "^"); + + Ref sideBranch = db.exactRef("refs/heads/side"); + + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setMessage("user message").call(); + + assertEquals("user message\n\n^ Conflicts:\n^\ta\n", + db.readMergeCommitMsg()); + } + } + + @Test + public void testMergeConflictWithMessageAndCommentCharAuto() + throws Exception { + try (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("a", "1\na(side)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); + + checkoutBranch("refs/heads/master"); + + writeTrashFile("a", "1\na(main)\n3\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("main").call(); + + StoredConfig config = db.getConfig(); + config.setString("core", null, "commentChar", "auto"); + + Ref sideBranch = db.exactRef("refs/heads/side"); + + git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE) + .setMessage("#user message").call(); + + assertEquals("#user message\n\n; Conflicts:\n;\ta\n", + db.readMergeCommitMsg()); + } + } + + @Test + public void testMergeCaseInsensitiveRename() throws Exception { + Assume.assumeTrue( + "Test makes only sense on a case-insensitive file system", + db.isWorkTreeCaseInsensitive()); + try (Git git = new Git(db)) { + writeTrashFile("a", "aaa"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + // "Rename" "a" to "A" + git.rm().addFilepattern("a").call(); + writeTrashFile("A", "aaa"); + git.add().addFilepattern("A").call(); + RevCommit master = git.commit().setMessage("rename to A").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("b", "bbb"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("side").call(); + + // Merge master into side + MergeResult result = git.merge().include(master) + .setStrategy(MergeStrategy.RECURSIVE).call(); + assertEquals(MergeStatus.MERGED, result.getMergeStatus()); + assertTrue(new File(db.getWorkTree(), "A").isFile()); + // Double check + boolean found = true; + try (DirectoryStream<Path> dir = Files + .newDirectoryStream(db.getWorkTree().toPath())) { + for (Path p : dir) { + found = "A".equals(p.getFileName().toString()); + if (found) { + break; + } + } + } + assertTrue(found); + } + } + + @Test + public void testMergeCaseInsensitiveRenameConflict() throws Exception { + Assume.assumeTrue( + "Test makes only sense on a case-insensitive file system", + db.isWorkTreeCaseInsensitive()); + try (Git git = new Git(db)) { + writeTrashFile("a", "aaa"); + git.add().addFilepattern("a").call(); + RevCommit initialCommit = git.commit().setMessage("initial").call(); + // "Rename" "a" to "A" and change it + git.rm().addFilepattern("a").call(); + writeTrashFile("A", "yyy"); + git.add().addFilepattern("A").call(); + RevCommit master = git.commit().setMessage("rename to A").call(); + + createBranch(initialCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "xxx"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("side").call(); + + // Merge master into side + MergeResult result = git.merge().include(master) + .setStrategy(MergeStrategy.RECURSIVE).call(); + assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus()); + File a = new File(db.getWorkTree(), "A"); + assertTrue(a.isFile()); + // Double check + boolean found = true; + try (DirectoryStream<Path> dir = Files + .newDirectoryStream(db.getWorkTree().toPath())) { + for (Path p : dir) { + found = "A".equals(p.getFileName().toString()); + if (found) { + break; + } + } + } + assertTrue(found); + assertEquals(1, result.getConflicts().size()); + assertTrue(result.getConflicts().containsKey("a")); + checkFile(a, "yyy"); + } } private static void setExecutable(Git git, String path, boolean executable) { @@ -1639,7 +2203,7 @@ public class MergeCommandTest extends RepositoryTestCase { .getWorkTree(), path)); } - private static RevCommit addAllAndCommit(final Git git) throws Exception { + private static RevCommit addAllAndCommit(Git git) throws Exception { git.add().addFilepattern(".").call(); return git.commit().setMessage("message").call(); } |