Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonrad Kügler2014-05-16 16:42:44 +0000
committerKonrad Kügler2014-05-17 17:18:07 +0000
commitb84057ad629f4dfc0a94b6a273570a53ba5a9d0a (patch)
tree9159244012ff1e727c676ca1b29ab694d700825e
parent2aa2b3af31e95b90c20794c727fc2e48b5f448e9 (diff)
downloadjgit-b84057ad629f4dfc0a94b6a273570a53ba5a9d0a.tar.gz
jgit-b84057ad629f4dfc0a94b6a273570a53ba5a9d0a.tar.xz
jgit-b84057ad629f4dfc0a94b6a273570a53ba5a9d0a.zip
Cherry-Pick: Support --mainline to pick merges
By specifying a mainline parent, a merge is cherry picked as if this parent was its only parent. If no mainline parent is given, cherry picking merges is not allowed, as before. Change-Id: I391cb73bf8f49e2df61428c17b40fae8c86a8b76 Signed-off-by: Konrad Kügler <swamblumat-eclipsebugs@yahoo.de>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CherryPickCommandTest.java58
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java50
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java1
4 files changed, 101 insertions, 9 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 2668c116a0..df73435803 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
@@ -46,6 +46,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
@@ -55,11 +56,13 @@ import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus;
import org.eclipse.jgit.api.ResetCommand.ResetType;
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.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.ReflogReader;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
@@ -336,4 +339,59 @@ public class CherryPickCommandTest extends RepositoryTestCase {
.startsWith("cherry-pick: "));
}
}
+
+ /**
+ * Cherry-picking merge commit M onto T
+ * <pre>
+ * M
+ * |\
+ * C D
+ * |/
+ * T B
+ * | /
+ * A
+ * </pre>
+ * @throws Exception
+ */
+ @Test
+ public void testCherryPickMerge() throws Exception {
+ 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");
+ }
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index b3049b07f4..7b073217a5 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -85,6 +85,7 @@ cannotUnloadAModifiedTree=Cannot unload a modified tree.
cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index.
canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported.
canOnlyRevertCommitsWithOneParent=Cannot revert commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported
+commitDoesNotHaveGivenParent=The commit ''{0}'' does not have a parent number {1}.
cantFindObjectInReversePackIndexForTheSpecifiedOffset=Can't find object in (reverse) pack index for the specified offset {0}
cantPassMeATree=Can't pass me a tree!
channelMustBeInRange0_255=channel {0} must be in range [0, 255]
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index b3415b3505..cf50160da5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -56,6 +56,7 @@ import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.UnmergedPathsException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.dircache.DirCacheCheckout;
+import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
@@ -90,6 +91,8 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
private MergeStrategy strategy = MergeStrategy.RECURSIVE;
+ private Integer mainlineParentNumber;
+
/**
* @param repo
*/
@@ -139,15 +142,7 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
RevCommit srcCommit = revWalk.parseCommit(srcObjectId);
// get the parent of the commit to cherry-pick
- if (srcCommit.getParentCount() != 1)
- throw new MultipleParentsNotAllowedException(
- MessageFormat.format(
- JGitText.get().canOnlyCherryPickCommitsWithOneParent,
- srcCommit.name(),
- Integer.valueOf(srcCommit.getParentCount())));
-
- RevCommit srcParent = srcCommit.getParent(0);
- revWalk.parseHeaders(srcParent);
+ final RevCommit srcParent = getParentCommit(srcCommit, revWalk);
String ourName = calculateOurName(headRef);
String cherryPickName = srcCommit.getId().abbreviate(7).name()
@@ -200,6 +195,31 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
return new CherryPickResult(newHead, cherryPickedRefs);
}
+ private RevCommit getParentCommit(RevCommit srcCommit, RevWalk revWalk)
+ throws MultipleParentsNotAllowedException, MissingObjectException,
+ IOException {
+ final RevCommit srcParent;
+ if (mainlineParentNumber == null) {
+ if (srcCommit.getParentCount() != 1)
+ throw new MultipleParentsNotAllowedException(
+ MessageFormat.format(
+ JGitText.get().canOnlyCherryPickCommitsWithOneParent,
+ srcCommit.name(),
+ Integer.valueOf(srcCommit.getParentCount())));
+ srcParent = srcCommit.getParent(0);
+ } else {
+ if (mainlineParentNumber.intValue() > srcCommit.getParentCount())
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().commitDoesNotHaveGivenParent, srcCommit,
+ mainlineParentNumber));
+ srcParent = srcCommit
+ .getParent(mainlineParentNumber.intValue() - 1);
+ }
+
+ revWalk.parseHeaders(srcParent);
+ return srcParent;
+ }
+
/**
* @param commit
* a reference to a commit which is cherry-picked to the current
@@ -271,6 +291,18 @@ public class CherryPickCommand extends GitCommand<CherryPickResult> {
return this;
}
+ /**
+ * @param mainlineParentNumber
+ * the (1-based) parent number to diff against. This allows
+ * cherry-picking of merges.
+ * @return {@code this}
+ * @since 3.4
+ */
+ public CherryPickCommand setMainlineParentNumber(int mainlineParentNumber) {
+ this.mainlineParentNumber = Integer.valueOf(mainlineParentNumber);
+ return this;
+ }
+
private String calculateOurName(Ref headRef) {
if (ourCommitName != null)
return ourCommitName;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 576ba0f493..39f203ca8b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -147,6 +147,7 @@ public class JGitText extends TranslationBundle {
/***/ public String cannotWorkWithOtherStagesThanZeroRightNow;
/***/ public String canOnlyCherryPickCommitsWithOneParent;
/***/ public String canOnlyRevertCommitsWithOneParent;
+ /***/ public String commitDoesNotHaveGivenParent;
/***/ public String cantFindObjectInReversePackIndexForTheSpecifiedOffset;
/***/ public String cantPassMeATree;
/***/ public String channelMustBeInRange0_255;

Back to the top