Browse Source

Refactored method to find branches from which a commit is reachable

The method uses some heuristics to obtain much better performance
than isMergeBase.

Since I wrote the relevant code in the method I approve the license
change from EPL to EDL implied by the move.

Change-Id: Ic4a7584811a2b0bf24e4f6b3eab2a7c022eabee8
Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
tags/v2.1.0.201209190230-r
Robin Rosenberg 12 years ago
parent
commit
d4fed9cb4b
1 changed files with 73 additions and 0 deletions
  1. 73
    0
      org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java

+ 73
- 0
org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalkUtils.java View File

@@ -45,10 +45,16 @@ package org.eclipse.jgit.revwalk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdSubclassMap;
import org.eclipse.jgit.lib.Ref;

/**
* Utility methods for {@link RevWalk}.
@@ -124,4 +130,71 @@ public final class RevWalkUtils {
commits.add(c);
return commits;
}

/**
* Find the list of branches a given commit is reachable from when following
* parent.s
* <p>
* Note that this method calls {@link RevWalk#reset()} at the beginning.
* <p>
* In order to improve performance this method assumes clock skew among
* committers is never larger than 24 hours.
*
* @param commit
* the commit we are looking at
* @param revWalk
* The RevWalk to be used.
* @param refs
* the set of branches we want to see reachability from
* @return the list of branches a given commit is reachable from
* @throws MissingObjectException
* @throws IncorrectObjectTypeException
* @throws IOException
*/
public static List<Ref> findBranchesReachableFrom(RevCommit commit,
RevWalk revWalk, Collection<Ref> refs)
throws MissingObjectException, IncorrectObjectTypeException,
IOException {

List<Ref> result = new ArrayList<Ref>();
// searches from branches can be cut off early if any parent of the
// search-for commit is found. This is quite likely, so optimize for this.
revWalk.markStart(Arrays.asList(commit.getParents()));
ObjectIdSubclassMap<ObjectId> cutOff = new ObjectIdSubclassMap<ObjectId>();

final int SKEW = 24*3600; // one day clock skew

for (Ref ref : refs) {
RevCommit headCommit = revWalk.parseCommit(ref.getObjectId());

// if commit is in the ref branch, then the tip of ref should be
// newer than the commit we are looking for. Allow for a large
// clock skew.
if (headCommit.getCommitTime() + SKEW < commit.getCommitTime())
continue;

List<ObjectId> maybeCutOff = new ArrayList<ObjectId>(cutOff.size()); // guess rough size
revWalk.resetRetain();
revWalk.markStart(headCommit);
RevCommit current;
Ref found = null;
while ((current = revWalk.next()) != null) {
if (AnyObjectId.equals(current, commit)) {
found = ref;
break;
}
if (cutOff.contains(current))
break;
maybeCutOff.add(current.toObjectId());
}
if (found != null)
result.add(ref);
else
for (ObjectId id : maybeCutOff)
cutOff.addIfAbsent(id);

}
return result;
}

}

Loading…
Cancel
Save