You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2020/01/26 16:56:58 UTC

[maven-release] branch MRELEASE-549 created (now 4126dc3)

This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a change to branch MRELEASE-549
in repository https://gitbox.apache.org/repos/asf/maven-release.git.


      at 4126dc3  [MRELEASE-549] Pin svn:externals when copying (tagging/branching)

This branch includes the following new commits:

     new 4126dc3  [MRELEASE-549] Pin svn:externals when copying (tagging/branching)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[maven-release] 01/01: [MRELEASE-549] Pin svn:externals when copying (tagging/branching)

Posted by mi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

michaelo pushed a commit to branch MRELEASE-549
in repository https://gitbox.apache.org/repos/asf/maven-release.git

commit 4126dc3499a02c6e99c8d09ac2ad1789f4602db0
Author: Thorsten Heit <th...@gmx.de>
AuthorDate: Fri Dec 20 12:27:02 2019 +0100

    [MRELEASE-549] Pin svn:externals when copying (tagging/branching)
    
    Add support for the "--pin-externals" option in SCM branch and tag
    operations. This feature was introducted in Subversion 1.9 and is
    available in Maven SCM since version 1.11.1.
    
    This closes #32
---
 .../shared/release/config/ReleaseDescriptor.java   | 134 +++++++++++----------
 .../config/PropertiesReleaseDescriptorStore.java   |   2 +
 .../release/config/ReleaseDescriptorBuilder.java   |   6 +
 .../maven/shared/release/config/ReleaseUtils.java  |   5 +
 .../maven/shared/release/phase/ScmBranchPhase.java |  11 +-
 .../maven/shared/release/phase/ScmTagPhase.java    |  14 ++-
 .../src/main/mdo/release-descriptor.mdo            |  14 +++
 .../phase/GenerateReleasePomsPhaseTest.java        |   2 +
 .../release/phase/IsScmBranchParametersEquals.java |   4 +-
 .../release/phase/IsScmTagParametersEquals.java    |   3 +-
 .../phase/ScmCommitDevelopmentPhaseTest.java       |   1 +
 .../phase/ScmCommitPreparationPhaseTest.java       |   1 +
 .../maven/plugins/release/BranchReleaseMojo.java   |  10 ++
 .../maven/plugins/release/PrepareReleaseMojo.java  |  10 ++
 14 files changed, 144 insertions(+), 73 deletions(-)

