diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java index ed1da4f30..d54ec996c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriterBitmapPreparer.java @@ -44,6 +44,7 @@ package org.eclipse.jgit.internal.storage.pack; import static org.eclipse.jgit.internal.storage.file.PackBitmapIndex.FLAG_REUSE; +import static org.eclipse.jgit.revwalk.RevFlag.SEEN; import java.io.IOException; import java.util.ArrayList; @@ -72,6 +73,7 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.util.BlockList; import org.eclipse.jgit.util.SystemReader; @@ -312,6 +314,45 @@ private boolean isRecentCommit(RevCommit revCommit) { return revCommit.getCommitTime() > inactiveBranchTimestamp; } + /** + * A RevFilter that excludes the commits named in a bitmap from the walk. + *

+ * If a commit is in {@code bitmap} then that commit is not emitted by the + * walk and its parents are marked as SEEN so the walk can skip them. The + * bitmaps passed in have the property that the parents of any commit in + * {@code bitmap} are also in {@code bitmap}, so marking the parents as + * SEEN speeds up the RevWalk by saving it from walking down blind alleys + * and does not change the commits emitted. + */ + private static class NotInBitmapFilter extends RevFilter { + private final BitmapBuilder bitmap; + + NotInBitmapFilter(BitmapBuilder bitmap) { + this.bitmap = bitmap; + } + + @Override + public final boolean include(RevWalk rw, RevCommit c) { + if (!bitmap.contains(c)) { + return true; + } + for (RevCommit p : c.getParents()) { + p.add(SEEN); + } + return false; + } + + @Override + public final NotInBitmapFilter clone() { + throw new UnsupportedOperationException(); + } + + @Override + public final boolean requiresCommitBody() { + return false; + } + } + /** * For each of the {@code want}s, which represent the tip commit of each * branch, set up an initial {@link BitmapBuilder}. Reuse previously built @@ -380,6 +421,7 @@ private CommitSelectionHelper setupTipCommitBitmaps(RevWalk rw, // Create a list of commits in reverse order (older to newer). // For each branch that contains the commit, mark its parents as being // in the bitmap. + rw.setRevFilter(new NotInBitmapFilter(reuse)); RevCommit[] commits = new RevCommit[expectedCommitCount]; int pos = commits.length; RevCommit rc;