diff options
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java')
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java | 797 |
1 files changed, 568 insertions, 229 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java index a999337964..3f5c5da55a 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java @@ -1,47 +1,16 @@ /* - * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2010, 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.api.CherryPickCommitMessageProvider.ORIGINAL; +import static org.eclipse.jgit.api.CherryPickCommitMessageProvider.ORIGINAL_WITH_REFERENCE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -58,13 +27,18 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.MultipleParentsNotAllowedException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.events.ChangeRecorder; +import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.ReflogReader; import org.eclipse.jgit.lib.RepositoryState; +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; import org.junit.Test; @@ -88,140 +62,176 @@ public class CherryPickCommandTest extends RepositoryTestCase { private void doTestCherryPick(boolean noCommit) throws IOException, JGitInternalException, GitAPIException { - Git git = new Git(db); - - writeTrashFile("a", "first line\nsec. line\nthird line\n"); - git.add().addFilepattern("a").call(); - RevCommit firstCommit = git.commit().setMessage("create a").call(); - - writeTrashFile("b", "content\n"); - git.add().addFilepattern("b").call(); - git.commit().setMessage("create b").call(); - - writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("enlarged a").call(); - - writeTrashFile("a", - "first line\nsecond line\nthird line\nfourth line\n"); - git.add().addFilepattern("a").call(); - RevCommit fixingA = git.commit().setMessage("fixed a").call(); - - git.branchCreate().setName("side").setStartPoint(firstCommit).call(); - checkoutBranch("refs/heads/side"); - - writeTrashFile("a", "first line\nsec. line\nthird line\nfeature++\n"); - git.add().addFilepattern("a").call(); - git.commit().setMessage("enhanced a").call(); - - CherryPickResult pickResult = git.cherryPick().include(fixingA) - .setNoCommit(noCommit).call(); + try (Git git = new Git(db)) { + writeTrashFile("a", "first line\nsec. line\nthird line\n"); + git.add().addFilepattern("a").call(); + RevCommit firstCommit = git.commit().setMessage("create a").call(); + + writeTrashFile("b", "content\n"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("create b").call(); + + writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("enlarged a").call(); + + writeTrashFile("a", + "first line\nsecond line\nthird line\nfourth line\n"); + git.add().addFilepattern("a").call(); + RevCommit fixingA = git.commit().setMessage("fixed a").call(); + + git.branchCreate().setName("side").setStartPoint(firstCommit).call(); + checkoutBranch("refs/heads/side"); + + writeTrashFile("a", "first line\nsec. line\nthird line\nfeature++\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("enhanced a").call(); + + CherryPickResult pickResult = git.cherryPick().include(fixingA) + .setNoCommit(noCommit).call(); + + assertEquals(CherryPickStatus.OK, pickResult.getStatus()); + assertFalse(new File(db.getWorkTree(), "b").exists()); + checkFile(new File(db.getWorkTree(), "a"), + "first line\nsecond line\nthird line\nfeature++\n"); + Iterator<RevCommit> history = git.log().call().iterator(); + if (!noCommit) + assertEquals("fixed a", history.next().getFullMessage()); + assertEquals("enhanced a", history.next().getFullMessage()); + assertEquals("create a", history.next().getFullMessage()); + assertFalse(history.hasNext()); + } + } - assertEquals(CherryPickStatus.OK, pickResult.getStatus()); - assertFalse(new File(db.getWorkTree(), "b").exists()); - checkFile(new File(db.getWorkTree(), "a"), - "first line\nsecond line\nthird line\nfeature++\n"); - Iterator<RevCommit> history = git.log().call().iterator(); - if (!noCommit) + @Test + public void testSequentialCherryPick() + throws IOException, JGitInternalException, GitAPIException { + try (Git git = new Git(db)) { + writeTrashFile("a", "first line\nsec. line\nthird line\n"); + git.add().addFilepattern("a").call(); + RevCommit firstCommit = git.commit().setMessage("create a").call(); + + writeTrashFile("a", + "first line\nsec. line\nthird line\nfourth line\n"); + git.add().addFilepattern("a").call(); + RevCommit enlargingA = git.commit().setMessage("enlarged a").call(); + + writeTrashFile("a", + "first line\nsecond line\nthird line\nfourth line\n"); + git.add().addFilepattern("a").call(); + RevCommit fixingA = git.commit().setMessage("fixed a").call(); + + git.branchCreate().setName("side").setStartPoint(firstCommit) + .call(); + checkoutBranch("refs/heads/side"); + + writeTrashFile("b", "nothing to do with a"); + git.add().addFilepattern("b").call(); + git.commit().setMessage("create b").call(); + + CherryPickResult result = git.cherryPick().include(enlargingA) + .include(fixingA).call(); + assertEquals(CherryPickResult.CherryPickStatus.OK, + result.getStatus()); + + Iterator<RevCommit> history = git.log().call().iterator(); assertEquals("fixed a", history.next().getFullMessage()); - assertEquals("enhanced a", history.next().getFullMessage()); - assertEquals("create a", history.next().getFullMessage()); - assertFalse(history.hasNext()); + assertEquals("enlarged a", history.next().getFullMessage()); + assertEquals("create b", history.next().getFullMessage()); + assertEquals("create a", history.next().getFullMessage()); + assertFalse(history.hasNext()); + } } - @Test - public void testSequentialCherryPick() throws IOException, JGitInternalException, - GitAPIException { - Git git = new Git(db); - - writeTrashFile("a", "first line\nsec. line\nthird line\n"); - git.add().addFilepattern("a").call(); - RevCommit firstCommit = git.commit().setMessage("create a").call(); - - writeTrashFile("a", "first line\nsec. line\nthird line\nfourth line\n"); - git.add().addFilepattern("a").call(); - RevCommit enlargingA = git.commit().setMessage("enlarged a").call(); - - writeTrashFile("a", - "first line\nsecond line\nthird line\nfourth line\n"); - git.add().addFilepattern("a").call(); - RevCommit fixingA = git.commit().setMessage("fixed a").call(); - - git.branchCreate().setName("side").setStartPoint(firstCommit).call(); - checkoutBranch("refs/heads/side"); - - writeTrashFile("b", "nothing to do with a"); - git.add().addFilepattern("b").call(); - git.commit().setMessage("create b").call(); - - CherryPickResult result = git.cherryPick().include(enlargingA).include(fixingA).call(); - assertEquals(CherryPickResult.CherryPickStatus.OK, result.getStatus()); - - Iterator<RevCommit> history = git.log().call().iterator(); - assertEquals("fixed a", history.next().getFullMessage()); - assertEquals("enlarged a", history.next().getFullMessage()); - assertEquals("create b", history.next().getFullMessage()); - assertEquals("create a", history.next().getFullMessage()); - assertFalse(history.hasNext()); - } + @Test + public void testRootCherryPick() + throws IOException, JGitInternalException, GitAPIException { + try (Git git = new Git(db)) { + writeTrashFile("a", "a"); + writeTrashFile("b", "b"); + git.add().addFilepattern("a").addFilepattern("b").call(); + RevCommit firstCommit = git.commit().setMessage("Create a and b") + .call(); + + git.checkout().setOrphan(true).setName("orphan").call(); + git.rm().addFilepattern("a").addFilepattern("b").call(); + writeTrashFile("a", "a"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("Orphan a").call(); + + CherryPickResult result = git.cherryPick().include(firstCommit) + .call(); + assertEquals(CherryPickResult.CherryPickStatus.OK, + result.getStatus()); + + Iterator<RevCommit> history = git.log().call().iterator(); + assertEquals("Create a and b", history.next().getFullMessage()); + assertEquals("Orphan a", history.next().getFullMessage()); + assertFalse(history.hasNext()); + } + } @Test public void testCherryPickDirtyIndex() throws Exception { - Git git = new Git(db); - RevCommit sideCommit = prepareCherryPick(git); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - // modify and add file a - writeTrashFile("a", "a(modified)"); - git.add().addFilepattern("a").call(); - // do not commit + // modify and add file a + writeTrashFile("a", "a(modified)"); + git.add().addFilepattern("a").call(); + // do not commit - doCherryPickAndCheckResult(git, sideCommit, - MergeFailureReason.DIRTY_INDEX); + doCherryPickAndCheckResult(git, sideCommit, + MergeFailureReason.DIRTY_INDEX); + } } @Test public void testCherryPickDirtyWorktree() throws Exception { - Git git = new Git(db); - RevCommit sideCommit = prepareCherryPick(git); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - // modify file a - writeTrashFile("a", "a(modified)"); - // do not add and commit + // modify file a + writeTrashFile("a", "a(modified)"); + // do not add and commit - doCherryPickAndCheckResult(git, sideCommit, - MergeFailureReason.DIRTY_WORKTREE); + doCherryPickAndCheckResult(git, sideCommit, + MergeFailureReason.DIRTY_WORKTREE); + } } @Test public void testCherryPickConflictResolution() throws Exception { - Git git = new Git(db); - RevCommit sideCommit = prepareCherryPick(git); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - CherryPickResult result = git.cherryPick().include(sideCommit.getId()) - .call(); + CherryPickResult result = git.cherryPick().include(sideCommit.getId()) + .call(); - assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); - assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); - assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg()); - assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) - .exists()); - assertEquals(sideCommit.getId(), db.readCherryPickHead()); - assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState()); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); + assertEquals("side\n\n# Conflicts:\n#\ta\n", + db.readMergeCommitMsg()); + assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) + .exists()); + assertEquals(sideCommit.getId(), db.readCherryPickHead()); + assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState()); - // Resolve - writeTrashFile("a", "a"); - git.add().addFilepattern("a").call(); + // Resolve + writeTrashFile("a", "a"); + git.add().addFilepattern("a").call(); - assertEquals(RepositoryState.CHERRY_PICKING_RESOLVED, - db.getRepositoryState()); + assertEquals(RepositoryState.CHERRY_PICKING_RESOLVED, + db.getRepositoryState()); - git.commit().setOnly("a").setMessage("resolve").call(); + git.commit().setOnly("a").setMessage("resolve").call(); - assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + } } @Test - public void testCherryPickConflictResolutionNoCOmmit() throws Exception { + public void testCherryPickConflictResolutionNoCommit() throws Exception { Git git = new Git(db); RevCommit sideCommit = prepareCherryPick(git); @@ -233,7 +243,7 @@ public class CherryPickCommandTest extends RepositoryTestCase { String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; assertEquals(expected, read("a")); assertTrue(new File(db.getDirectory(), Constants.MERGE_MSG).exists()); - assertEquals("side\n\nConflicts:\n\ta\n", db.readMergeCommitMsg()); + assertEquals("side\n\n# Conflicts:\n#\ta\n", db.readMergeCommitMsg()); assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) .exists()); assertEquals(RepositoryState.SAFE, db.getRepositoryState()); @@ -251,88 +261,208 @@ public class CherryPickCommandTest extends RepositoryTestCase { @Test public void testCherryPickConflictReset() throws Exception { - Git git = new Git(db); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - RevCommit sideCommit = prepareCherryPick(git); - - CherryPickResult result = git.cherryPick().include(sideCommit.getId()) - .call(); + CherryPickResult result = git.cherryPick().include(sideCommit.getId()) + .call(); - assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); - assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState()); - assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) - .exists()); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + assertEquals(RepositoryState.CHERRY_PICKING, db.getRepositoryState()); + assertTrue(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) + .exists()); - git.reset().setMode(ResetType.MIXED).setRef("HEAD").call(); + git.reset().setMode(ResetType.MIXED).setRef("HEAD").call(); - assertEquals(RepositoryState.SAFE, db.getRepositoryState()); - assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) - .exists()); + assertEquals(RepositoryState.SAFE, db.getRepositoryState()); + assertFalse(new File(db.getDirectory(), Constants.CHERRY_PICK_HEAD) + .exists()); + } } @Test public void testCherryPickOverExecutableChangeOnNonExectuableFileSystem() throws Exception { - Git git = new Git(db); - File file = writeTrashFile("test.txt", "a"); - assertNotNull(git.add().addFilepattern("test.txt").call()); - assertNotNull(git.commit().setMessage("commit1").call()); + try (Git git = new Git(db)) { + File file = writeTrashFile("test.txt", "a"); + assertNotNull(git.add().addFilepattern("test.txt").call()); + assertNotNull(git.commit().setMessage("commit1").call()); - assertNotNull(git.checkout().setCreateBranch(true).setName("a").call()); + assertNotNull(git.checkout().setCreateBranch(true).setName("a").call()); - writeTrashFile("test.txt", "b"); - assertNotNull(git.add().addFilepattern("test.txt").call()); - RevCommit commit2 = git.commit().setMessage("commit2").call(); - assertNotNull(commit2); + writeTrashFile("test.txt", "b"); + assertNotNull(git.add().addFilepattern("test.txt").call()); + RevCommit commit2 = git.commit().setMessage("commit2").call(); + assertNotNull(commit2); - assertNotNull(git.checkout().setName(Constants.MASTER).call()); + assertNotNull(git.checkout().setName(Constants.MASTER).call()); - DirCache cache = db.lockDirCache(); - cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE); - cache.write(); - assertTrue(cache.commit()); - cache.unlock(); + DirCache cache = db.lockDirCache(); + cache.getEntry("test.txt").setFileMode(FileMode.EXECUTABLE_FILE); + cache.write(); + assertTrue(cache.commit()); + cache.unlock(); - assertNotNull(git.commit().setMessage("commit3").call()); + assertNotNull(git.commit().setMessage("commit3").call()); - db.getFS().setExecute(file, false); - git.getRepository() - .getConfig() - .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, - ConfigConstants.CONFIG_KEY_FILEMODE, false); + db.getFS().setExecute(file, false); + git.getRepository() + .getConfig() + .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_FILEMODE, false); - CherryPickResult result = git.cherryPick().include(commit2).call(); - assertNotNull(result); - assertEquals(CherryPickStatus.OK, result.getStatus()); + CherryPickResult result = git.cherryPick().include(commit2).call(); + assertNotNull(result); + assertEquals(CherryPickStatus.OK, result.getStatus()); + } + } + + @Test + public void testCherryPickOurs() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); + + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()) + .setStrategy(MergeStrategy.OURS) + .call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + + String expected = "a(master)"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + + @Test + public void testCherryPickTheirs() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); + + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()) + .setStrategy(MergeStrategy.THEIRS) + .call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + + String expected = "a(side)"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + + @Test + public void testCherryPickXours() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPickStrategyOption(git); + + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()) + .setContentMergeStrategy(ContentMergeStrategy.OURS) + .call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + + String expected = "a\nmaster\nc\nd\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + + @Test + public void testCherryPickXtheirs() throws Exception { + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPickStrategyOption(git); + + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()) + .setContentMergeStrategy(ContentMergeStrategy.THEIRS) + .call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + + String expected = "a\nside\nc\nd\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } } @Test public void testCherryPickConflictMarkers() throws Exception { - Git git = new Git(db); - RevCommit sideCommit = prepareCherryPick(git); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - CherryPickResult result = git.cherryPick().include(sideCommit.getId()) - .call(); - assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + CherryPickResult result = git.cherryPick().include(sideCommit.getId()) + .call(); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); - String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; - checkFile(new File(db.getWorkTree(), "a"), expected); + String expected = "<<<<<<< master\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } + } + + @Test + public void testCherryPickConflictFiresModifiedEvent() throws Exception { + ListenerHandle listener = null; + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); + ChangeRecorder recorder = new ChangeRecorder(); + listener = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + CherryPickResult result = git.cherryPick() + .include(sideCommit.getId()).call(); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + recorder.assertEvent(new String[] { "a" }, ChangeRecorder.EMPTY); + } finally { + if (listener != null) { + listener.remove(); + } + } + } + + @Test + public void testCherryPickNewFileFiresModifiedEvent() throws Exception { + ListenerHandle listener = null; + try (Git git = new Git(db)) { + writeTrashFile("test.txt", "a"); + git.add().addFilepattern("test.txt").call(); + git.commit().setMessage("commit1").call(); + git.checkout().setCreateBranch(true).setName("a").call(); + + writeTrashFile("side.txt", "side"); + git.add().addFilepattern("side.txt").call(); + RevCommit side = git.commit().setMessage("side").call(); + assertNotNull(side); + + assertNotNull(git.checkout().setName(Constants.MASTER).call()); + writeTrashFile("test.txt", "b"); + assertNotNull(git.add().addFilepattern("test.txt").call()); + assertNotNull(git.commit().setMessage("commit2").call()); + + ChangeRecorder recorder = new ChangeRecorder(); + listener = db.getListenerList() + .addWorkingTreeModifiedListener(recorder); + CherryPickResult result = git.cherryPick() + .include(side.getId()).call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + recorder.assertEvent(new String[] { "side.txt" }, + ChangeRecorder.EMPTY); + } finally { + if (listener != null) { + listener.remove(); + } + } } @Test public void testCherryPickOurCommitName() throws Exception { - Git git = new Git(db); - RevCommit sideCommit = prepareCherryPick(git); + try (Git git = new Git(db)) { + RevCommit sideCommit = prepareCherryPick(git); - CherryPickResult result = git.cherryPick().include(sideCommit.getId()) - .setOurCommitName("custom name").call(); - assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); + CherryPickResult result = git.cherryPick().include(sideCommit.getId()) + .setOurCommitName("custom name").call(); + assertEquals(CherryPickStatus.CONFLICTING, result.getStatus()); - String expected = "<<<<<<< custom name\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; - checkFile(new File(db.getWorkTree(), "a"), expected); + String expected = "<<<<<<< custom name\na(master)\n=======\na(side)\n>>>>>>> 527460a side\n"; + checkFile(new File(db.getWorkTree(), "a"), expected); + } } - private RevCommit prepareCherryPick(final Git git) throws Exception { + private RevCommit prepareCherryPick(Git git) throws Exception { // create, add and commit file a writeTrashFile("a", "a"); git.add().addFilepattern("a").call(); @@ -356,6 +486,31 @@ public class CherryPickCommandTest extends RepositoryTestCase { return sideCommit; } + private RevCommit prepareCherryPickStrategyOption(Git git) + throws Exception { + // create, add and commit file a + writeTrashFile("a", "a\nb\nc\n"); + git.add().addFilepattern("a").call(); + RevCommit firstMasterCommit = git.commit().setMessage("first master") + .call(); + + // create and checkout side branch + createBranch(firstMasterCommit, "refs/heads/side"); + checkoutBranch("refs/heads/side"); + // modify, add and commit file a + writeTrashFile("a", "a\nside\nc\nd\n"); + git.add().addFilepattern("a").call(); + RevCommit sideCommit = git.commit().setMessage("side").call(); + + // checkout master branch + checkoutBranch("refs/heads/master"); + // modify, add and commit file a + writeTrashFile("a", "a\nmaster\nc\n"); + git.add().addFilepattern("a").call(); + git.commit().setMessage("second master").call(); + return sideCommit; + } + private void doCherryPickAndCheckResult(final Git git, final RevCommit sideCommit, final MergeFailureReason reason) throws Exception { @@ -375,10 +530,11 @@ public class CherryPickCommandTest extends RepositoryTestCase { assertEquals(RepositoryState.SAFE, db.getRepositoryState()); if (reason == null) { - ReflogReader reader = db.getReflogReader(Constants.HEAD); + RefDatabase refDb = db.getRefDatabase(); + ReflogReader reader = refDb.getReflogReader(Constants.HEAD); assertTrue(reader.getLastEntry().getComment() .startsWith("cherry-pick: ")); - reader = db.getReflogReader(db.getBranch()); + reader = refDb.getReflogReader(db.getFullBranch()); assertTrue(reader.getLastEntry().getComment() .startsWith("cherry-pick: ")); } @@ -399,43 +555,226 @@ public class CherryPickCommandTest extends RepositoryTestCase { */ @Test public void testCherryPickMerge() throws Exception { - Git git = new Git(db); + try (Git git = new Git(db)) { + commitFile("file", "1\n2\n3\n", "master"); + commitFile("file", "1\n2\n3\n", "side"); + checkoutBranch("refs/heads/side"); + RevCommit commitD = commitFile("file", "1\n2\n3\n4\n5\n", "side2"); + commitFile("file", "a\n2\n3\n", "side"); + MergeResult mergeResult = git.merge().include(commitD).call(); + ObjectId commitM = mergeResult.getNewHead(); + checkoutBranch("refs/heads/master"); + RevCommit commitT = commitFile("another", "t", "master"); + + try { + git.cherryPick().include(commitM).call(); + fail("merges should not be cherry-picked by default"); + } catch (MultipleParentsNotAllowedException e) { + // expected + } + try { + git.cherryPick().include(commitM).setMainlineParentNumber(3).call(); + fail("specifying a non-existent parent should fail"); + } catch (JGitInternalException e) { + // expected + assertTrue(e.getMessage().endsWith( + "does not have a parent number 3.")); + } + + CherryPickResult result = git.cherryPick().include(commitM) + .setMainlineParentNumber(1).call(); + assertEquals(CherryPickStatus.OK, result.getStatus()); + checkFile(new File(db.getWorkTree(), "file"), "1\n2\n3\n4\n5\n"); + + git.reset().setMode(ResetType.HARD).setRef(commitT.getName()).call(); + + CherryPickResult result2 = git.cherryPick().include(commitM) + .setMainlineParentNumber(2).call(); + assertEquals(CherryPickStatus.OK, result2.getStatus()); + checkFile(new File(db.getWorkTree(), "file"), "a\n2\n3\n"); + } + } - commitFile("file", "1\n2\n3\n", "master"); - commitFile("file", "1\n2\n3\n", "side"); + private void doCherryPickWithCustomProviderBaseTest(Git git, + CherryPickCommitMessageProvider commitMessageProvider) + throws Exception { + writeTrashFile("fileA", "line 1\nline 2\nline 3\n"); + git.add().addFilepattern("fileA").call(); + RevCommit commitFirst = git.commit().setMessage("create fileA").call(); + + writeTrashFile("fileB", "content from file B\n"); + git.add().addFilepattern("fileB").call(); + RevCommit commitCreateFileB = git.commit() + .setMessage("create fileB\n\nsome commit details").call(); + + writeTrashFile("fileA", "line 1\nline 2\nline 3\nline 4\n"); + git.add().addFilepattern("fileA").call(); + RevCommit commitEditFileA1 = git.commit().setMessage("patch fileA 1") + .call(); + + writeTrashFile("fileA", "line 1\nline 2\nline 3\nline 4\nline 5\n"); + git.add().addFilepattern("fileA").call(); + RevCommit commitEditFileA2 = git.commit().setMessage("patch fileA 2") + .call(); + + git.branchCreate().setName("side").setStartPoint(commitFirst).call(); checkoutBranch("refs/heads/side"); - RevCommit commitD = commitFile("file", "1\n2\n3\n4\n5\n", "side2"); - commitFile("file", "a\n2\n3\n", "side"); - MergeResult mergeResult = git.merge().include(commitD).call(); - ObjectId commitM = mergeResult.getNewHead(); - checkoutBranch("refs/heads/master"); - RevCommit commitT = commitFile("another", "t", "master"); - try { - git.cherryPick().include(commitM).call(); - fail("merges should not be cherry-picked by default"); - } catch (MultipleParentsNotAllowedException e) { - // expected + CherryPickResult pickResult = git.cherryPick() + .setCherryPickCommitMessageProvider(commitMessageProvider) + .include(commitCreateFileB).include(commitEditFileA1) + .include(commitEditFileA2).call(); + + assertEquals(CherryPickStatus.OK, pickResult.getStatus()); + + assertTrue(new File(db.getWorkTree(), "fileA").exists()); + assertTrue(new File(db.getWorkTree(), "fileB").exists()); + + checkFile(new File(db.getWorkTree(), "fileA"), + "line 1\nline 2\nline 3\nline 4\nline 5\n"); + checkFile(new File(db.getWorkTree(), "fileB"), "content from file B\n"); + } + + @Test + public void testCherryPickWithCustomCommitMessageProvider() + throws Exception { + try (Git git = new Git(db)) { + @SuppressWarnings("boxing") + CherryPickCommitMessageProvider messageProvider = srcCommit -> { + String message = srcCommit.getFullMessage(); + return String.format("%s (message length: %d)", message, + message.length()); + }; + doCherryPickWithCustomProviderBaseTest(git, messageProvider); + + Iterator<RevCommit> history = git.log().call().iterator(); + assertEquals("patch fileA 2 (message length: 13)", + history.next().getFullMessage()); + assertEquals("patch fileA 1 (message length: 13)", + history.next().getFullMessage()); + assertEquals( + "create fileB\n\nsome commit details (message length: 33)", + history.next().getFullMessage()); + assertEquals("create fileA", history.next().getFullMessage()); + assertFalse(history.hasNext()); } - try { - git.cherryPick().include(commitM).setMainlineParentNumber(3).call(); - fail("specifying a non-existent parent should fail"); - } catch (JGitInternalException e) { - // expected - assertTrue(e.getMessage().endsWith( - "does not have a parent number 3.")); + } + + @Test + public void testCherryPickWithCustomCommitMessageProvider_ORIGINAL() + throws Exception { + try (Git git = new Git(db)) { + doCherryPickWithCustomProviderBaseTest(git, ORIGINAL); + + Iterator<RevCommit> history = git.log().call().iterator(); + assertEquals("patch fileA 2", history.next().getFullMessage()); + assertEquals("patch fileA 1", history.next().getFullMessage()); + assertEquals("create fileB\n\nsome commit details", + history.next().getFullMessage()); + assertEquals("create fileA", history.next().getFullMessage()); + assertFalse(history.hasNext()); } + } - CherryPickResult result = git.cherryPick().include(commitM) - .setMainlineParentNumber(1).call(); - assertEquals(CherryPickStatus.OK, result.getStatus()); - checkFile(new File(db.getWorkTree(), "file"), "1\n2\n3\n4\n5\n"); + @Test + public void testCherryPickWithCustomCommitMessageProvider_ORIGINAL_WITH_REFERENCE() + throws Exception { + try (Git git = new Git(db)) { + doCherryPickWithCustomProviderBaseTest(git, + ORIGINAL_WITH_REFERENCE); + + Iterator<RevCommit> history = git.log().call().iterator(); + assertEquals("patch fileA 2\n\n(cherry picked from commit 1ac121e90b0fb6fb18bbb4307e3e9731ceeba9e1)", history.next().getFullMessage()); + assertEquals("patch fileA 1\n\n(cherry picked from commit 71475239df59076e18564fa360e3a74280926c2a)", history.next().getFullMessage()); + assertEquals("create fileB\n\nsome commit details\n\n(cherry picked from commit 29b4501297ccf8de9de9f451e7beb384b51f5378)", + history.next().getFullMessage()); + assertEquals("create fileA", history.next().getFullMessage()); + assertFalse(history.hasNext()); + } + } - git.reset().setMode(ResetType.HARD).setRef(commitT.getName()).call(); + @Test + public void testCherryPickWithCustomCommitMessageProvider_ORIGINAL_WITH_REFERENCE_DonNotAddNewLineAfterFooter() + throws Exception { + try (Git git = new Git(db)) { + CherryPickCommitMessageProvider commitMessageProvider = CherryPickCommitMessageProvider.ORIGINAL_WITH_REFERENCE; + + RevCommit commit1 = addFileAndCommit(git, "file1", "content 1", + "commit1: no footer line"); + RevCommit commit2 = addFileAndCommit(git, "file2", "content 2", + "commit2: simple single footer line" + + "\n\nSigned-off-by: Alice <alice@example.com>"); + RevCommit commit3 = addFileAndCommit(git, "file3", "content 3", + "commit3: multiple footer lines\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>"); + RevCommit commit4 = addFileAndCommit(git, "file4", "content 4", + "commit4: extra commit text before footer line\n\n" + + "Commit message details\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>"); + RevCommit commit5 = addFileAndCommit(git, "file5", "content 5", + "commit5: extra commit text after footer line\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>\n\n" + + "some extra description after footer"); + + git.branchCreate().setName("side").setStartPoint(commit1).call(); + checkoutBranch("refs/heads/side"); + + CherryPickResult pickResult = git.cherryPick() + .setCherryPickCommitMessageProvider(commitMessageProvider) + .include(commit2).include(commit3).include(commit4) + .include(commit5).call(); + + assertEquals(CherryPickStatus.OK, pickResult.getStatus()); + + assertTrue(new File(db.getWorkTree(), "file1").exists()); + assertTrue(new File(db.getWorkTree(), "file2").exists()); + assertTrue(new File(db.getWorkTree(), "file3").exists()); + assertTrue(new File(db.getWorkTree(), "file4").exists()); + assertTrue(new File(db.getWorkTree(), "file5").exists()); + + Iterator<RevCommit> history = git.log().call().iterator(); + RevCommit cpCommit1 = history.next(); + RevCommit cpCommit2 = history.next(); + RevCommit cpCommit3 = history.next(); + RevCommit cpCommit4 = history.next(); + RevCommit cpCommitInit = history.next(); + assertFalse(history.hasNext()); + + assertEquals("commit5: extra commit text after footer line\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>\n\n" + + "some extra description after footer\n\n" + + "(cherry picked from commit c3c9959207dc7ae7c83da5d36dc14ef2ca42d572)", + cpCommit1.getFullMessage()); + assertEquals("commit4: extra commit text before footer line\n\n" + + "Commit message details\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>\n" + + "(cherry picked from commit af3e8106c12cb946a37b403ddb2dd6c11a883698)", + cpCommit2.getFullMessage()); + assertEquals("commit3: multiple footer lines\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "Signed-off-by: Bob <bob@example.com>\n" + + "(cherry picked from commit 6d60f1a70a11a32dff4402c157c4ac328c32ce6c)", + cpCommit3.getFullMessage()); + assertEquals("commit2: simple single footer line\n\n" + + "Signed-off-by: Alice <alice@example.com>\n" + + "(cherry picked from commit 92bf0ec458814ecc73da8e050e60547d2ea6cce5)", + cpCommit4.getFullMessage()); + + assertEquals("commit1: no footer line", + cpCommitInit.getFullMessage()); + } + } - CherryPickResult result2 = git.cherryPick().include(commitM) - .setMainlineParentNumber(2).call(); - assertEquals(CherryPickStatus.OK, result2.getStatus()); - checkFile(new File(db.getWorkTree(), "file"), "a\n2\n3\n"); + private RevCommit addFileAndCommit(Git git, String fileName, + String fileText, String commitMessage) + throws IOException, GitAPIException { + writeTrashFile(fileName, fileText); + git.add().addFilepattern(fileName).call(); + return git.commit().setMessage(commitMessage).call(); } } |