diff --git a/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java b/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
index ba117a1..a482727 100644
--- a/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
+++ b/maven-release-api/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptor.java
@@ -24,14 +24,14 @@ import java.util.List;
 import org.apache.maven.model.Scm;
 
 /**
- * 
+ *
  * @author Robert Scholte
  */
 public interface ReleaseDescriptor
 {
     /**
      * Get if updateDependencies is false, dependencies version won't be updated to the next development version.
-     * 
+     *
      * @return boolean
      */
     boolean isUpdateDependencies();
@@ -39,56 +39,56 @@ public interface ReleaseDescriptor
     /**
      * Get whether to use the release profile that adds sources and javadocs to the released artifact, if appropriate.
      * If set to true, this will set the property "performRelease" to true.
-     * 
+     *
      * @return boolean
      */
     boolean isUseReleaseProfile();
 
     /**
      * Get whether to use the parent pom version for submodule versions.
-     * 
+     *
      * @return boolean
      */
     boolean isAutoVersionSubmodules();
 
     /**
      * Get whether a SNAPSHOT of the release plugin is allowed.
-     * 
+     *
      * @return boolean
      */
     boolean isSnapshotReleasePluginAllowed();
 
     /**
      * Get the commits must be done by modules or not. Set it to true in case of flat directory structure.
-     * 
+     *
      * @return boolean
      */
     boolean isCommitByProject();
 
     /**
      * Get whether to create a branch instead of do a release.
-     * 
+     *
      * @return boolean
      */
     boolean isBranchCreation();
 
     /**
      * Get whether to update branch POM versions.
-     * 
+     *
      * @return boolean
      */
     boolean isUpdateBranchVersions();
 
     /**
      * Get whether to update working copy POM versions.
-     * 
+     *
      * @return boolean
      */
     boolean isUpdateWorkingCopyVersions();
 
     /**
      * Get whether to suppress a commit of changes to the working copy before a tag or branch is created.
-     * 
+     *
      * @return boolean
      */
     boolean isSuppressCommitBeforeTagOrBranch();
@@ -96,14 +96,14 @@ public interface ReleaseDescriptor
     /**
      * Get should timestamped SNAPSHOT dependencies be allowed? Default is to fail when any SNAPSHOT dependency is
      * found.
-     * 
+     *
      * @return boolean
      */
     boolean isAllowTimestampedSnapshots();
 
     /**
      * Get whether to update branch versions to SNAPSHOT.
-     * 
+     *
      * @return boolean
      */
     boolean isUpdateVersionsToSnapshot();
@@ -111,7 +111,7 @@ public interface ReleaseDescriptor
     /**
      * Get nOTE : currently only implemented with svn scm. Enable a workaround to prevent issue due to svn client &gt;
      * 1.5.0 (https://issues.apache.org/jira/browse/SCM-406).
-     * 
+     *
      * @return boolean
      */
     boolean isRemoteTagging();
@@ -119,7 +119,7 @@ public interface ReleaseDescriptor
     /**
      * Get if the scm provider should use local checkouts via file://${basedir} instead of doing a clean checkout over
      * the network. This is very helpful for releasing large projects!
-     * 
+     *
      * @return boolean
      */
     boolean isLocalCheckout();
@@ -128,54 +128,54 @@ public interface ReleaseDescriptor
      * Get should distributed changes be pushed to the central repository? For many distributed SCMs like Git, a change
      * like a commit is only stored in your local copy of the repository. Pushing the change allows your to more easily
      * share it with other users.
-     * 
+     *
      * @return boolean
      */
     boolean isPushChanges();
 
     /**
      * Get default version to use for new working copy.
-     * 
+     *
      * Some SCMs may require a Work Item or a Task to allow the
      * changes to be pushed or delivered.
      * This field allows you to specify that Work Item
      * or Task. It is optional, and only relevant if pushChanges is true.
-     *  
+     *
      * @return String
      */
     String getWorkItem();
 
     /**
      * Get default version to use for new working copy.
-     * 
+     *
      * @return String
      */
     String getDefaultDevelopmentVersion();
 
     /**
      * Get relative path of the project returned by the checkout command.
-     * 
+     *
      * @return String
      */
     String getScmRelativePathProjectDirectory();
 
     /**
      * Get the directory where the tag will be checked out.
-     * 
+     *
      * @return String
      */
     String getCheckoutDirectory();
 
     /**
      * Get the goals to execute in perform phase for the release.
-     * 
+     *
      * @return String
      */
     String getPerformGoals();
 
     /**
      * Get default version to use for the tagged release or the new branch.
-     * 
+     *
      * @return String
      */
     String getDefaultReleaseVersion();
@@ -183,7 +183,7 @@ public interface ReleaseDescriptor
     /**
      * Get nOTE : currently only implemented with svn scm. It contains the revision of the committed released pom to
      * remotely tag the source code with this revision.
-     * 
+     *
      * @return String
      */
     String getScmReleasedPomRevision();
@@ -191,14 +191,14 @@ public interface ReleaseDescriptor
     /**
      * Get whether to add the model schema to the top of the rewritten POM if it wasn't there already. If
      * <code>false</code> then the root element will remain untouched.
-     * 
+     *
      * @return boolean
      */
     boolean isAddSchema();
 
     /**
      * Get whether to generate release POMs.
-     * 
+     *
      * @return boolean
      */
     boolean isGenerateReleasePoms();
@@ -206,7 +206,7 @@ public interface ReleaseDescriptor
     /**
      * Get whether the release process is interactive and the release manager should be prompted to confirm values, or
      * whether the defaults are used regardless.
-     * 
+     *
      * @return boolean
      */
     boolean isInteractive();
@@ -214,69 +214,69 @@ public interface ReleaseDescriptor
     /**
      * Get whether to use edit mode when making SCM modifications. This setting is disregarded if the SCM does not
      * support edit mode, or if edit mode is compulsory for the given SCM.
-     * 
+     *
      * @return boolean
      */
     boolean isScmUseEditMode();
 
     /**
-     * 
+     *
      * @return list of profiles to activate
      */
     List<String> getActivateProfiles();
 
     /**
      * Get the last completed phase.
-     * 
+     *
      * @return String
      */
     String getCompletedPhase();
 
     /**
      * Method getCheckModificationExcludes.
-     * 
+     *
      * @return List
      */
     List<String> getCheckModificationExcludes();
 
     /**
      * Get additional arguments to pass to any executed Maven process.
-     * 
+     *
      * @return String
      */
     String getAdditionalArguments();
 
     /**
      * Get the goals to execute in preparation for the release.
-     * 
+     *
      * @return String
      */
     String getPreparationGoals();
 
     /**
      * Get the goals to execute in on completion of preparation for the release.
-     * 
+     *
      * @return String
      */
     String getCompletionGoals();
 
     /**
      * Get the file name of the POM to pass to any executed Maven process.
-     * 
+     *
      * @return String
      */
     String getPomFileName();
 
     /**
      * Get the prefix of SCM modification messages.
-     * 
+     *
      * @return String
      */
     String getScmCommentPrefix();
 
     /**
      * Get the SCM commit comment when setting pom.xml to release.
-     * 
+     *
      * @return String
      * @since 3.0.0-M1
      */
@@ -284,7 +284,7 @@ public interface ReleaseDescriptor
 
     /**
      * Get the SCM commit comment when setting pom.xml back to development.
-     * 
+     *
      * @return String
      * @since 3.0.0-M1
      */
@@ -292,7 +292,7 @@ public interface ReleaseDescriptor
 
     /**
      * Get the SCM commit comment when branching.
-     * 
+     *
      * @return String
      * @since 3.0.0-M1
      */
@@ -300,7 +300,7 @@ public interface ReleaseDescriptor
 
     /**
      * Get the SCM commit comment when rolling back.
-     * 
+     *
      * @return String
      * @since 3.0.0-M1
      */
@@ -308,35 +308,35 @@ public interface ReleaseDescriptor
 
     /**
      * Get pass phrase for the private key.
-     * 
+     *
      * @return String
      */
     String getScmPrivateKeyPassPhrase();
 
     /**
      * Get the password for the user interacting with the scm.
-     * 
+     *
      * @return String
      */
     String getScmPassword();
 
     /**
      * Get private key for an SSH based SCM repository.
-     * 
+     *
      * @return String
      */
     String getScmPrivateKey();
 
     /**
      * Get tag or branch name: the identifier for the tag/branch. Example: maven-release-plugin-2.0.
-     * 
+     *
      * @return String
      */
     String getScmReleaseLabel();
 
     /**
      * Get where you are going to put your tagged sources Example https://svn.apache.org/repos/asf/maven/plugins/tags.
-     * 
+     *
      * @return String
      */
     String getScmTagBase();
@@ -344,14 +344,14 @@ public interface ReleaseDescriptor
     /**
      * Get where you are going to put your branched sources Example
      * https://svn.apache.org/repos/asf/maven/plugins/branches.
-     * 
+     *
      * @return String
      */
     String getScmBranchBase();
 
     /**
      * Get the id can be used to get the credentials by the server-id from the settings.xml.
-     * 
+     *
      * @return String
      */
     String getScmId();
@@ -359,28 +359,28 @@ public interface ReleaseDescriptor
     /**
      * Get this is a MavenSCM of where you're going to get the sources to make the release with. Example:
      * scm:svn:https://svn.apache.org/repos/asf/maven/plugins/trunk/maven-release-plugin.
-     * 
+     *
      * @return String
      */
     String getScmSourceUrl();
 
     /**
      * Get the user name to interact with the scm.
-     * 
+     *
      * @return String
      */
     String getScmUsername();
 
     /**
      * Get wait the specified number of seconds before creating a tag.
-     * 
+     *
      * @return int
      */
     int getWaitBeforeTagging();
 
     /**
      * Get the directory where the release is performed.
-     * 
+     *
      * @return String
      */
     String getWorkingDirectory();
@@ -388,28 +388,28 @@ public interface ReleaseDescriptor
     /**
      * Get specifies the format for generating a tag name. Property expansion is used with the optional prefix of
      * project, where properties are delimited with @{ and }.
-     * 
+     *
      * @return String
      */
     String getScmTagNameFormat();
 
     /**
      * Get the role-hint for the NamingPolicy implementation used to calculate the project branch and tag names.
-     * 
+     *
      * @return String
      */
     String getProjectNamingPolicyId();
 
     /**
      * Get the role-hint for the VersionPolicy implementation used to calculate the project versions.
-     * 
+     *
      * @return String
      */
-    String getProjectVersionPolicyId(); 
+    String getProjectVersionPolicyId();
 
     /**
      * Get the role-hint for the release Strategy implementation.
-     * 
+     *
      * @return String
      */
     String getReleaseStrategyId();
@@ -420,22 +420,22 @@ public interface ReleaseDescriptor
      * @param artifactKey the artifact key {@code String}
      */
     String getDependencyOriginalVersion( String artifactKey );
-    
+
     /**
      * @return {@code String} the release version for the resolved snapshot dependency.
      *
      * @param artifactKey the artifact key {@code String}
      */
-    String getDependencyReleaseVersion( String artifactKey ); 
+    String getDependencyReleaseVersion( String artifactKey );
 
     /**
      * @return {@code String} the release version for the resolved snapshot dependency.
      *
      * @param artifactKey the artifact key {@code String}
      */
-    String getDependencyDevelopmentVersion( String artifactKey ); 
+    String getDependencyDevelopmentVersion( String artifactKey );
+
 
-    
     String getProjectOriginalVersion( String projectKey );
 
     String getProjectDevelopmentVersion( String projectKey );
@@ -444,7 +444,7 @@ public interface ReleaseDescriptor
 
     /**
      * @return the original {@code Scm} information.
-     * 
+     *
      * @param projectKey the project key {@code String}
      */
     Scm getOriginalScmInfo( String projectKey );
@@ -452,8 +452,8 @@ public interface ReleaseDescriptor
     // Modifiable
     void addDependencyOriginalVersion( String versionlessKey, String string );
 
-    void addDependencyReleaseVersion( String versionlessKey, String version ); 
-    
+    void addDependencyReleaseVersion( String versionlessKey, String version );
+
     void addDependencyDevelopmentVersion( String versionlessKey, String version );
 
     void addReleaseVersion( String projectId, String nextVersion );
@@ -480,8 +480,16 @@ public interface ReleaseDescriptor
      * <li>"reports" or "3": resolve report dependencies</li>
      * <li>"extensions" or "4": resolve extension dependencies</li>
      * </ul>
-     * 
+     *
      * @return String
      */
     String getAutoResolveSnapshots();
+
+    /**
+     * Determines whether the {@code --pin-externals} option in {@code svn copy} command is enabled
+     * which is new in Subversion 1.9.
+     *
+     * @return boolean
+     */
+    boolean isPinExternals();
 }
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
index f1272de..9937104 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/PropertiesReleaseDescriptorStore.java
@@ -249,6 +249,8 @@ public class PropertiesReleaseDescriptorStore
 
         properties.setProperty( "remoteTagging", Boolean.toString( config.isRemoteTagging() ) );
 
