You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by GitBox <gi...@apache.org> on 2019/01/01 23:23:01 UTC

[GitHub] asfgit closed pull request #79: WIP: [SCM-318] Untag command, with Git implementations

asfgit closed pull request #79: WIP: [SCM-318] Untag command, with Git implementations
URL: https://github.com/apache/maven-scm/pull/79
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/command/tag/AbstractTagCommand.java b/maven-scm-api/src/main/java/org/apache/maven/scm/command/tag/AbstractTagCommand.java
index 41493d295..c0b4d56e0 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/command/tag/AbstractTagCommand.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/command/tag/AbstractTagCommand.java
@@ -37,7 +37,7 @@
     extends AbstractCommand
 {
     /**
-     * @deprecated use method {@link #executeTagCommand(ScmProviderRepository, ScmFileSet, String, ScmTagParameters)} 
+     * @deprecated use method {@link #executeTagCommand(ScmProviderRepository, ScmFileSet, String, ScmTagParameters)}
      * @param repository
      * @param fileSet
      * @param tagName
@@ -54,8 +54,8 @@ protected ScmResult executeTagCommand( ScmProviderRepository repository, ScmFile
 
     protected abstract ScmResult executeTagCommand( ScmProviderRepository repository, ScmFileSet fileSet,
                                                     String tagName, ScmTagParameters scmTagParameters )
-        throws ScmException;    
-    
+        throws ScmException;
+
     /** {@inheritDoc} */
     public ScmResult executeCommand( ScmProviderRepository repository, ScmFileSet fileSet,
                                      CommandParameters parameters )
@@ -81,5 +81,5 @@ public ScmResult executeCommand( ScmProviderRepository repository, ScmFileSet fi
 
         return executeTagCommand( repository, fileSet, tagName, scmTagParameters );
     }
-    
+
 }
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java
new file mode 100644
index 000000000..53296c505
--- /dev/null
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/AbstractUntagCommand.java
@@ -0,0 +1,47 @@
+package org.apache.maven.scm.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.AbstractCommand;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+
+public abstract class AbstractUntagCommand
+    extends AbstractCommand
+{
+    protected abstract ScmResult executeUntagCommand( ScmProviderRepository repository,
+        ScmFileSet fileSet, String tagName )
+        throws ScmException;
+
+    /** {@inheritDoc} */
+    public ScmResult executeCommand( ScmProviderRepository repository, ScmFileSet fileSet,
+                                     CommandParameters parameters )
+        throws ScmException
+    {
+        String tagName = parameters.getString( CommandParameter.TAG_NAME );
+
+        return executeUntagCommand( repository, fileSet, tagName );
+    }
+
+}
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java
new file mode 100644
index 000000000..565628a92
--- /dev/null
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/command/untag/UntagScmResult.java
@@ -0,0 +1,43 @@
+package org.apache.maven.scm.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.scm.ScmResult;
+
+public class UntagScmResult
+    extends ScmResult
+{
+    private static final long serialVersionUID = -5068975000282095635L;
+
+    public UntagScmResult( String commandLine, String providerMessage, String commandOutput, boolean success )
+    {
+        super( commandLine, providerMessage, commandOutput, success );
+    }
+
+    public UntagScmResult( String commandLine )
+    {
+        super( commandLine, null, null, true );
+    }
+
+    public UntagScmResult( ScmResult result )
+    {
+        super( result );
+    }
+}
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
index dfcc88d8b..dcacd1158 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/AbstractScmProvider.java
@@ -49,6 +49,7 @@
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.log.ScmLogDispatcher;
 import org.apache.maven.scm.log.ScmLogger;
