Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Implemented git describe command and plumbing

* Supports --abbrev
* should output the same as `git describe` with default args
* Wrote tests
* Implementation uses RevWalk object and a one-pass algorithm like cgit
* TODO: implement complete set of `git describe` functionality

Change-Id: I8d6849d43578e1dc65dc754f1bd1bc42e55699e3
  • Loading branch information...
commit 0be557151b12cf5b7a977b82c037fa0f3e49434d 1 parent 200d3f5
@terabyte authored
View
1  org.eclipse.jgit.pgm/META-INF/services/org.eclipse.jgit.pgm.TextBuiltin
@@ -6,6 +6,7 @@ org.eclipse.jgit.pgm.Checkout
org.eclipse.jgit.pgm.Clone
org.eclipse.jgit.pgm.Commit
org.eclipse.jgit.pgm.Daemon
+org.eclipse.jgit.pgm.Describe
org.eclipse.jgit.pgm.Diff
org.eclipse.jgit.pgm.DiffTree
org.eclipse.jgit.pgm.Fetch
View
81 org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Describe.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012, Carl Myers <cmyers@cmyers.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.pgm;
+
+import org.eclipse.jgit.api.DescribeCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryBuilder;
+import org.kohsuke.args4j.Argument;
+import org.kohsuke.args4j.Option;
+
+class Describe extends TextBuiltin {
+ @Option(name = "--abbrev", metaVar = "metaVar_n")
+ private Integer abbrev;
+
+ @Argument(index = 0, required = false, metaVar = "metaVar_refspec")
+ private String revstr;
+
+ @Override
+ protected void run() throws Exception {
+ Repository r = new RepositoryBuilder().readEnvironment()
+ .findGitDir()
+ .build();
+
+ Git g = new Git(r);
+
+ DescribeCommand dc = g.describe();
+ if (revstr != null) {
+ dc.setObjectId(db.resolve(revstr));
+ } else {
+ dc.setObjectId(db.resolve("HEAD"));
+
+ }
+ if (abbrev != null) {
+ dc.setAbbrev(abbrev);
+ }
+ out.print(dc.call());
+ out.println();
+ }
+}
View
286 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2011, GitHub Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.junit.Test;
+
+public class DescribeCommandTest extends RepositoryTestCase {
+
+ @Test
+ public void testDescribeCommandFirstCommit() throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+
+ git.tag()
+ .setName("TEST")
+ .setObjectId(initialCommit)
+ .setTagger(
+ new PersonIdent("Test Tagger", "tagger@example.coml"))
+ .setMessage("Tag to test DescribeCommand").call();
+
+ {
+ String actual = git.describe().call();
+ String expected = "TEST";
+ assertEquals(expected, actual);
+ }
+ }
+
+ @Test
+ public void testDescribeCommandLaterCommit() throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+
+ git.tag()
+ .setName("TEST")
+ .setObjectId(initialCommit)
+ .setTagger(
+ new PersonIdent("Test Tagger", "tagger@example.coml"))
+ .setMessage("Tag to test DescribeCommand").call();
+
+ writeTrashFile("Test1.txt", "Hello world!");
+ git.add().addFilepattern("Test1.txt").call();
+ RevCommit secondCommit = git.commit().setMessage("new commit").call();
+
+ String defaultAbbreviationLength = Integer.toString(DescribeCommand
+ .getDefaultAbbreviationLength());
+ String actual = git.describe().setObjectId(secondCommit).call();
+ String expectedRegex = "TEST-1-g[0-9a-f]{" + defaultAbbreviationLength
+ + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+ }
+
+ @Test
+ public void testDescribeCommandVariableAbbreviationLength()
+ throws Exception {
+ Git git = Git.wrap(db);
+
+ /*
+ * XXX: Technically, this test might fail intermittently, only very
+ * rarely, if the repo created to test happened to have objects which
+ * conflict by more than 2 letters (as then, the abbreviate method might
+ * return more than 2 letters even when called with a length of 2).
+ */
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ RevCommit initialCommit = git.commit().setMessage("initial commit")
+ .call();
+
+ git.tag()
+ .setName("TEST")
+ .setObjectId(initialCommit)
+ .setTagger(
+ new PersonIdent("Test Tagger", "tagger@example.coml"))
+ .setMessage("Tag to test DescribeCommand").call();
+
+ writeTrashFile("Test1.txt", "Hello world!");
+ git.add().addFilepattern("Test1.txt").call();
+ RevCommit secondCommit = git.commit().setMessage("new commit").call();
+
+ {
+ // special case testing abbrev = 0, should just return the tag name
+ DescribeCommand dc = git.describe().setAbbrev(0)
+ .setObjectId(secondCommit);
+ String actual = dc.call();
+ String expected = "TEST";
+ assertEquals(expected, actual);
+ }
+
+ int lengthsToTest[] = { 2, 5, 8, 16, 32, 40 };
+ for (int length : lengthsToTest) {
+ DescribeCommand dc = git.describe().setAbbrev(length)
+ .setObjectId(secondCommit);
+ String actual = dc.call();
+ String expectedRegex = "TEST-1-g[0-9a-f]{"
+ + Integer.toString(length) + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+
+ }
+ }
+
+ @Test
+ public void testDescribeThrowsWithInvalidArgs() throws Exception {
+ Git git = Git.wrap(db);
+
+ writeTrashFile("Test.txt", "Hello world");
+ git.add().addFilepattern("Test.txt").call();
+ git.commit().setMessage("initial commit").call();
+ try {
+ DescribeCommand dc = git.describe();
+ dc.setAbbrev(1).call();
+ throw new IllegalStateException(
+ "Expected throw when given invalid arguments");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testDescribeCommandAfterMerge() throws Exception {
+ /*
+ * This test confirms that describe behaves the same as cgit's describe.
+ *
+ * For the following tree:
+ * * E
+ * / |
+ * * | D
+ * * | C
+ * | * B
+ * \|
+ * * A (TEST)
+ *
+ * If commit A is labeled as "TEST", then git-describe returns the following:
+ * A: TEST
+ * B: TEST-1-...
+ * C: TEST-1-...
+ * D: TEST-2-...
+ * E: TEST-4-...
+ *
+ * NOTE: eclipse auto-format ruins this comment. Please do not commit edits
+ * which ruin this comment.
+ */
+
+ Git git = Git.wrap(db);
+
+ writeTrashFile("File_A.txt", "Hello world");
+ git.add().addFilepattern("File_A.txt").call();
+ RevCommit commitA = git.commit().setMessage("Commit A")
+ .call();
+ git.branchCreate().setName("A").call();
+
+ git.tag()
+ .setName("TEST")
+ .setObjectId(commitA)
+ .setTagger(
+ new PersonIdent("Test Tagger", "tagger@example.coml"))
+ .setMessage("Tag to test DescribeCommand").call();
+
+ git.branchCreate().setName("B").call();
+ git.checkout().setName("B").call();
+ writeTrashFile("File_B.txt", "Hello world");
+ git.add().addFilepattern("File_B.txt").call();
+ RevCommit secondCommit = git.commit().setMessage("Commit B").call();
+
+ git.checkout().setName("A").call();
+
+ git.branchCreate().setName("C").call();
+ git.checkout().setName("C").call();
+ writeTrashFile("File_C.txt", "Hello world");
+ git.add().addFilepattern("File_C.txt").call();
+ RevCommit thirdCommit = git.commit().setMessage("Commit C").call();
+
+ git.branchCreate().setName("D").call();
+ git.checkout().setName("D").call();
+ writeTrashFile("File_D.txt", "Hello world");
+ git.add().addFilepattern("File_D.txt").call();
+ RevCommit fourthCommit = git.commit().setMessage("Commit D").call();
+
+ git.checkout().setName("B").call();
+
+ git.branchCreate().setName("E").call();
+ git.checkout().setName("E").call();
+ MergeResult mr = git.merge().include(fourthCommit).call();
+
+ RevWalk w = new RevWalk(db);
+ RevCommit fifthCommit = w.parseCommit(mr.getNewHead());
+ w.release();
+
+ String defaultAbbreviationLength = Integer.toString(DescribeCommand
+ .getDefaultAbbreviationLength());
+
+ {
+ String actual = git.describe().setObjectId(secondCommit).call();
+ String expectedRegex = "TEST-1-g[0-9a-f]{"
+ + defaultAbbreviationLength + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+ }
+ {
+ String actual = git.describe().setObjectId(thirdCommit).call();
+ String expectedRegex = "TEST-1-g[0-9a-f]{"
+ + defaultAbbreviationLength + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+ }
+ {
+ String actual = git.describe().setObjectId(fourthCommit).call();
+ String expectedRegex = "TEST-2-g[0-9a-f]{"
+ + defaultAbbreviationLength + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+ }
+ {
+ String actual = git.describe().setObjectId(fifthCommit).call();
+ String expectedRegex = "TEST-4-g[0-9a-f]{"
+ + defaultAbbreviationLength
+ + "}";
+ assertTrue("Describe String matches expected regex",
+ actual.matches(expectedRegex));
+ }
+ /*
+ * TODO: test that when there are multiple tags, the newest is picked.
+ * The tag must be at least 1 second newer for this test and no matter
+ * what I did (thread.sleep, etc) the second tag always had the same
+ * time as the first tag, making that test difficult to write.
+ */
+
+
+
+ }
+}
View
3  org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -142,6 +142,8 @@ deleteBranchUnexpectedResult=Delete branch returned unexpected result {0}
deleteFileFailed=Could not delete file {0}
deleteTagUnexpectedResult=Delete tag returned unexpected result {0}
deletingNotSupported=Deleting {0} not supported.
+describeInvalidAbbreviation=Abbreviation must be 0 or 2-40
+describeObjectIdNotSet=Describe id not set and HEAD could not be resolved
destinationIsNotAWildcard=Destination is not a wildcard.
detachedHeadDetected=HEAD is detached
dirCacheDoesNotHaveABackingFile=DirCache does not have a backing file
@@ -175,6 +177,7 @@ errorReadingInfoRefs=error reading info/refs
exceptionCaughtDuringExecutionOfAddCommand=Exception caught during execution of add command
exceptionCaughtDuringExecutionOfCherryPickCommand=Exception caught during execution of cherry-pick command. {0}
exceptionCaughtDuringExecutionOfCommitCommand=Exception caught during execution of commit command
+exceptionCaughtDuringExecutionOfDescribeCommand=Exception caught during execution of describe command
exceptionCaughtDuringExecutionOfFetchCommand=Exception caught during execution of fetch command
exceptionCaughtDuringExecutionOfLsRemoteCommand=Exception caught during execution of ls-remote command
exceptionCaughtDuringExecutionOfMergeCommand=Exception caught during execution of merge command. {0}
View
3  org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -202,6 +202,8 @@ public static JGitText get() {
/***/ public String deleteFileFailed;
/***/ public String deleteTagUnexpectedResult;
/***/ public String deletingNotSupported;
+ /***/ public String describeInvalidAbbreviation;
+ /***/ public String describeObjectIdNotSet;
/***/ public String destinationIsNotAWildcard;
/***/ public String detachedHeadDetected;
/***/ public String dirCacheDoesNotHaveABackingFile;
@@ -235,6 +237,7 @@ public static JGitText get() {
/***/ public String exceptionCaughtDuringExecutionOfAddCommand;
/***/ public String exceptionCaughtDuringExecutionOfCherryPickCommand;
/***/ public String exceptionCaughtDuringExecutionOfCommitCommand;
+ /***/ public String exceptionCaughtDuringExecutionOfDescribeCommand;
/***/ public String exceptionCaughtDuringExecutionOfFetchCommand;
/***/ public String exceptionCaughtDuringExecutionOfLsRemoteCommand;
/***/ public String exceptionCaughtDuringExecutionOfMergeCommand;
View
246 org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2012, Carl Myers <cmyers@cmyers.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.api;
+
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevFlag;
+import org.eclipse.jgit.revwalk.RevSort;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+
+/**
+ * A class used to execute a {@code Describe} command. It has setters for all
+ * supported options and arguments of this command and a {@link #call()} method
+ * to finally execute the command. Each instance of this class should only be
+ * used for one invocation of the command (means: one call to {@link #call()})
+ * <p>
+ *
+ * TODO: Implement the following options: --all: Use any ref found in .git/refs
+ * --tags: use any tag found in .git/refs instead of just annotated tags
+ * --contains: Find the tag that comes after the commit --exact-match,
+ * --candidates --long --match --always
+ *
+ * @see <a
+ * href="http://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
+ * >Git documentation about Describe</a>
+ */
+public class DescribeCommand extends GitCommand<String> {
+ // this is the default for git
+ private static final int DEFAULT_ABBREVIATION_LENGTH = 7;
+
+ private int abbreviationLength;
+ private ObjectId oid;
+
+ /**
+ * @param repo
+ */
+ protected DescribeCommand(Repository repo) {
+ super(repo);
+ abbreviationLength = DEFAULT_ABBREVIATION_LENGTH;
+ // Use HEAD by default (mirrors cgit impl)
+ try {
+ oid = repo.resolve("HEAD");
+ } catch (IOException e) {
+ // Ignored, will throw if oid not set before call()
+ }
+ }
+
+ /**
+ * Set the length of hash abbreviation.
+ *
+ * @param abbrev
+ * length to abbreviate commands to.
+ * @return a reference to {@code this}, allows chaining calls
+ * @throws IllegalArgumentException
+ */
+ public DescribeCommand setAbbrev(final int abbrev)
+ throws IllegalArgumentException {
+ checkCallable();
+ if (abbrev < 0 || abbrev == 1 || abbrev > 40) {
+ throw new IllegalArgumentException(
+ JGitText.get().describeInvalidAbbreviation);
+ }
+ this.abbreviationLength = abbrev;
+ return this;
+ }
+
+ /**
+ * Executes the {@code Describe} command with all the options and parameters
+ * collected by the setter methods. Each instance of this class should only
+ * be used for one invocation of the command. Don't call this method twice
+ * on an instance.
+ *
+ * @return a String containing the unique identifier, or an empty string if
+ * no tags were found.
+ */
+ public String call() throws NoHeadException, JGitInternalException {
+ checkCallable();
+ setCallable(false);
+
+ if (oid == null) {
+ throw new JGitInternalException(
+ JGitText.get().describeObjectIdNotSet,
+ new NullPointerException());
+ }
+
+ RevWalk w = new RevWalk(repo);
+ Map<RevCommit, List<String>> tagLookup = new HashMap<RevCommit, List<String>>();
+ try {
+ RevFlag f = w.newFlag("wanted");
+ for (Ref tag : repo.getTags().values()) {
+ // Tags can point to non-commits - skip those
+ if (w.parseCommit(tag.getObjectId()).getType() != Constants.OBJ_COMMIT)
+ continue;
+ RevCommit rc = w.parseCommit(tag.getObjectId());
+ rc.add(f);
+ String fullTagName = tag.getName();
+ String[] tagParts = fullTagName.split("/");
+ String tagName = tagParts[Array.getLength(tagParts)-1];
+ if (tagLookup.containsKey(rc)) {
+ tagLookup.get(rc).add(tagName);
+ } else {
+ List<String> l = new ArrayList<String>();
+ l.add(tagName);
+ tagLookup.put(rc, l);
+ }
+ }
+
+ RevCommit start = w.parseCommit(oid);
+ RevCommit candidate = null;
+ int candidateDistance = 0;
+
+ w.markStart(start);
+ w.setRevFilter(RevFilter.ALL);
+ w.sort(RevSort.TOPO);
+ RevCommit r = null;
+ while ((r = w.next()) != null) {
+ if (r.has(f)) {
+ candidate = r;
+ w.markUninteresting(w.parseCommit(r));
+ }
+ ++candidateDistance;
+ }
+
+ if (candidate == null) {
+ // not found
+ return null;
+ }
+
+ // Determine tag name - if there happens to be more than one tag at
+ // the same commit, use the one with the most recent date. This is
+ // what cgit does.
+ int age = 0;
+ String tagName = null;
+ for (Map.Entry<String, Ref> e : repo.getTags().entrySet()) {
+ ObjectId thisOid = w.parseCommit(e.getValue().getObjectId());
+ ObjectId candidateOid = candidate.getId();
+ if (thisOid.equals(candidateOid)) {
+ if (w.parseCommit(thisOid).getCommitTime() > age) {
+ age = w.parseCommit(thisOid).getCommitTime();
+ tagName = e.getKey();
+ }
+
+ }
+ }
+
+ if (candidateDistance == 1 || abbreviationLength == 0) {
+ return tagName;
+ }
+ return tagName + "-" + Integer.toString(candidateDistance-1) + "-" + "g"
+ + repo.getObjectDatabase().newReader()
+ .abbreviate(oid, abbreviationLength).name();
+ } catch (MissingObjectException e) {
+ throw new JGitInternalException(
+ JGitText.get().exceptionCaughtDuringExecutionOfDescribeCommand,
+ e);
+ } catch (IOException e) {
+ throw new JGitInternalException(
+ JGitText.get().exceptionCaughtDuringExecutionOfDescribeCommand,
+ e);
+ } finally {
+ w.release();
+ }
+ }
+
+ /**
+ * @return the object to run describe for.
+ */
+ public ObjectId getObjectId() {
+ return oid;
+ }
+
+ /**
+ * Set the object id to run describe for.
+ *
+ * @param oid
+ * @return this object, for chaining calls
+ */
+ public DescribeCommand setObjectId(ObjectId oid) {
+ this.oid = oid;
+ return this;
+ }
+
+ /**
+ * Returns the default abbreviation length
+ *
+ * @return default abbreviation length
+ */
+ public static int getDefaultAbbreviationLength() {
+ return DEFAULT_ABBREVIATION_LENGTH;
+ }
+}
View
13 org.eclipse.jgit/src/org/eclipse/jgit/api/Git.java
@@ -274,6 +274,19 @@ public AddCommand add() {
}
/**
+ * Returns a command object to execute a {@code Describe} command
+ *
+ * @see <a
+ * href="http://www.kernel.org/pub/software/scm/git/docs/git-describe.html"
+ * >Git documentation about Describe</a>
+ * @return a {@link DescribeCommand} used to collect all optional parameters
+ * and to finally execute the {@code Describe} command
+ */
+ public DescribeCommand describe() {
+ return new DescribeCommand(repo);
+ }
+
+ /**
* Returns a command object to execute a {@code Tag} command
*
* @see <a
Please sign in to comment.
Something went wrong with that request. Please try again.