+        properties.setProperty( "pinExternals", Boolean.toString( config.isPinExternals() ) );
+
         properties.setProperty( "pushChanges", Boolean.toString( config.isPushChanges() ) );
 
         if ( config.getWorkItem() != null )
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
index 629a897..7ff677a 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseDescriptorBuilder.java
@@ -446,6 +446,12 @@ public class ReleaseDescriptorBuilder
         return this;
     }
 
+    public ReleaseDescriptorBuilder setPinExternals( boolean pinExternals )
+    {
+        releaseDescriptor.setPinExternals( pinExternals );
+        return this;
+    }
+
     BuilderReleaseDescriptor build()
     {
         return releaseDescriptor;
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
index bcaf758..870f285 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/config/ReleaseUtils.java
@@ -161,6 +161,11 @@ public class ReleaseUtils
             String remoteTaggingStr = properties.getProperty( "remoteTagging" );
             builder.setRemoteTagging( Boolean.valueOf( remoteTaggingStr ) );
         }
+        if ( properties.containsKey( "pinExternals" ) )
+        {
+            String pinExternals = properties.getProperty( "pinExternals" );
+            builder.setPinExternals( Boolean.valueOf( pinExternals ) );
+        }
         if ( properties.containsKey( "pushChanges" ) )
         {
             String pushChanges = properties.getProperty( "pushChanges" );
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmBranchPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmBranchPhase.java
index d1d85b6..576f511 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmBranchPhase.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmBranchPhase.java
@@ -108,6 +108,7 @@ public class ScmBranchPhase
             scmBranchParameters.setMessage( releaseDescriptor.getScmCommentPrefix() + "copy for branch " + branchName );
             scmBranchParameters.setRemoteBranching( releaseDescriptor.isRemoteTagging() );
             scmBranchParameters.setScmRevision( releaseDescriptor.getScmReleasedPomRevision() );
+            scmBranchParameters.setPinExternals( releaseDescriptor.isPinExternals() );
 
             result = provider.branch( repository, fileSet, branchName, scmBranchParameters );
         }