@@ -899,6 +900,17 @@ protected UnEditScmResult unedit( ScmProviderRepository repository, ScmFileSet f
         return new UnEditScmResult( "", null, null, true );
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet,
+        CommandParameters parameters )
+        throws ScmException
+    {
+        getLogger().warn( "Provider " + this.getScmType() + " does not support untag operation." );
+        return new UntagScmResult( "", null, null, true );
+    }
+
     /**
      * {@inheritDoc}
      *
diff --git a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
index a2d005f48..168c846f7 100644
--- a/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
+++ b/maven-scm-api/src/main/java/org/apache/maven/scm/provider/ScmProvider.java
@@ -45,6 +45,7 @@
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.log.ScmLogger;
 import org.apache.maven.scm.repository.ScmRepository;
@@ -641,6 +642,18 @@ StatusScmResult status( ScmRepository repository, ScmFileSet fileSet )
     TagScmResult tag( ScmRepository repository, ScmFileSet fileSet, String tagName )
         throws ScmException;
 
+    /**
+     * Deletes a tag.
+     *
+     * @param repository the source control system
+     * @param fileSet    a fileset with the relevant working directory as basedir
+     * @param parameters
+     * @return
+     * @throws ScmException if any
+     */
+    UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
+        throws ScmException;
+
     /**
      * Tag (or label in some systems) will tag the source file with a certain tag
      *
diff --git a/maven-scm-plugin/pom.xml b/maven-scm-plugin/pom.xml
index 9df467ac3..f865c360d 100644
--- a/maven-scm-plugin/pom.xml
+++ b/maven-scm-plugin/pom.xml
@@ -128,6 +128,11 @@
       <artifactId>maven-scm-provider-svntest</artifactId>
       <scope>test</scope>
     </dependency>
+      <dependency>
+          <groupId>org.apache.maven.scm</groupId>
+          <artifactId>maven-scm-provider-gittest</artifactId>
+          <scope>test</scope>
+      </dependency>
   </dependencies>
 
   <build>
diff --git a/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UntagMojo.java b/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UntagMojo.java
new file mode 100644
index 000000000..3368b5393
--- /dev/null
+++ b/maven-scm-plugin/src/main/java/org/apache/maven/scm/plugin/UntagMojo.java
@@ -0,0 +1,76 @@
+package org.apache.maven.scm.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.repository.ScmRepository;
+
+/**
+ * Untag the project.
+ */
+@Mojo( name = "untag", aggregator = true )
+public class UntagMojo
+    extends AbstractScmMojo
+{
+    /**
+     * The tag name.
+     */
+    @Parameter( property = "tag", required = true )
+    private String tag;
+
+    /** {@inheritDoc} */
+    public void execute()
+        throws MojoExecutionException
+    {
+        super.execute();
+
+        try
+        {
+            ScmRepository repository = getScmRepository();
+            ScmProvider provider = getScmManager().getProviderByRepository( repository );
+
+            String finalTag = provider.sanitizeTagName( tag );
+            getLog().info( "Final Tag Name: '" + finalTag + "'" );
+
+            CommandParameters parameters = new CommandParameters();
+            parameters.setString( CommandParameter.TAG_NAME, finalTag );
+
+            UntagScmResult result = provider.untag( repository, getFileSet(), parameters );
+
+            checkResult( result );
+        }
+        catch ( IOException e )
+        {
+            throw new MojoExecutionException( "Cannot run untag command", e );
+        }
+        catch ( ScmException e )
+        {
+            throw new MojoExecutionException( "Cannot run untag command", e );
+        }
+    }
+}
diff --git a/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UntagMojoTest.java b/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UntagMojoTest.java
new file mode 100644
index 000000000..ee9ffe9f5
--- /dev/null
+++ b/maven-scm-plugin/src/test/java/org/apache/maven/scm/plugin/UntagMojoTest.java
@@ -0,0 +1,115 @@
+package org.apache.maven.scm.plugin;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import org.apache.maven.plugin.testing.AbstractMojoTestCase;
+import org.apache.maven.scm.provider.git.GitScmTestUtils;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+public class UntagMojoTest
+    extends AbstractMojoTestCase
+{
+    File checkoutDir;
+
+    File repository;
+
+    File assertionDir;
+
+    protected void setUp()
+        throws Exception
+    {
+        super.setUp();
+
+        checkoutDir = getTestFile( "target/checkout" );
+
+        FileUtils.forceDelete( checkoutDir );
+
+        repository = getTestFile( "target/repository" );
+
+        FileUtils.forceDelete( repository );
+
+        assertionDir = getTestFile( "target/assert" );
+
+        FileUtils.forceDelete( assertionDir );
+
+        GitScmTestUtils.initRepo("src/test/resources/git", checkoutDir, assertionDir);
+
+        CheckoutMojo checkoutMojo = (CheckoutMojo) lookupMojo( "checkout", getTestFile(
+            "src/test/resources/mojos/untag/checkout.xml" ) );
+        checkoutMojo.setWorkingDirectory( checkoutDir );
+
+        String connectionUrl = checkoutMojo.getConnectionUrl();
+        connectionUrl = StringUtils.replace( connectionUrl, "${basedir}", getBasedir() );
+        connectionUrl = StringUtils.replace( connectionUrl, "\\", "/" );
+        checkoutMojo.setConnectionUrl( connectionUrl );
+
+        checkoutMojo.setCheckoutDirectory( checkoutDir );
+
+        checkoutMojo.execute();
+    }
+
+    public void testUnTag()
+        throws Exception
+    {
+
+        TagMojo tagMojo = (TagMojo) lookupMojo( "tag", getTestFile( "src/test/resources/mojos/untag/tag.xml" ) );
+        tagMojo.setWorkingDirectory( checkoutDir );
+        tagMojo.setConnectionUrl( getConnectionLocalAddress( tagMojo ) );
+        tagMojo.execute();
+
+        CheckoutMojo checkoutMojo =
+            (CheckoutMojo) lookupMojo( "checkout", getTestFile( "src/test/resources/mojos/untag/checkout-tag.xml" ) );
+        checkoutMojo.setWorkingDirectory( new File( getBasedir() ) );
+        checkoutMojo.setConnectionUrl( getConnectionLocalAddress( checkoutMojo ) );
+
+        File tagCheckoutDir = getTestFile( "target/tags/mytag" );
+
+        if ( tagCheckoutDir.exists() )
+        {
+            FileUtils.deleteDirectory( tagCheckoutDir );
+        }
+
+        checkoutMojo.setCheckoutDirectory( tagCheckoutDir );
+        checkoutMojo.execute();
+
+        UntagMojo mojo = (UntagMojo) lookupMojo( "untag", getTestFile( "src/test/resources/mojos/untag/untag.xml" ) );
+        mojo.setWorkingDirectory( checkoutDir );
+        mojo.setConnectionUrl( getConnectionLocalAddress( mojo ) );
+
+        mojo.execute();
+
+        FileUtils.deleteDirectory( tagCheckoutDir );
+
+        try {
+            checkoutMojo.execute();
+            fail("checkoutMojo should have failed to check out deleted tag");
+        } catch (Exception expected) {}
+    }
+
+    private String getConnectionLocalAddress(AbstractScmMojo mojo)
+    {
+        String connectionUrl = mojo.getConnectionUrl();
+        connectionUrl = StringUtils.replace( connectionUrl, "${basedir}", getBasedir() );
+        connectionUrl = StringUtils.replace( connectionUrl, "\\", "/" );
+        return connectionUrl;
+    }
+}
diff --git a/maven-scm-plugin/src/test/resources/git/.gitattributes b/maven-scm-plugin/src/test/resources/git/.gitattributes
new file mode 100644
index 000000000..5e0feff41
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/.gitattributes
@@ -0,0 +1,3 @@
+objects/** binary
+* text eol=lf
+
diff --git a/maven-scm-plugin/src/test/resources/git/HEAD b/maven-scm-plugin/src/test/resources/git/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/maven-scm-plugin/src/test/resources/git/config b/maven-scm-plugin/src/test/resources/git/config
new file mode 100644
index 000000000..942d2b2eb
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/config
@@ -0,0 +1,8 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+	ignorecase = true
+[user]
+	email = test@apache.org
+	name = Maven SCM Test User
diff --git a/maven-scm-plugin/src/test/resources/git/description b/maven-scm-plugin/src/test/resources/git/description
new file mode 100644
index 000000000..c6f25e80b
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file to name it for gitweb.
diff --git a/maven-scm-plugin/src/test/resources/git/hooks/empty.txt b/maven-scm-plugin/src/test/resources/git/hooks/empty.txt
new file mode 100644
index 000000000..e69de29bb
diff --git a/maven-scm-plugin/src/test/resources/git/info/exclude b/maven-scm-plugin/src/test/resources/git/info/exclude
new file mode 100644
index 000000000..2c87b72df
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/info/exclude
@@ -0,0 +1,6 @@
+# git-ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/maven-scm-plugin/src/test/resources/git/logs/HEAD b/maven-scm-plugin/src/test/resources/git/logs/HEAD
new file mode 100644
index 000000000..3cf80ca19
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/logs/HEAD
@@ -0,0 +1,3 @@
+0000000000000000000000000000000000000000 c51dcd33e7b71897603c203b5e0afc1d75f70051 Mark Struberg <st...@yahoo.de> 1196106917 +0100
+c51dcd33e7b71897603c203b5e0afc1d75f70051 baa229a9193371fad604444f64c4f26f8ff702f3 Mark Struberg <st...@yahoo.de> 1197041894 +0100	push
+baa229a9193371fad604444f64c4f26f8ff702f3 1d308c3b92eb0df9c0dc76436d50edfd0ca41d18 Mark Struberg <st...@yahoo.de> 1197042012 +0100	push
diff --git a/maven-scm-plugin/src/test/resources/git/logs/refs/heads/master b/maven-scm-plugin/src/test/resources/git/logs/refs/heads/master
new file mode 100644
index 000000000..3cf80ca19
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/logs/refs/heads/master
@@ -0,0 +1,3 @@
+0000000000000000000000000000000000000000 c51dcd33e7b71897603c203b5e0afc1d75f70051 Mark Struberg <st...@yahoo.de> 1196106917 +0100
+c51dcd33e7b71897603c203b5e0afc1d75f70051 baa229a9193371fad604444f64c4f26f8ff702f3 Mark Struberg <st...@yahoo.de> 1197041894 +0100	push
+baa229a9193371fad604444f64c4f26f8ff702f3 1d308c3b92eb0df9c0dc76436d50edfd0ca41d18 Mark Struberg <st...@yahoo.de> 1197042012 +0100	push
diff --git a/maven-scm-plugin/src/test/resources/git/logs/refs/remotes/origin/master b/maven-scm-plugin/src/test/resources/git/logs/refs/remotes/origin/master
new file mode 100644
index 000000000..6cb21b122
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/logs/refs/remotes/origin/master
@@ -0,0 +1 @@
+0000000000000000000000000000000000000000 c51dcd33e7b71897603c203b5e0afc1d75f70051 Mark Struberg <st...@yahoo.de> 1196106917 +0100	clone: from /home/msx/tmp/maven-git/repository/.git
diff --git a/maven-scm-plugin/src/test/resources/git/objects/17/e953589369a48dcb0a0cbad084a76ef852cd11 b/maven-scm-plugin/src/test/resources/git/objects/17/e953589369a48dcb0a0cbad084a76ef852cd11
new file mode 100644
index 000000000..4c7bbd623
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/17/e953589369a48dcb0a0cbad084a76ef852cd11 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/1d/308c3b92eb0df9c0dc76436d50edfd0ca41d18 b/maven-scm-plugin/src/test/resources/git/objects/1d/308c3b92eb0df9c0dc76436d50edfd0ca41d18
new file mode 100644
index 000000000..7d4c24766
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/1d/308c3b92eb0df9c0dc76436d50edfd0ca41d18 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/3b/459fa9451a94fc1acd10e2e29ab73d93eb816d b/maven-scm-plugin/src/test/resources/git/objects/3b/459fa9451a94fc1acd10e2e29ab73d93eb816d
new file mode 100644
index 000000000..6b6bfad97
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/3b/459fa9451a94fc1acd10e2e29ab73d93eb816d differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/3b/d305c57c635aead10cf59f7c1dc51af03edaf7 b/maven-scm-plugin/src/test/resources/git/objects/3b/d305c57c635aead10cf59f7c1dc51af03edaf7
new file mode 100644
index 000000000..0a079e76d
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/3b/d305c57c635aead10cf59f7c1dc51af03edaf7 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/3c/f7bb86c15554148bf5b0b12bfd639e54a77e58 b/maven-scm-plugin/src/test/resources/git/objects/3c/f7bb86c15554148bf5b0b12bfd639e54a77e58
new file mode 100644
index 000000000..c8859bdcc
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/3c/f7bb86c15554148bf5b0b12bfd639e54a77e58 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/61/4a3fd04313593d67f4154855a06941046326b3 b/maven-scm-plugin/src/test/resources/git/objects/61/4a3fd04313593d67f4154855a06941046326b3
new file mode 100644
index 000000000..bca48ac73
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/61/4a3fd04313593d67f4154855a06941046326b3 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/61/a0d22b023d6e31894d736cca8c1a47b6edd822 b/maven-scm-plugin/src/test/resources/git/objects/61/a0d22b023d6e31894d736cca8c1a47b6edd822
new file mode 100644
index 000000000..26470dbae
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/61/a0d22b023d6e31894d736cca8c1a47b6edd822 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/92/09a983605d6e43e5cf841a1ea18a1914bb7407 b/maven-scm-plugin/src/test/resources/git/objects/92/09a983605d6e43e5cf841a1ea18a1914bb7407
new file mode 100644
index 000000000..94939851d
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/92/09a983605d6e43e5cf841a1ea18a1914bb7407 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/92/f139dfec4d1dfb79c3cd2f94e83bf13129668b b/maven-scm-plugin/src/test/resources/git/objects/92/f139dfec4d1dfb79c3cd2f94e83bf13129668b
new file mode 100644
index 000000000..a352d5ab2
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/objects/92/f139dfec4d1dfb79c3cd2f94e83bf13129668b
@@ -0,0 +1 @@
+x��1�0@Q��;���	!.��	\ǡ�A��=�ly�R��@k����1H�������p�Q(I ��5q��W�j��;\����_�:�y�u����H=}[$D'ߥ�_ؕ�X���Y����<m
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/git/objects/94/d3d586e355f318d67e3da6bb16a91be7aad1a7 b/maven-scm-plugin/src/test/resources/git/objects/94/d3d586e355f318d67e3da6bb16a91be7aad1a7
new file mode 100644
index 000000000..ea35629bb
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/94/d3d586e355f318d67e3da6bb16a91be7aad1a7 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/9e/131cfc732b0d9f42b9b712a528d0632d9bcca7 b/maven-scm-plugin/src/test/resources/git/objects/9e/131cfc732b0d9f42b9b712a528d0632d9bcca7
new file mode 100644
index 000000000..0ba67da66
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/9e/131cfc732b0d9f42b9b712a528d0632d9bcca7 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/b5/3306f849b69ef0459ddf5cccff06b5fbb08c23 b/maven-scm-plugin/src/test/resources/git/objects/b5/3306f849b69ef0459ddf5cccff06b5fbb08c23
new file mode 100644
index 000000000..314330e20
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/b5/3306f849b69ef0459ddf5cccff06b5fbb08c23 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/ba/a229a9193371fad604444f64c4f26f8ff702f3 b/maven-scm-plugin/src/test/resources/git/objects/ba/a229a9193371fad604444f64c4f26f8ff702f3
new file mode 100644
index 000000000..e94938a48
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/objects/ba/a229a9193371fad604444f64c4f26f8ff702f3
@@ -0,0 +1 @@
+x��MN1@a�9����O���XqDZ��ʤ nB����<�~��|��9T�I�K��������ENV��� F��w��IԤ���f*K>b��&E6���e�D������x��9�U����:}����/@�d�TJ���_��͎[��~‡�}����Ƕ���}���jP�
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/git/objects/ba/cd4ee105073117b30e5dcdba5150373b6b53c6 b/maven-scm-plugin/src/test/resources/git/objects/ba/cd4ee105073117b30e5dcdba5150373b6b53c6
new file mode 100644
index 000000000..fe99cd8b9
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/ba/cd4ee105073117b30e5dcdba5150373b6b53c6 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/c3/8b0351660113545db270ba6918cc22a9eb17ce b/maven-scm-plugin/src/test/resources/git/objects/c3/8b0351660113545db270ba6918cc22a9eb17ce
new file mode 100644
index 000000000..bb5b1d508
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/c3/8b0351660113545db270ba6918cc22a9eb17ce differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/c5/1dcd33e7b71897603c203b5e0afc1d75f70051 b/maven-scm-plugin/src/test/resources/git/objects/c5/1dcd33e7b71897603c203b5e0afc1d75f70051
new file mode 100644
index 000000000..ec76cb09f
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/c5/1dcd33e7b71897603c203b5e0afc1d75f70051 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/dc/4204852765c12f398ef4a5fbcabf23cf17a183 b/maven-scm-plugin/src/test/resources/git/objects/dc/4204852765c12f398ef4a5fbcabf23cf17a183
new file mode 100644
index 000000000..2234dd6df
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/dc/4204852765c12f398ef4a5fbcabf23cf17a183 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/e8/174b6eb52916a296a8fd5724c5fa6a2bb154a1 b/maven-scm-plugin/src/test/resources/git/objects/e8/174b6eb52916a296a8fd5724c5fa6a2bb154a1
new file mode 100644
index 000000000..61eb7c502
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/objects/e8/174b6eb52916a296a8fd5724c5fa6a2bb154a1
@@ -0,0 +1,2 @@
+xE��
+�0E��o��&Mc"����84�K[5IIR!o�\.���	��;���HjH'G���d4� u�Gj$Cѩ�*9�JyE���%U�8l.��	\�D��s�~��IN$����ZL3�E�q>���ʹ�ySMѝ�����nE�V��tu��Q�k���_D=�
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/git/objects/f7/1429f9ff9214a546b438c611ae942c9cf5a49e b/maven-scm-plugin/src/test/resources/git/objects/f7/1429f9ff9214a546b438c611ae942c9cf5a49e
new file mode 100644
index 000000000..b543850b6
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/f7/1429f9ff9214a546b438c611ae942c9cf5a49e differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/fd/39fa3de0f63bc5c78eca219e74e0a8531bd3e6 b/maven-scm-plugin/src/test/resources/git/objects/fd/39fa3de0f63bc5c78eca219e74e0a8531bd3e6
new file mode 100644
index 000000000..1497fffc0
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/fd/39fa3de0f63bc5c78eca219e74e0a8531bd3e6 differ
diff --git a/maven-scm-plugin/src/test/resources/git/objects/fe/a16119a5b4ec0562d4f65b4237314250773bf8 b/maven-scm-plugin/src/test/resources/git/objects/fe/a16119a5b4ec0562d4f65b4237314250773bf8
new file mode 100644
index 000000000..6c36970db
Binary files /dev/null and b/maven-scm-plugin/src/test/resources/git/objects/fe/a16119a5b4ec0562d4f65b4237314250773bf8 differ
diff --git a/maven-scm-plugin/src/test/resources/git/refs/heads/master b/maven-scm-plugin/src/test/resources/git/refs/heads/master
new file mode 100644
index 000000000..d262065bd
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/refs/heads/master
@@ -0,0 +1 @@
+92f139dfec4d1dfb79c3cd2f94e83bf13129668b
diff --git a/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/HEAD b/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/HEAD
new file mode 100644
index 000000000..6efe28fff
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/HEAD
@@ -0,0 +1 @@
+ref: refs/remotes/origin/master
diff --git a/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/master b/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/master
new file mode 100644
index 000000000..b1c9092ec
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/git/refs/remotes/origin/master
@@ -0,0 +1 @@
+c51dcd33e7b71897603c203b5e0afc1d75f70051
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/checkout-tag.xml b/maven-scm-plugin/src/test/resources/mojos/untag/checkout-tag.xml
new file mode 100644
index 000000000..cbfad7b79
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/checkout-tag.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <checkoutDirectory>target/tags/mytag</checkoutDirectory>
+          <connectionType>connection</connectionType>
+          <scmVersion>mytag</scmVersion>
+          <scmVersionType>tag</scmVersionType>
+          <connectionUrl>scm:git:file:///${basedir}/src/test/resources/git</connectionUrl>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml b/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml
new file mode 100644
index 000000000..60ca18161
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/checkout.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <checkoutDirectory>target/tags/mytag</checkoutDirectory>
+          <connectionType>connection</connectionType>
+          <connectionUrl>scm:git:file:///${basedir}/src/test/resources/git</connectionUrl>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/tag.xml b/maven-scm-plugin/src/test/resources/mojos/untag/tag.xml
new file mode 100644
index 000000000..e23c55b04
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/tag.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <connectionUrl>scm:git:file:///${basedir}/src/test/resources/git</connectionUrl>
+          <connectionType>connection</connectionType>
+          <tag>mytag</tag>
+          <pushChanges>true</pushChanges>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml b/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml
new file mode 100644
index 000000000..e23c55b04
--- /dev/null
+++ b/maven-scm-plugin/src/test/resources/mojos/untag/untag.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-scm-plugin</artifactId>
+        <configuration>
+          <settings implementation="org.apache.maven.settings.Settings"/>
+          <connectionUrl>scm:git:file:///${basedir}/src/test/resources/git</connectionUrl>
+          <connectionType>connection</connectionType>
+          <tag>mytag</tag>
+          <pushChanges>true</pushChanges>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
\ No newline at end of file
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
index dbeadac05..73a879c2c 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/main/java/org/apache/maven/scm/provider/git/AbstractGitScmProvider.java
@@ -40,11 +40,13 @@
 import org.apache.maven.scm.command.remove.RemoveScmResult;
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.provider.AbstractScmProvider;
 import org.apache.maven.scm.provider.ScmProviderRepository;
 import org.apache.maven.scm.provider.git.command.GitCommand;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.apache.maven.scm.repository.ScmRepository;
 import org.apache.maven.scm.repository.ScmRepositoryException;
 import org.apache.maven.scm.repository.UnknownRepositoryStructure;
 
@@ -272,6 +274,16 @@ public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, C
         return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
     }
 
+    protected abstract GitCommand getUntagCommand();
+
+    /** {@inheritDoc} */
+    public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
+        throws ScmException
+    {
+        return (UntagScmResult) executeCommand( getUntagCommand(),
+            repository.getProviderRepository(), fileSet, parameters );
+    }
+
     protected abstract GitCommand getUpdateCommand();
 
     /** {@inheritDoc} */
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
index 3f07e9a31..d1f231aa2 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-git-commons/src/test/java/org/apache/maven/scm/provider/git/TestGitScmProvider.java
@@ -76,6 +76,11 @@ protected GitCommand getTagCommand()
         return null;
     }
 
