Code

Make cherry-pick use rerere for conflict resolution.
[git.git] / git-svn.perl
index cf6dbbc42773fef394c27cd87109b69c3144753c..4dc33801a88c63f62a263b5008649b05fc1b9d7d 100755 (executable)
@@ -66,7 +66,7 @@ my ($_stdin, $_help, $_edit,
        $_version, $_fetch_all, $_no_rebase,
        $_merge, $_strategy, $_dry_run, $_local,
        $_prefix, $_no_checkout, $_url, $_verbose,
-       $_git_format);
+       $_git_format, $_commit_url);
 $Git::SVN::_follow_parent = 1;
 my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                     'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@ -127,6 +127,8 @@ my %cmd = (
                          'verbose|v' => \$_verbose,
                          'dry-run|n' => \$_dry_run,
                          'fetch-all|all' => \$_fetch_all,
+                         'commit-url=s' => \$_commit_url,
+                         'revision|r=i' => \$_revision,
                          'no-rebase' => \$_no_rebase,
                        %cmt_opts, %fc_opts } ],
        'set-tree' => [ \&cmd_set_tree,
@@ -169,7 +171,8 @@ my %cmd = (
                          'color' => \$Git::SVN::Log::color,
                          'pager=s' => \$Git::SVN::Log::pager
                        } ],