@@ -137,12 +138,16 @@ public class ScmBranchPhase
         ReleaseDescriptor basedirAlignedReleaseDescriptor =
             ReleaseUtil.createBasedirAlignedReleaseDescriptor( releaseDescriptor, reactorProjects );
 
-        logInfo( result, "Full run would be branching " + basedirAlignedReleaseDescriptor.getWorkingDirectory() );
+        logInfo( result, "Full run would branch " + basedirAlignedReleaseDescriptor.getWorkingDirectory() );
         if ( releaseDescriptor.getScmBranchBase() != null )
         {
-            logInfo( result, "  To SCM URL: " + releaseDescriptor.getScmBranchBase() );
+            logInfo( result, "  to SCM URL " + releaseDescriptor.getScmBranchBase() );
+        }
+        logInfo( result, "  with label '" + releaseDescriptor.getScmReleaseLabel() + "'" );
+        if ( releaseDescriptor.isPinExternals() )
+        {
+            logInfo( result, "  and pinned externals" );
         }
-        logInfo( result, "  with label: '" + releaseDescriptor.getScmReleaseLabel() + "'" );
 
         result.setResultCode( ReleaseResult.SUCCESS );
 
diff --git a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmTagPhase.java b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmTagPhase.java
index 5f52d39..64f5511 100644
--- a/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmTagPhase.java
+++ b/maven-release-manager/src/main/java/org/apache/maven/shared/release/phase/ScmTagPhase.java
@@ -120,12 +120,15 @@ public class ScmTagPhase
                 new ScmTagParameters( releaseDescriptor.getScmCommentPrefix() + "copy for tag " + tagName );
             scmTagParameters.setRemoteTagging( releaseDescriptor.isRemoteTagging() );
             scmTagParameters.setScmRevision( releaseDescriptor.getScmReleasedPomRevision() );
