X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-svnimport.perl;h=45b6a1986d1989d372077c5f388010ea988220e6;hb=d44e8cf0298a794648271cbff2f74a0063a672b3;hp=2f89c31e54eac82a4f0fa04c3681a2378dda82d1;hpb=25f6f325d7a8f7cb686a9ffd9fa2c00b3aa85a60;p=git.git diff --git a/git-svnimport.perl b/git-svnimport.perl index 2f89c31e..45b6a198 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -10,7 +10,7 @@ # The head revision is on branch "origin" by default. # You can change that with the '-o' option. -require v5.8.0; # for shell-safe open("-|",LIST) +require 5.008; # for shell-safe open("-|",LIST) use strict; use warnings; use Getopt::Std; @@ -108,7 +108,7 @@ sub conn { sub file { my($self,$path,$rev) = @_; - my ($fh, $name) = tempfile('gitsvn.XXXXXX', + my ($fh, $name) = tempfile('gitsvn.XXXXXX', DIR => File::Spec->tmpdir(), UNLINK => 1); print "... $rev $path ...\n" if $opt_v; @@ -163,9 +163,9 @@ sub getwd() { sub get_headref($$) { my $name = shift; - my $git_dir = shift; + my $git_dir = shift; my $sha; - + if (open(C,"$git_dir/refs/heads/$name")) { chomp($sha = ); close(C); @@ -235,7 +235,7 @@ EOM $forward_master = $opt_o ne 'master' && -f "$git_dir/refs/heads/master" && - system('cmp', '-s', "$git_dir/refs/heads/master", + system('cmp', '-s', "$git_dir/refs/heads/master", "$git_dir/refs/heads/$opt_o") == 0; # populate index @@ -265,11 +265,11 @@ sub get_file($$$) { my $svnpath; $path = "" if $path eq "/"; # this should not happen, but ... if($branch eq "/") { - $svnpath = "/$trunk_name/$path"; + $svnpath = "$trunk_name/$path"; } elsif($branch =~ m#^/#) { - $svnpath = "/$tag_name$branch/$path"; + $svnpath = "$tag_name$branch/$path"; } else { - $svnpath = "/$branch_name/$branch/$path"; + $svnpath = "$branch_name/$branch/$path"; } # now get it @@ -280,13 +280,13 @@ sub get_file($$$) { # /svn/!svn/bc/2/django/trunk/django-docs/build.py my $url=$svn_url->clone(); $url->path($url->path."/!svn/bc/$rev/$svn_dir$svnpath"); - print "Fetching $url...\n" if $opt_v; + print "... $path...\n" if $opt_v; $req = HTTP::Request->new(GET => $url); $res = $lwp_ua->request($req); if ($res->is_success) { my $fh; - ($fh, $name) = tempfile('gitsvn.XXXXXX', - DIR => File::Spec->tmpdir(), UNLINK => 1); + ($fh, $name) = tempfile('gitsvn.XXXXXX', + DIR => File::Spec->tmpdir(), UNLINK => 1); print $fh $res->content; close($fh) or die "Could not write $name: $!\n"; } else { @@ -294,7 +294,7 @@ sub get_file($$$) { die $res->status_line." at $url\n"; } } else { - $name = $svn->file($svnpath,$rev); + $name = $svn->file("/$svnpath",$rev); return undef unless defined $name; } @@ -326,6 +326,36 @@ sub split_path($$) { return ($branch,$path); } +sub copy_subdir($$$$$$) { + # Somebody copied a whole subdirectory. + # We need to find the index entries from the old version which the + # SVN log entry points to, and add them to the new place. + + my($newrev,$newbranch,$path,$oldpath,$rev,$new) = @_; + my($branch,$srcpath) = split_path($rev,$oldpath); + + my $gitrev = $branches{$branch}{$rev}; + unless($gitrev) { + print STDERR "$newrev:$newbranch: could not find $oldpath \@ $rev\n"; + return; + } + print "$newrev:$newbranch:$path: copying from $branch:$srcpath @ $rev\n" if $opt_v; + $srcpath =~ s#/*$#/#; + open my $f,"-|","git-ls-tree","-r","-z",$gitrev,$srcpath; + local $/ = "\0"; + while(<$f>) { + chomp; + my($m,$p) = split(/\t/,$_,2); + my($mode,$type,$sha1) = split(/ /,$m); + next if $type ne "blob"; + $p = substr($p,length($srcpath)-1); + print "... found $path$p ...\n" if $opt_v; + push(@$new,[$mode,$sha1,$path.$p]); + } + close($f) or + print STDERR "$newrev:$newbranch: could not list files in $oldpath \@ $rev\n"; +} + sub commit { my($branch, $changed_paths, $revision, $author, $date, $message) = @_; my($author_name,$author_email,$dest); @@ -420,10 +450,20 @@ sub commit { if($tag and not %$changed_paths) { $cid = $rev; } else { - while(my($path,$action) = each %$changed_paths) { + my @paths = sort keys %$changed_paths; + foreach my $path(@paths) { + my $action = $changed_paths->{$path}; + if ($action->[0] eq "A") { my $f = get_file($revision,$branch,$path); - push(@new,$f) if $f; + if($f) { + push(@new,$f) if $f; + } elsif($action->[1]) { + copy_subdir($revision,$branch,$path,$action->[1],$action->[2],\@new); + } else { + my $opath = $action->[3]; + print STDERR "$revision: $branch: could not fetch '$opath'\n"; + } } elsif ($action->[0] eq "D") { push(@old,$path); } elsif ($action->[0] eq "M") { @@ -434,16 +474,19 @@ sub commit { push(@old,$path); # remove any old stuff # ... and add any new stuff - my($b,$p) = split_path($revision,$action->[1]); - open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->[2]}, $p; - local $/ = '\0'; + my($b,$srcpath) = split_path($revision,$action->[1]); + $srcpath =~ s#/*$#/#; + open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->[2]}, $srcpath; + local $/ = "\0"; while(<$F>) { chomp; my($m,$p) = split(/\t/,$_,2); my($mode,$type,$sha1) = split(/ /,$m); next if $type ne "blob"; - push(@new,[$mode,$sha1,$p]); + $p = substr($p,length($srcpath)-1); + push(@new,[$mode,$sha1,$path.$p]); } + close($F); } else { die "$revision: unknown action '".$action->[0]."' for $path\n"; } @@ -452,7 +495,7 @@ sub commit { if(@old) { open my $F, "-|", "git-ls-files", "-z", @old or die $!; @old = (); - local $/ = '\0'; + local $/ = "\0"; while(<$F>) { chomp; push(@old,$_); @@ -524,7 +567,7 @@ sub commit { push @par, '-p', $mparent; print OUT "Merge parent branch: $mparent\n" if $opt_v; } - } + } } exec("env", @@ -561,7 +604,7 @@ sub commit { print "... no known parent\n" if $opt_v; } elsif(not $tag) { print "Writing to refs/heads/$dest\n" if $opt_v; - open(C,">$git_dir/refs/heads/$dest") and + open(C,">$git_dir/refs/heads/$dest") and print C ("$cid\n") and close(C) or die "Cannot write branch $dest for update: $!\n"; @@ -571,7 +614,7 @@ sub commit { my($in, $out) = ('',''); $last_rev = "-" if %$changed_paths; # the tag was 'complex', i.e. did not refer to a "real" revision - + $dest =~ tr/_/\./ if $opt_u; my $pid = open2($in, $out, 'git-mktag'); @@ -609,7 +652,7 @@ sub _commit_all { ($changed_paths, $revision, $author, $date, $message, $pool) = @_; my %p; while(my($path,$action) = each %$changed_paths) { - $p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev ]; + $p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev, $path ]; } $changed_paths = \%p; } @@ -634,7 +677,8 @@ while(++$current_rev <= $svn->{'maxrev'}) { $svn->{'svn'}->get_log("/",$current_rev,$current_rev,$current_rev,1,1,\&_commit_all,""); commit_all(); if($opt_l and not --$opt_l) { - print STDERR "Exiting due to a memory leak. Repeat, please.\n"; + print STDERR "Stopping, because there is a memory leak (in the SVN library).\n"; + print STDERR "Please repeat this command; it will continue safely\n"; last; } }