Anthony Foglia wrote:
I have found a bug in the svncopy.pl script that fails to properly handle fully-contained externals when branching and copying from a single source. When branching from a single source, the externals are updated to directories that do not exist.

I've figured out where the problem is and have attached a patch (single_source_and_branching.patch) that correctly rewrites the externals when branching using Bradey Honsinger's patch.

There is still another bug with his patch that is probably too complicated for my perl skills. When you use svncopy.pl to copy from a single source to a destination folder that already exists, like "svn copy" it makes a subdirectory named with the last component of the source directory. But when it tries to fix the externals, it checks out the destination directory (as passed on the command-line), and any of its siblings, and tries to change the externals in those directories.

So, if you have a repository of the form

repos/
  branches/
    release_2.0/
  tags/
    release_1.0/

And you do

$ svncopy.pl --tag repos/branches/release_2.0 repos/tags

The script will make repos/tags/release_2.0, but checkout repos/tags and try to change all the externals in there, including those in release_1.0.

The workaround is to make sure the source is always a non-existent directory, and let the script create it. So the above command should be.

$ svncopy.pl --tag repos/branches/release_2.0 repos/tags/release_2.0

--
Anthony Foglia
Princeton Consultants
(609) 987-8787 x233
diff --git a/svncopy.README b/svncopy.README
index f85c784..215545b 100644
--- a/svncopy.README
+++ b/svncopy.README
@@ -237,13 +237,13 @@ branches/
             foo1.c
             foo2.c
             X common    -r 4997 http://svn/repos/trunk/common
-            X inc       http://svn/repos/branches/3.2_bugfix/trunk/inc
+            X inc       http://svn/repos/branches/3.2_bugfix/inc
         proj_bar/
             bar1.c
             bar2.c
             bar2.h
-            X common    http://svn/repos/branches/3.2_bugfix/trunk/common
-            X inc       http://svn/repos/branches/3.2_bugfix/trunk/inc
+            X common    http://svn/repos/branches/3.2_bugfix/common
+            X inc       http://svn/repos/branches/3.2_bugfix/inc
             X public    http://someserver/repos/public
 
 The svn:externals are now pointing to the corresponding directories in the
diff --git a/svncopy.pl.in b/svncopy.pl.in
index 4a6ddb8..c03cac2 100644
--- a/svncopy.pl.in
+++ b/svncopy.pl.in
@@ -527,6 +527,8 @@ sub UpdateExternalsOnDir
   my @new_externals;
   my %changed;
 
+  $multiple_sources = scalar( @sources ) > 1;
+
   # Do any updating required
   foreach my $external ( @externals )
     {
@@ -548,7 +550,15 @@ sub UpdateExternalsOnDir
               my $old_external = $external;
               foreach my $source ( @sources )
                 {
-                  my $dest_dir = DestinationSubdir( $source, $destination );
+                  my $dest_dir;
+                  if ( $multiple_sources )
+                    {
+                      $dest_dir = DestinationSubdir( $source, $destination );
+                    }
+                  else
+                    {
+                      $dest_dir = $destination;
+                    }
                   #info( "Checking against '$source'\n" );
                   if ( $ext_val =~ s|^$source|$dest_dir| )
                     {
diff --git a/testsvncopy.pl.in b/testsvncopy.pl.in
index 59057c2..9125ac3 100644
--- a/testsvncopy.pl.in
+++ b/testsvncopy.pl.in
@@ -190,7 +190,7 @@ sub testUpdateExternals
           update => 1,
           ext_dir => "dir1",
           expected_externals => [
-                    "DIR2 $testURL/dest/dirA/dir2",
+                    "DIR2 $testURL/dest/dir2",
                     "DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
                     "DIR3     $testURL/source/dirB/dir3",
                     "DIR4		$testURL/wibble/dirA/dir2"

Reply via email to