[pgm] Implement git tag --contains option

Change-Id: I390bcd2c2c563d4b27e1369f09548be59ba7c111
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
index e8d61a5..26d617d 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/TagTest.java
@@ -9,24 +9,30 @@
  */
 package org.eclipse.jgit.pgm;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.lib.CLIRepositoryTestCase;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Before;
 import org.junit.Test;
 
 public class TagTest extends CLIRepositoryTestCase {
 	private Git git;
 
+	private RevCommit initialCommit;
+
 	@Override
 	@Before
 	public void setUp() throws Exception {
 		super.setUp();
 		git = new Git(db);
-		git.commit().setMessage("initial commit").call();
+		initialCommit = git.commit().setMessage("initial commit").call();
 	}
 
 	@Test
@@ -57,4 +63,39 @@ public void testTagDeleteFail() throws Exception {
 			assertEquals("fatal: error: tag 'test' not found", e.getMessage());
 		}
 	}
+
+	@Test
+	public void testContains() throws Exception {
+		/*      c3
+		 *      |
+		 * v2 - c2   b2 - v1
+		 *      |    |
+		 *      c1   b1
+		 *       \   /
+		 *         a
+		 */
+		try (TestRepository<Repository> r = new TestRepository<>(
+				db)) {
+			RevCommit b1 = r.commit(initialCommit);
+			RevCommit b2 = r.commit(b1);
+			RevCommit c1 = r.commit(initialCommit);
+			RevCommit c2 = r.commit(c1);
+			RevCommit c3 = r.commit(c2);
+			r.update("refs/tags/v1", r.tag("v1", b2));
+			r.update("refs/tags/v2", r.tag("v1.1", c2));
+
+			assertArrayEquals(
+					new String[] { "v1", "v2", "" },
+					execute("git tag --contains " + initialCommit.name()));
+
+			assertArrayEquals(new String[] { "v1", "" },
+					execute("git tag --contains " + b1.name()));
+
+			assertArrayEquals(new String[] { "v2", "" },
+					execute("git tag --contains " + c1.name()));
+
+			assertArrayEquals(new String[] { "" },
+					execute("git tag --contains " + c3.name()));
+		}
+	}
 }
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 98d711d..7b81af5 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -469,6 +469,7 @@
 usage_noTrustExitCode=This option can be used to override --trust-exit-code setting.
 usage_notags=do not fetch tags
 usage_tagAnnotated=create an annotated tag, unsigned unless -s or -u are given, or config tag.gpgSign is true
+usage_tagContains=Only list tags which contain the specified commit
 usage_tagDelete=delete tag
 usage_tagLocalUser=create a signed annotated tag using the specified GPG key ID
 usage_tagMessage=create an annotated tag with the given message, unsigned unless -s or -u are given, or config tag.gpgSign is true, or tar.forceSignAnnotated is true and -a is not given
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
index e2cd31d..0603de1 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Tag.java
@@ -33,6 +33,7 @@
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.pgm.internal.CLIText;
 import org.eclipse.jgit.pgm.internal.VerificationUtils;
+import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTag;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.kohsuke.args4j.Argument;
@@ -76,6 +77,11 @@ class Tag extends TextBuiltin {
 			"--local-user" }, usage = "usage_tagVerify")
 	private boolean verify;
 
+	@Option(name = "--contains", forbids = { "--delete", "--force",
+			"--annotate", "-m", "--sign", "--no-sign",
+			"--local-user" }, metaVar = "metaVar_commitish", usage = "usage_tagContains")
+	private RevCommit contains;
+
 	@Argument(index = 0, metaVar = "metaVar_name")
 	private String tagName;
 
@@ -142,6 +148,9 @@ protected void run() {
 				}
 			} else {
 				ListTagCommand command = git.tagList();
+				if (contains != null) {
+					command.setContains(contains);
+				}
 				List<Ref> list = command.call();
 				for (Ref ref : list) {
 					outw.println(Repository.shortenRefName(ref.getName()));