How to define a “In between” JGit RevFilter?

倖福魔咒の 提交于 2021-02-11 01:30:59

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!