From d4eff2bda5fc28559e96d62604ecaf78a4ff806b Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Tue, 30 Jan 2007 14:04:22 -0800 Subject: 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 --- git-svn.perl | 75 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/git-svn.perl b/git-svn.perl index b2f86e84b4..efc5515663 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1038,27 +1038,15 @@ sub revisions_eq { 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 { my ($self, $paths, $rev) = @_; return undef unless $_follow_parent; 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 = dup_changed_paths($_[0]) }); + $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, sub { + $paths = + Git::SVN::Ra::dup_changed_paths($_[0]) }); $SVN::Error::handler = $err_handler; } return undef unless defined $paths; @@ -1134,7 +1122,6 @@ sub find_parent_branch { or die "SVN connection failed somewhere...\n"; } print STDERR "Successfully followed parent\n"; - $ed->{new_fetch} = 1; return $self->make_log_entry($rev, [$parent], $ed); } not_found: @@ -1170,7 +1157,6 @@ sub do_fetch { return $log_entry; } $ed = SVN::Git::Fetcher->new($self); - $ed->{new_fetch} = 1; } unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) { die "SVN connection failed somewhere...\n"; @@ -1243,8 +1229,6 @@ sub make_log_entry { my ($self, $rev, $parents, $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 $!; print $un "r$rev\n" or croak $!; print $un $_, "\n" foreach @$untracked; @@ -2314,38 +2298,53 @@ sub gs_fetch_loop_common { my ($self, $base, $head, @gs) = @_; my $inc = 1000; my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc); - my @paths = @gs == 1 ? ($gs[0]->{path}) : (''); foreach my $gs (@gs) { if (my $last_commit = $gs->last_commit) { $gs->assert_index_clean($last_commit); } } while (1) { - my @revs; + my %revs; my $err; my $err_handler = $SVN::Error::handler; $SVN::Error::handler = sub { ($err) = @_; skip_unknown_revs($err); }; - $self->get_log(\@paths, $min, $max, 0, 1, 1, - sub { push @revs, [ dup_changed_paths($_[0]), $_[1] ]; }); - $SVN::Error::handler = $err_handler; - - if (! @revs && $err && $max >= $head) { - print STDERR "Branch probably deleted:\n ", - $err->expanded_message, - "\nWill attempt to follow revisions ", - "r$min .. r$max ", - "committed before the deletion\n"; - @revs = map { [ undef, $_ ] } ($min .. $max); - } - foreach (@revs) { - my ($paths, $r) = @$_; - foreach my $gs (@gs) { - if ($paths) { - $gs->match_paths($paths) or next; + foreach my $gs (@gs) { + $self->get_log([$gs->{path}], $min, $max, 0, 1, 1, sub + { my ($paths, $rev) = @_; + push @{$revs{$rev}}, + [ $gs, + dup_changed_paths($paths) ] }); + + next unless ($err && $max >= $head); + + print STDERR "Path '$gs->{path}' ", + "was probably deleted:\n", + $err->expanded_message, + "\nWill attempt to follow ", + "revisions r$min .. r$max ", + "committed before the deletion\n"; + my $hi = $max; + while (--$hi >= $min) { + my $ok; + $self->get_log([$gs->{path}], $min, $hi, + 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; next if defined $lr && $lr >= $r; next if defined $gs->rev_db_get($r); -- cgit v1.2.3