git-svn: enable --minimize to simplify the config and connections

--minimize will update the git-svn configuration to attempt to
connect to the repository root (instead of directly to the
path(s) we are tracking) in order to allow more efficient reuse
of connections (for multi-fetch and follow-parent).

Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
Eric Wong 2007-01-21 04:27:09 -08:00
Родитель f6f0987646
Коммит 47e39c55c9
2 изменённых файлов: 129 добавлений и 6 удалений

Просмотреть файл

@ -119,8 +119,6 @@ my %cmd = (
\%fc_opts ],
'migrate' => [ sub { },
# no-op, we automatically run this anyways,
# we may add a flag to automatically optimize the
# configuration to avoid reconnects in the future
'Migrate configuration/metadata/layout from
previous versions of git-svn',
\%remote_opts ],
@ -158,6 +156,8 @@ my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
read_repo_config(\%opts);
my $rv = GetOptions(%opts, 'help|H|h' => \$_help,
'version|V' => \$_version,
'minimize-connections' =>
\$Git::SVN::Migration::_minimize,
'id|i=s' => \$Git::SVN::default_repo_id);
exit 1 if (!$rv && $cmd ne 'log');
@ -702,10 +702,22 @@ BEGIN {
svn:entry:committed-date/;
}
# we allow dashes, unlike remotes2config.sh
sub read_all_remotes {
my $r = {};
foreach (grep { s/^svn-remote\.// } command(qw/repo-config -l/)) {
if (m!^(.+)\.fetch=\s*(.*)\s*:\s*refs/remotes/(.+)\s*$!) {
$r->{$1}->{fetch}->{$2} = $3;
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
$r->{$1}->{url} = $2;
}
}
$r;
}
# we allow more chars than remotes2config.sh...
sub sanitize_remote_name {
my ($name) = @_;
$name =~ tr/A-Za-z0-9-/./c;
$name =~ tr{A-Za-z0-9:,/+-}{.}c;
$name;
}
@ -2467,7 +2479,8 @@ use strict;
use warnings;
use Carp qw/croak/;
use File::Path qw/mkpath/;
use File::Basename qw/dirname/;
use File::Basename qw/dirname basename/;
use vars qw/$_minimize/;
sub migrate_from_v0 {
my $git_dir = $ENV{GIT_DIR};
@ -2577,16 +2590,101 @@ sub migrate_from_v2 {
my $migrated = 0;
foreach my $ref_id (sort keys %l_map) {
Git::SVN->init($l_map{$ref_id}, $ref_id);
Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
$migrated++;
}
$migrated;
}
sub minimize_connections {
my $r = Git::SVN::read_all_remotes();
my $new_urls = {};
my $root_repos = {};
foreach my $repo_id (keys %$r) {
my $url = $r->{$repo_id}->{url} or next;
my $fetch = $r->{$repo_id}->{fetch} or next;
my $ra = Git::SVN::Ra->new($url);
# skip existing cases where we already connect to the root
if (($ra->{url} eq $ra->{repos_root}) ||
(Git::SVN::sanitize_remote_name($ra->{repos_root}) eq
$repo_id)) {
$root_repos->{$ra->{url}} = $repo_id;
next;
}
my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
my $root_path = $ra->{url};
$root_path =~ s#^\Q$ra->{repos_root}\E/*##;
foreach my $path (keys %$fetch) {
my $ref_id = $fetch->{$path};
my $gs = Git::SVN->new($ref_id, $repo_id, $path);
# make sure we can read when connecting to
# a higher level of a repository
my ($last_rev, undef) = $gs->last_rev_commit;
if (!defined $last_rev) {
$last_rev = eval {
$root_ra->get_latest_revnum;
};
next if $@;
}
my $new = $root_path;
$new .= length $path ? "/$path" : '';
eval {
$root_ra->get_log([$new], $last_rev, $last_rev,
0, 0, 1, sub { });
};
next if $@;
$new_urls->{$ra->{repos_root}}->{$new} =
{ ref_id => $ref_id,
old_repo_id => $repo_id,
old_path => $path };
}
}
my @emptied;
foreach my $url (keys %$new_urls) {
# see if we can re-use an existing [svn-remote "repo_id"]
# instead of creating a(n ugly) new section:
my $repo_id = $root_repos->{$url} ||
Git::SVN::sanitize_remote_name($url);
my $fetch = $new_urls->{$url};
foreach my $path (keys %$fetch) {
my $x = $fetch->{$path};
Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
my $pfx = "svn-remote.$x->{old_repo_id}";
my $old_fetch = quotemeta("$x->{old_path}:".
"refs/remotes/$x->{ref_id}");
command_noisy(qw/repo-config --unset/,
"$pfx.fetch", '^'. $old_fetch . '$');
delete $r->{$x->{old_repo_id}}->
{fetch}->{$x->{old_path}};
if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
command_noisy(qw/repo-config --unset/,
"$pfx.url");
push @emptied, $x->{old_repo_id}
}
}
}
if (@emptied) {
my $file = $ENV{GIT_CONFIG} || $ENV{GIT_CONFIG_LOCAL} ||
"$ENV{GIT_DIR}/config";
print STDERR <<EOF;
The following [svn-remote] sections in your config file ($file) are empty
and can be safely removed:
EOF
print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
}
}
sub migration_check {
migrate_from_v0();
migrate_from_v1();
migrate_from_v2();
minimize_connections() if $_minimize;
}
__END__

Просмотреть файл

@ -46,6 +46,7 @@ test_expect_success 'initialize a multi-repository repo' "
grep '^tags/0\.3:refs/remotes/tags/0\.3$' fetch.out
"
# refs should all be different, but the trees should all be the same:
test_expect_success 'multi-fetch works on partial urls + paths' "
git-svn multi-fetch &&
for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do
@ -59,5 +60,29 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
refs/remotes/\$j\`\" ||exit 1; done; done
"
test_expect_success 'migrate --minimize on old multi-inited layout' "
git repo-config --unset-all svn-remote.git-svn.fetch &&
git repo-config --unset-all svn-remote.git-svn.url &&
rm -rf $GIT_DIR/svn &&
for i in \`cat fetch.out\`; do
path=\`expr \$i : '\\([^:]*\\):.*$'\`
ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
if test -z \"\$ref\"; then continue; fi
if test -n \"\$path\"; then path=\"/\$path\"; fi
( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
done &&
git-svn migrate --minimize &&
test -z \"\`git-repo-config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
git-repo-config --get-all svn-remote.git-svn.fetch > fetch.out &&
grep '^trunk:refs/remotes/trunk$' fetch.out &&
grep '^branches/a:refs/remotes/a$' fetch.out &&
grep '^branches/b:refs/remotes/b$' fetch.out &&
grep '^tags/0\.1:refs/remotes/tags/0\.1$' fetch.out &&
grep '^tags/0\.2:refs/remotes/tags/0\.2$' fetch.out &&
grep '^tags/0\.3:refs/remotes/tags/0\.3$' fetch.out
grep '^:refs/remotes/git-svn' fetch.out
"
test_done