git-svn: run get_log() on a sub-directory if possible
authorEric Wong <normalperson@yhbt.net>
Wed, 7 Feb 2007 19:50:16 +0000 (11:50 -0800)
committerEric Wong <normalperson@yhbt.net>
Fri, 23 Feb 2007 08:57:11 +0000 (00:57 -0800)
This is an optimization that should conserve network
bandwidth on certain repositories and configurations.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
git-svn.perl

index d0bde71f2e0464832344ec16f9e56a7c7a67dce3..5e1a64c6d650fe453625f8afa5f4c0e5602ed3b9 100755 (executable)
@@ -2433,21 +2433,62 @@ sub gs_fetch_loop_common {
        my ($self, $base, $head, @gs) = @_;
        my $inc = 1000;
        my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
+
+       my %common;
        foreach my $gs (@gs) {
                if (my $last_commit = $gs->last_commit) {
                        $gs->assert_index_clean($last_commit);
                }
+               my @tmp = split m#/#, $gs->{path};
+               my $p = '';
+               foreach (@tmp) {
+                       $p .= length($p) ? "/$_" : $_;
+                       $common{$p} ||= 0;
+                       $common{$p}++;
+               }
+       }
+       my $longest_path = '';
+       foreach (sort {length $b <=> length $a} keys %common) {
+               if ($common{$_} == @gs) {
+                       $longest_path = $_;
+                       last;
+               }
        }
        while (1) {
                my %revs;
+               my $err;
                my $err_handler = $SVN::Error::handler;
-               $SVN::Error::handler = \&skip_unknown_revs;
-               $self->get_log([''], $min, $max, 0, 1, 1, sub {
-                              my ($paths, $r, $author, $date, $log) = @_;
-                              $revs{$r} = [ dup_changed_paths($paths),
-                                            { author => $author,
-                                              date => $date,
-                                              log => $log } ] });
+               $SVN::Error::handler = sub {
+                       ($err) = @_;
+                       skip_unknown_revs($err);
+               };
+               sub _cb {
+                       my ($paths, $r, $author, $date, $log) = @_;
+                       [ dup_changed_paths($paths),
+                         { author => $author, date => $date, log => $log } ];
+               }
+               $self->get_log([$longest_path], $min, $max, 0, 1, 1,
+                              sub { $revs{$_[1]} = _cb(@_) });
+               if ($err && $max >= $head) {
+                       print STDERR "Path '$longest_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([$longest_path], $min, $hi,
+                                              0, 1, 1, sub {
+                                              $ok ||= $_[1];
+                                              $revs{$_[1]} = _cb(@_) });
+                               if ($ok) {
+                                       print STDERR "r$min .. r$ok OK\n";
+                                       last;
+                               }
+                       }
+               }
                $SVN::Error::handler = $err_handler;
 
                foreach my $r (sort {$a <=> $b} keys %revs) {