git-svn: correctly track revisions made to deleted branches
git-svn has never been able to handle deleted branches very well because svn_ra_get_log() is all-or-nothing, meaning that if the max revision passed to it does not contain the path we're tracking, we miss all the revisions in the repository. Branches fetched using --follow-parent still do this sub-optimally (will be fixed soon). --follow-parent will soon become the default, so we will assume that when using get_log(); We will also avoid tracking revprops for revisions with no path-related changes since otherwise we just end up pulling logs to paths we don't care about. Also added a test for this to t9104-git-svn-follow-parent.sh and correctly commit the log message in the preceeding test (which conflicted with a filename). Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
parent
97f6987afa
commit
e5a0b240fc
46
git-svn.perl
46
git-svn.perl
@ -1100,6 +1100,11 @@ sub revisions_eq {
|
|||||||
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) {
|
||||||
|
$self->ra->get_log([''], $rev, $rev, 0, 1, 1,
|
||||||
|
sub { $paths = $_[0] });
|
||||||
|
}
|
||||||
|
return undef unless defined $paths;
|
||||||
|
|
||||||
# look for a parent from another branch:
|
# look for a parent from another branch:
|
||||||
my @b_path_components = split m#/#, $self->rel_path;
|
my @b_path_components = split m#/#, $self->rel_path;
|
||||||
@ -1146,11 +1151,11 @@ sub find_parent_branch {
|
|||||||
}
|
}
|
||||||
my ($r0, $parent) = $gs->find_rev_before($r, 1);
|
my ($r0, $parent) = $gs->find_rev_before($r, 1);
|
||||||
if ($::_follow_parent && (!defined $r0 || !defined $parent)) {
|
if ($::_follow_parent && (!defined $r0 || !defined $parent)) {
|
||||||
$gs->ra->get_log([$gs->{path}], 0, $r, 0, 1, 1, sub {
|
foreach (1 .. $r) {
|
||||||
my ($paths, $rev) = @_;
|
if (my $log_entry = $gs->do_fetch(undef, $_)) {
|
||||||
my $log_entry = eval { $gs->do_fetch($paths, $rev) };
|
$gs->do_git_commit($log_entry);
|
||||||
$gs->do_git_commit($log_entry) if $log_entry;
|
}
|
||||||
});
|
}
|
||||||
($r0, $parent) = $gs->last_rev_commit;
|
($r0, $parent) = $gs->last_rev_commit;
|
||||||
}
|
}
|
||||||
if (defined $r0 && defined $parent && $gs->revisions_eq($r0, $r)) {
|
if (defined $r0 && defined $parent && $gs->revisions_eq($r0, $r)) {
|
||||||
@ -1178,16 +1183,8 @@ sub find_parent_branch {
|
|||||||
}
|
}
|
||||||
not_found:
|
not_found:
|
||||||
print STDERR "Branch parent for path: '/",
|
print STDERR "Branch parent for path: '/",
|
||||||
$self->rel_path, "' not found\n";
|
$self->rel_path, "' @ $rev not found\n";
|
||||||
return undef unless $paths;
|
print STDERR ' ', $_, "\n" foreach (sort keys %$paths);
|
||||||
foreach my $x (sort keys %$paths) {
|
|
||||||
my $p = $paths->{$x};
|
|
||||||
print STDERR ' ', $p->action, ' ', $x;
|
|
||||||
if (my $cp_from = $p->copyfrom_path) {
|
|
||||||
print STDERR "(from $cp_from:", $p->copyfrom_rev, ')';
|
|
||||||
}
|
|
||||||
print STDERR "\n";
|
|
||||||
}
|
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,6 +1276,8 @@ 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->{nr} == 0 && scalar @$untracked == 0);
|
||||||
|
|
||||||
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;
|
||||||
@ -1296,10 +1295,6 @@ sub make_log_entry {
|
|||||||
}
|
}
|
||||||
close $un or croak $!;
|
close $un or croak $!;
|
||||||
|
|
||||||
delete $rp->{'svn:date'}; # this is the only revprop for r0
|
|
||||||
return undef if ($ed->{nr} == 0 && scalar @$untracked == 0 &&
|
|
||||||
scalar keys %$rp == 0);
|
|
||||||
|
|
||||||
$log_entry{date} = parse_svn_date($log_entry{date});
|
$log_entry{date} = parse_svn_date($log_entry{date});
|
||||||
$log_entry{author} = check_author($log_entry{author});
|
$log_entry{author} = check_author($log_entry{author});
|
||||||
$log_entry{log} .= "\n";
|
$log_entry{log} .= "\n";
|
||||||
@ -1317,18 +1312,26 @@ sub fetch {
|
|||||||
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 $err_handler = $SVN::Error::handler;
|
my $err_handler = $SVN::Error::handler;
|
||||||
$SVN::Error::handler = \&skip_unknown_revs;
|
my $err;
|
||||||
|
$SVN::Error::handler = sub { ($err) = @_; skip_unknown_revs($err); } ;
|
||||||
while (1) {
|
while (1) {
|
||||||
my @revs;
|
my @revs;
|
||||||
$self->ra->get_log([$self->{path}], $min, $max, 0, 1, 1, sub {
|
$self->ra->get_log([$self->{path}], $min, $max, 0, 1, 1, sub {
|
||||||
my ($paths, $rev, $author, $date, $log) = @_;
|
my ($paths, $rev, $author, $date, $log) = @_;
|
||||||
push @revs, [ $paths, $rev ] });
|
push @revs, [ $paths, $rev ] });
|
||||||
|
if (! @revs && $err) {
|
||||||
|
print STDERR "Branch probably deleted:\n ",
|
||||||
|
$err->expanded_message,
|
||||||
|
"\nWill attempt to follow revisions ",
|
||||||
|
"committed before the deletion\n";
|
||||||
|
@revs = map { [ undef, $_ ] } ($min .. $max);
|
||||||
|
}
|
||||||
foreach (@revs) {
|
foreach (@revs) {
|
||||||
if (my $log_entry = $self->do_fetch(@$_)) {
|
if (my $log_entry = $self->do_fetch(@$_)) {
|
||||||
$self->do_git_commit($log_entry, @parents);
|
$self->do_git_commit($log_entry, @parents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last if $max >= $head;
|
last if $max >= $head || $err;
|
||||||
$min = $max + 1;
|
$min = $max + 1;
|
||||||
$max += $inc;
|
$max += $inc;
|
||||||
$max = $head if ($max > $head);
|
$max = $head if ($max > $head);
|
||||||
@ -2226,7 +2229,6 @@ sub dup {
|
|||||||
sub get_log {
|
sub get_log {
|
||||||
my ($self, @args) = @_;
|
my ($self, @args) = @_;
|
||||||
my $pool = SVN::Pool->new;
|
my $pool = SVN::Pool->new;
|
||||||
$args[4]-- if $args[4] && ! $::_follow_parent;
|
|
||||||
splice(@args, 3, 1) if ($SVN::Core::VERSION le '1.2.0');
|
splice(@args, 3, 1) if ($SVN::Core::VERSION le '1.2.0');
|
||||||
my $ret = $self->SUPER::get_log(@args, $pool);
|
my $ret = $self->SUPER::get_log(@args, $pool);
|
||||||
$pool->clear;
|
$pool->clear;
|
||||||
|
@ -85,7 +85,7 @@ test_expect_success 'follow higher-level parent' "
|
|||||||
cd blob &&
|
cd blob &&
|
||||||
echo hi > hi &&
|
echo hi > hi &&
|
||||||
svn add hi &&
|
svn add hi &&
|
||||||
svn commit -m 'hi' &&
|
svn commit -m 'hihi' &&
|
||||||
cd ..
|
cd ..
|
||||||
svn mkdir -m 'new glob at top level' $svnrepo/glob &&
|
svn mkdir -m 'new glob at top level' $svnrepo/glob &&
|
||||||
svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
|
svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
|
||||||
@ -93,6 +93,15 @@ test_expect_success 'follow higher-level parent' "
|
|||||||
git-svn fetch -i blob --follow-parent
|
git-svn fetch -i blob --follow-parent
|
||||||
"
|
"
|
||||||
|
|
||||||
|
test_expect_success 'follow deleted directory' "
|
||||||
|
svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye&&
|
||||||
|
svn rm -m 'remove glob' $svnrepo/glob &&
|
||||||
|
git-svn init -i glob $svnrepo/glob &&
|
||||||
|
git-svn fetch -i glob &&
|
||||||
|
test \"\`git cat-file blob refs/remotes/glob~1:blob/bye\`\" = hi &&
|
||||||
|
test -z \"\`git ls-tree -z refs/remotes/glob\`\"
|
||||||
|
"
|
||||||
|
|
||||||
test_debug 'gitk --all &'
|
test_debug 'gitk --all &'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user