+    protected GitCommand getUntagCommand()
+    {
+        return null;
+    }
+
     protected GitCommand getUpdateCommand()
     {
         return null;
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
index 2096cadfc..9cb43342b 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/GitExeScmProvider.java
@@ -38,6 +38,7 @@
 import org.apache.maven.scm.provider.git.gitexe.command.remove.GitRemoveCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.status.GitStatusCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.tag.GitTagCommand;
+import org.apache.maven.scm.provider.git.gitexe.command.untag.GitUntagCommand;
 import org.apache.maven.scm.provider.git.gitexe.command.update.GitUpdateCommand;
 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
 import org.apache.maven.scm.repository.ScmRepositoryException;
@@ -110,6 +111,12 @@ protected GitCommand getTagCommand()
         return new GitTagCommand();
     }
 
+    /** {@inheritDoc} */
+    protected GitCommand getUntagCommand()
+    {
+        return new GitUntagCommand();
+    }
+
     /** {@inheritDoc} */
     protected GitCommand getUpdateCommand()
     {
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java
new file mode 100644
index 000000000..157466590
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitUntagCommand.java
@@ -0,0 +1,109 @@
+package org.apache.maven.scm.provider.git.gitexe.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.untag.AbstractUntagCommand;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+import org.apache.maven.scm.provider.git.command.GitCommand;
+import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+
+public class GitUntagCommand
+    extends AbstractUntagCommand
+    implements GitCommand
+{
+
+    /** {@inheritDoc} */
+    public ScmResult executeUntagCommand( ScmProviderRepository repo, ScmFileSet fileSet, String tag )
+        throws ScmException
+    {
+        if ( tag == null || StringUtils.isEmpty( tag.trim() ) )
+        {
+            throw new ScmException( "tag name must be specified" );
+        }
+
+        GitScmProviderRepository repository = (GitScmProviderRepository) repo;
+
+        CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
+        CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
+
+        int exitCode;
+
+        Commandline clTag = createCommandLine( repository, fileSet.getBasedir(), tag );
+
+        exitCode = GitCommandLineUtils.execute( clTag, stdout, stderr, getLogger() );
+        if ( exitCode != 0 )
+        {
+            return new UntagScmResult( clTag.toString(), "The git-tag command failed.", stderr.getOutput(), false );
+        }
+
+        if ( repo.isPushChanges() )
+        {
+            // and now push the tag to the configured upstream repository
+            Commandline clPush = createPushCommandLine( repository, fileSet, tag );
+
+            exitCode = GitCommandLineUtils.execute( clPush, stdout, stderr, getLogger() );
+            if ( exitCode != 0 )
+            {
+                return new UntagScmResult( clPush.toString(), "The git-push command failed.", stderr.getOutput(),
+                                         false );
+            }
+        }
+
+        return new UntagScmResult( clTag.toString() );
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    public static Commandline createCommandLine( GitScmProviderRepository repository, File workingDirectory,
+                                                 String tag )
+    {
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( workingDirectory, "tag" );
+
+        cl.createArg().setValue( "-d" );
+        cl.createArg().setValue( tag );
+
+        return cl;
+    }
+
+    public static Commandline createPushCommandLine( GitScmProviderRepository repository, ScmFileSet fileSet,
+                                                     String tag )
+    {
+        Commandline cl = GitCommandLineUtils.getBaseGitCommandLine( fileSet.getBasedir(), "push" );
+
+        cl.createArg().setValue( "--delete" );
+        cl.createArg().setValue( repository.getPushUrl() );
+        cl.createArg().setValue( "refs/tags/" + tag );
+
+        return cl;
+    }
+
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitExeUntagCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitExeUntagCommandTckTest.java
new file mode 100644
index 000000000..0a1984753
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/untag/GitExeUntagCommandTckTest.java
@@ -0,0 +1,34 @@
+package org.apache.maven.scm.provider.git.gitexe.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.scm.provider.git.GitScmTestUtils;
+import org.apache.maven.scm.provider.git.command.untag.GitUntagCommandTckTest;
+
+public class GitExeUntagCommandTckTest
+    extends GitUntagCommandTckTest
+{
+        /** {@inheritDoc} */
+        public String getScmUrl()
+            throws Exception
+        {
+            return GitScmTestUtils.getScmUrl( getRepositoryRoot(), "git" );
+        }
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java
new file mode 100644
index 000000000..8a258f005
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gittest/src/main/java/org/apache/maven/scm/provider/git/command/untag/GitUntagCommandTckTest.java
@@ -0,0 +1,50 @@
+package org.apache.maven.scm.provider.git.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import org.apache.maven.scm.command.checkout.CheckOutScmResult;
+import org.apache.maven.scm.provider.git.GitScmTestUtils;
+import org.apache.maven.scm.repository.ScmRepository;
+import org.apache.maven.scm.tck.command.untag.UntagCommandTckTest;
+
+public abstract class GitUntagCommandTckTest
+    extends UntagCommandTckTest
+{
+    /** {@inheritDoc} */
+    public void initRepo()
+        throws Exception
+    {
+        GitScmTestUtils.initRepo( "src/test/resources/repository/", getRepositoryRoot(), getWorkingDirectory() );
+    }
+
+    @Override
+    protected CheckOutScmResult checkOut( File workingDirectory, ScmRepository repository ) throws Exception
+    {
+        try
+        {
+            return super.checkOut( workingDirectory, repository );
+        }
+        finally
+        {
+            GitScmTestUtils.setDefaultUser( workingDirectory );
+        }
+    }
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
index b155deaef..0c6d351c9 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/JGitScmProvider.java
@@ -39,6 +39,7 @@
 import org.apache.maven.scm.provider.git.jgit.command.remoteinfo.JGitRemoteInfoCommand;
 import org.apache.maven.scm.provider.git.jgit.command.status.JGitStatusCommand;
 import org.apache.maven.scm.provider.git.jgit.command.tag.JGitTagCommand;
+import org.apache.maven.scm.provider.git.jgit.command.untag.JGitUntagCommand;
 import org.apache.maven.scm.repository.ScmRepositoryException;
 
 /**
@@ -130,6 +131,14 @@ protected GitCommand getTagCommand()
         return new JGitTagCommand();
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    protected GitCommand getUntagCommand()
+    {
+        return new JGitUntagCommand();
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java
new file mode 100644
index 000000000..ddb6a8c3b
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/main/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommand.java
@@ -0,0 +1,103 @@
+package org.apache.maven.scm.provider.git.jgit.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Collection;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmResult;
+import org.apache.maven.scm.command.untag.AbstractUntagCommand;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.log.ScmLogger;
+import org.apache.maven.scm.provider.ScmProviderRepository;
+import org.apache.maven.scm.provider.git.command.GitCommand;
+import org.apache.maven.scm.provider.git.jgit.command.JGitTransportConfigCallback;
+import org.apache.maven.scm.provider.git.jgit.command.JGitUtils;
+import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
+import org.codehaus.plexus.util.StringUtils;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PushCommand;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.PushResult;
+import org.eclipse.jgit.transport.RefSpec;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+
+public class JGitUntagCommand extends AbstractUntagCommand implements GitCommand
+{
+
+    @Override
+    protected ScmResult executeUntagCommand( ScmProviderRepository repository, ScmFileSet fileSet,
+        String tagName ) throws ScmException
+    {
+        if ( tagName == null || StringUtils.isEmpty( tagName.trim() ) )
+        {
+            throw new ScmException( "tag name must be specified" );
+        }
+        String escapedTagName = tagName.trim().replace( ' ', '_' );
+
+        Git git = null;
+        try
+        {
+            git = JGitUtils.openRepo( fileSet.getBasedir() );
+
+            // delete the tag
+            if ( git.tagDelete().setTags( escapedTagName ).call().isEmpty() )
+            {
+                return new UntagScmResult( "JGit tagDelete", "Failed to delete tag", "", false );
+            }
+
+            if ( repository.isPushChanges() )
+            {
+                // From https://stackoverflow.com/questions/11892766/how-to-remove-remote-branch-with-jgit
+                RefSpec refSpec = new RefSpec()
+                    .setSource( null )
+                    .setDestination( Constants.R_TAGS + escapedTagName );
+
+                getLogger().info( "push delete tag [" + escapedTagName + "] to remote..." );
+                ScmLogger logger = getLogger();
+
+                Iterable<PushResult> pushResultList
+                        = JGitUtils.push( logger, git, (GitScmProviderRepository) repository, refSpec );
+                if ( logger.isInfoEnabled() )
+                {
+                    for ( PushResult pushResult : pushResultList )
+                    {
+                        Collection<RemoteRefUpdate> ru = pushResult.getRemoteUpdates();
+                        for ( RemoteRefUpdate remoteRefUpdate : ru )
+                        {
+                            logger.info( remoteRefUpdate.getStatus() + " - " + remoteRefUpdate );
+                        }
+                    }
+                }
+            }
+
+            return new UntagScmResult( "JGit tagDelete" );
+        }
+        catch ( Exception e )
+        {
+            throw new ScmException( "JGit tagDelete failure!", e );
+        }
+        finally
+        {
+            JGitUtils.closeRepo( git );
+        }
+    }
+}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommandTckTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommandTckTest.java
new file mode 100644
index 000000000..268ef41b7
--- /dev/null
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-jgit/src/test/java/org/apache/maven/scm/provider/git/jgit/command/untag/JGitUntagCommandTckTest.java
@@ -0,0 +1,52 @@
+package org.apache.maven.scm.provider.git.jgit.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.maven.scm.provider.git.GitScmTestUtils;
+import org.apache.maven.scm.provider.git.command.untag.GitUntagCommandTckTest;
+import org.eclipse.jgit.util.FileUtils;
+
+/**
+ * This test tests the untag command.
+ */
+public class JGitUntagCommandTckTest
+    extends GitUntagCommandTckTest
+{
+    /**
+     * {@inheritDoc}
+     */
+    public String getScmUrl()
+        throws Exception
+    {
+        return GitScmTestUtils.getScmUrl( getRepositoryRoot(), "jgit" );
+    }
+
+    @Override
+    protected void deleteDirectory( File directory )
+        throws IOException
+    {
+        if ( directory.exists() )
+        {
+            FileUtils.delete( directory, FileUtils.RECURSIVE | FileUtils.RETRY );
+        }
+    }
+}
diff --git a/maven-scm-test/src/main/java/org/apache/maven/scm/provider/ScmProviderStub.java b/maven-scm-test/src/main/java/org/apache/maven/scm/provider/ScmProviderStub.java
index 9edf2c2ed..2b6c284ef 100644
--- a/maven-scm-test/src/main/java/org/apache/maven/scm/provider/ScmProviderStub.java
+++ b/maven-scm-test/src/main/java/org/apache/maven/scm/provider/ScmProviderStub.java
@@ -46,6 +46,7 @@
 import org.apache.maven.scm.command.status.StatusScmResult;
 import org.apache.maven.scm.command.tag.TagScmResult;
 import org.apache.maven.scm.command.unedit.UnEditScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
 import org.apache.maven.scm.command.update.UpdateScmResult;
 import org.apache.maven.scm.log.ScmLogger;
 import org.apache.maven.scm.repository.ScmRepository;
@@ -113,6 +114,8 @@
 
     private MkdirScmResult mkdirScmResult;
 
+    private UntagScmResult untagScmResult;
+
     /**
      * Create a new ScmProviderStub with bogus (not null) attributes
      */
@@ -131,6 +134,7 @@ public ScmProviderStub()
         setStatusScmResult( new StatusScmResult( "", "", "", true ) );
         setTagScmResult( new TagScmResult( "", "", "", true ) );
         setUnEditScmResult( new UnEditScmResult( "", "", "", true ) );
+        setUntagScmResult( new UntagScmResult( "", "", "", true ) );
         setUpdateScmResult( new UpdateScmResult( "", "", "", true ) );
         setBlameScmResult( new BlameScmResult( "", "", "", true ) );
         setMkdirScmResult( new MkdirScmResult( "", "", "", true ) );
@@ -258,6 +262,16 @@ public TagScmResult getTagScmResult()
         return tagScmResult;
     }
 
+    public void setUntagScmResult( UntagScmResult untagScmResult )
+    {
+        this.untagScmResult = untagScmResult;
+    }
+
+    public UntagScmResult getUntagScmResult()
+    {
+        return untagScmResult;
+    }
+
     public void setRemoveScmResult( RemoveScmResult removeScmResult )
     {
         this.removeScmResult = removeScmResult;
@@ -745,6 +759,12 @@ public TagScmResult tag( ScmRepository repository, ScmFileSet fileSet, String ta
         return getTagScmResult();
     }
 
+    public UntagScmResult untag( ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters )
+        throws ScmException
+    {
+        return getUntagScmResult();
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/maven-scm-test/src/main/java/org/apache/maven/scm/tck/command/untag/UntagCommandTckTest.java b/maven-scm-test/src/main/java/org/apache/maven/scm/tck/command/untag/UntagCommandTckTest.java
new file mode 100644
index 000000000..2968cacdb
--- /dev/null
+++ b/maven-scm-test/src/main/java/org/apache/maven/scm/tck/command/untag/UntagCommandTckTest.java
@@ -0,0 +1,84 @@
+package org.apache.maven.scm.tck.command.untag;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.scm.CommandParameter;
+import org.apache.maven.scm.CommandParameters;
+import org.apache.maven.scm.ScmException;
+import org.apache.maven.scm.ScmFileSet;
+import org.apache.maven.scm.ScmTag;
+import org.apache.maven.scm.ScmTagParameters;
+import org.apache.maven.scm.ScmTckTestCase;
+import org.apache.maven.scm.command.checkout.CheckOutScmResult;
+import org.apache.maven.scm.command.tag.TagScmResult;
+import org.apache.maven.scm.command.untag.UntagScmResult;
+import org.apache.maven.scm.provider.ScmProvider;
+import org.apache.maven.scm.repository.ScmRepository;
+
+/**
+ * This test tests the untag command.
+ */
+public abstract class UntagCommandTckTest
+    extends ScmTckTestCase
+{
+
+    protected String getTagName()
+    {
+        return "test-untag";
+    }
+
+    public void testUntagCommandTest()
+        throws Exception
+    {
+        String tag = getTagName();
+        ScmProvider scmProvider = getScmManager().getProviderByUrl( getScmUrl() );
+        ScmRepository scmRepository = getScmRepository();
+        ScmFileSet files = new ScmFileSet( getWorkingCopy() );
+        TagScmResult tagResult = scmProvider.tag( scmRepository, files, tag, new ScmTagParameters() );
+
+        assertResultIsSuccess( tagResult );
+        CommandParameters params = new CommandParameters();
+        params.setString( CommandParameter.TAG_NAME, tag );
+
+        UntagScmResult untagResult = scmProvider.untag( scmRepository, files, params );
+
+        assertResultIsSuccess( untagResult );
+
+        try
+        {
+            untagResult = scmProvider.untag( scmRepository, files, params );
+            assertFalse( untagResult.isSuccess() ); // already been deleted
+        }
+        catch ( ScmException ignored )
+        {
+        }
+
+        try
+        {
+            CheckOutScmResult checkoutResult =
+                getScmManager().checkOut( scmRepository, new ScmFileSet( getAssertionCopy() ), new ScmTag( tag ) );
+            assertFalse( checkoutResult.isSuccess() ); // can't check out a deleted tags
+        }
+        catch ( ScmException ignored )
+        {
+        }
+    }
+
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services