1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-06-02 02:26:11 +02:00

git-svn: fix several fetch bugs related to repeated invocations

We no longer delete the top-level directory even if it got
deleted from the upstream repository.  In gs_do_update; we
double-check that the path we're tracking exists at both
endpoints before proceeding.  We have also added additional
protection against fetching revisions out-of-order.

To simplify our internal interfaces, I've disabled passing the
'recursive' flag to the gs_do_{switch,update} wrapper functions
since we always want it in git-svn.  We also pass the
entire Git::SVN object rather than just the path because it
helped me debug.

When printing progress, the refname is printed out to make
it less confusing when multi-fetch is running.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
Eric Wong 2007-01-31 02:45:50 -08:00
parent f0ecca1041
commit 8a603774de
2 changed files with 43 additions and 15 deletions

View File

@ -981,6 +981,12 @@ sub full_url {
sub do_git_commit {
my ($self, $log_entry) = @_;
my $lr = $self->last_rev;
if (defined $lr && $lr >= $log_entry->{revision}) {
die "Last fetched revision of ", $self->refname,
" was r$lr, but we are about to fetch: ",
"r$log_entry->{revision}!\n";
}
if (my $c = $self->rev_db_get($log_entry->{revision})) {
croak "$log_entry->{revision} = $c already exists! ",
"Why are we refetching it?\n";
@ -1024,7 +1030,7 @@ sub do_git_commit {
$self->{last_rev} = $log_entry->{revision};
$self->{last_commit} = $commit;
print "r$log_entry->{revision} = $commit\n";
print "r$log_entry->{revision} = $commit ($self->{ref_id})\n";
return $commit;
}
@ -1121,14 +1127,13 @@ sub find_parent_branch {
# at the moment), so we can't rely on it
$self->{last_commit} = $parent;
$ed = SVN::Git::Fetcher->new($self);
$gs->ra->gs_do_switch($r0, $rev, $gs->{path}, 1,
$gs->ra->gs_do_switch($r0, $rev, $gs,
$self->full_url, $ed)
or die "SVN connection failed somewhere...\n";
} else {
print STDERR "Following parent with do_update\n";
$ed = SVN::Git::Fetcher->new($self);
$self->ra->gs_do_update($rev, $rev, $self->{path},
1, $ed)
$self->ra->gs_do_update($rev, $rev, $self, $ed)
or die "SVN connection failed somewhere...\n";
}
print STDERR "Successfully followed parent\n";
@ -1170,8 +1175,7 @@ sub do_fetch {
$ed = SVN::Git::Fetcher->new($self);
$ed->{new_fetch} = 1;
}
unless ($self->ra->gs_do_update($last_rev, $rev,
$self->{path}, 1, $ed)) {
unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) {
die "SVN connection failed somewhere...\n";
}
$self->make_log_entry($rev, \@parents, $ed);
@ -1616,6 +1620,8 @@ sub delete_entry {
my ($self, $path, $rev, $pb) = @_;
my $gpath = $self->git_path($path);
return undef if ($gpath eq '');
# remove entire directories.
if (command('ls-tree', $self->{c}, '--', $gpath) =~ /^040000 tree/) {
my ($ls, $ctx) = command_output_pipe(qw/ls-tree
@ -2233,12 +2239,23 @@ sub uuid {
}
sub gs_do_update {
my ($self, $rev_a, $rev_b, $path, $recurse, $editor) = @_;
my ($self, $rev_a, $rev_b, $gs, $editor) = @_;
my $new = ($rev_a == $rev_b);
my $path = $gs->{path};
my $ta = $self->check_path($path, $rev_a);
my $tb = $new ? $ta : $self->check_path($path, $rev_b);
return 1 if ($tb != $SVN::Node::dir && $ta != $SVN::Node::dir);
if ($ta == $SVN::Node::none) {
$rev_a = $rev_b;
$new = 1;
}
my $pool = SVN::Pool->new;
$editor->set_path_strip($path);
my (@pc) = split m#/#, $path;
my $reporter = $self->do_update($rev_b, (@pc ? shift @pc : ''),
$recurse, $editor, $pool);
1, $editor, $pool);
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
# Since we can't rely on svn_ra_reparent being available, we'll
@ -2253,7 +2270,6 @@ sub gs_do_update {
}
die "BUG: '$sp' != '$final'\n" if ($sp ne $final);
my $new = ($rev_a == $rev_b);
$reporter->set_path($sp, $rev_a, $new, @lock, $pool);
$reporter->finish_report($pool);
@ -2264,7 +2280,8 @@ sub gs_do_update {
# this requires SVN 1.4.3 or later (do_switch didn't work before 1.4.3, and
# svn_ra_reparent didn't work before 1.4)
sub gs_do_switch {
my ($self, $rev_a, $rev_b, $path, $recurse, $url_b, $editor) = @_;
my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_;
my $path = $gs->{path};
my $pool = SVN::Pool->new;
my $full_url = $self->{url};
@ -2282,8 +2299,7 @@ sub gs_do_switch {
}
}
$ra ||= $self;
my $reporter = $ra->do_switch($rev_b, '',
$recurse, $url_b, $editor, $pool);
my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : ();
$reporter->set_path('', $rev_a, 0, @lock, $pool);
$reporter->finish_report($pool);
@ -2333,6 +2349,8 @@ sub gs_fetch_loop_common {
if ($paths) {
$gs->match_paths($paths) or next;
}
my $lr = $gs->last_rev;
next if defined $lr && $lr >= $r;
next if defined $gs->rev_db_get($r);
if (my $log_entry = $gs->do_fetch($paths, $r)) {
$gs->do_git_commit($log_entry);

View File

@ -95,12 +95,12 @@ test_expect_success 'follow higher-level parent' "
"
test_expect_success 'follow deleted directory' "
svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye&&
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 \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
"
# ref: r9270 of the Subversion repository: (http://svn.collab.net/repos/svn)
@ -146,6 +146,16 @@ test_expect_success "track initial change if it was only made to parent" "
\"\`git rev-parse r9270-d~1\`\"
"
test_expect_success "multi-fetch continues to work" "
git-svn multi-fetch --follow-parent
"
test_expect_success "multi-fetch works off a 'clean' repository" "
rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
mkdir $GIT_DIR/svn &&
git-svn multi-fetch --follow-parent
"
test_debug 'gitk --all &'
test_done