-       'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish",
+       'find-rev' => [ \&cmd_find_rev,
+                       "Translate between SVN revision numbers and tree-ish",
                        {} ],
        'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
                        { 'merge|m|M' => \$_merge,
@@ -229,7 +232,9 @@ unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
 my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
 
 read_repo_config(\%opts);
-Getopt::Long::Configure('pass_through') if ($cmd && ($cmd eq 'log' || $cmd eq 'blame'));
+if ($cmd && ($cmd eq 'log' || $cmd eq 'blame')) {
+       Getopt::Long::Configure('pass_through');
+}
 my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
                     'minimize-connections' => \$Git::SVN::Migration::_minimize,
                     'id|i=s' => \$Git::SVN::default_ref_id,
@@ -416,6 +421,8 @@ sub cmd_dcommit {
        $head ||= 'HEAD';
        my @refs;
        my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
+       $url = $_commit_url if defined $_commit_url;
+       my $last_rev = $_revision if defined $_revision;
        if ($url) {
                print "Committing to $url ...\n";
        }
@@ -423,7 +430,6 @@ sub cmd_dcommit {
                die "Unable to determine upstream SVN information from ",
                    "$head history.\nPerhaps the repository is empty.";
        }
-       my $last_rev;
        my ($linear_refs, $parents) = linearize_history($gs, \@refs);
        if ($_no_rebase && scalar(@$linear_refs) > 1) {
                warn "Attempting to commit more than one change while ",
@@ -446,7 +452,7 @@ sub cmd_dcommit {
                        my $cmt_rev;
                        my %ed_opts = ( r => $last_rev,
                                        log => get_commit_entry($d)->{log},
-                                       ra => Git::SVN::Ra->new($gs->full_url),
+                                       ra => Git::SVN::Ra->new($url),
                                        config => SVN::Core::config_get_config(
                                                $Git::SVN::Ra::config_dir
                                        ),
@@ -796,8 +802,8 @@ sub cmd_commit_diff {
 }
 
 sub cmd_info {
-       my $path = canonicalize_path(shift or ".");
-       unless (scalar(@_) == 0) {
+       my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
+       if (exists $_[1]) {
                die "Too many arguments specified\n";
        }
 
@@ -813,6 +819,10 @@ sub cmd_info {
                die "Unable to determine upstream SVN information from ",
                    "working tree history\n";
        }
+
+       # canonicalize_path() will return "" to make libsvn 1.5.x happy,
+       $path = "." if $path eq "";
+
        my $full_url = $url . ($path eq "." ? "" : "/$path");
 
        if ($_url) {
@@ -980,8 +990,10 @@ sub complete_url_ls_init {
        if (length $pfx && $pfx !~ m#/$#) {
                die "--prefix='$pfx' must have a trailing slash '/'\n";
        }
-       command_noisy('config', "svn-remote.$gs->{repo_id}.$n",
-                               "$remote_path:refs/remotes/$pfx*");
+       command_noisy('config',
+                     "svn-remote.$gs->{repo_id}.$n",
+                     "$remote_path:refs/remotes/$pfx*" .
+                       ('/*' x (($remote_path =~ tr/*/*/) - 1)) );
 }
 
 sub verify_ref {
@@ -1420,8 +1432,12 @@ sub read_all_remotes {
            svn.useSvmProps/) };
        $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
        foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
-               if (m!^(.+)\.fetch=\s*(.*)\s*:\s*refs/remotes/(.+)\s*$!) {
-                       my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
+               if (m!^(.+)\.fetch=\s*(.*)\s*:\s*(.+)\s*$!) {
+                       my ($remote, $local_ref, $_remote_ref) = ($1, $2, $3);
+                       die("svn-remote.$remote: remote ref '$_remote_ref' "
+                           . "must start with 'refs/remotes/'\n")
+                               unless $_remote_ref =~ m{^refs/remotes/(.+)};
+                       my $remote_ref = $1;
                        $local_ref =~ s{^/}{};
                        $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
                        $r->{$remote}->{svm} = {} if $use_svm_props;
@@ -4113,16 +4129,38 @@ sub gs_fetch_loop_common {
        Git::SVN::gc();
 }
 
+sub get_dir_globbed {
+       my ($self, $left, $depth, $r) = @_;
+
+       my @x = eval { $self->get_dir($left, $r) };
+       return unless scalar @x == 3;
+       my $dirents = $x[0];
+       my @finalents;
+       foreach my $de (keys %$dirents) {
+               next if $dirents->{$de}->{kind} != $SVN::Node::dir;
+               if ($depth > 1) {
+                       my @args = ("$left/$de", $depth - 1, $r);
+                       foreach my $dir ($self->get_dir_globbed(@args)) {
+                               push @finalents, "$de/$dir";
+                       }
+               } else {
+                       push @finalents, $de;
+               }
+       }
+       @finalents;
+}
+
 sub match_globs {
        my ($self, $exists, $paths, $globs, $r) = @_;
 
        sub get_dir_check {
                my ($self, $exists, $g, $r) = @_;
-               my @x = eval { $self->get_dir($g->{path}->{left}, $r) };
-               return unless scalar @x == 3;
-               my $dirents = $x[0];
-               foreach my $de (keys %$dirents) {
-                       next if $dirents->{$de}->{kind} != $SVN::Node::dir;
+
+               my @dirs = $self->get_dir_globbed($g->{path}->{left},
+                                                 $g->{path}->{depth},
+                                                 $r);
+
+               foreach my $de (@dirs) {
                        my $p = $g->{path}->full_path($de);
                        next if $exists->{$p};
                        next if (length $g->{path}->{right} &&
@@ -4904,15 +4942,20 @@ sub new {
        my ($class, $glob) = @_;
        my $re = $glob;
        $re =~ s!/+$!!g; # no need for trailing slashes
-       my $nr = ($re =~ s!^(.*)\*(.*)$!\(\[^/\]+\)!g);
-       my ($left, $right) = ($1, $2);
-       if ($nr > 1) {
-               die "Only one '*' wildcard expansion ",
-                   "is supported (got $nr): '$glob'\n";
-       } elsif ($nr == 0) {
+       $re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
+       my $temp = $re;
+       my ($left, $right) = ($1, $3);
+       $re = $2;
+       my $depth = $re =~ tr/*/*/;
+       if ($depth != $temp =~ tr/*/*/) {
+               die "Only one set of wildcard directories " .
+                       "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
+       }
+       if ($depth == 0) {
                die "One '*' is needed for glob: '$glob'\n";
        }
-       $re = quotemeta($left) . $re . quotemeta($right);
+       $re =~ s!\*!\[^/\]*!g;
+       $re = quotemeta($left) . "($re)" . quotemeta($right);
        if (length $left && !($left =~ s!/+$!!g)) {
                die "Missing trailing '/' on left side of: '$glob' ($left)\n";
        }
@@ -4921,7 +4964,7 @@ sub new {
        }
        my $left_re = qr/^\/\Q$left\E(\/|$)/;
        bless { left => $left, right => $right, left_regex => $left_re,
-               regex => qr/$re/, glob => $glob }, $class;
+               regex => qr/$re/, glob => $glob, depth => $depth }, $class;
 }
 
 sub full_path {