+            scmTagParameters.setPinExternals( releaseDescriptor.isPinExternals() );
             if ( getLogger().isDebugEnabled() )
             {
                 getLogger().debug(
                     "ScmTagPhase :: scmTagParameters remotingTag " + releaseDescriptor.isRemoteTagging() );
                 getLogger().debug(
                     "ScmTagPhase :: scmTagParameters scmRevision " + releaseDescriptor.getScmReleasedPomRevision() );
+                getLogger().debug(
+                        "ScmTagPhase :: scmTagParameters pinExternals " + releaseDescriptor.isPinExternals() );
                 getLogger().debug( "ScmTagPhase :: fileSet  " + fileSet );
             }
             result = provider.tag( repository, fileSet, tagName, scmTagParameters );
@@ -160,13 +163,16 @@ public class ScmTagPhase
         if ( releaseDescriptor.isRemoteTagging() )
         {
             logInfo( result,
-                     "Full run would be tagging working copy " + basedirAlignedReleaseDescriptor.getWorkingDirectory()
-                         + " with label: '" + releaseDescriptor.getScmReleaseLabel() + "'" );
+                     "Full run would tag working copy '" + basedirAlignedReleaseDescriptor.getWorkingDirectory() + "'" );
         }
         else
         {
-            logInfo( result, "Full run would be tagging remotely " + basedirAlignedReleaseDescriptor.getScmSourceUrl()
-                + " with label: '" + releaseDescriptor.getScmReleaseLabel() + "'" );
+            logInfo( result, "Full run would tag remotely '" + basedirAlignedReleaseDescriptor.getScmSourceUrl() + "'" );
+        }
+        logInfo( result, "  with label '" + releaseDescriptor.getScmReleaseLabel() + "'" );
+        if ( releaseDescriptor.isPinExternals() )
+        {
+            logInfo( result, "  and pinned externals" );
         }
 
         result.setResultCode( ReleaseResult.SUCCESS );
