diff options
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java')
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java | 349 |
1 files changed, 209 insertions, 140 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java index 57888e70a8..695681de8d 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java @@ -1,47 +1,15 @@ /* - * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@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 java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -53,18 +21,23 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.util.Map; import java.util.concurrent.Callable; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.MergeResult.MergeStatus; import org.eclipse.jgit.api.errors.NoHeadException; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.IndexDiff.StageState; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.merge.ContentMergeStrategy; +import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevSort; import org.eclipse.jgit.revwalk.RevWalk; @@ -140,11 +113,13 @@ public class PullCommandTest extends RepositoryTestCase { ObjectId[] mergedCommits = mergeResult.getMergedCommits(); assertEquals(targetCommit.getId(), mergedCommits[0]); assertEquals(sourceCommit.getId(), mergedCommits[1]); - RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult - .getNewHead()); - String message = "Merge branch 'master' of " - + db.getWorkTree().getAbsolutePath(); - assertEquals(message, mergeCommit.getShortMessage()); + try (RevWalk rw = new RevWalk(dbTarget)) { + RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead()); + String message = "Merge branch 'master' of " + + db.getWorkTree().getAbsolutePath(); + assertEquals(message, mergeCommit.getShortMessage()); + } + assertTrue(target.status().call().isClean()); } @Test @@ -181,6 +156,113 @@ public class PullCommandTest extends RepositoryTestCase { assertFileContentsEqual(targetFile, result); assertEquals(RepositoryState.MERGING, target.getRepository() .getRepositoryState()); + Status status = target.status().call(); + Map<String, StageState> conflicting = status.getConflictingStageState(); + assertEquals(1, conflicting.size()); + assertEquals(StageState.BOTH_MODIFIED, conflicting.get("SomeFile.txt")); + } + + @Test + public void testPullConflictTheirs() throws Exception { + PullResult res = target.pull().call(); + // nothing to update since we don't have different data yet + assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty()); + assertTrue(res.getMergeResult().getMergeStatus() + .equals(MergeStatus.ALREADY_UP_TO_DATE)); + + assertFileContentsEqual(targetFile, "Hello world"); + + // change the source file + writeToFile(sourceFile, "Source change"); + source.add().addFilepattern("SomeFile.txt").call(); + source.commit().setMessage("Source change in remote").call(); + + // change the target file + writeToFile(targetFile, "Target change"); + target.add().addFilepattern("SomeFile.txt").call(); + target.commit().setMessage("Target change in local").call(); + + res = target.pull().setStrategy(MergeStrategy.THEIRS).call(); + + assertTrue(res.isSuccessful()); + assertFileContentsEqual(targetFile, "Source change"); + assertEquals(RepositoryState.SAFE, + target.getRepository().getRepositoryState()); + assertTrue(target.status().call().isClean()); + } + + @Test + public void testPullConflictXtheirs() throws Exception { + PullResult res = target.pull().call(); + // nothing to update since we don't have different data yet + assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty()); + assertTrue(res.getMergeResult().getMergeStatus() + .equals(MergeStatus.ALREADY_UP_TO_DATE)); + + assertFileContentsEqual(targetFile, "Hello world"); + + // change the source file + writeToFile(sourceFile, "a\nHello\nb\n"); + source.add().addFilepattern("SomeFile.txt").call(); + source.commit().setMessage("Multi-line change in remote").call(); + + // Pull again + res = target.pull().call(); + assertTrue(res.isSuccessful()); + assertFileContentsEqual(targetFile, "a\nHello\nb\n"); + + // change the source file + writeToFile(sourceFile, "a\nSource change\nb\n"); + source.add().addFilepattern("SomeFile.txt").call(); + source.commit().setMessage("Source change in remote").call(); + + // change the target file + writeToFile(targetFile, "a\nTarget change\nb\nc\n"); + target.add().addFilepattern("SomeFile.txt").call(); + target.commit().setMessage("Target change in local").call(); + + res = target.pull().setContentMergeStrategy(ContentMergeStrategy.THEIRS) + .call(); + + assertTrue(res.isSuccessful()); + assertFileContentsEqual(targetFile, "a\nSource change\nb\nc\n"); + assertEquals(RepositoryState.SAFE, + target.getRepository().getRepositoryState()); + assertTrue(target.status().call().isClean()); + } + + @Test + public void testPullWithUntrackedStash() throws Exception { + target.pull().call(); + + // change the source file + writeToFile(sourceFile, "Source change"); + source.add().addFilepattern("SomeFile.txt").call(); + source.commit().setMessage("Source change in remote").call(); + + // write untracked file + writeToFile(new File(dbTarget.getWorkTree(), "untracked.txt"), + "untracked"); + RevCommit stash = target.stashCreate().setIndexMessage("message here") + .setIncludeUntracked(true).call(); + assertNotNull(stash); + assertTrue(target.status().call().isClean()); + + // pull from source + assertTrue(target.pull().call().isSuccessful()); + assertEquals("[SomeFile.txt, mode:100644, content:Source change]", + indexState(dbTarget, CONTENT)); + assertFalse(JGitTestUtil.check(dbTarget, "untracked.txt")); + assertEquals("Source change", + JGitTestUtil.read(dbTarget, "SomeFile.txt")); + + // apply the stash + target.stashApply().setStashRef(stash.getName()).call(); + assertEquals("[SomeFile.txt, mode:100644, content:Source change]", + indexState(dbTarget, CONTENT)); + assertEquals("untracked", JGitTestUtil.read(dbTarget, "untracked.txt")); + assertEquals("Source change", + JGitTestUtil.read(dbTarget, "SomeFile.txt")); } @Test @@ -259,11 +341,12 @@ public class PullCommandTest extends RepositoryTestCase { ObjectId[] mergedCommits = mergeResult.getMergedCommits(); assertEquals(targetCommit.getId(), mergedCommits[0]); assertEquals(sourceCommit.getId(), mergedCommits[1]); - RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult - .getNewHead()); - String message = "Merge branch 'other' of " - + db.getWorkTree().getAbsolutePath(); - assertEquals(message, mergeCommit.getShortMessage()); + try (RevWalk rw = new RevWalk(dbTarget)) { + RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead()); + String message = "Merge branch 'other' of " + + db.getWorkTree().getAbsolutePath(); + assertEquals(message, mergeCommit.getShortMessage()); + } } @Test @@ -293,70 +376,78 @@ public class PullCommandTest extends RepositoryTestCase { ObjectId[] mergedCommits = mergeResult.getMergedCommits(); assertEquals(targetCommit.getId(), mergedCommits[0]); assertEquals(sourceCommit.getId(), mergedCommits[1]); - RevCommit mergeCommit = new RevWalk(dbTarget).parseCommit(mergeResult - .getNewHead()); - String message = "Merge branch 'other' of " - + db.getWorkTree().getAbsolutePath() + " into other"; - assertEquals(message, mergeCommit.getShortMessage()); + try (RevWalk rw = new RevWalk(dbTarget)) { + RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead()); + String message = "Merge branch 'other' of " + + db.getWorkTree().getAbsolutePath() + " into other"; + assertEquals(message, mergeCommit.getShortMessage()); + } } private enum TestPullMode { - MERGE, REBASE, REBASE_PREASERVE + MERGE, REBASE, REBASE_MERGES } @Test /** global rebase config should be respected */ - public void testPullWithRebasePreserve1Config() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "preserve"); - config.save(); - return target.pull().call(); - } + public void testPullWithRebaseMerges1Config() throws Exception { + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "merges"); + config.save(); + return target.pull().call(); + }; + doTestPullWithRebase(setup, TestPullMode.REBASE_MERGES); + } + + @Test + /** + * global rebase config using old "preserve" value which was renamed to + * "merges" should be respected to ensure backwards compatibility + */ + public void testPullWithRebaseMerges1ConfigAlias() throws Exception { + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "preserve"); + config.save(); + return target.pull().call(); }; - doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE); + doTestPullWithRebase(setup, TestPullMode.REBASE_MERGES); } @Test /** the branch-local config should win over the global config */ - public void testPullWithRebasePreserveConfig2() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "false"); - config.setString("branch", "master", "rebase", "preserve"); - config.save(); - return target.pull().call(); - } + public void testPullWithRebaseMergesConfig2() throws Exception { + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "false"); + config.setString("branch", "master", "rebase", "merges"); + config.save(); + return target.pull().call(); }; - doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE); + doTestPullWithRebase(setup, TestPullMode.REBASE_MERGES); } @Test /** the branch-local config should be respected */ - public void testPullWithRebasePreserveConfig3() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("branch", "master", "rebase", "preserve"); - config.save(); - return target.pull().call(); - } + public void testPullWithRebaseMergesConfig3() throws Exception { + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("branch", "master", "rebase", "merges"); + config.save(); + return target.pull().call(); }; - doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE); + doTestPullWithRebase(setup, TestPullMode.REBASE_MERGES); } @Test /** global rebase config should be respected */ public void testPullWithRebaseConfig1() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "true"); - config.save(); - return target.pull().call(); - } + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "true"); + config.save(); + return target.pull().call(); }; doTestPullWithRebase(setup, TestPullMode.REBASE); } @@ -364,14 +455,12 @@ public class PullCommandTest extends RepositoryTestCase { @Test /** the branch-local config should win over the global config */ public void testPullWithRebaseConfig2() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "preserve"); - config.setString("branch", "master", "rebase", "true"); - config.save(); - return target.pull().call(); - } + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "merges"); + config.setString("branch", "master", "rebase", "true"); + config.save(); + return target.pull().call(); }; doTestPullWithRebase(setup, TestPullMode.REBASE); } @@ -379,13 +468,11 @@ public class PullCommandTest extends RepositoryTestCase { @Test /** the branch-local config should be respected */ public void testPullWithRebaseConfig3() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("branch", "master", "rebase", "true"); - config.save(); - return target.pull().call(); - } + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("branch", "master", "rebase", "true"); + config.save(); + return target.pull().call(); }; doTestPullWithRebase(setup, TestPullMode.REBASE); } @@ -393,25 +480,19 @@ public class PullCommandTest extends RepositoryTestCase { @Test /** without config it should merge */ public void testPullWithoutConfig() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - return target.pull().call(); - } - }; + Callable<PullResult> setup = target.pull(); doTestPullWithRebase(setup, TestPullMode.MERGE); } @Test /** the branch local config should win over the global config */ public void testPullWithMergeConfig() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "true"); - config.setString("branch", "master", "rebase", "false"); - config.save(); - return target.pull().call(); - } + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "true"); + config.setString("branch", "master", "rebase", "false"); + config.save(); + return target.pull().call(); }; doTestPullWithRebase(setup, TestPullMode.MERGE); } @@ -419,13 +500,11 @@ public class PullCommandTest extends RepositoryTestCase { @Test /** the branch local config should win over the global config */ public void testPullWithMergeConfig2() throws Exception { - Callable<PullResult> setup = new Callable<PullResult>() { - public PullResult call() throws Exception { - StoredConfig config = dbTarget.getConfig(); - config.setString("pull", null, "rebase", "false"); - config.save(); - return target.pull().call(); - } + Callable<PullResult> setup = () -> { + StoredConfig config = dbTarget.getConfig(); + config.setString("pull", null, "rebase", "false"); + config.save(); + return target.pull().call(); }; doTestPullWithRebase(setup, TestPullMode.MERGE); } @@ -486,7 +565,7 @@ public class PullCommandTest extends RepositoryTestCase { assertEquals(sourceCommit, next.getParent(1)); // since both parents are known do no further checks here } else { - if (expectedPullMode == TestPullMode.REBASE_PREASERVE) { + if (expectedPullMode == TestPullMode.REBASE_MERGES) { next = rw.next(); assertEquals(2, next.getParentCount()); } @@ -510,6 +589,7 @@ public class PullCommandTest extends RepositoryTestCase { public void setUp() throws Exception { super.setUp(); dbTarget = createWorkRepository(); + addRepoToClose(dbTarget); source = new Git(db); target = new Git(dbTarget); @@ -543,34 +623,23 @@ public class PullCommandTest extends RepositoryTestCase { private static void writeToFile(File actFile, String string) throws IOException { - FileOutputStream fos = null; - try { - fos = new FileOutputStream(actFile); - fos.write(string.getBytes("UTF-8")); - fos.close(); - } finally { - if (fos != null) - fos.close(); + try (FileOutputStream fos = new FileOutputStream(actFile)) { + fos.write(string.getBytes(UTF_8)); } } private static void assertFileContentsEqual(File actFile, String string) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - FileInputStream fis = null; byte[] buffer = new byte[100]; - try { - fis = new FileInputStream(actFile); + try (FileInputStream fis = new FileInputStream(actFile)) { int read = fis.read(buffer); while (read > 0) { bos.write(buffer, 0, read); read = fis.read(buffer); } - String content = new String(bos.toByteArray(), "UTF-8"); + String content = new String(bos.toByteArray(), UTF_8); assertEquals(string, content); - } finally { - if (fis != null) - fis.close(); } } } |