diff options
author | Tomasz Zarna <Tomasz.Zarna@pl.ibm.com> | 2012-06-13 23:28:55 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2012-06-15 08:59:41 +0200 |
commit | 2656ac1b5acb9b73c6b47e2cf8830a0a0b2cc214 (patch) | |
tree | 1f48ca5fafef4ae7482c88b2084d532508bb944c /org.eclipse.jgit | |
parent | c4087af65ddfd976f2a2513a773f50b1fd790336 (diff) | |
download | jgit-2656ac1b5acb9b73c6b47e2cf8830a0a0b2cc214.tar.gz jgit-2656ac1b5acb9b73c6b47e2cf8830a0a0b2cc214.zip |
Add "--squash" option to MergeCommand
CQ: 6570
Bug: 351806
Change-Id: I5e47810376419264ecf4247b5a333af5c8945080
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
Diffstat (limited to 'org.eclipse.jgit')
11 files changed, 335 insertions, 54 deletions
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 be60802285..1131c15608 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -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 diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java index eac6fe6a40..ae6d62963e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java @@ -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); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java index c5a9552112..3ca861c06c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java @@ -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; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java index c1733f5b7d..484039e708 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java @@ -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 diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java index b34b902cec..fc3d147c68 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java @@ -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); 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 aca9574a5b..539f837564 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -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; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 5332ffa711..d5be3157d5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -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 diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 7b9d453aa2..2c04a74f40 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -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. @@ -1281,6 +1262,65 @@ public abstract class Repository { } /** + * 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. * * @param filename diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java index 1a26ecfe1f..cacaff4c5d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java @@ -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"); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java new file mode 100644 index 0000000000..6d0ff9ba9c --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java @@ -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(); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java index 50b222bcc0..94400b06ed 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java @@ -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; } } |