diff --git a/maven-release-manager/src/main/mdo/release-descriptor.mdo b/maven-release-manager/src/main/mdo/release-descriptor.mdo
index 6bf44f2..ed0ea58 100644
--- a/maven-release-manager/src/main/mdo/release-descriptor.mdo
+++ b/maven-release-manager/src/main/mdo/release-descriptor.mdo
@@ -583,6 +583,18 @@
           </description>
         </field>
 
+        <field>
+          <name>pinExternals</name>
+          <version>3.0.0+</version>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+          <description>
+            Enable the "--pin-externals" option in svn copy commands which is new in Subversion 1.9.
+            NOTE : Currently only implemented with Subversion.
+            (https://issues.apache.org/jira/browse/SCM-805)
+          </description>
+        </field>
+
         <!-- Announcement Information
 
         Announcement related info, this can be a second part of the process.
@@ -805,6 +817,7 @@
              updateVersionsToSnapshot         != that.isUpdateVersionsToSnapshot()         ||
              allowTimestampedSnapshots        != that.isAllowTimestampedSnapshots()        ||
              remoteTagging                    != that.isRemoteTagging()                    ||
+             pinExternals                     != that.isPinExternals()                     ||
              localCheckout                    != that.isLocalCheckout()                    ||
              pushChanges                      != that.isPushChanges()
            )
@@ -1076,6 +1089,7 @@
         result = 29 * result + java.util.Objects.hashCode( scmReleasedPomRevision );
         result = 29 * result + java.util.Objects.hashCode( workItem );
         result = 29 * result + java.util.Objects.hashCode( autoResolveSnapshots );
+        result = 29 * result + java.util.Objects.hashCode( pinExternals );
 
         return result;
     }
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/GenerateReleasePomsPhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/GenerateReleasePomsPhaseTest.java
index c150589..ad381ee 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/GenerateReleasePomsPhaseTest.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/GenerateReleasePomsPhaseTest.java
@@ -117,6 +117,7 @@ public class GenerateReleasePomsPhaseTest
         builder.setGenerateReleasePoms( true );
         builder.setSuppressCommitBeforeTagOrBranch( true );
         builder.setRemoteTagging( false );
+        builder.setPinExternals( false );
         mapNextVersion( builder, "groupId:artifactId" );
 
         phase.execute( ReleaseUtils.buildReleaseDescriptor( builder ), new DefaultReleaseEnvironment(), reactorProjects );
@@ -135,6 +136,7 @@ public class GenerateReleasePomsPhaseTest
         builder.setGenerateReleasePoms( true );
         builder.setSuppressCommitBeforeTagOrBranch( true );
         builder.setRemoteTagging( true );
