Show usage string for 'git get-tar-commit-id -h'
[gitweb.git] / git-svn.perl
index eb4b75aff347670b1817fb1c2584cff11a08fad5..6a3b501d24ebaa50e297511ccf0b18e3bbd2bb16 100755 (executable)
@@ -1765,7 +1765,7 @@ sub read_all_remotes {
        my $use_svm_props = eval { command_oneline(qw/config --bool
            svn.useSvmProps/) };
        $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
-       my $svn_refspec = qr{\s*/?(.*?)\s*:\s*(.+?)\s*};
+       my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};
        foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
                if (m!^(.+)\.fetch=$svn_refspec$!) {
                        my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
@@ -1979,7 +1979,7 @@ sub find_ref {
        my ($ref_id) = @_;
        foreach (command(qw/config -l/)) {
                next unless m!^svn-remote\.(.+)\.fetch=
-                             \s*/?(.*?)\s*:\s*(.+?)\s*$!x;
+                             \s*(.*?)\s*:\s*(.+?)\s*$!x;
                my ($repo_id, $path, $ref) = ($1, $2, $3);
                if ($ref eq $ref_id) {
                        $path = '' if ($path =~ m#^\./?#);
@@ -2878,14 +2878,157 @@ sub check_author {
        $author;
 }
 
+sub find_extra_svk_parents {
+       my ($self, $ed, $tickets, $parents) = @_;
+       # aha!  svk:merge property changed...
+       my @tickets = split "\n", $tickets;
+       my @known_parents;
+       for my $ticket ( @tickets ) {
+               my ($uuid, $path, $rev) = split /:/, $ticket;
+               if ( $uuid eq $self->ra_uuid ) {
+                       my $url = $self->rewrite_root || $self->{url};
+                       my $repos_root = $url;
+                       my $branch_from = $path;
+                       $branch_from =~ s{^/}{};
+                       my $gs = $self->other_gs($repos_root."/".$branch_from,
+                                                $url,
+                                                $branch_from,
+                                                $rev,
+                                                $self->{ref_id});
+                       if ( my $commit = $gs->rev_map_get($rev, $uuid) ) {
+                               # wahey!  we found it, but it might be
+                               # an old one (!)
+                               push @known_parents, $commit;
+                       }
+               }
+       }
+       for my $parent ( @known_parents ) {
+               my @cmd = ('rev-list', $parent, map { "^$_" } @$parents );
+               my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+               my $new;
+               while ( <$msg_fh> ) {
+                       $new=1;last;
+               }
+               command_close_pipe($msg_fh, $ctx);
+               if ( $new ) {
+                       print STDERR
+                           "Found merge parent (svk:merge ticket): $parent\n";
+                       push @$parents, $parent;
+               }
+       }
+}
+
+# note: this function should only be called if the various dirprops
+# have actually changed
+sub find_extra_svn_parents {
+       my ($self, $ed, $mergeinfo, $parents) = @_;
+       # aha!  svk:merge property changed...
+
+       # We first search for merged tips which are not in our
+       # history.  Then, we figure out which git revisions are in
+       # that tip, but not this revision.  If all of those revisions
+       # are now marked as merge, we can add the tip as a parent.
+       my @merges = split "\n", $mergeinfo;
+       my @merge_tips;
+       my @merged_commit_ranges;
+       my $url = $self->rewrite_root || $self->{url};
+       for my $merge ( @merges ) {
+               my ($source, $revs) = split ":", $merge;
+               my $path = $source;
+               $path =~ s{^/}{};
+               my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
+               if ( !$gs ) {
+                       warn "Couldn't find revmap for $url$source\n";
+                       next;
+               }
+               my @ranges = split ",", $revs;
+               my ($tip, $tip_commit);
+               # find the tip
+               for my $range ( @ranges ) {
+                       my ($bottom, $top) = split "-", $range;
+                       $top ||= $bottom;
+                       my $bottom_commit =
+                               $gs->rev_map_get($bottom, $self->ra_uuid) ||
+                               $gs->rev_map_get($bottom+1, $self->ra_uuid);
+                       my $top_commit =
+                               $gs->rev_map_get($top, $self->ra_uuid);
+
+                       unless ($top_commit and $bottom_commit) {
+                               warn "W:unknown path/rev in svn:mergeinfo "
+                                       ."dirprop: $source:$range\n";
+                               next;
+                       }
+
+                       push @merged_commit_ranges,
+                               "$bottom_commit..$top_commit";
+
+                       if ( !defined $tip or $top > $tip ) {
+                               $tip = $top;
+                               $tip_commit = $top_commit;
+                       }
+               }
+               unless (!$tip_commit or
+                               grep { $_ eq $tip_commit } @$parents ) {
+                       push @merge_tips, $tip_commit;
+               } else {
+                       push @merge_tips, undef;
+               }
+       }
+       for my $merge_tip ( @merge_tips ) {
+               my $spec = shift @merges;
+               next unless $merge_tip;
+               my @cmd = ('rev-list', "-1", $merge_tip,
+                          "--not", @$parents );
+               my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+               my $new;
+               while ( <$msg_fh> ) {
+                       $new=1;last;
+               }
+               command_close_pipe($msg_fh, $ctx);
+               if ( $new ) {
+                       push @cmd, @merged_commit_ranges;
+                       my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+                       my $unmerged;
+                       while ( <$msg_fh> ) {
+                               $unmerged=1;last;
+                       }
+                       command_close_pipe($msg_fh, $ctx);
+                       if ( $unmerged ) {
+                               warn "W:svn cherry-pick ignored ($spec)\n";
+                       } else {
+                               warn
+                                 "Found merge parent (svn:mergeinfo prop): ",
+                                 $merge_tip, "\n";
+                               push @$parents, $merge_tip;
+                       }
+               }
+       }
+}
+
 sub make_log_entry {
        my ($self, $rev, $parents, $ed) = @_;
        my $untracked = $self->get_untracked($ed);
 
+       my @parents = @$parents;
+       my $ps = $ed->{path_strip} || "";
+       for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) {
+               my $props = $ed->{dir_prop}{$path};
+               if ( $props->{"svk:merge"} ) {
+                       $self->find_extra_svk_parents
+                               ($ed, $props->{"svk:merge"}, \@parents);
+               }
+               if ( $props->{"svn:mergeinfo"} ) {
+                       $self->find_extra_svn_parents
+                               ($ed,
+                                $props->{"svn:mergeinfo"},
+                                \@parents);
+               }
+       }
+
        open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
        print $un "r$rev\n" or croak $!;
        print $un $_, "\n" foreach @$untracked;
-       my %log_entry = ( parents => $parents || [], revision => $rev,
+       my %log_entry = ( parents => \@parents, revision => $rev,
                          log => '');
 
        my $headrev;