Code

grep: do not segfault when -f is used
[git.git] / git-svn.perl
index b1245cbab2ec7303482d7405e594ba666dfc3f58..24bdbf5b813ddd6c7f242189b9bb22fbe7dfff11 100755 (executable)
@@ -19,6 +19,7 @@ $ENV{GIT_DIR} ||= '.git';
 $Git::SVN::default_repo_id = 'svn';
 $Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn';
 $Git::SVN::Ra::_log_window_size = 100;
+$Git::SVN::_minimize_url = 'unset';
 
 $Git::SVN::Log::TZ = $ENV{TZ};
 $ENV{TZ} = 'UTC';
@@ -31,6 +32,7 @@ require SVN::Delta;
 if ($SVN::Core::VERSION lt '1.1.0') {
        fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)";
 }
+my $can_compress = eval { require Compress::Zlib; 1};
 push @Git::SVN::Ra::ISA, 'SVN::Ra';
 push @SVN::Git::Editor::ISA, 'SVN::Delta::Editor';
 push @SVN::Git::Fetcher::ISA, 'SVN::Delta::Editor';
@@ -40,6 +42,7 @@ use IO::File qw//;
 use File::Basename qw/dirname basename/;
 use File::Path qw/mkpath/;
 use File::Spec;
+use File::Find;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
 use IPC::Open3;
 use Git;
@@ -63,7 +66,7 @@ my ($SVN);
 $sha1 = qr/[a-f\d]{40}/;
 $sha1_short = qr/[a-f\d]{4,40}/;
 my ($_stdin, $_help, $_edit,
-       $_message, $_file,
+       $_message, $_file, $_branch_dest,
        $_template, $_shared,
        $_version, $_fetch_all, $_no_rebase, $_fetch_parent,
        $_merge, $_strategy, $_dry_run, $_local,
@@ -92,13 +95,13 @@ my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
                'localtime' => \$Git::SVN::_localtime,
                %remote_opts );
 
-my ($_trunk, $_tags, $_branches, $_stdlayout);
+my ($_trunk, @_tags, @_branches, $_stdlayout);
 my %icv;
 my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
-                  'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
-                  'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+                  'trunk|T=s' => \$_trunk, 'tags|t=s@' => \@_tags,
+                  'branches|b=s@' => \@_branches, 'prefix=s' => \$_prefix,
                   'stdlayout|s' => \$_stdlayout,
-                  'minimize-url|m' => \$Git::SVN::_minimize_url,
+                  'minimize-url|m!' => \$Git::SVN::_minimize_url,
                  'no-metadata' => sub { $icv{noMetadata} = 1 },
                  'use-svm-props' => sub { $icv{useSvmProps} = 1 },
                  'use-svnsync-props' => sub { $icv{useSvnsyncProps} = 1 },
