CQ: 6570 Bug: 351806 Change-Id: I5e47810376419264ecf4247b5a333af5c8945080 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>tags/v2.1.0.201209190230-r
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2011, GitHub Inc. | |||
* Copyright (C) 2011-2012, GitHub Inc. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -44,6 +44,7 @@ package org.eclipse.jgit.api; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.File; | |||
@@ -68,7 +69,7 @@ import org.eclipse.jgit.util.FS; | |||
import org.junit.Test; | |||
/** | |||
* Unit tests of {@link CommitCommand} | |||
* Unit tests of {@link CommitCommand}. | |||
*/ | |||
public class CommitCommandTest extends RepositoryTestCase { | |||
@@ -365,4 +366,42 @@ public class CommitCommandTest extends RepositoryTestCase { | |||
assertEquals(file1Size, cache.getEntry("file1.txt").getLength()); | |||
assertEquals(0, cache.getEntry("file2.txt").getLength()); | |||
} | |||
@Test | |||
public void commitAfterSquashMerge() 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(); | |||
git.commit().setMessage("second commit").call(); | |||
assertTrue(new File(db.getWorkTree(), "file2").exists()); | |||
checkoutBranch("refs/heads/master"); | |||
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.FAST_FORWARD_SQUASHED, | |||
result.getMergeStatus()); | |||
// comment not set, should be inferred from SQUASH_MSG | |||
RevCommit squashedCommit = git.commit().call(); | |||
assertEquals(1, squashedCommit.getParentCount()); | |||
assertNull(db.readSquashCommitMsg()); | |||
assertEquals("commit: Squashed commit of the following:", db | |||
.getReflogReader(Constants.HEAD).getLastEntry().getComment()); | |||
assertEquals("commit: Squashed commit of the following:", db | |||
.getReflogReader(db.getBranch()).getLastEntry().getComment()); | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> | |||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> | |||
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -45,6 +45,7 @@ package org.eclipse.jgit.api; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
@@ -62,6 +63,9 @@ import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
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.Before; | |||
import org.junit.Test; | |||
import org.junit.experimental.theories.DataPoints; | |||
import org.junit.experimental.theories.Theories; | |||
@@ -74,6 +78,15 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
public static @DataPoints | |||
MergeStrategy[] mergeStrategies = MergeStrategy.get(); | |||
private GitDateFormatter dateFormatter; | |||
@Override | |||
@Before | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
dateFormatter = new GitDateFormatter(Format.DEFAULT); | |||
} | |||
@Test | |||
public void testMergeInItself() throws Exception { | |||
Git git = new Git(db); | |||
@@ -1096,6 +1109,180 @@ public class MergeCommandTest extends RepositoryTestCase { | |||
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(StatusCommandTest.set("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(StatusCommandTest.set("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(StatusCommandTest.set("file2"), stat.getConflicting()); | |||
} | |||
private void setExecutable(Git git, String path, boolean executable) { | |||
FS.DETECTED.setExecute( | |||
new File(git.getRepository().getWorkTree(), path), executable); |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com> | |||
* Copyright (C) 2011-2012, Chris Aniszczyk <caniszczyk@gmail.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -46,6 +46,7 @@ import static org.eclipse.jgit.api.ResetCommand.ResetType.HARD; | |||
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; | |||
@@ -359,6 +360,37 @@ public class ResetCommandTest extends RepositoryTestCase { | |||
assertTrue(head.equals(secondCommit)); | |||
} | |||
@Test | |||
public void testHardResetAfterSquashMerge() throws Exception { | |||
Git g = new Git(db); | |||
writeTrashFile("file1", "file1"); | |||
g.add().addFilepattern("file1").call(); | |||
RevCommit first = g.commit().setMessage("initial commit").call(); | |||
assertTrue(new File(db.getWorkTree(), "file1").exists()); | |||
createBranch(first, "refs/heads/branch1"); | |||
checkoutBranch("refs/heads/branch1"); | |||
writeTrashFile("file2", "file2"); | |||
g.add().addFilepattern("file2").call(); | |||
g.commit().setMessage("second commit").call(); | |||
assertTrue(new File(db.getWorkTree(), "file2").exists()); | |||
checkoutBranch("refs/heads/master"); | |||
MergeResult result = g.merge().include(db.getRef("branch1")) | |||
.setSquash(true).call(); | |||
assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED, | |||
result.getMergeStatus()); | |||
assertNotNull(db.readSquashCommitMsg()); | |||
g.reset().setMode(ResetType.HARD).setRef(first.getName()).call(); | |||
assertNull(db.readSquashCommitMsg()); | |||
} | |||
private void assertReflog(ObjectId prevHead, ObjectId head) | |||
throws IOException { | |||
// Check the reflog for HEAD |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> | |||
* Copyright (C) 2010-2012 Christian Halstrick <christian.halstrick@sap.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -78,7 +78,7 @@ public class MergeHeadMsgTest extends RepositoryTestCase { | |||
assertEquals(db.readMergeHeads().size(), 2); | |||
assertEquals(db.readMergeHeads().get(0), ObjectId.zeroId()); | |||
assertEquals(db.readMergeHeads().get(1), ObjectId.fromString(sampleId)); | |||
db.writeMergeHeads(Collections.EMPTY_LIST); | |||
db.writeMergeHeads(Collections.<ObjectId> emptyList()); | |||
assertEquals(read(new File(db.getDirectory(), "MERGE_HEAD")), ""); | |||
assertEquals(db.readMergeHeads(), null); | |||
fos = new FileOutputStream(new File(db.getDirectory(), |
@@ -0,0 +1,77 @@ | |||
/* | |||
* Copyright (C) 2012, IBM Corporation and others. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* 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 | |||
* | |||
* 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. | |||
*/ | |||
package org.eclipse.jgit.lib; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import org.junit.Test; | |||
public class SquashCommitMsgTest extends RepositoryTestCase { | |||
private static final String squashMsg = "squashed commit"; | |||
@Test | |||
public void testReadWriteMergeMsg() throws IOException { | |||
assertEquals(db.readSquashCommitMsg(), null); | |||
assertFalse(new File(db.getDirectory(), Constants.SQUASH_MSG).exists()); | |||
db.writeSquashCommitMsg(squashMsg); | |||
assertEquals(squashMsg, db.readSquashCommitMsg()); | |||
assertEquals(read(new File(db.getDirectory(), Constants.SQUASH_MSG)), | |||
squashMsg); | |||
db.writeSquashCommitMsg(null); | |||
assertEquals(db.readSquashCommitMsg(), null); | |||
assertFalse(new File(db.getDirectory(), Constants.SQUASH_MSG).exists()); | |||
FileOutputStream fos = new FileOutputStream(new File(db.getDirectory(), | |||
Constants.SQUASH_MSG)); | |||
try { | |||
fos.write(squashMsg.getBytes(Constants.CHARACTER_ENCODING)); | |||
} finally { | |||
fos.close(); | |||
} | |||
assertEquals(db.readSquashCommitMsg(), squashMsg); | |||
} | |||
} |
@@ -0,0 +1,89 @@ | |||
/* | |||
* Copyright (C) 2012, IBM Corporation and others. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* 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 | |||
* | |||
* 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. | |||
*/ | |||
package org.eclipse.jgit.merge; | |||
import static org.junit.Assert.assertEquals; | |||
import java.util.Arrays; | |||
import org.eclipse.jgit.api.Git; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.SampleDataRepositoryTestCase; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.util.GitDateFormatter; | |||
import org.eclipse.jgit.util.GitDateFormatter.Format; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
/** | |||
* Test construction of squash message by {@link SquashMessageFormatterTest}. | |||
*/ | |||
public class SquashMessageFormatterTest extends SampleDataRepositoryTestCase { | |||
private GitDateFormatter dateFormatter; | |||
private SquashMessageFormatter msgFormatter; | |||
private RevCommit revCommit; | |||
@Override | |||
@Before | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
dateFormatter = new GitDateFormatter(Format.DEFAULT); | |||
msgFormatter = new SquashMessageFormatter(); | |||
} | |||
@Test | |||
public void testCommit() throws Exception { | |||
Git git = new Git(db); | |||
revCommit = git.commit().setMessage("squash_me").call(); | |||
Ref master = db.getRef("refs/heads/master"); | |||
String message = msgFormatter.format(Arrays.asList(revCommit), master); | |||
assertEquals( | |||
"Squashed commit of the following:\n\ncommit " | |||
+ revCommit.getName() + "\nAuthor: " | |||
+ revCommit.getAuthorIdent().getName() + " <" | |||
+ revCommit.getAuthorIdent().getEmailAddress() | |||
+ ">\nDate: " + dateFormatter.formatDate(author) | |||
+ "\n\n\tsquash_me\n", message); | |||
} | |||
} |
@@ -424,6 +424,7 @@ sourceDestinationMustMatch=Source/Destination must match. | |||
sourceIsNotAWildcard=Source is not a wildcard. | |||
sourceRefDoesntResolveToAnyObject=Source ref {0} doesn't resolve to any object. | |||
sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0} | |||
squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD | |||
staleRevFlagsOn=Stale RevFlags on {0} | |||
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported | |||
stashApplyFailed=Applying stashed changes did not successfully complete |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> | |||
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -488,9 +488,20 @@ public class CommitCommand extends GitCommand<RevCommit> { | |||
Constants.MERGE_MSG, e), e); | |||
} | |||
} | |||
} else if (state == RepositoryState.SAFE && message == null) { | |||
try { | |||
message = repo.readSquashCommitMsg(); | |||
if (message != null) | |||
repo.writeSquashCommitMsg(null /* delete */); | |||
} catch (IOException e) { | |||
throw new JGitInternalException(MessageFormat.format( | |||
JGitText.get().exceptionOccurredDuringReadingOfGIT_DIR, | |||
Constants.MERGE_MSG, e), e); | |||
} | |||
} | |||
if (message == null) | |||
// as long as we don't suppport -C option we have to have | |||
// as long as we don't support -C option we have to have | |||
// an explicit message | |||
throw new NoMessageException(JGitText.get().commitMessageNotSpecified); | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> | |||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> | |||
* Copyright (C) 2010-2012, Stefan Lay <stefan.lay@sap.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -76,8 +76,10 @@ import org.eclipse.jgit.merge.MergeStrategy; | |||
import org.eclipse.jgit.merge.Merger; | |||
import org.eclipse.jgit.merge.ResolveMerger; | |||
import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason; | |||
import org.eclipse.jgit.merge.SquashMessageFormatter; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.revwalk.RevWalk; | |||
import org.eclipse.jgit.revwalk.RevWalkUtils; | |||
import org.eclipse.jgit.treewalk.FileTreeIterator; | |||
/** | |||
@@ -95,6 +97,8 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
private List<Ref> commits = new LinkedList<Ref>(); | |||
private boolean squash; | |||
/** | |||
* @param repo | |||
*/ | |||
@@ -184,18 +188,41 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
srcCommit.getTree()); | |||
dco.setFailOnConflict(true); | |||
dco.checkout(); | |||
updateHead(refLogMessage, srcCommit, headId); | |||
String msg = null; | |||
ObjectId newHead, base = null; | |||
MergeStatus mergeStatus = null; | |||
if (!squash) { | |||
updateHead(refLogMessage, srcCommit, headId); | |||
newHead = base = srcCommit; | |||
mergeStatus = MergeStatus.FAST_FORWARD; | |||
} else { | |||
msg = JGitText.get().squashCommitNotUpdatingHEAD; | |||
newHead = base = headId; | |||
mergeStatus = MergeStatus.FAST_FORWARD_SQUASHED; | |||
List<RevCommit> squashedCommits = RevWalkUtils.find( | |||
revWalk, srcCommit, headCommit); | |||
String squashMessage = new SquashMessageFormatter().format( | |||
squashedCommits, head); | |||
repo.writeSquashCommitMsg(squashMessage); | |||
} | |||
setCallable(false); | |||
return new MergeResult(srcCommit, srcCommit, new ObjectId[] { | |||
headCommit, srcCommit }, MergeStatus.FAST_FORWARD, | |||
mergeStrategy, null, null); | |||
return new MergeResult(newHead, base, new ObjectId[] { | |||
headCommit, srcCommit }, mergeStatus, mergeStrategy, | |||
null, msg); | |||
} else { | |||
String mergeMessage = new MergeMessageFormatter().format( | |||
commits, head); | |||
repo.writeMergeCommitMsg(mergeMessage); | |||
repo.writeMergeHeads(Arrays.asList(ref.getObjectId())); | |||
String mergeMessage = ""; | |||
if (!squash) { | |||
mergeMessage = new MergeMessageFormatter().format( | |||
commits, head); | |||
repo.writeMergeCommitMsg(mergeMessage); | |||
repo.writeMergeHeads(Arrays.asList(ref.getObjectId())); | |||
} else { | |||
List<RevCommit> squashedCommits = RevWalkUtils.find( | |||
revWalk, srcCommit, headCommit); | |||
String squashMessage = new SquashMessageFormatter().format( | |||
squashedCommits, head); | |||
repo.writeSquashCommitMsg(squashMessage); | |||
} | |||
Merger merger = mergeStrategy.newMerger(repo); | |||
boolean noProblems; | |||
Map<String, org.eclipse.jgit.merge.MergeResult<?>> lowLevelResults = null; | |||
@@ -223,12 +250,22 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
dco.setFailOnConflict(true); | |||
dco.checkout(); | |||
RevCommit newHead = new Git(getRepository()).commit() | |||
String msg = null; | |||
RevCommit newHead = null; | |||
MergeStatus mergeStatus = null; | |||
if (!squash) { | |||
newHead = new Git(getRepository()).commit() | |||
.setReflogComment(refLogMessage.toString()).call(); | |||
return new MergeResult(newHead.getId(), | |||
null, new ObjectId[] { | |||
headCommit.getId(), srcCommit.getId() }, | |||
MergeStatus.MERGED, mergeStrategy, null, null); | |||
mergeStatus = MergeStatus.MERGED; | |||
} else { | |||
msg = JGitText.get().squashCommitNotUpdatingHEAD; | |||
newHead = headCommit; | |||
mergeStatus = MergeStatus.MERGED_SQUASHED; | |||
} | |||
return new MergeResult(newHead.getId(), null, | |||
new ObjectId[] { headCommit.getId(), | |||
srcCommit.getId() }, mergeStatus, | |||
mergeStrategy, null, msg); | |||
} else { | |||
if (failingPaths != null) { | |||
repo.writeMergeCommitMsg(null); | |||
@@ -334,4 +371,25 @@ public class MergeCommand extends GitCommand<MergeResult> { | |||
return include(new ObjectIdRef.Unpeeled(Storage.LOOSE, name, | |||
commit.copy())); | |||
} | |||
/** | |||
* If <code>true</code>, will prepare the next commit in working tree and | |||
* index as if a real merge happened, but do not make the commit or move the | |||
* HEAD. Otherwise, perform the merge and commit the result. | |||
* <p> | |||
* In case the merge was successful but this flag was set to | |||
* <code>true</code> a {@link MergeResult} with status | |||
* {@link MergeStatus#MERGED_SQUASHED} or | |||
* {@link MergeStatus#FAST_FORWARD_SQUASHED} is returned. | |||
* | |||
* @param squash | |||
* whether to squash commits or not | |||
* @return {@code this} | |||
* @since 2.0 | |||
*/ | |||
public MergeCommand setSquash(boolean squash) { | |||
checkCallable(); | |||
this.squash = squash; | |||
return this; | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
/* | |||
* Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com> | |||
* Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com> | |||
* Copyright (C) 2010-2012, Christian Halstrick <christian.halstrick@sap.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -76,6 +76,20 @@ public class MergeResult { | |||
return true; | |||
} | |||
}, | |||
/** | |||
* @since 2.0 | |||
*/ | |||
FAST_FORWARD_SQUASHED { | |||
@Override | |||
public String toString() { | |||
return "Fast-forward-squashed"; | |||
} | |||
@Override | |||
public boolean isSuccessful() { | |||
return true; | |||
} | |||
}, | |||
/** */ | |||
ALREADY_UP_TO_DATE { | |||
@Override | |||
@@ -112,6 +126,20 @@ public class MergeResult { | |||
return true; | |||
} | |||
}, | |||
/** | |||
* @since 2.0 | |||
*/ | |||
MERGED_SQUASHED { | |||
@Override | |||
public String toString() { | |||
return "Merged-squashed"; | |||
} | |||
@Override | |||
public boolean isSuccessful() { | |||
return true; | |||
} | |||
}, | |||
/** */ | |||
CONFLICTING { | |||
@Override |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2011, Chris Aniszczyk <caniszczyk@gmail.com> | |||
* Copyright (C) 2011-2012, Chris Aniszczyk <caniszczyk@gmail.com> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -221,6 +221,8 @@ public class ResetCommand extends GitCommand<Ref> { | |||
resetMerge(); | |||
else if (cherryPicking) | |||
resetCherryPick(); | |||
else if (repo.readSquashCommitMsg() != null) | |||
repo.writeSquashCommitMsg(null /* delete */); | |||
} | |||
setCallable(false); |
@@ -484,6 +484,7 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String sourceIsNotAWildcard; | |||
/***/ public String sourceRefDoesntResolveToAnyObject; | |||
/***/ public String sourceRefNotSpecifiedForRefspec; | |||
/***/ public String squashCommitNotUpdatingHEAD; | |||
/***/ public String staleRevFlagsOn; | |||
/***/ public String startingReadStageWithoutWrittenRequestDataPendingIsNotSupported; | |||
/***/ public String stashApplyFailed; |
@@ -1,7 +1,7 @@ | |||
/* | |||
* Copyright (C) 2008, Google Inc. | |||
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> | |||
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> | |||
* Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -553,6 +553,9 @@ public final class Constants { | |||
/** name of the file containing the ID of a cherry pick commit in case of conflicts */ | |||
public static final String CHERRY_PICK_HEAD = "CHERRY_PICK_HEAD"; | |||
/** name of the file containing the commit msg for a squash commit */ | |||
public static final String SQUASH_MSG = "SQUASH_MSG"; | |||
/** | |||
* name of the ref ORIG_HEAD used by certain commands to store the original | |||
* value of HEAD |
@@ -2,7 +2,7 @@ | |||
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com> | |||
* Copyright (C) 2008-2010, Google Inc. | |||
* Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com> | |||
* Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> | |||
* Copyright (C) 2006-2012, Shawn O. Pearce <spearce@spearce.org> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -1125,24 +1125,14 @@ public abstract class Repository { | |||
* See {@link #isBare()}. | |||
*/ | |||
public String readMergeCommitMsg() throws IOException, NoWorkTreeException { | |||
if (isBare() || getDirectory() == null) | |||
throw new NoWorkTreeException(); | |||
File mergeMsgFile = new File(getDirectory(), Constants.MERGE_MSG); | |||
try { | |||
return RawParseUtils.decode(IO.readFully(mergeMsgFile)); | |||
} catch (FileNotFoundException e) { | |||
// MERGE_MSG file has disappeared in the meantime | |||
// ignore it | |||
return null; | |||
} | |||
return readCommitMsgFile(Constants.MERGE_MSG); | |||
} | |||
/** | |||
* Write new content to the file $GIT_DIR/MERGE_MSG. In this file operations | |||
* triggering a merge will store a template for the commit message of the | |||
* merge commit. If <code>null</code> is specified as message the file will | |||
* be deleted | |||
* be deleted. | |||
* | |||
* @param msg | |||
* the message which should be written or <code>null</code> to | |||
@@ -1152,16 +1142,7 @@ public abstract class Repository { | |||
*/ | |||
public void writeMergeCommitMsg(String msg) throws IOException { | |||
File mergeMsgFile = new File(gitDir, Constants.MERGE_MSG); | |||
if (msg != null) { | |||
FileOutputStream fos = new FileOutputStream(mergeMsgFile); | |||
try { | |||
fos.write(msg.getBytes(Constants.CHARACTER_ENCODING)); | |||
} finally { | |||
fos.close(); | |||
} | |||
} else { | |||
FileUtils.delete(mergeMsgFile, FileUtils.SKIP_MISSING); | |||
} | |||
writeCommitMsg(mergeMsgFile, msg); | |||
} | |||
/** | |||
@@ -1169,9 +1150,9 @@ public abstract class Repository { | |||
* file operations triggering a merge will store the IDs of all heads which | |||
* should be merged together with HEAD. | |||
* | |||
* @return a list of commits which IDs are listed in the MERGE_HEAD | |||
* file or {@code null} if this file doesn't exist. Also if the file | |||
* exists but is empty {@code null} will be returned | |||
* @return a list of commits which IDs are listed in the MERGE_HEAD file or | |||
* {@code null} if this file doesn't exist. Also if the file exists | |||
* but is empty {@code null} will be returned | |||
* @throws IOException | |||
* @throws NoWorkTreeException | |||
* if this is bare, which implies it has no working directory. | |||
@@ -1280,6 +1261,65 @@ public abstract class Repository { | |||
return raw != null ? ObjectId.fromString(raw, 0) : null; | |||
} | |||
/** | |||
* Return the information stored in the file $GIT_DIR/SQUASH_MSG. In this | |||
* file operations triggering a squashed merge will store a template for the | |||
* commit message of the squash commit. | |||
* | |||
* @return a String containing the content of the SQUASH_MSG file or | |||
* {@code null} if this file doesn't exist | |||
* @throws IOException | |||
* @throws NoWorkTreeException | |||
* if this is bare, which implies it has no working directory. | |||
* See {@link #isBare()}. | |||
*/ | |||
public String readSquashCommitMsg() throws IOException { | |||
return readCommitMsgFile(Constants.SQUASH_MSG); | |||
} | |||
/** | |||
* Write new content to the file $GIT_DIR/SQUASH_MSG. In this file | |||
* operations triggering a squashed merge will store a template for the | |||
* commit message of the squash commit. If <code>null</code> is specified as | |||
* message the file will be deleted. | |||
* | |||
* @param msg | |||
* the message which should be written or <code>null</code> to | |||
* delete the file | |||
* | |||
* @throws IOException | |||
*/ | |||
public void writeSquashCommitMsg(String msg) throws IOException { | |||
File squashMsgFile = new File(gitDir, Constants.SQUASH_MSG); | |||
writeCommitMsg(squashMsgFile, msg); | |||
} | |||
private String readCommitMsgFile(String msgFilename) throws IOException { | |||
if (isBare() || getDirectory() == null) | |||
throw new NoWorkTreeException(); | |||
File mergeMsgFile = new File(getDirectory(), msgFilename); | |||
try { | |||
return RawParseUtils.decode(IO.readFully(mergeMsgFile)); | |||
} catch (FileNotFoundException e) { | |||
// the file has disappeared in the meantime ignore it | |||
return null; | |||
} | |||
} | |||
private void writeCommitMsg(File msgFile, String msg) throws IOException { | |||
if (msg != null) { | |||
FileOutputStream fos = new FileOutputStream(msgFile); | |||
try { | |||
fos.write(msg.getBytes(Constants.CHARACTER_ENCODING)); | |||
} finally { | |||
fos.close(); | |||
} | |||
} else { | |||
FileUtils.delete(msgFile, FileUtils.SKIP_MISSING); | |||
} | |||
} | |||
/** | |||
* Read a file from the git directory. | |||
* |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2010, Robin Stocker <robin@nibor.org> | |||
* Copyright (C) 2010-2012, Robin Stocker <robin@nibor.org> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -134,7 +134,7 @@ public class MergeMessageFormatter { | |||
public String formatWithConflicts(String message, | |||
List<String> conflictingPaths) { | |||
StringBuilder sb = new StringBuilder(message); | |||
if (!message.endsWith("\n")) | |||
if (!message.endsWith("\n") && message.length() != 0) | |||
sb.append("\n"); | |||
sb.append("\n"); | |||
sb.append("Conflicts:\n"); |
@@ -0,0 +1,106 @@ | |||
/* | |||
* Copyright (C) 2012, IBM Corporation and others. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* 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 | |||
* | |||
* 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. | |||
*/ | |||
package org.eclipse.jgit.merge; | |||
import java.util.List; | |||
import org.eclipse.jgit.lib.PersonIdent; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.util.GitDateFormatter; | |||
import org.eclipse.jgit.util.GitDateFormatter.Format; | |||
/** | |||
* Formatter for constructing the commit message for a squashed commit. | |||
* <p> | |||
* The format should be the same as C Git does it, for compatibility. | |||
*/ | |||
public class SquashMessageFormatter { | |||
private GitDateFormatter dateFormatter; | |||
/** | |||
* Create a new squash message formatter. | |||
*/ | |||
public SquashMessageFormatter() { | |||
dateFormatter = new GitDateFormatter(Format.DEFAULT); | |||
} | |||
/** | |||
* Construct the squashed commit message. | |||
* | |||
* @param squashedCommits | |||
* the squashed commits | |||
* @param target | |||
* the target branch | |||
* @return squashed commit message | |||
*/ | |||
public String format(List<RevCommit> squashedCommits, Ref target) { | |||
StringBuilder sb = new StringBuilder(); | |||
sb.append("Squashed commit of the following:\n"); | |||
for (RevCommit c : squashedCommits) { | |||
sb.append("\ncommit "); | |||
sb.append(c.getName()); | |||
sb.append("\n"); | |||
sb.append(toString(c.getAuthorIdent())); | |||
sb.append("\n\t"); | |||
sb.append(c.getShortMessage()); | |||
sb.append("\n"); | |||
} | |||
return sb.toString(); | |||
} | |||
private String toString(PersonIdent author) { | |||
final StringBuilder a = new StringBuilder(); | |||
a.append("Author: "); | |||
a.append(author.getName()); | |||
a.append(" <"); | |||
a.append(author.getEmailAddress()); | |||
a.append(">\n"); | |||
a.append("Date: "); | |||
a.append(dateFormatter.formatDate(author)); | |||
a.append("\n"); | |||
return a.toString(); | |||
} | |||
} |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2011, Robin Stocker <robin@nibor.org> | |||
* Copyright (C) 2011-2012, Robin Stocker <robin@nibor.org> | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* This program and the accompanying materials are made available | |||
@@ -44,6 +44,8 @@ | |||
package org.eclipse.jgit.revwalk; | |||
import java.io.IOException; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.eclipse.jgit.errors.IncorrectObjectTypeException; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
@@ -83,14 +85,43 @@ public final class RevWalkUtils { | |||
public static int count(final RevWalk walk, final RevCommit start, | |||
final RevCommit end) throws MissingObjectException, | |||
IncorrectObjectTypeException, IOException { | |||
return find(walk, start, end).size(); | |||
} | |||
/** | |||
* Find commits that are reachable from <code>start</code> until a commit | |||
* that is reachable from <code>end</code> is encountered. In other words, | |||
* Find of commits that are in <code>start</code>, but not in | |||
* <code>end</code>. | |||
* <p> | |||
* Note that this method calls {@link RevWalk#reset()} at the beginning. | |||
* Also note that the existing rev filter on the walk is left as-is, so be | |||
* sure to set the right rev filter before calling this method. | |||
* | |||
* @param walk | |||
* the rev walk to use | |||
* @param start | |||
* the commit to start counting from | |||
* @param end | |||
* the commit where counting should end, or null if counting | |||
* should be done until there are no more commits | |||
* @return the commits found | |||
* @throws MissingObjectException | |||
* @throws IncorrectObjectTypeException | |||
* @throws IOException | |||
*/ | |||
public static List<RevCommit> find(final RevWalk walk, | |||
final RevCommit start, final RevCommit end) | |||
throws MissingObjectException, IncorrectObjectTypeException, | |||
IOException { | |||
walk.reset(); | |||
walk.markStart(start); | |||
if (end != null) | |||
walk.markUninteresting(end); | |||
int count = 0; | |||
for (RevCommit c = walk.next(); c != null; c = walk.next()) | |||
count++; | |||
return count; | |||
List<RevCommit> commits = new ArrayList<RevCommit>(); | |||
for (RevCommit c : walk) | |||
commits.add(c); | |||
return commits; | |||
} | |||
} |