Java tutorial
/* * Copyright (c) 2011 Kevin Sawicki <kevinsawicki@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ package org.gitective.core; import static org.eclipse.jgit.lib.Constants.HEAD; import static org.eclipse.jgit.lib.Constants.MASTER; import static org.eclipse.jgit.lib.Constants.R_HEADS; import static org.eclipse.jgit.lib.Constants.R_REMOTES; import static org.eclipse.jgit.lib.Constants.R_TAGS; import static org.eclipse.jgit.revwalk.filter.RevFilter.MERGE_BASE; import java.io.IOException; import java.text.MessageFormat; import java.util.Collection; import java.util.HashSet; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefDatabase; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; /** * Utilities for dealing with Git commits. * <p> * This class provides helpers for finding the commits that branches and tags * reference. */ public abstract class CommitUtils { /** * Get the commit that the revision references. * * @param repository * @param revision * @return commit */ public static RevCommit getCommit(final Repository repository, final String revision) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (revision == null) throw new IllegalArgumentException(Assert.formatNotNull("Revision")); if (revision.length() == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Revision")); return parse(repository, resolve(repository, revision)); } /** * Get the commit with the given id * * @param repository * @param commitId * @return commit */ public static RevCommit getCommit(final Repository repository, final ObjectId commitId) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (commitId == null) throw new IllegalArgumentException(Assert.formatNotNull("Commit id")); return parse(repository, commitId); } /** * Get the HEAD commit in the given repository. * * @param repository * @return commit never null */ public static RevCommit getHead(final Repository repository) { return getCommit(repository, HEAD); } /** * Get the commit at the tip of the master branch in the given repository. * * @param repository * @return commit never null */ public static RevCommit getMaster(final Repository repository) { return getCommit(repository, MASTER); } /** * Get the common base commit of the given commits. * * @param repository * @param commits * @return base commit or null if none */ public static RevCommit getBase(final Repository repository, final ObjectId... commits) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (commits == null) throw new IllegalArgumentException(Assert.formatNotNull("Commits")); if (commits.length == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Commits")); return walkToBase(repository, commits); } /** * Get the common base commit between the given revisions. * * @param repository * @param revisions * @return base commit or null if none */ public static RevCommit getBase(final Repository repository, final String... revisions) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (revisions == null) throw new IllegalArgumentException(Assert.formatNotNull("Revisions")); if (revisions.length == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Revisions")); final int length = revisions.length; final ObjectId[] commits = new ObjectId[length]; for (int i = 0; i < length; i++) { commits[i] = strictResolve(repository, revisions[i]); } return walkToBase(repository, commits); } /** * Get the commit that the given name references. * * @param repository * @param refName * @return commit, may be null */ public static RevCommit getRef(final Repository repository, final String refName) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (refName == null) throw new IllegalArgumentException(Assert.formatNotNull("Ref name")); if (refName.length() == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Ref name")); Ref ref; try { ref = repository.getRef(refName); } catch (IOException e) { throw new GitException(e, repository); } return ref != null ? lookupRef(repository, ref) : null; } /** * Get the commit for the given reference. * * @param repository * @param ref * @return commit, may be null */ public static RevCommit getRef(final Repository repository, final Ref ref) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (ref == null) throw new IllegalArgumentException(Assert.formatNotNull("Ref")); return lookupRef(repository, ref); } /** * Get all the commits that tags in the given repository reference. * * @param repository * @return non-null but possibly empty collection of commits */ public static Collection<RevCommit> getTags(final Repository repository) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); final Collection<RevCommit> commits = new HashSet<RevCommit>(); final RevWalk walk = new RevWalk(repository); final RefDatabase refDb = repository.getRefDatabase(); try { getRefCommits(walk, refDb, R_TAGS, commits); } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } return commits; } /** * Get all the commits that branches in the given repository reference. * * @param repository * @return non-null but possibly empty collection of commits */ public static Collection<RevCommit> getBranches(final Repository repository) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); final Collection<RevCommit> commits = new HashSet<RevCommit>(); final RevWalk walk = new RevWalk(repository); final RefDatabase refDb = repository.getRefDatabase(); try { getRefCommits(walk, refDb, R_HEADS, commits); getRefCommits(walk, refDb, R_REMOTES, commits); } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } return commits; } private static void getRefCommits(final RevWalk walk, final RefDatabase refDb, final String prefix, final Collection<RevCommit> commits) throws IOException { for (Ref ref : refDb.getRefs(prefix).values()) { final RevCommit commit = getRef(walk, ref); if (commit != null) commits.add(commit); } } private static RevCommit lookupRef(final Repository repository, final Ref ref) { final RevWalk walk = new RevWalk(repository); try { return getRef(walk, ref); } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } } private static RevCommit getRef(final RevWalk walk, final Ref ref) throws IOException { ObjectId id = ref.getPeeledObjectId(); if (id == null) id = ref.getObjectId(); return id != null ? walk.parseCommit(id) : null; } /** * Resolve the revision string to a commit object id * * @param repository * @param revision * @return commit id */ protected static ObjectId resolve(final Repository repository, final String revision) { try { return repository.resolve(revision); } catch (IOException e) { throw new GitException(e, repository); } } /** * Resolve the revision string to a commit object id. * <p> * A {@link GitException} will be thrown when the revision can not be * resolved to an {@link ObjectId} * * @param repository * @param revision * @return commit id */ protected static ObjectId strictResolve(final Repository repository, final String revision) { final ObjectId resolved = resolve(repository, revision); if (resolved == null) throw new GitException(MessageFormat.format("Revision ''{0}'' could not be resolved", revision), repository); return resolved; } private static RevCommit walkToBase(final Repository repository, final ObjectId... commits) { final RevWalk walk = new RevWalk(repository); walk.setRevFilter(MERGE_BASE); try { for (int i = 0; i < commits.length; i++) walk.markStart(walk.parseCommit(commits[i])); final RevCommit base = walk.next(); if (base != null) walk.parseBody(base); return base; } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } } /** * Parse a commit from the repository * * @param repository * @param commit * @return commit */ protected static RevCommit parse(final Repository repository, final ObjectId commit) { final RevWalk walk = new RevWalk(repository); walk.setRetainBody(true); try { return walk.parseCommit(commit); } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } } /** * Parse a commit from the object reader * * @param repository * @param reader * @param commit * @return commit */ protected static RevCommit parse(final Repository repository, final ObjectReader reader, final ObjectId commit) { final RevWalk walk = new RevWalk(reader); walk.setRetainBody(true); try { return walk.parseCommit(commit); } catch (IOException e) { throw new GitException(e, repository); } } /** * Find the commit that last changed the given path starting at the commit * that HEAD currently points to * * @param repository * @param path * @return commit */ public static RevCommit getLastCommit(final Repository repository, final String path) { return getLastCommit(repository, HEAD, path); } /** * Find the commit that last changed the given path starting with the commit * at the given revision * * @param repository * @param revision * @param path * @return commit */ public static RevCommit getLastCommit(final Repository repository, final String revision, final String path) { if (repository == null) throw new IllegalArgumentException(Assert.formatNotNull("Repository")); if (revision == null) throw new IllegalArgumentException(Assert.formatNotNull("Revision")); if (revision.length() == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Revision")); if (path == null) throw new IllegalArgumentException(Assert.formatNotNull("Path")); if (path.length() == 0) throw new IllegalArgumentException(Assert.formatNotEmpty("Path")); final RevWalk walk = new RevWalk(repository); walk.setRetainBody(true); try { walk.markStart(walk.parseCommit(strictResolve(repository, revision))); walk.setTreeFilter(PathFilterUtils.and(path)); return walk.next(); } catch (IOException e) { throw new GitException(e, repository); } finally { walk.release(); } } }