@@ -141,11 +144,13 @@ my %cmd = (
        branch => [ \&cmd_branch,
                    'Create a branch in the SVN repository',
                    { 'message|m=s' => \$_message,
+                     'destination|d=s' => \$_branch_dest,
                      'dry-run|n' => \$_dry_run,
                      'tag|t' => \$_tag } ],
        tag => [ sub { $_tag = 1; cmd_branch(@_) },
                 'Create a tag in the SVN repository',
                 { 'message|m=s' => \$_message,
+                  'destination|d=s' => \$_branch_dest,
                   'dry-run|n' => \$_dry_run } ],
        'set-tree' => [ \&cmd_set_tree,
                        "Set an SVN repository to a git tree-ish",
@@ -215,6 +220,10 @@ my %cmd = (
                     "Undo fetches back to the specified SVN revision",
                     { 'revision|r=s' => \$_revision,
                       'parent|p' => \$_fetch_parent } ],
+       'gc' => [ \&cmd_gc,
+                 "Compress unhandled.log files in .git/svn and remove " .
+                 "index files in .git/svn",
+               {} ],
 );
 
 my $cmd;
@@ -365,7 +374,7 @@ sub init_subdir {
 sub cmd_clone {
        my ($url, $path) = @_;
        if (!defined $path &&
-           (defined $_trunk || defined $_branches || defined $_tags ||
+           (defined $_trunk || @_branches || @_tags ||
             defined $_stdlayout) &&
            $url !~ m#^[a-z\+]+://#) {
                $path = $url;
@@ -379,17 +388,22 @@ sub cmd_clone {
 sub cmd_init {
        if (defined $_stdlayout) {
                $_trunk = 'trunk' if (!defined $_trunk);
-               $_tags = 'tags' if (!defined $_tags);
-               $_branches = 'branches' if (!defined $_branches);
+               @_tags = 'tags' if (! @_tags);
+               @_branches = 'branches' if (! @_branches);
        }
-       if (defined $_trunk || defined $_branches || defined $_tags) {
+       if (defined $_trunk || @_branches || @_tags) {
                return cmd_multi_init(@_);
        }
        my $url = shift or die "SVN repository location required ",
                               "as a command-line argument\n";
+       $url = canonicalize_url($url);
        init_subdir(@_);
        do_git_init_db();
 
+       if ($Git::SVN::_minimize_url eq 'unset') {
+               $Git::SVN::_minimize_url = 0;
+       }
+
        Git::SVN->init($url);
 }
 
@@ -630,7 +644,46 @@ sub cmd_branch {
        my ($src, $rev, undef, $gs) = working_head_info($head);
 
        my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
-       my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
+       my $allglobs = $remote->{ $_tag ? 'tags' : 'branches' };
+       my $glob;
+       if ($#{$allglobs} == 0) {
+               $glob = $allglobs->[0];
+       } else {
+               unless(defined $_branch_dest) {
+                       die "Multiple ",
+                           $_tag ? "tag" : "branch",
+                           " paths defined for Subversion repository.\n",
+                           "You must specify where you want to create the ",
+                           $_tag ? "tag" : "branch",
+                           " with the --destination argument.\n";
+               }
+               foreach my $g (@{$allglobs}) {
+                       # SVN::Git::Editor could probably be moved to Git.pm..
+                       my $re = SVN::Git::Editor::glob2pat($g->{path}->{left});
+                       if ($_branch_dest =~ /$re/) {
+                               $glob = $g;
+                               last;
+                       }
+               }
+               unless (defined $glob) {
+                       my $dest_re = qr/\b\Q$_branch_dest\E\b/;
+                       foreach my $g (@{$allglobs}) {
+                               $g->{path}->{left} =~ /$dest_re/ or next;
+                               if (defined $glob) {
+                                       die "Ambiguous destination: ",
+                                           $_branch_dest, "\nmatches both '",
+                                           $glob->{path}->{left}, "' and '",
+                                           $g->{path}->{left}, "'\n";
+                               }
+                               $glob = $g;
+                       }
+                       unless (defined $glob) {
+                               die "Unknown ",
+                                   $_tag ? "tag" : "branch",
+                                   " destination $_branch_dest\n";
+                       }
+               }
+       }
        my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
        my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
 
@@ -778,6 +831,12 @@ sub canonicalize_path {
        return $path;
 }
 
+sub canonicalize_url {
+       my ($url) = @_;
+       $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
+       return $url;
+}
+
 # get_svnprops(PATH)
 # ------------------
 # Helper for cmd_propget and cmd_proplist below.
@@ -837,17 +896,13 @@ sub cmd_proplist {
 
 sub cmd_multi_init {
        my $url = shift;
-       unless (defined $_trunk || defined $_branches || defined $_tags) {
+       unless (defined $_trunk || @_branches || @_tags) {
                usage(1);
        }
 
-       # there are currently some bugs that prevent multi-init/multi-fetch
-       # setups from working well without this.
-       $Git::SVN::_minimize_url = 1;
-
        $_prefix = '' unless defined $_prefix;
        if (defined $url) {
-               $url =~ s#/+$##;
+               $url = canonicalize_url($url);
                init_subdir(@_);
        }
        do_git_init_db();
@@ -862,10 +917,14 @@ sub cmd_multi_init {
                                                   undef, $trunk_ref);
                }
        }
-       return unless defined $_branches || defined $_tags;
+       return unless @_branches || @_tags;
        my $ra = $url ? Git::SVN::Ra->new($url) : undef;
-       complete_url_ls_init($ra, $_branches, '--branches/-b', $_prefix);
-       complete_url_ls_init($ra, $_tags, '--tags/-t', $_prefix . 'tags/');
+       foreach my $path (@_branches) {
+               complete_url_ls_init($ra, $path, '--branches/-b', $_prefix);
+       }
+       foreach my $path (@_tags) {
+               complete_url_ls_init($ra, $path, '--tags/-t', $_prefix.'tags/');
+       }
 }
 
 sub cmd_multi_fetch {
@@ -1072,6 +1131,14 @@ sub cmd_reset {
        print "r$r = $c ($gs->{ref_id})\n";
 }
 
+sub cmd_gc {
+       if (!$can_compress) {
+               warn "Compress::Zlib could not be found; unhandled.log " .
+                    "files will not be compressed.\n";
+       }
+       find({ wanted => \&gc_directory, no_chdir => 1}, "$ENV{GIT_DIR}/svn");
+}
+
 ########################### utility functions #########################
 
 sub rebase_cmd {
@@ -1141,7 +1208,7 @@ sub complete_url_ls_init {
                    "wanted to set to: $gs->{url}\n";
        }
        command_oneline('config', $k, $gs->{url}) unless $orig_url;
-       my $remote_path = "$ra->{svn_path}/$repo_path";
+       my $remote_path = "$gs->{path}/$repo_path";
        $remote_path =~ s#/+#/#g;
        $remote_path =~ s#^/##g;
        $remote_path .= "/*" if $remote_path !~ /\*/;
@@ -1150,6 +1217,7 @@ sub complete_url_ls_init {
                die "--prefix='$pfx' must have a trailing slash '/'\n";
        }
        command_noisy('config',
+                     '--add',
                      "svn-remote.$gs->{repo_id}.$n",
                      "$remote_path:refs/remotes/$pfx*" .
                        ('/*' x (($remote_path =~ tr/*/*/) - 1)) );
@@ -1323,11 +1391,11 @@ sub read_repo_config {
 sub extract_metadata {
        my $id = shift or return (undef, undef, undef);
        my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
-                                                       \s([a-f\d\-]+)$/x);
+                                                       \s([a-f\d\-]+)$/ix);
        if (!defined $rev || !$uuid || !$url) {
                # some of the original repositories I made had
                # identifiers like this:
-               ($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
+               ($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/i);
        }
        return ($url, $rev, $uuid);
 }
@@ -1491,6 +1559,25 @@ sub md5sum {
        return $md5->hexdigest();
 }
 
+sub gc_directory {
+       if ($can_compress && -f $_ && basename($_) eq "unhandled.log") {
+               my $out_filename = $_ . ".gz";
+               open my $in_fh, "<", $_ or die "Unable to open $_: $!\n";
+               binmode $in_fh;
+               my $gz = Compress::Zlib::gzopen($out_filename, "ab") or
+                               die "Unable to open $out_filename: $!\n";
+
+               my $res;
+               while ($res = sysread($in_fh, my $str, 1024)) {
+                       $gz->gzwrite($str) or
+                               die "Unable to write: ".$gz->gzerror()."!\n";
+               }
+               unlink $_ or die "unlink $File::Find::name: $!\n";
+       } elsif (-f $_ && basename($_) eq "index") {
+               unlink $_ or die "unlink $_: $!\n";
+       }
+}
+
 package Git::SVN;
 use strict;
 use warnings;
@@ -1611,12 +1698,14 @@ sub fetch_all {
        my $ra = Git::SVN::Ra->new($url);
        my $uuid = $ra->get_uuid;
        my $head = $ra->get_latest_revnum;
+       $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] });
        my $base = defined $fetch ? $head : 0;
 
        # read the max revs for wildcard expansion (branches/*, tags/*)
        foreach my $t (qw/branches tags/) {
                defined $remote->{$t} or next;
-               push @globs, $remote->{$t};
+               push @globs, @{$remote->{$t}};
+
                my $max_rev = eval { tmp_config(qw/--int --get/,
                                         "svn-remote.$repo_id.${t}-maxRev") };
                if (defined $max_rev && ($max_rev < $base)) {
@@ -1663,15 +1752,16 @@ sub read_all_remotes {
                } elsif (m!^(.+)\.(branches|tags)=
                           (.*):refs/remotes/(.+)\s*$/!x) {
                        my ($p, $g) = ($3, $4);
-                       my $rs = $r->{$1}->{$2} = {
-                                         t => $2,
-                                         remote => $1,
-                                         path => Git::SVN::GlobSpec->new($p),
-                                         ref => Git::SVN::GlobSpec->new($g) };
+                       my $rs = {
+                           t => $2,
+                           remote => $1,
+                           path => Git::SVN::GlobSpec->new($p),
+                           ref => Git::SVN::GlobSpec->new($g) };
                        if (length($rs->{ref}->{right}) != 0) {
                                die "The '*' glob character must be the last ",
                                    "character of '$g'\n";
                        }
+                       push @{ $r->{$1}->{$2} }, $rs;
                }
        }
 
@@ -1811,9 +1901,10 @@ sub find_by_url { # repos_root and, path are optional
                next if defined $repos_root && $repos_root ne $u;
 
                my $fetch = $remotes->{$repo_id}->{fetch} || {};
-               foreach (qw/branches tags/) {
-                       resolve_local_globs($u, $fetch,
-                                           $remotes->{$repo_id}->{$_});
+               foreach my $t (qw/branches tags/) {
+                       foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
+                               resolve_local_globs($u, $fetch, $globspec);
+                       }
                }
                my $p = $path;
                my $rwr = rewrite_root({repo_id => $repo_id});
@@ -1971,7 +2062,7 @@ sub _set_svm_vars {
 
                chomp($src, $uuid);
 
-               $uuid =~ m{^[0-9a-f\-]{30,}$}
+               $uuid =~ m{^[0-9a-f\-]{30,}$}i
                    or die "doesn't look right - svm:uuid is '$uuid'\n";
 
                # the '!' is used to mark the repos_root!/relative/path
@@ -2057,7 +2148,7 @@ sub svnsync {
                   die "doesn't look right - svn:sync-from-url is '$url'\n";
 
                my $uuid = tmp_config('--get', "$section.svnsync-uuid");
-               ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or
+               ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
                   die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
 
                $svnsync = { url => $url, uuid => $uuid }
@@ -2075,7 +2166,7 @@ sub svnsync {
                   die "doesn't look right - svn:sync-from-url is '$url'\n";
 
        my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n";
-       ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}) or
+       ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or
                   die "doesn't look right - svn:sync-from-uuid is '$uuid'\n";
 
        my $section = "svn-remote.$self->{repo_id}";
@@ -2091,7 +2182,7 @@ sub ra_uuid {
        unless ($self->{ra_uuid}) {
                my $key = "svn-remote.$self->{repo_id}.uuid";
                my $uuid = eval { tmp_config('--get', $key) };
-               if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/) {
+               if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
                        $self->{ra_uuid} = $uuid;
                } else {
                        die "ra_uuid called without URL\n" unless $self->{url};
@@ -2134,16 +2225,6 @@ sub ra {
        $ra;
 }
 
-sub rel_path {
-       my ($self) = @_;
-       my $repos_root = $self->ra->{repos_root};
-       return $self->{path} if ($self->{url} eq $repos_root);
-       my $url = $self->{url} .
-                 (length $self->{path} ? "/$self->{path}" : $self->{path});
-       $url =~ s!^\Q$repos_root\E(?:/+|$)!!g;
-       $url;
-}
-
 # prop_walk(PATH, REV, SUB)
 # -------------------------
 # Recursively traverse PATH at revision REV and invoke SUB for each
@@ -2469,10 +2550,7 @@ sub match_paths {
        if (my $path = $paths->{"/$self->{path}"}) {
                return ($path->{action} eq 'D') ? 0 : 1;
        }
-       my $repos_root = $self->ra->{repos_root};
-       my $extended_path = $self->{url} . '/' . $self->{path};
-       $extended_path =~ s#^\Q$repos_root\E(/|$)##;
-       $self->{path_regex} ||= qr/^\/\Q$extended_path\E\//;
+       $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
        if (grep /$self->{path_regex}/, keys %$paths) {
                return 1;
        }
@@ -2495,15 +2573,14 @@ sub find_parent_branch {
        unless (defined $paths) {
                my $err_handler = $SVN::Error::handler;
                $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
-               $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, sub {
-                                  $paths =
-                                     Git::SVN::Ra::dup_changed_paths($_[0]) });
+               $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
+                                  sub { $paths = $_[0] });
                $SVN::Error::handler = $err_handler;
        }
        return undef unless defined $paths;
 
        # look for a parent from another branch:
-       my @b_path_components = split m#/#, $self->rel_path;
+       my @b_path_components = split m#/#, $self->{path};
        my @a_path_components;
        my $i;
        while (@b_path_components) {
@@ -2521,11 +2598,11 @@ sub find_parent_branch {
        my $r = $i->{copyfrom_rev};
        my $repos_root = $self->ra->{repos_root};
        my $url = $self->ra->{url};
-       my $new_url = $repos_root . $branch_from;
+       my $new_url = $url . $branch_from;
        print STDERR  "Found possible branch point: ",
                      "$new_url => ", $self->full_url, ", $r\n";
        $branch_from =~ s#^/##;
-       my $gs = $self->other_gs($new_url, $url, $repos_root,
+       my $gs = $self->other_gs($new_url, $url,
                                 $branch_from, $r, $self->{ref_id});
        my ($r0, $parent) = $gs->find_rev_before($r, 1);
        {
@@ -2710,9 +2787,9 @@ sub parse_svn_date {
 }
 
 sub other_gs {
-       my ($self, $new_url, $url, $repos_root,
+       my ($self, $new_url, $url,
            $branch_from, $r, $old_ref_id) = @_;
-       my $gs = Git::SVN->find_by_url($new_url, $repos_root, $branch_from);
+       my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from);
        unless ($gs) {
                my $ref_id = $old_ref_id;
                $ref_id =~ s/\@\d+$//;
@@ -2733,6 +2810,7 @@ sub other_gs {
 
 sub call_authors_prog {
        my ($orig_author) = @_;
+       $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author);
        my $author = `$::_authors_prog $orig_author`;
        if ($? != 0) {
                die "$::_authors_prog failed with exit code $?\n"
@@ -2823,7 +2901,7 @@ sub make_log_entry {
                        die "Can't have both 'useSvmProps' and 'rewriteRoot' ",
                            "options set!\n";
                }
-               my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$};
+               my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i;
                # we don't want "SVM: initializing mirror for junk" ...
                return undef if $r == 0;
                my $svm = $self->svm;
@@ -3928,7 +4006,7 @@ sub repo_path {
 sub url_path {
        my ($self, $path) = @_;
        if ($self->{url} =~ m#^https?://#) {
-               $path =~ s/([^~a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
+               $path =~ s!([^~a-zA-Z0-9_./-])!uc sprintf("%%%02x",ord($1))!eg;
        }
        $self->{url} . '/' . $self->repo_path($path);
 }
@@ -4388,6 +4466,34 @@ sub get_log {
        my ($self, @args) = @_;
        my $pool = SVN::Pool->new;
 
+       # svn_log_changed_path_t objects passed to get_log are likely to be
+       # overwritten even if only the refs are copied to an external variable,
+       # so we should dup the structures in their entirety.  Using an
+       # externally passed pool (instead of our temporary and quickly cleared
+       # pool in Git::SVN::Ra) does not help matters at all...
+       my $receiver = pop @args;
+       my $prefix = "/".$self->{svn_path};
+       $prefix =~ s#/+($)##;
+       my $prefix_regex = qr#^\Q$prefix\E#;
+       push(@args, sub {
+               my ($paths) = $_[0];
+               return &$receiver(@_) unless $paths;
+               $_[0] = ();
+               foreach my $p (keys %$paths) {
+                       my $i = $paths->{$p};
+                       # Make path relative to our url, not repos_root
+                       $p =~ s/$prefix_regex//;
+                       my %s = map { $_ => $i->$_; }
+                               qw/copyfrom_path copyfrom_rev action/;
+                       if ($s{'copyfrom_path'}) {
+                               $s{'copyfrom_path'} =~ s/$prefix_regex//;
+                       }
+                       $_[0]{$p} = \%s;
+               }
+               &$receiver(@_);
+       });
+
+
        # the limit parameter was not supported in SVN 1.1.x, so we
        # drop it.  Therefore, the receiver callback passed to it
        # is made aware of this limitation by being wrapped if
@@ -4472,10 +4578,12 @@ sub gs_do_switch {
 
        my $full_url = $self->{url};
        my $old_url = $full_url;
-       $full_url .= '/' . escape_uri_only($path) if length $path;
+       $full_url .= '/' . $path if length $path;
        my ($ra, $reparented);
 
-       if ($old_url =~ m#^svn(\+ssh)?://#) {
+       if ($old_url =~ m#^svn(\+ssh)?://# ||
+           ($full_url =~ m#^https?://# &&
+            escape_url($full_url) ne $full_url)) {
                $_[0] = undef;
                $self = undef;
                $RA = undef;
@@ -4557,7 +4665,7 @@ sub gs_fetch_loop_common {
                };
                sub _cb {
                        my ($paths, $r, $author, $date, $log) = @_;
-                       [ dup_changed_paths($paths),
+                       [ $paths,
                          { author => $author, date => $date, log => $log } ];
                }
                $self->get_log([$longest_path], $min, $max, 0, 1, 1,
@@ -4724,7 +4832,11 @@ sub minimize_url {
        my $c = '';
        do {
                $url .= "/$c" if length $c;
-               eval { (ref $self)->new($url)->get_latest_revnum };
+               eval {
+                       my $ra = (ref $self)->new($url);
+                       my $latest = $ra->get_latest_revnum;
+                       $ra->get_log("", $latest, 0, 1, 0, 1, sub {});
+               };
        } while ($@ && ($c = shift @components));
        $url;
 }
@@ -4780,24 +4892,6 @@ sub skip_unknown_revs {
        die "Error from SVN, ($errno): ", $err->expanded_message,"\n";
 }
 
-# svn_log_changed_path_t objects passed to get_log are likely to be
-# overwritten even if only the refs are copied to an external variable,
-# so we should dup the structures in their entirety.  Using an externally
-# passed pool (instead of our temporary and quickly cleared pool in
-# Git::SVN::Ra) does not help matters at all...
-sub dup_changed_paths {
-       my ($paths) = @_;
-       return undef unless $paths;
-       my %ret;
-       foreach my $p (keys %$paths) {
-               my $i = $paths->{$p};
-               my %s = map { $_ => $i->$_ }
-                             qw/copyfrom_path copyfrom_rev action/;
-               $ret{$p} = \%s;
-       }
-       \%ret;
-}
-
 package Git::SVN::Log;
 use strict;
 use warnings;