Skip to content

Commit b772cb9

Browse files
schwernEric Wong
authored andcommitted
Extract Git::SVN::Migration from git-svn.
Straight cut & paste. Signed-off-by: Eric Wong <[email protected]>
1 parent b0e7525 commit b772cb9

File tree

4 files changed

+262
-258
lines changed

4 files changed

+262
-258
lines changed

git-svn.perl

Lines changed: 1 addition & 257 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use Git::SVN;
1414
use Git::SVN::Log;
15+
use Git::SVN::Migration;
1516
use Git::SVN::Utils qw(fatal can_compress);
1617

1718
use Git qw(
@@ -2041,263 +2042,6 @@ sub gc_directory {
20412042
}
20422043

20432044

2044-
package Git::SVN::Migration;
2045-
# these version numbers do NOT correspond to actual version numbers
2046-
# of git nor git-svn. They are just relative.
2047-
#
2048-
# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD
2049-
#
2050-
# v1 layout: .git/$id/info/url, refs/remotes/$id
2051-
#
2052-
# v2 layout: .git/svn/$id/info/url, refs/remotes/$id
2053-
#
2054-
# v3 layout: .git/svn/$id, refs/remotes/$id
2055-
# - info/url may remain for backwards compatibility
2056-
# - this is what we migrate up to this layout automatically,
2057-
# - this will be used by git svn init on single branches
2058-
# v3.1 layout (auto migrated):
2059-
# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink
2060-
# for backwards compatibility
2061-
#
2062-
# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id
2063-
# - this is only created for newly multi-init-ed
2064-
# repositories. Similar in spirit to the
2065-
# --use-separate-remotes option in git-clone (now default)
2066-
# - we do not automatically migrate to this (following
2067-
# the example set by core git)
2068-
#
2069-
# v5 layout: .rev_db.$UUID => .rev_map.$UUID
2070-
# - newer, more-efficient format that uses 24-bytes per record
2071-
# with no filler space.
2072-
# - use xxd -c24 < .rev_map.$UUID to view and debug
2073-
# - This is a one-way migration, repositories updated to the
2074-
# new format will not be able to use old git-svn without
2075-
# rebuilding the .rev_db. Rebuilding the rev_db is not
2076-
# possible if noMetadata or useSvmProps are set; but should
2077-
# be no problem for users that use the (sensible) defaults.
2078-
use strict;
2079-
use warnings;
2080-
use Carp qw/croak/;
2081-
use File::Path qw/mkpath/;
2082-
use File::Basename qw/dirname basename/;
2083-
2084-
our $_minimize;
2085-
use Git qw(
2086-
command
2087-
command_noisy
2088-
command_output_pipe
2089-
command_close_pipe
2090-
);
2091-
2092-
sub migrate_from_v0 {
2093-
my $git_dir = $ENV{GIT_DIR};
2094-
return undef unless -d $git_dir;
2095-
my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
2096-
my $migrated = 0;
2097-
while (<$fh>) {
2098-
chomp;
2099-
my ($id, $orig_ref) = ($_, $_);
2100-
next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#;
2101-
next unless -f "$git_dir/$id/info/url";
2102-
my $new_ref = "refs/remotes/$id";
2103-
if (::verify_ref("$new_ref^0")) {
2104-
print STDERR "W: $orig_ref is probably an old ",
2105-
"branch used by an ancient version of ",
2106-
"git-svn.\n",
2107-
"However, $new_ref also exists.\n",
2108-
"We will not be able ",
2109-
"to use this branch until this ",
2110-
"ambiguity is resolved.\n";
2111-
next;
2112-
}
2113-
print STDERR "Migrating from v0 layout...\n" if !$migrated;
2114-
print STDERR "Renaming ref: $orig_ref => $new_ref\n";
2115-
command_noisy('update-ref', $new_ref, $orig_ref);
2116-
command_noisy('update-ref', '-d', $orig_ref, $orig_ref);
2117-
$migrated++;
2118-
}
2119-
command_close_pipe($fh, $ctx);
2120-
print STDERR "Done migrating from v0 layout...\n" if $migrated;
2121-
$migrated;
2122-
}
2123-
2124-
sub migrate_from_v1 {
2125-
my $git_dir = $ENV{GIT_DIR};
2126-
my $migrated = 0;
2127-
return $migrated unless -d $git_dir;
2128-
my $svn_dir = "$git_dir/svn";
2129-
2130-
# just in case somebody used 'svn' as their $id at some point...
2131-
return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url";
2132-
2133-
print STDERR "Migrating from a git-svn v1 layout...\n";
2134-
mkpath([$svn_dir]);
2135-
print STDERR "Data from a previous version of git-svn exists, but\n\t",
2136-
"$svn_dir\n\t(required for this version ",
2137-
"($::VERSION) of git-svn) does not exist.\n";
2138-
my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/);
2139-
while (<$fh>) {
2140-
my $x = $_;
2141-
next unless $x =~ s#^refs/remotes/##;
2142-
chomp $x;
2143-
next unless -f "$git_dir/$x/info/url";
2144-
my $u = eval { ::file_to_s("$git_dir/$x/info/url") };
2145-
next unless $u;
2146-
my $dn = dirname("$git_dir/svn/$x");
2147-
mkpath([$dn]) unless -d $dn;
2148-
if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID:
2149-
mkpath(["$git_dir/svn/svn"]);
2150-
print STDERR " - $git_dir/$x/info => ",
2151-
"$git_dir/svn/$x/info\n";
2152-
rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or
2153-
croak "$!: $x";
2154-
# don't worry too much about these, they probably
2155-
# don't exist with repos this old (save for index,
2156-
# and we can easily regenerate that)
2157-
foreach my $f (qw/unhandled.log index .rev_db/) {
2158-
rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f";
2159-
}
2160-
} else {
2161-
print STDERR " - $git_dir/$x => $git_dir/svn/$x\n";
2162-
rename "$git_dir/$x", "$git_dir/svn/$x" or
2163-
croak "$!: $x";
2164-
}
2165-
$migrated++;
2166-
}
2167-
command_close_pipe($fh, $ctx);
2168-
print STDERR "Done migrating from a git-svn v1 layout\n";
2169-
$migrated;
2170-
}
2171-
2172-
sub read_old_urls {
2173-
my ($l_map, $pfx, $path) = @_;
2174-
my @dir;
2175-
foreach (<$path/*>) {
2176-
if (-r "$_/info/url") {
2177-
$pfx .= '/' if $pfx && $pfx !~ m!/$!;
2178-
my $ref_id = $pfx . basename $_;
2179-
my $url = ::file_to_s("$_/info/url");
2180-
$l_map->{$ref_id} = $url;
2181-
} elsif (-d $_) {
2182-
push @dir, $_;
2183-
}
2184-
}
2185-
foreach (@dir) {
2186-
my $x = $_;
2187-
$x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o;
2188-
read_old_urls($l_map, $x, $_);
2189-
}
2190-
}
2191-
2192-
sub migrate_from_v2 {
2193-
my @cfg = command(qw/config -l/);
2194-
return if grep /^svn-remote\..+\.url=/, @cfg;
2195-
my %l_map;
2196-
read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn");
2197-
my $migrated = 0;
2198-
2199-
require Git::SVN;
2200-
foreach my $ref_id (sort keys %l_map) {
2201-
eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) };
2202-
if ($@) {
2203-
Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id);
2204-
}
2205-
$migrated++;
2206-
}
2207-
$migrated;
2208-
}
2209-
2210-
sub minimize_connections {
2211-
require Git::SVN;
2212-
require Git::SVN::Ra;
2213-
2214-
my $r = Git::SVN::read_all_remotes();
2215-
my $new_urls = {};
2216-
my $root_repos = {};
2217-
foreach my $repo_id (keys %$r) {
2218-
my $url = $r->{$repo_id}->{url} or next;
2219-
my $fetch = $r->{$repo_id}->{fetch} or next;
2220-
my $ra = Git::SVN::Ra->new($url);
2221-
2222-
# skip existing cases where we already connect to the root
2223-
if (($ra->{url} eq $ra->{repos_root}) ||
2224-
($ra->{repos_root} eq $repo_id)) {
2225-
$root_repos->{$ra->{url}} = $repo_id;
2226-
next;
2227-
}
2228-
2229-
my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
2230-
my $root_path = $ra->{url};
2231-
$root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
2232-
foreach my $path (keys %$fetch) {
2233-
my $ref_id = $fetch->{$path};
2234-
my $gs = Git::SVN->new($ref_id, $repo_id, $path);
2235-
2236-
# make sure we can read when connecting to
2237-
# a higher level of a repository
2238-
my ($last_rev, undef) = $gs->last_rev_commit;
2239-
if (!defined $last_rev) {
2240-
$last_rev = eval {
2241-
$root_ra->get_latest_revnum;
2242-
};
2243-
next if $@;
2244-
}
2245-
my $new = $root_path;
2246-
$new .= length $path ? "/$path" : '';
2247-
eval {
2248-
$root_ra->get_log([$new], $last_rev, $last_rev,
2249-
0, 0, 1, sub { });
2250-
};
2251-
next if $@;
2252-
$new_urls->{$ra->{repos_root}}->{$new} =
2253-
{ ref_id => $ref_id,
2254-
old_repo_id => $repo_id,
2255-
old_path => $path };
2256-
}
2257-
}
2258-
2259-
my @emptied;
2260-
foreach my $url (keys %$new_urls) {
2261-
# see if we can re-use an existing [svn-remote "repo_id"]
2262-
# instead of creating a(n ugly) new section:
2263-
my $repo_id = $root_repos->{$url} || $url;
2264-
2265-
my $fetch = $new_urls->{$url};
2266-
foreach my $path (keys %$fetch) {
2267-
my $x = $fetch->{$path};
2268-
Git::SVN->init($url, $path, $repo_id, $x->{ref_id});
2269-
my $pfx = "svn-remote.$x->{old_repo_id}";
2270-
2271-
my $old_fetch = quotemeta("$x->{old_path}:".
2272-
"$x->{ref_id}");
2273-
command_noisy(qw/config --unset/,
2274-
"$pfx.fetch", '^'. $old_fetch . '$');
2275-
delete $r->{$x->{old_repo_id}}->
2276-
{fetch}->{$x->{old_path}};
2277-
if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) {
2278-
command_noisy(qw/config --unset/,
2279-
"$pfx.url");
2280-
push @emptied, $x->{old_repo_id}
2281-
}
2282-
}
2283-
}
2284-
if (@emptied) {
2285-
my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config";
2286-
print STDERR <<EOF;
2287-
The following [svn-remote] sections in your config file ($file) are empty
2288-
and can be safely removed:
2289-
EOF
2290-
print STDERR "[svn-remote \"$_\"]\n" foreach @emptied;
2291-
}
2292-
}
2293-
2294-
sub migration_check {
2295-
migrate_from_v0();
2296-
migrate_from_v1();
2297-
migrate_from_v2();
2298-
minimize_connections() if $_minimize;
2299-
}
2300-
23012045
package Git::IndexInfo;
23022046
use strict;
23032047
use warnings;

0 commit comments

Comments
 (0)