+        builder.setPinExternals( false );
         mapNextVersion( builder, "groupId:artifactId" );
 
         phase.execute( ReleaseUtils.buildReleaseDescriptor( builder ), new DefaultReleaseEnvironment(), reactorProjects );
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmBranchParametersEquals.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmBranchParametersEquals.java
index 9fb572f..8431b85 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmBranchParametersEquals.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmBranchParametersEquals.java
@@ -40,7 +40,7 @@ public class IsScmBranchParametersEquals extends ArgumentMatcher<ScmBranchParame
     {
         ScmBranchParameters sbp = (ScmBranchParameters) argument;
         return sbp.getMessage().equals( this.scmBranchParameters.getMessage() )
-            //&& stp.isRemoteTagging() == this.scmBranchParameters.isRemoteTagging()
-            ;
+            && sbp.isRemoteBranching() == this.scmBranchParameters.isRemoteBranching()
+            && sbp.isPinExternals() == this.scmBranchParameters.isPinExternals();
     }
 }
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmTagParametersEquals.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmTagParametersEquals.java
index 0c3dc75..6196256 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmTagParametersEquals.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/IsScmTagParametersEquals.java
@@ -39,6 +39,7 @@ public class IsScmTagParametersEquals extends ArgumentMatcher<ScmTagParameters>
     {
         ScmTagParameters stp = (ScmTagParameters) argument;
         return stp.getMessage().equals( this.scmTagParameters.getMessage() )
-            && stp.isRemoteTagging() == this.scmTagParameters.isRemoteTagging();
+            && stp.isRemoteTagging() == this.scmTagParameters.isRemoteTagging()
+            && stp.isPinExternals() == this.scmTagParameters.isPinExternals();
     }
 }
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitDevelopmentPhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitDevelopmentPhaseTest.java
index 50ba849..8378869 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitDevelopmentPhaseTest.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitDevelopmentPhaseTest.java
@@ -96,6 +96,7 @@ public class ScmCommitDevelopmentPhaseTest
         List<MavenProject> reactorProjects = createReactorProjects();
 
         builder.setRemoteTagging( false );
+        builder.setPinExternals( false );
         builder.setSuppressCommitBeforeTagOrBranch( true );
         builder.setUpdateWorkingCopyVersions( false );
 
diff --git a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java
index 863cdbd..954086c 100644
--- a/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java
+++ b/maven-release-manager/src/test/java/org/apache/maven/shared/release/phase/ScmCommitPreparationPhaseTest.java
@@ -488,6 +488,7 @@ public class ScmCommitPreparationPhaseTest
         List<MavenProject> reactorProjects = createReactorProjects();
 
         builder.setRemoteTagging( true );
+        builder.setPinExternals( false );
         builder.setSuppressCommitBeforeTagOrBranch( true );
 
         ScmProvider scmProviderMock = mock( ScmProvider.class );
diff --git a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
index 1cbd467..955b01a 100644
--- a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
+++ b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/BranchReleaseMojo.java
@@ -230,6 +230,15 @@ public class BranchReleaseMojo
     @Parameter( defaultValue = "@{prefix} prepare branch @{releaseLabel}", property = "scmBranchCommitComment" )
     private String scmBranchCommitComment = "@{prefix} prepare branch @{releaseLabel}";
 
+    /**
+     * Currently only implemented with svn scm. Enable the {@code --pin-externals} option in
+     * {@code svn copy} command which is new in Subversion 1.9.
+     *
+     * @since 3.0.0
+     */
+    @Parameter( defaultValue = "false", property = "pinExternals" )
+    private boolean pinExternals;
+
     @Override
     public void execute()
         throws MojoExecutionException, MojoFailureException
@@ -254,6 +263,7 @@ public class BranchReleaseMojo
         config.setProjectVersionPolicyId( projectVersionPolicyId );
         config.setProjectNamingPolicyId( projectBranchNamingPolicyId );
         config.setScmBranchCommitComment( scmBranchCommitComment );
+        config.setPinExternals( pinExternals );
 
         if ( checkModificationExcludeList != null )
         {
diff --git a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
index 7579c2f..7422354 100644
--- a/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
+++ b/maven-release-plugin/src/main/java/org/apache/maven/plugins/release/PrepareReleaseMojo.java
@@ -299,6 +299,15 @@ public class PrepareReleaseMojo
     private String autoResolveSnapshots;
 
     /**
+     * Currently only implemented with svn scm. Enable the {@code --pin-externals} option in
+     * {@code svn copy} command which is new in Subversion 1.9.
+     *
+     * @since 3.0.0
+     */
+    @Parameter( defaultValue = "false", property = "pinExternals" )
+    private boolean pinExternals;
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -343,6 +352,7 @@ public class PrepareReleaseMojo
         config.setScmDevelopmentCommitComment( scmDevelopmentCommitComment );
         config.setScmReleaseCommitComment( scmReleaseCommitComment );
         config.setAutoResolveSnapshots( autoResolveSnapshots );
+        config.setPinExternals( pinExternals );
 
         if ( checkModificationExcludeList != null )
         {