git-svn: make (multi-)fetch safer but slower
get_log with explicit paths is the safest way to get revisions that change a particular path we're interested in. Unfortunately that means we still have to run get_log multiple times for each path we're interested in, and even more if a path gets deleted. The first argument of get_log() is an array reference, but we shouldn't use more than one element in that array ref because the non-existence of _one_ of those paths for a particular range would cause an error for all paths in that range, so yes, we need multiple get_log calls to be on the safe side... Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
parent
c7eba7163b
commit
d4eff2bda5
73
git-svn.perl
73
git-svn.perl
@ -1038,27 +1038,15 @@ sub revisions_eq {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub match_paths {
|
|
||||||
my ($self, $paths) = @_;
|
|
||||||
return 1 if $paths->{'/'};
|
|
||||||
$self->{path_regex} ||= qr/^\/\Q$self->{path}\E\/?/;
|
|
||||||
grep /$self->{path_regex}/, keys %$paths and return 1;
|
|
||||||
my $c = '';
|
|
||||||
foreach (split m#/#, $self->rel_path) {
|
|
||||||
$c .= "/$_";
|
|
||||||
return 1 if $paths->{$c};
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub find_parent_branch {
|
sub find_parent_branch {
|
||||||
my ($self, $paths, $rev) = @_;
|
my ($self, $paths, $rev) = @_;
|
||||||
return undef unless $_follow_parent;
|
return undef unless $_follow_parent;
|
||||||
unless (defined $paths) {
|
unless (defined $paths) {
|
||||||
my $err_handler = $SVN::Error::handler;
|
my $err_handler = $SVN::Error::handler;
|
||||||
$SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
|
$SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
|
||||||
$self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
|
$self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, sub {
|
||||||
sub { $paths = dup_changed_paths($_[0]) });
|
$paths =
|
||||||
|
Git::SVN::Ra::dup_changed_paths($_[0]) });
|
||||||
$SVN::Error::handler = $err_handler;
|
$SVN::Error::handler = $err_handler;
|
||||||
}
|
}
|
||||||
return undef unless defined $paths;
|
return undef unless defined $paths;
|
||||||
@ -1134,7 +1122,6 @@ sub find_parent_branch {
|
|||||||
or die "SVN connection failed somewhere...\n";
|
or die "SVN connection failed somewhere...\n";
|
||||||
}
|
}
|
||||||
print STDERR "Successfully followed parent\n";
|
print STDERR "Successfully followed parent\n";
|
||||||
$ed->{new_fetch} = 1;
|
|
||||||
return $self->make_log_entry($rev, [$parent], $ed);
|
return $self->make_log_entry($rev, [$parent], $ed);
|
||||||
}
|
}
|
||||||
not_found:
|
not_found:
|
||||||
@ -1170,7 +1157,6 @@ sub do_fetch {
|
|||||||
return $log_entry;
|
return $log_entry;
|
||||||
}
|
}
|
||||||
$ed = SVN::Git::Fetcher->new($self);
|
$ed = SVN::Git::Fetcher->new($self);
|
||||||
$ed->{new_fetch} = 1;
|
|
||||||
}
|
}
|
||||||
unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
|
unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
|
||||||
die "SVN connection failed somewhere...\n";
|
die "SVN connection failed somewhere...\n";
|
||||||
@ -1243,8 +1229,6 @@ sub make_log_entry {
|
|||||||
my ($self, $rev, $parents, $ed) = @_;
|
my ($self, $rev, $parents, $ed) = @_;
|
||||||
my $untracked = $self->get_untracked($ed);
|
my $untracked = $self->get_untracked($ed);
|
||||||
|
|
||||||
return undef if (! $ed->{new_fetch} && ! $ed->{nr} && ! @$untracked);
|
|
||||||
|
|
||||||
open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
|
open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
|
||||||
print $un "r$rev\n" or croak $!;
|
print $un "r$rev\n" or croak $!;
|
||||||
print $un $_, "\n" foreach @$untracked;
|
print $un $_, "\n" foreach @$untracked;
|
||||||
@ -2314,38 +2298,53 @@ sub gs_fetch_loop_common {
|
|||||||
my ($self, $base, $head, @gs) = @_;
|
my ($self, $base, $head, @gs) = @_;
|
||||||
my $inc = 1000;
|
my $inc = 1000;
|
||||||
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
|
my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
|
||||||
my @paths = @gs == 1 ? ($gs[0]->{path}) : ('');
|
|
||||||
foreach my $gs (@gs) {
|
foreach my $gs (@gs) {
|
||||||
if (my $last_commit = $gs->last_commit) {
|
if (my $last_commit = $gs->last_commit) {
|
||||||
$gs->assert_index_clean($last_commit);
|
$gs->assert_index_clean($last_commit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
my @revs;
|
my %revs;
|
||||||
my $err;
|
my $err;
|
||||||
my $err_handler = $SVN::Error::handler;
|
my $err_handler = $SVN::Error::handler;
|
||||||
$SVN::Error::handler = sub {
|
$SVN::Error::handler = sub {
|
||||||
($err) = @_;
|
($err) = @_;
|
||||||
skip_unknown_revs($err);
|
skip_unknown_revs($err);
|
||||||
};
|
};
|
||||||
$self->get_log(\@paths, $min, $max, 0, 1, 1,
|
foreach my $gs (@gs) {
|
||||||
sub { push @revs, [ dup_changed_paths($_[0]), $_[1] ]; });
|
$self->get_log([$gs->{path}], $min, $max, 0, 1, 1, sub
|
||||||
$SVN::Error::handler = $err_handler;
|
{ my ($paths, $rev) = @_;
|
||||||
|
push @{$revs{$rev}},
|
||||||
|
[ $gs,
|
||||||
|
dup_changed_paths($paths) ] });
|
||||||
|
|
||||||
if (! @revs && $err && $max >= $head) {
|
next unless ($err && $max >= $head);
|
||||||
print STDERR "Branch probably deleted:\n ",
|
|
||||||
$err->expanded_message,
|
print STDERR "Path '$gs->{path}' ",
|
||||||
"\nWill attempt to follow revisions ",
|
"was probably deleted:\n",
|
||||||
"r$min .. r$max ",
|
$err->expanded_message,
|
||||||
"committed before the deletion\n";
|
"\nWill attempt to follow ",
|
||||||
@revs = map { [ undef, $_ ] } ($min .. $max);
|
"revisions r$min .. r$max ",
|
||||||
}
|
"committed before the deletion\n";
|
||||||
foreach (@revs) {
|
my $hi = $max;
|
||||||
my ($paths, $r) = @$_;
|
while (--$hi >= $min) {
|
||||||
foreach my $gs (@gs) {
|
my $ok;
|
||||||
if ($paths) {
|
$self->get_log([$gs->{path}], $min, $hi,
|
||||||
$gs->match_paths($paths) or next;
|
0, 1, 1, sub {
|
||||||
|
my ($paths, $rev) = @_;
|
||||||
|
$ok = $rev;
|
||||||
|
push @{$revs{$rev}}, [ $gs,
|
||||||
|
dup_changed_paths($_[0])]});
|
||||||
|
if ($ok) {
|
||||||
|
print STDERR "r$min .. r$ok OK\n";
|
||||||
|
last;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$SVN::Error::handler = $err_handler;
|
||||||
|
foreach my $r (sort {$a <=> $b} keys %revs) {
|
||||||
|
foreach (@{$revs{$r}}) {
|
||||||
|
my ($gs, $paths) = @$_;
|
||||||
my $lr = $gs->last_rev;
|
my $lr = $gs->last_rev;
|
||||||
next if defined $lr && $lr >= $r;
|
next if defined $lr && $lr >= $r;
|
||||||
next if defined $gs->rev_db_get($r);
|
next if defined $gs->rev_db_get($r);
|
||||||
|
Loading…
Reference in New Issue
Block a user