my ($_stdin, $_help, $_edit,
$_message, $_file,
$_template, $_shared,
- $_version, $_fetch_all,
+ $_version, $_fetch_all, $_no_rebase,
$_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_verbose);
$Git::SVN::_follow_parent = 1;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ '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 },
'verbose|v' => \$_verbose,
'dry-run|n' => \$_dry_run,
'fetch-all|all' => \$_fetch_all,
+ 'no-rebase' => \$_no_rebase,
%cmt_opts, %fc_opts } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
'color' => \$Git::SVN::Log::color,
'pager=s' => \$Git::SVN::Log::pager,
} ],
+ '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,
'verbose|v' => \$_verbose,
} else {
my %ed_opts = ( r => $last_rev,
log => get_commit_entry($d)->{log},
- ra => Git::SVN::Ra->new($url),
+ ra => Git::SVN::Ra->new($gs->full_url),
tree_a => "$d~1",
tree_b => $d,
editor_cb => sub {
return;
}
$_fetch_all ? $gs->fetch_all : $gs->fetch;
- # we always want to rebase against the current HEAD, not any
- # head that was passed to us
- my @diff = command('diff-tree', 'HEAD', $gs->refname, '--');
- my @finish;
- if (@diff) {
- @finish = rebase_cmd();
- print STDERR "W: HEAD and ", $gs->refname, " differ, ",
- "using @finish:\n", "@diff";
+ unless ($_no_rebase) {
+ # we always want to rebase against the current HEAD, not any
+ # head that was passed to us
+ my @diff = command('diff-tree', 'HEAD', $gs->refname, '--');
+ my @finish;
+ if (@diff) {
+ @finish = rebase_cmd();
+ print STDERR "W: HEAD and ", $gs->refname, " differ, ",
+ "using @finish:\n", "@diff";
+ } else {
+ print "No changes between current HEAD and ",
+ $gs->refname, "\nResetting to the latest ",
+ $gs->refname, "\n";
+ @finish = qw/reset --mixed/;
+ }
+ command_noisy(@finish, $gs->refname);
+ }
+}
+
+sub cmd_find_rev {
+ my $revision_or_hash = shift;
+ my $result;
+ if ($revision_or_hash =~ /^r\d+$/) {
+ my $head = shift;
+ $head ||= 'HEAD';
+ my @refs;
+ my (undef, undef, undef, $gs) = working_head_info($head, \@refs);
+ unless ($gs) {
+ die "Unable to determine upstream SVN information from ",
+ "$head history\n";
+ }
+ my $desired_revision = substr($revision_or_hash, 1);
+ $result = $gs->rev_db_get($desired_revision);
} else {
- print "No changes between current HEAD and ",
- $gs->refname, "\nResetting to the latest ",
- $gs->refname, "\n";
- @finish = qw/reset --mixed/;
+ my (undef, $rev, undef) = cmt_metadata($revision_or_hash);
+ $result = $rev;
}
- command_noisy(@finish, $gs->refname);
+ print "$result\n" if $result;
}
sub cmd_rebase {
sub working_head_info {
my ($head, $refs) = @_;
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
- while (<$fh>) {
- chomp;
- my ($url, $rev, $uuid) = cmt_metadata($_);
+ while (my $hash = <$fh>) {
+ chomp($hash);
+ my ($url, $rev, $uuid) = cmt_metadata($hash);
if (defined $url && defined $rev) {
if (my $gs = Git::SVN->find_by_url($url)) {
my $c = $gs->rev_db_get($rev);
- if ($c && $c eq $_) {
+ if ($c && $c eq $hash) {
close $fh; # break the pipe
return ($url, $rev, $uuid, $gs);
}
}
}
- unshift @$refs, $_ if $refs;
+ unshift @$refs, $hash if $refs;
}
command_close_pipe($fh, $ctx);
(undef, undef, undef, undef);
use warnings;
use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent
$_repack $_repack_flags $_use_svm_props $_head
- $_use_svnsync_props $no_reuse_existing/;
+ $_use_svnsync_props $no_reuse_existing $_minimize_url/;
use Carp qw/croak/;
use File::Path qw/mkpath/;
use File::Copy qw/copy/;
"[svn-remote \"$existing\"]\n";
}
$self->{repo_id} = $existing;
- } else {
+ } elsif ($_minimize_url) {
my $min_url = Git::SVN::Ra->new($url)->minimize_url;
$existing = find_existing_remote($min_url, $r);
if ($existing) {
sub find_by_url { # repos_root and, path are optional
my ($class, $full_url, $repos_root, $path) = @_;
+
return undef unless defined $full_url;
+ remove_username($full_url);
+ remove_username($repos_root) if defined $repos_root;
my $remotes = read_all_remotes();
if (defined $full_url && defined $repos_root && !defined $path) {
$path = $full_url;
}
foreach my $repo_id (keys %$remotes) {
my $u = $remotes->{$repo_id}->{url} or next;
+ remove_username($u);
next if defined $repos_root && $repos_root ne $u;
my $fetch = $remotes->{$repo_id}->{fetch} || {};
}
}
foreach (sort keys %$dirent) {
- next if $dirent->{$_}->kind != $SVN::Node::dir;
+ next if $dirent->{$_}->{kind} != $SVN::Node::dir;
$self->traverse_ignore($fh, "$path/$_", $r);
}
}
} elsif ($self->use_svnsync_props) {
my $full_url = $self->svnsync->{url};
$full_url .= "/$self->{path}" if length $self->{path};
+ remove_username($full_url);
my $uuid = $self->svnsync->{uuid};
$log_entry{metadata} = "$full_url\@$rev $uuid";
$email ||= "$author\@$uuid"
} else {
- $log_entry{metadata} = $self->metadata_url. "\@$rev " .
+ my $url = $self->metadata_url;
+ remove_username($url);
+ $log_entry{metadata} = "$url\@$rev " .
$self->ra->get_uuid;
$email ||= "$author\@" . $self->ra->get_uuid;
}
my $got = $md5->hexdigest;
die "Checksum mismatch: $path\n",
"expected: $exp\n got: $got\n" if ($got ne $exp);
- seek($fh, 0, 0) or croak $!;
+ sysseek($fh, 0, 0) or croak $!;
if ($fb->{mode_b} == 120000) {
- read($fh, my $buf, 5) == 5 or croak $!;
+ sysread($fh, my $buf, 5) == 5 or croak $!;
$buf eq 'link ' or die "$path has mode 120000",
"but is not a link\n";
}
BEGIN {
# enforce temporary pool usage for some simple functions
my $e;
- foreach (qw/get_latest_revnum get_uuid get_repos_root/) {
+ foreach (qw/rev_proplist get_latest_revnum get_uuid get_repos_root/) {
$e .= "sub $_ {
my \$self = shift;
my \$pool = SVN::Pool->new;
wantarray ? \@ret : \$ret[0]; }\n";
}
- # get_dir needs $pool held in cache for dirents to work,
- # check_path is cacheable and rev_proplist is close enough
- # for our purposes.
- foreach (qw/check_path get_dir rev_proplist/) {
- $e .= "my \%${_}_cache; my \$${_}_rev = 0; sub $_ {
- my \$self = shift;
- my \$r = pop;
- my \$k = join(\"\\0\", \@_);
- if (my \$x = \$${_}_cache{\$r}->{\$k}) {
- return wantarray ? \@\$x : \$x->[0];
- }
- my \$pool = SVN::Pool->new;
- my \@ret = \$self->SUPER::$_(\@_, \$r, \$pool);
- if (\$r != \$${_}_rev) {
- \%${_}_cache = ( pool => [] );
- \$${_}_rev = \$r;
- }
- \$${_}_cache{\$r}->{\$k} = \\\@ret;
- push \@{\$${_}_cache{pool}}, \$pool;
- wantarray ? \@ret : \$ret[0]; }\n";
- }
- $e .= "\n1;";
- eval $e or die $@;
+ eval "$e; 1;" or die $@;
}
sub new {
my ($class, $url) = @_;
$url =~ s!/+$!!;
return $RA if ($RA && $RA->{url} eq $url);
- $RA->{pool}->clear if $RA;
SVN::_Core::svn_config_ensure($config_dir, undef);
my ($baton, $callbacks) = SVN::Core::auth_open_helper([
$self->{svn_path} = $url;
$self->{repos_root} = $self->get_repos_root;
$self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
+ $self->{cache} = { check_path => { r => 0, data => {} },
+ get_dir => { r => 0, data => {} } };
$RA = bless $self, $class;
}
+sub check_path {
+ my ($self, $path, $r) = @_;
+ my $cache = $self->{cache}->{check_path};
+ if ($r == $cache->{r} && exists $cache->{data}->{$path}) {
+ return $cache->{data}->{$path};
+ }
+ my $pool = SVN::Pool->new;
+ my $t = $self->SUPER::check_path($path, $r, $pool);
+ $pool->clear;
+ if ($r != $cache->{r}) {
+ %{$cache->{data}} = ();
+ $cache->{r} = $r;
+ }
+ $cache->{data}->{$path} = $t;
+}
+
+sub get_dir {
+ my ($self, $dir, $r) = @_;
+ my $cache = $self->{cache}->{get_dir};
+ if ($r == $cache->{r}) {
+ if (my $x = $cache->{data}->{$dir}) {
+ return wantarray ? @$x : $x->[0];
+ }
+ }
+ my $pool = SVN::Pool->new;
+ my ($d, undef, $props) = $self->SUPER::get_dir($dir, $r, $pool);
+ my %dirents = map { $_ => { kind => $d->{$_}->kind } } keys %$d;
+ $pool->clear;
+ if ($r != $cache->{r}) {
+ %{$cache->{data}} = ();
+ $cache->{r} = $r;
+ }
+ $cache->{data}->{$dir} = [ \%dirents, $r, $props ];
+ wantarray ? (\%dirents, $r, $props) : \%dirents;
+}
+
sub DESTROY {
# do not call the real DESTROY since we store ourselves in $RA
}
return unless scalar @x == 3;
my $dirents = $x[0];
foreach my $de (keys %$dirents) {
- next if $dirents->{$de}->kind != $SVN::Node::dir;
+ next if $dirents->{$de}->{kind} != $SVN::Node::dir;
my $p = $g->{path}->full_path($de);
next if $exists->{$p};
next if (length $g->{path}->{right} &&