问题
I am trying to implement a RevFilter
to be used through RevWalk#setRevFilter()
. In the following what I have tried:
private class InBetweenRevFilter extends RevFilter {
private AnyObjectId end;
private AnyObjectId begin;
public InBetweenRevFilter(AnyObjectId begin, AnyObjectId end) {
this.begin = begin;
this.end = end;
}
@Override
public RevFilter clone() {
return this;
}
@Override
public boolean include(RevWalk walker, RevCommit c)
throws StopWalkException, MissingObjectException,
IncorrectObjectTypeException, IOException {
RevCommit from = walker.parseCommit(begin);
RevCommit to = walker.parseCommit(end);
return (walker.isMergedInto(from, c) && walker.isMergedInto(c, to));
}
}
The result of the filter should be the commit pushed after the begin
and before the end
. The problem is that when I set this filter, only the commit marked as the start point with RevWalk.markStart(RevCommit c)
is returned by the RevWalk.next()
. In the following, I show show how I tried to use the filter:
RevWalk walk = new RevWalk(getRepository());
RevCommit beginCommit = walk.parseCommit(getRepository().resolve(start));
RevCommit endCommit = walk.parseCommit(getRepository().resolve(end));
walk.setRevFilter(new InBetweenRevFilter(beginCommit.getId(), endCommit.getId()));
walk.markStart(endCommit);
for (RevCommit rev : walk) {
System.out.println(rev.getFullMessage());
}
walk.close();
In this example, only the message from endCommit
printed in the console. Is there any other way to do this? Or, what am I missing or did wrong?
回答1:
I just published a snippet at the jgit-cookbook that shows one way to do this:
Basically you can start a walk at one commit and run the walk until you find the second or the commits on the branch run out.
Note that you go backwards in time here as this is how Git stores the links between commits, i.e. we start with "to" which is the newer commit and walk until we reach "from".
String from = "3408efc41a51555d488d30d8a91ea560c5e13311";
String to = "7228de6ebe2a3087118562414061af4e189624c0";
// a RevWalk allows to walk over commits based on some filtering that is defined
try (RevWalk walk = new RevWalk(repository)) {
RevCommit commit = walk.parseCommit(repository.resolve(to));
System.out.println("Walking all commits starting at " + to + " until we find " + from);
walk.markStart(commit);
int count = 0;
for (RevCommit rev : walk) {
System.out.println("Commit: " + rev);
count++;
if(rev.getId().getName().equals(from)) {
System.out.println("Found from, stopping walk");
break;
}
}
System.out.println(count);
walk.dispose();
}
回答2:
This was my solution, but @centic's one seems easier.
public List<RevCommit> between(String start, String end) throws Exception {
RevWalk walk = new RevWalk(getRepository());
RevCommit beginCommit = walk.parseCommit(getRepository().resolve(start));
RevCommit endCommit = walk.parseCommit(getRepository().resolve(end));
walk.close();
return commitsBetween(beginCommit, endCommit);
}
private List<RevCommit> commitsBetween(RevCommit begin, RevCommit end) throws Exception {
List<RevCommit> commits = new LinkedList<>();
RevWalk walk = new RevWalk(getRepository());
RevCommit parent = walk.parseCommit(end.getParent(0).getId());
if (parent.getName().equals(begin.getName())) {
commits.add(end);
walk.close();
return commits;
} else {
commits.add(end);
commits.addAll(commitsBetween(begin, parent));
walk.close();
return commits;
}
}
UPDATE: I have got this answer in the EGit/JGit forum, which is as simple as the @centic's answer.
RevCommit begin = getBeginCommit();
RevCommit end = getEndCommit();
try (RevWalk rw = new RevWalk(getRepository())) {
rw.markStart(rw.lookupCommit(begin));
rw.markUninteresting(rw.lookupCommit(end));
for (RevCommit curr; (curr = rw.next()) != null;)
System.out.println("Inspecting entry: " + curr.getShortMessage());
}
来源:https://stackoverflow.com/questions/36730329/how-to-define-a-in-between-jgit-revfilter