my $sha1 = qr/[a-f\d]{40}/;
my $sha1_short = qr/[a-f\d]{4,40}/;
my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
- $_find_copies_harder, $_l, $_cp_similarity,
+ $_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,
$_repack, $_repack_nr, $_repack_flags,
$_template, $_shared, $_no_default_regex, $_no_graft_copy,
$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,
{ 'revision|r=i' => \$_revision } ],
rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)",
{ 'no-ignore-externals' => \$_no_ignore_ext,
+ 'copy-remote|remote=s' => \$_cp_remote,
'upgrade' => \$_upgrade } ],
'graft-branches' => [ \&graft_branches,
'Detect merges/branches from already imported history',
init_vars();
load_authors() if $_authors;
load_all_refs() if $_branch_all_refs;
-svn_compat_check();
-migration_check() unless $cmd =~ /^(?:init|multi-init)$/;
+svn_compat_check() unless $_use_lib;
+migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/;
$cmd{$cmd}->[0]->(@ARGV);
exit 0;
}
sub rebuild {
+ if (quiet_run(qw/git-rev-parse --verify/,"refs/remotes/$GIT_SVN^0")) {
+ copy_remote_ref();
+ }
$SVN_URL = shift or undef;
my $newest_rev = 0;
if ($_upgrade) {
# performance sucks with it enabled, so it's much
# faster to fetch revision ranges instead of relying
# on the limiter.
- $SVN_LOG->get_log( '/'.$SVN_PATH, $min, $max, 0, 1, 1,
+ libsvn_get_log($SVN_LOG, '/'.$SVN_PATH,
+ $min, $max, 0, 1, 1,
sub {
my $log_msg;
if ($last_commit) {
my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();
my $commit_msg = "$GIT_SVN_DIR/.svn-commit.tmp.$$";
+ if (defined $LC_ALL) {
+ $ENV{LC_ALL} = $LC_ALL;
+ } else {
+ delete $ENV{LC_ALL};
+ }
foreach my $c (@revs) {
+ my $log_msg = get_commit_message($c, $commit_msg);
+
# fork for each commit because there's a memory leak I
# can't track down... (it's probably in the SVN code)
defined(my $pid = open my $fh, '-|') or croak $!;
if (!$pid) {
- if (defined $LC_ALL) {
- $ENV{LC_ALL} = $LC_ALL;
- } else {
- delete $ENV{LC_ALL};
- }
- my $log_msg = get_commit_message($c, $commit_msg);
my $ed = SVN::Git::Editor->new(
{ r => $r_last,
ra => $SVN,
($r_last, $cmt_last) = ($r_new, $cmt_new);
}
}
+ $ENV{LC_ALL} = 'C';
unlink $commit_msg;
}
$SVN::Error::handler = \&libsvn_skip_unknown_revs;
while (1) {
my $pool = SVN::Pool->new;
- $SVN_LOG->get_log( "/$path", $min, $max, 0, 1, 1,
+ libsvn_get_log($SVN_LOG, "/$path", $min, $max, 0, 1, 1,
sub {
libsvn_graft_file_copies($grafts, $tree_paths,
$path, @_);
sub check_upgrade_needed {
if (!-r $REVDB) {
+ -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]);
open my $fh, '>>',$REVDB or croak $!;
close $fh;
}
init_vars();
exit 0 if -r $REVDB;
print "Upgrading svn => git mapping...\n";
+ -d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]);
open my $fh, '>>',$REVDB or croak $!;
close $fh;
rebuild();
return unless $_use_lib;
$_use_lib = eval {
require SVN::Core;
- if ($SVN::Core::VERSION lt '1.2.1') {
- die "Need SVN::Core 1.2.1 or better ",
+ if ($SVN::Core::VERSION lt '1.1.0') {
+ die "Need SVN::Core 1.1.0 or better ",
"(got $SVN::Core::VERSION) ",
"Falling back to command-line svn\n";
}
my $pool = SVN::Pool->new;
defined($pid = open3($in, $out, '>&STDERR',
qw/git-hash-object -w --stdin/)) or croak $!;
- my ($r, $props) = $SVN->get_file($f, $rev, $in, $pool);
+ # redirect STDOUT for SVN 1.1.x compatibility
+ open my $stdout, '>&', \*STDOUT or croak $!;
+ open STDOUT, '>&', $in or croak $!;
+ $| = 1; # not sure if this is necessary, better safe than sorry...
+ my ($r, $props) = $SVN->get_file($f, $rev, \*STDOUT, $pool);
$in->flush == 0 or croak $!;
+ open STDOUT, '>&', $stdout or croak $!;
close $in or croak $!;
+ close $stdout or croak $!;
$pool->clear;
chomp($hash = do { local $/; <$out> });
close $out or croak $!;
if ($_use_lib) {
# should be OK to use Pool here (r1 - r0) should be small
my $pool = SVN::Pool->new;
- $SVN->get_log("/$path", $r0, $r1, 0, 1, 1, sub {$nr++},$pool);
+ libsvn_get_log($SVN, "/$path", $r0, $r1,
+ 0, 1, 1, sub {$nr++}, $pool);
$pool->clear;
} else {
my ($url, undef) = repo_path_split($SVN_URL);
return undef;
}
+sub libsvn_get_log {
+ my ($ra, @args) = @_;
+ if ($SVN::Core::VERSION le '1.2.0') {
+ splice(@args, 3, 1);
+ }
+ $ra->get_log(@args);
+}
+
sub libsvn_new_tree {
if (my $log_entry = libsvn_find_parent_branch(@_)) {
return $log_entry;
return $ret;
}
+sub copy_remote_ref {
+ my $origin = $_cp_remote ? $_cp_remote : 'origin';
+ my $ref = "refs/remotes/$GIT_SVN";
+ if (safe_qx('git-ls-remote', $origin, $ref)) {
+ sys(qw/git fetch/, $origin, "$ref:$ref");
+ } else {
+ die "Unable to find remote reference: ",
+ "refs/remotes/$GIT_SVN on $origin\n";
+ }
+}
+
package SVN::Git::Editor;
use vars qw/@ISA/;
use strict;
exec qw/git-ls-tree --name-only -r -z/, $self->{c} or croak $!;
}
local $/ = "\0";
+ my @svn_path = split m#/#, $self->{svn_path};
while (<$fh>) {
chomp;
- $_ = $self->{svn_path} . '/' . $_;
- my ($dn) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);
- delete $rm->{$dn};
- last unless %$rm;
+ my @dn = (@svn_path, (split m#/#, $_));
+ while (pop @dn) {
+ delete $rm->{join '/', @dn};
+ }
+ unless (%$rm) {
+ close $fh;
+ return;
+ }
}
+ close $fh;
+
my ($r, $p, $bat) = ($self->{r}, $self->{pool}, $self->{bat});
foreach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) {
$self->close_directory($bat->{$d}, $p);