use of org.eclipse.jgit.revwalk.RevFlagSet in project egit by eclipse.
the class GitCommitsModelCache method build.
/**
* Scans given {@code repo} and build list of commits between two given
* RevCommit objectId's. Each commit contains list of changed resources
*
* @param repo
* repository that should be scanned
* @param srcId
* commit id that is considered the "local" version (e.g. from
* master)
* @param dstId
* commit id that is considered the "remote" version (e.g. from
* origin/master)
* @param pathFilter
* path filter definition or {@code null} when all paths should
* be included
* @return list of {@link Commit} object's between {@code srcId} and
* {@code dstId}
* @throws IOException
*/
public static List<Commit> build(Repository repo, ObjectId srcId, ObjectId dstId, TreeFilter pathFilter) throws IOException {
if (dstId.equals(srcId))
return new ArrayList<Commit>(0);
try (RevWalk rw = new RevWalk(repo)) {
// $NON-NLS-1$
final RevFlag localFlag = rw.newFlag("local");
// $NON-NLS-1$
final RevFlag remoteFlag = rw.newFlag("remote");
final RevFlagSet allFlags = new RevFlagSet();
allFlags.add(localFlag);
allFlags.add(remoteFlag);
rw.carry(allFlags);
RevCommit srcCommit = rw.parseCommit(srcId);
srcCommit.add(localFlag);
rw.markStart(srcCommit);
// free not needed resources
srcCommit = null;
RevCommit dstCommit = rw.parseCommit(dstId);
dstCommit.add(remoteFlag);
rw.markStart(dstCommit);
// free not needed resources
dstCommit = null;
if (pathFilter != null)
rw.setTreeFilter(pathFilter);
List<Commit> result = new ArrayList<Commit>();
for (RevCommit revCommit : rw) {
if (revCommit.hasAll(allFlags))
break;
Commit commit = new Commit();
commit.shortMessage = revCommit.getShortMessage();
commit.commitId = AbbreviatedObjectId.fromObjectId(revCommit);
commit.authorName = revCommit.getAuthorIdent().getName();
commit.committerName = revCommit.getCommitterIdent().getName();
commit.commitDate = revCommit.getAuthorIdent().getWhen();
RevCommit parentCommit = getParentCommit(revCommit);
if (revCommit.has(localFlag))
// Outgoing
commit.direction = RIGHT;
else if (revCommit.has(remoteFlag))
// Incoming
commit.direction = LEFT;
else
throw new GitCommitsModelDirectionException();
commit.children = getChangedObjects(repo, revCommit, parentCommit, pathFilter, commit.direction);
if (commit.children != null)
result.add(commit);
}
rw.dispose();
return result;
}
}
use of org.eclipse.jgit.revwalk.RevFlagSet in project git-client-plugin by jenkinsci.
the class JGitAPIImpl method describe.
/**
* {@inheritDoc}
*
* This implementation is based on my reading of the cgit source code at https://github.com/git/git/blob/master/builtin/describe.c
*
* <p>
* The basic structure of the algorithm is as follows. We walk the commit graph,
* find tags, and mark commits that are reachable from those tags. The marking
* uses flags given by JGit, so there's a fairly small upper bound in the number of tags
* we can keep track of.
*
* <p>
* As we walk commits, we count commits that each tag doesn't contain.
* We call it "depth", following the variable name in C Git.
* As we walk further and find enough tags, we go into wind-down mode and only walk
* to the point of accurately determining all the depths.
*/
@Override
public String describe(String tip) throws GitException, InterruptedException {
try (Repository repo = getRepository()) {
final ObjectReader or = repo.newObjectReader();
// How to dispose of this ?
final RevWalk w = new RevWalk(or);
w.setRetainBody(false);
Map<ObjectId, Ref> tags = new HashMap<>();
for (Ref r : repo.getTags().values()) {
ObjectId key = repo.peel(r).getPeeledObjectId();
if (key == null)
key = r.getObjectId();
tags.put(key, r);
}
// combined flags of all the Candidate instances
final RevFlagSet allFlags = new RevFlagSet();
/**
* Tracks the depth of each tag as we find them.
*/
class Candidate {
final Ref tag;
final RevFlag flag;
/**
* This field number of commits that are reachable from the tip but
* not reachable from the tag.
*/
int depth;
Candidate(RevCommit commit, Ref tag) {
this.tag = tag;
this.flag = w.newFlag(tag.getName());
// we'll mark all the nodes reachable from this tag accordingly
allFlags.add(flag);
w.carry(flag);
commit.add(flag);
commit.carry(flag);
}
/**
* Does this tag contains the given commit?
*/
public boolean reaches(RevCommit c) {
return c.has(flag);
}
public String describe(ObjectId tip) throws IOException {
return String.format("%s-%d-g%s", tag.getName().substring(R_TAGS.length()), depth, or.abbreviate(tip).name());
}
}
// all the candidates we find
List<Candidate> candidates = new ArrayList<>();
ObjectId tipId = repo.resolve(tip);
Ref lucky = tags.get(tipId);
if (lucky != null)
return lucky.getName().substring(R_TAGS.length());
w.markStart(w.parseCommit(tipId));
int maxCandidates = 10;
// commit seen thus far
int seen = 0;
RevCommit c;
while ((c = w.next()) != null) {
if (!c.hasAny(allFlags)) {
// if a tag already dominates this commit,
// then there's no point in picking a tag on this commit
// since the one that dominates it is always more preferable
Ref t = tags.get(c);
if (t != null) {
Candidate cd = new Candidate(c, t);
candidates.add(cd);
cd.depth = seen;
}
}
// it counts toward the total depth.
for (Candidate cd : candidates) {
if (!cd.reaches(c)) {
cd.depth++;
}
}
// all tags even if we wanted to.
if (candidates.size() >= maxCandidates)
break;
// TODO: if all the commits in the queue of RevWalk has allFlags
// there's no point in continuing search as we'll not discover any more
// tags. But RevWalk doesn't expose this.
seen++;
}
// but we still need to count all the depths correctly.
while ((c = w.next()) != null) {
if (c.hasAll(allFlags)) {
// no point in visiting further from here, so cut the search here
for (RevCommit p : c.getParents()) p.add(RevFlag.SEEN);
} else {
for (Candidate cd : candidates) {
if (!cd.reaches(c)) {
cd.depth++;
}
}
}
}
if (candidates.isEmpty())
throw new GitException("No tags can describe " + tip);
// if all the nodes are dominated by all the tags, the walk stops
candidates.sort(Comparator.comparingInt((Candidate o) -> o.depth));
return candidates.get(0).describe(tipId);
} catch (IOException e) {
throw new GitException(e);
}
}
Aggregations