From 89764f5d8b0ca8600e3a200e9f863c3c7a3ff5e8 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 11:15:09 +0200 Subject: cvsimport: report merge parents Matching and reporting merge parents happens in a subprocess. Re-open stdout before redirecting stdout to the pipe, so that printing verbose messages doesn't go to the wrong place. Signed-Off-By: Matthias Urlichs diff --git a/git-cvsimport.perl b/git-cvsimport.perl index f35c0d0..cc0eed2 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -567,6 +567,7 @@ my $commit = sub { unless($pid) { $pr->writer(); $pw->reader(); + open(OUT,">&STDOUT"); dup2($pw->fileno(),0); dup2($pr->fileno(),1); $pr->close(); @@ -584,10 +585,9 @@ my $commit = sub { if ( -e "$git_dir/refs/heads/$mparent") { $mparent = get_headref($mparent, $git_dir); push @par, '-p', $mparent; - # printing here breaks import # - # # print "Merge parent branch: $mparent\n" if $opt_v; + print OUT "Merge parent branch: $mparent\n" if $opt_v; } - } + } } exec("env", -- cgit v0.10.2-6-g49f6 From eaf718f3ece277462de4e47391e5a965bbbaa297 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 11:40:43 +0200 Subject: New: git-svnimport. As the name suggests, this script imports from SVN. Only "normal" SVN repositories (with single trunk/, branches/, and tags/ subdrectories) are supported. Incremental imports require preserving the file .git/svn2git. Signed-Off-by: Matthias Urlichs diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt new file mode 100644 index 0000000..be03a65 --- /dev/null +++ b/Documentation/git-svnimport.txt @@ -0,0 +1,99 @@ +git-svnimport(1) +================ +v0.1, July 2005 + +NAME +---- +git-svnimport - Import a SVN repository into git + + +SYNOPSIS +-------- +'git-svnimport' [ -o ] [ -h ] [ -v ] + [ -C ] [ -i ] [ -u ] + [ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ] + [ -m ] [ -M regex ] [ ] + + +DESCRIPTION +----------- +Imports a SVN repository into git. It will either create a new +repository, or incrementally import into an existing one. + +SVN access is done by the SVN:: Perl module. + +git-svnimport assumes that SVN repositories are organized into one +"trunk" directory where the main development happens, "branch/FOO" +directories for branches, and "/tags/FOO" directories for tags. +Other subdirectories are ignored. + +git-svnimport creates a file ".git/svn2git", which is required for +incremental SVN imports. + +OPTIONS +------- +-C :: + The GIT repository to import to. If the directory doesn't + exist, it will be created. Default is the current directory. + +-i:: + Import-only: don't perform a checkout after importing. This option + ensures the working directory and cache remain untouched and will + not create them if they do not exist. + +-t :: + Name the SVN trunk. Default "trunk". + +-T :: + Name the SVN subdirectory for tags. Default "tags". + +-b :: + Name the SVN subdirectory for branches. Default "branches". + +-o :: + The 'trunk' branch from SVN is imported to the 'origin' branch within + the git repository. Use this option if you want to import into a + different branch. + +-m:: + Attempt to detect merges based on the commit message. This option + will enable default regexes that try to capture the name source + branch name from the commit message. + +-M :: + Attempt to detect merges based on the commit message with a custom + regex. It can be used with -m to also see the default regexes. + You must escape forward slashes. + +-v:: + Verbosity: let 'svnimport' report what it is doing. + +:: + The URL of the SVN module you want to import. For local + repositories, use "file:///absolute/path". + +-h:: + Print a short usage message and exit. + +OUTPUT +------ +If '-v' is specified, the script reports what it is doing. + +Otherwise, success is indicated the Unix way, i.e. by simply exiting with +a zero exit status. + +Author +------ +Written by Matthias Urlichs , with help from +various participants of the git-list . + +Based on a cvs2git script by the same author. + +Documentation +-------------- +Documentation by Matthias Urlichs . + +GIT +--- +Part of the gitlink:git[7] suite + diff --git a/Makefile b/Makefile index fd4e163..30fda9e 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,8 @@ SCRIPT_SH = \ SCRIPT_PERL = \ git-archimport.perl git-cvsimport.perl git-relink.perl \ - git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl + git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \ + git-svnimport-perl SCRIPT_PYTHON = \ git-merge-recursive.py diff --git a/git-svnimport.perl b/git-svnimport.perl new file mode 100755 index 0000000..08645f7 --- /dev/null +++ b/git-svnimport.perl @@ -0,0 +1,671 @@ +#!/usr/bin/perl -w + +# This tool is copyright (c) 2005, Matthias Urlichs. +# It is released under the Gnu Public License, version 2. +# +# The basic idea is to pull and analyze SVN changes. +# +# Checking out the files is done by a single long-running CVS connection +# / server process. +# +# 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) +use strict; +use warnings; +use Getopt::Std; +use File::Spec; +use File::Temp qw(tempfile); +use File::Path qw(mkpath); +use File::Basename qw(basename dirname); +use Time::Local; +use IO::Pipe; +use POSIX qw(strftime dup2); +use IPC::Open2; +use SVN::Core; +use SVN::Ra; + +$SIG{'PIPE'}="IGNORE"; +$ENV{'TZ'}="UTC"; + +our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b); + +sub usage() { + print STDERR <; + chomp $cvs_tree; + close $f; +} else { + usage(); +} + +our @mergerx = (); +if ($opt_m) { + @mergerx = ( qr/\W(?:from|of|merge|merging|merged) (\w+)/i ); +} +if ($opt_M) { + push (@mergerx, qr/$opt_M/); +} + +select(STDERR); $|=1; select(STDOUT); + + +package SVNconn; +# Basic SVN connection. +# We're only interested in connecting and downloading, so ... + +use File::Spec; +use File::Temp qw(tempfile); +use POSIX qw(strftime dup2); + +sub new { + my($what,$repo) = @_; + $what=ref($what) if ref($what); + + my $self = {}; + $self->{'buffer'} = ""; + bless($self,$what); + + $repo =~ s#/+$##; + $self->{'fullrep'} = $repo; + $self->conn(); + + $self->{'lines'} = undef; + + return $self; +} + +sub conn { + my $self = shift; + my $repo = $self->{'fullrep'}; + my $s = SVN::Ra->new($repo); + + die "SVN connection to $repo: $!\n" unless defined $s; + $self->{'svn'} = $s; + $self->{'repo'} = $repo; + $self->{'maxrev'} = $s->get_latest_revnum(); +} + +sub file { + my($self,$path,$rev) = @_; + my $res; + + my ($fh, $name) = tempfile('gitsvn.XXXXXX', + DIR => File::Spec->tmpdir(), UNLINK => 1); + + $self->{'svn'}->get_file($path,$rev,$fh) or do { + # retry + $self->conn(); + $self->{'svn'}->get_file($path,$rev,$fh) + or die "$rev: No file $path at $rev\n"; + }; + close ($fh); + + return ($name, $res); +} + + +package main; + +my $svn = SVNconn->new($cvs_tree); + + +sub pdate($) { + my($d) = @_; + $d =~ m#(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)# + or die "Unparseable date: $d\n"; + my $y=$1; $y-=1900 if $y>1900; + return timegm($6||0,$5,$4,$3,$2-1,$y); +} + +sub pmode($) { + my($mode) = @_; + my $m = 0; + my $mm = 0; + my $um = 0; + for my $x(split(//,$mode)) { + if($x eq ",") { + $m |= $mm&$um; + $mm = 0; + $um = 0; + } elsif($x eq "u") { $um |= 0700; + } elsif($x eq "g") { $um |= 0070; + } elsif($x eq "o") { $um |= 0007; + } elsif($x eq "r") { $mm |= 0444; + } elsif($x eq "w") { $mm |= 0222; + } elsif($x eq "x") { $mm |= 0111; + } elsif($x eq "=") { # do nothing + } else { die "Unknown mode: $mode\n"; + } + } + $m |= $mm&$um; + return $m; +} + +sub getwd() { + my $pwd = `pwd`; + chomp $pwd; + return $pwd; +} + + +sub get_headref($$) { + my $name = shift; + my $git_dir = shift; + my $sha; + + if (open(C,"$git_dir/refs/heads/$name")) { + chomp($sha = ); + close(C); + length($sha) == 40 + or die "Cannot get head id for $name ($sha): $!\n"; + } + return $sha; +} + + +-d $git_tree + or mkdir($git_tree,0777) + or die "Could not create $git_tree: $!"; +chdir($git_tree); + +my $orig_branch = ""; +my $forward_master = 0; +my %branches; + +my $git_dir = $ENV{"GIT_DIR"} || ".git"; +$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#; +$ENV{"GIT_DIR"} = $git_dir; +my $orig_git_index; +$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE}; +my ($git_ih, $git_index) = tempfile('gitXXXXXX', SUFFIX => '.idx', + DIR => File::Spec->tmpdir()); +close ($git_ih); +$ENV{GIT_INDEX_FILE} = $git_index; +my $maxnum = 0; +my $last_rev = ""; +my $last_branch; +my $current_rev = 0; +unless(-d $git_dir) { + system("git-init-db"); + die "Cannot init the GIT db at $git_tree: $?\n" if $?; + system("git-read-tree"); + die "Cannot init an empty tree: $?\n" if $?; + + $last_branch = $opt_o; + $orig_branch = ""; +} else { + -f "$git_dir/refs/heads/$opt_o" + or die "Branch '$opt_o' does not exist.\n". + "Either use the correct '-o branch' option,\n". + "or import to a new repository.\n"; + + -f "$git_dir/svn2git" + or die "'$git_dir/svn2git' does not exist.\n". + "You need that file for incremental imports.\n"; + $last_branch = basename(readlink("$git_dir/HEAD")); + unless($last_branch) { + warn "Cannot read the last branch name: $! -- assuming 'master'\n"; + $last_branch = "master"; + } + $orig_branch = $last_branch; + $last_rev = get_headref($orig_branch, $git_dir); + if (-f "$git_dir/SVN2GIT_HEAD") { + die <) { + chomp; + my($num,$branch,$ref) = split; + $branches{$branch}{$num} = $ref; + $branches{$branch}{"LAST"} = $ref; + $current_rev = $num+1 if $current_rev < $num+1; + } + close($B); +} +-d $git_dir + or die "Could not create git subdir ($git_dir).\n"; + +open BRANCHES,">>", "$git_dir/svn2git"; + + +## cvsps output: +#--------------------- +#PatchSet 314 +#Date: 1999/09/18 13:03:59 +#Author: wkoch +#Branch: STABLE-BRANCH-1-0 +#Ancestor branch: HEAD +#Tag: (none) +#Log: +# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch +#Members: +# README:1.57->1.57.2.1 +# VERSION:1.96->1.96.2.1 +# +#--------------------- + +my $state = 0; + +sub get_file($$$) { + my($rev,$branch,$path) = @_; + + # revert split_path(), below + my $svnpath; + $path = "" if $path eq "/"; # this should not happen, but ... + if($branch eq "/") { + $svnpath = "/$trunk_name/$path"; + } elsif($branch =~ m#^/#) { + $svnpath = "/$tag_name$branch/$path"; + } else { + $svnpath = "/$branch_name/$branch/$path"; + } + + # now get it + my ($name, $res) = $svn->file($svnpath,$rev); + + open my $F, '-|', "git-hash-object -w $name" + or die "Cannot create object: $!\n"; + my $sha = <$F>; + chomp $sha; + close $F; + # my $mode = pmode($cvs->{'mode'}); + my $mode = "0644"; # SV does not seem to store any file modes + return [$mode, $sha, $path]; +} + +sub split_path($$) { + my($rev,$path) = @_; + my $branch; + + if($path =~ s#^/\Q$tag_name\E/([^/]+)/?##) { + $branch = "/$1"; + } elsif($path =~ s#^/\Q$trunk_name\E/?##) { + $branch = "/"; + } elsif($path =~ s#^/\Q$branch_name\E/([^/]+)/?##) { + $branch = $1; + } else { + print STDERR "$rev: Unrecognized path: $path\n"; + return () + } + $path = "/" if $path eq ""; + return ($branch,$path); +} + +sub commit { + my($branch, $changed_paths, $revision, $author, $date, $message) = @_; + my($author_name,$author_email,$dest); + my(@old,@new); + + if ($author =~ /^(.*?)\s+<(.*)>$/) { + ($author_name, $author_email) = ($1, $2); + } else { + $author =~ s/^<(.*)>$/$1/; + $author_name = $author_email = $author; + } + $date = pdate($date); + + my $tag; + my $parent; + if($branch eq "/") { # trunk + $parent = $opt_o; + } elsif($branch =~ m#^/(.+)#) { # tag + $tag = 1; + $parent = $1; + } else { # "normal" branch + # nothing to do + $parent = $branch; + } + $dest = $parent; + + my $prev = $changed_paths->{"/"}; + if($prev and $prev->action eq "A") { + delete $changed_paths->{"/"}; + my $oldpath = $prev->copyfrom_path; + my $rev; + if(defined $oldpath) { + my $p; + ($parent,$p) = split_path($revision,$oldpath); + if($parent eq "/") { + $parent = $opt_o; + } else { + $parent =~ s#^/##; # if it's a tag + } + } else { + $parent = undef; + } + } + + my $rev; + if(defined $parent) { + open(H,"git-rev-parse --verify $parent |"); + $rev = ; + close(H) or do { + print STDERR "$revision: cannot find commit '$parent'!\n"; + return; + }; + chop $rev; + if(length($rev) != 40) { + print STDERR "$revision: cannot find commit '$parent'!\n"; + return; + } + $rev = $branches{($parent eq $opt_o) ? "/" : $parent}{"LAST"}; + if($revision != 1 and not $rev) { + print STDERR "$revision: do not know ancestor for '$parent'!\n"; + return; + } + } else { + $rev = undef; + } + +# if($prev and $prev->action eq "A") { +# if(not $tag) { +# unless(open(H,"> $git_dir/refs/heads/$branch")) { +# print STDERR "$revision: Could not create branch $branch: $!\n"; +# $state=11; +# next; +# } +# print H "$rev\n" +# or die "Could not write branch $branch: $!"; +# close(H) +# or die "Could not write branch $branch: $!"; +# } +# } + if(not defined $rev) { + unlink($git_index); + } elsif ($rev ne $last_rev) { + print "Switching from $last_rev to $rev ($branch)\n" if $opt_v; + system("git-read-tree", $rev); + die "read-tree failed for $rev: $?\n" if $?; + $last_rev = $rev; + } + + while(my($path,$action) = each %$changed_paths) { + if ($action->action eq "A") { + my $f = get_file($revision,$branch,$path); + push(@new,$f) if $f; + } elsif ($action->action eq "D") { + push(@old,$path); + } elsif ($action->action eq "M") { + my $f = get_file($revision,$branch,$path); + push(@new,$f) if $f; + } elsif ($action->action eq "R") { + # refer to a file/tree in an earlier commit + push(@old,$path); # remove any old stuff + + # ... and add any new stuff + my($b,$p) = split_path($revision,$action->oldpath); + open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->oldrev}, $p; + 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]); + } + } else { + die "$revision: unknown action '".$action->action."' for $path\n"; + } + } + + if(@old) { + open F, "-│", "git-ls-files", "-z", @old or die $!; + @old = (); + local $/ = '\0'; + while() { + chomp; + push(@old,$_); + } + close(F); + + while(@old) { + my @o2; + if(@old > 55) { + @o2 = splice(@old,0,50); + } else { + @o2 = @old; + @old = (); + } + system("git-update-index","--force-remove","--",@o2); + die "Cannot remove files: $?\n" if $?; + } + } + while(@new) { + my @n2; + if(@new > 12) { + @n2 = splice(@new,0,10); + } else { + @n2 = @new; + @new = (); + } + system("git-update-index","--add", + (map { ('--cacheinfo', @$_) } @n2)); + die "Cannot add files: $?\n" if $?; + } + + my $pid = open(C,"-|"); + die "Cannot fork: $!" unless defined $pid; + unless($pid) { + exec("git-write-tree"); + die "Cannot exec git-write-tree: $!\n"; + } + chomp(my $tree = ); + length($tree) == 40 + or die "Cannot get tree id ($tree): $!\n"; + close(C) + or die "Error running git-write-tree: $?\n"; + print "Tree ID $tree\n" if $opt_v; + + my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n"; + my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n"; + $pid = fork(); + die "Fork: $!\n" unless defined $pid; + unless($pid) { + $pr->writer(); + $pw->reader(); + open(OUT,">&STDOUT"); + dup2($pw->fileno(),0); + dup2($pr->fileno(),1); + $pr->close(); + $pw->close(); + + my @par = (); + @par = ("-p",$rev) if defined $rev; + + # loose detection of merges + # based on the commit msg + foreach my $rx (@mergerx) { + if ($message =~ $rx) { + my $mparent = $1; + if ($mparent eq 'HEAD') { $mparent = $opt_o }; + if ( -e "$git_dir/refs/heads/$mparent") { + $mparent = get_headref($mparent, $git_dir); + push @par, '-p', $mparent; + print OUT "Merge parent branch: $mparent\n" if $opt_v; + } + } + } + + exec("env", + "GIT_AUTHOR_NAME=$author_name", + "GIT_AUTHOR_EMAIL=$author_email", + "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), + "GIT_COMMITTER_NAME=$author_name", + "GIT_COMMITTER_EMAIL=$author_email", + "GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), + "git-commit-tree", $tree,@par); + die "Cannot exec git-commit-tree: $!\n"; + } + $pw->writer(); + $pr->reader(); + + $message =~ s/[\s\n]+\z//; + + print $pw "$message\n" + or die "Error writing to git-commit-tree: $!\n"; + $pw->close(); + + print "Committed change $revision:$branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v; + chomp(my $cid = <$pr>); + length($cid) == 40 + or die "Cannot get commit id ($cid): $!\n"; + print "Commit ID $cid\n" if $opt_v; + $pr->close(); + + waitpid($pid,0); + die "Error running git-commit-tree: $?\n" if $?; + + if(defined $dest) { + print "Writing to refs/heads/$dest\n" if $opt_v; + open(C,">$git_dir/refs/heads/$dest") and + print C ("$cid\n") and + close(C) + or die "Cannot write branch $dest for update: $!\n"; + } else { + print "... no known parent\n" if $opt_v; + } + $branches{$branch}{"LAST"} = $cid; + $branches{$branch}{$revision} = $cid; + $last_rev = $cid; + print BRANCHES "$revision $branch $cid\n"; + print "DONE: $revision $dest $cid\n" if $opt_v; + + if($tag) { + my($in, $out) = ('',''); + $last_rev = "-" if %$changed_paths; + # the tag was 'complex', i.e. did not refer to a "real" revision + + $tag =~ tr/_/\./ if $opt_u; + + my $pid = open2($in, $out, 'git-mktag'); + print $out ("object $cid\n". + "type commit\n". + "tag $tag\n". + "tagger $author_name <$author_email>\n") and + close($out) + or die "Cannot create tag object $tag: $!\n"; + + my $tagobj = <$in>; + chomp $tagobj; + + if ( !close($in) or waitpid($pid, 0) != $pid or + $? != 0 or $tagobj !~ /^[0123456789abcdef]{40}$/ ) { + die "Cannot create tag object $tag: $!\n"; + } + + + open(C,">$git_dir/refs/tags/$tag") + or die "Cannot create tag $tag: $!\n"; + print C "$tagobj\n" + or die "Cannot write tag $tag: $!\n"; + close(C) + or die "Cannot write tag $tag: $!\n"; + + print "Created tag '$tag' on '$branch'\n" if $opt_v; + } +} + +my ($changed_paths, $revision, $author, $date, $message, $pool) = @_; +sub _commit_all { + ($changed_paths, $revision, $author, $date, $message, $pool) = @_; +} +sub commit_all { + my %done; + my @col; + my $pref; + my $branch; + + while(my($path,$action) = each %$changed_paths) { + ($branch,$path) = split_path($revision,$path); + next if not defined $branch; + $done{$branch}{$path} = $action; + } + while(($branch,$changed_paths) = each %done) { + commit($branch, $changed_paths, $revision, $author, $date, $message); + } +} + +while(++$current_rev < $svn->{'maxrev'}) { + $svn->{'svn'}->get_log("/",$current_rev,$current_rev,$current_rev,1,1,\&_commit_all,""); + commit_all(); +} + + +unlink($git_index); + +if (defined $orig_git_index) { + $ENV{GIT_INDEX_FILE} = $orig_git_index; +} else { + delete $ENV{GIT_INDEX_FILE}; +} + +# Now switch back to the branch we were in before all of this happened +if($orig_branch) { + print "DONE\n" if $opt_v; + system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") + if $forward_master; + unless ($opt_i) { + system('git-read-tree', '-m', '-u', 'SVN2GIT_HEAD', 'HEAD'); + die "read-tree failed: $?\n" if $?; + } +} else { + $orig_branch = "master"; + print "DONE; creating $orig_branch branch\n" if $opt_v; + system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") + unless -f "$git_dir/refs/heads/master"; + unlink("$git_dir/HEAD"); + symlink("refs/heads/$orig_branch","$git_dir/HEAD"); + unless ($opt_i) { + system('git checkout'); + die "checkout failed: $?\n" if $?; + } +} +unlink("$git_dir/SVN2GIT_HEAD"); +close(BRANCHES); -- cgit v0.10.2-6-g49f6 From 2b5e63d1b4a6f1b0ef58755a192ecb2d04e3569d Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 12:33:22 +0200 Subject: svn import: add eval() Trying to downlaod a file that's really a subdirectory doesn't work too well. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 08645f7..920b23e 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -121,12 +121,15 @@ sub file { my ($fh, $name) = tempfile('gitsvn.XXXXXX', DIR => File::Spec->tmpdir(), UNLINK => 1); - $self->{'svn'}->get_file($path,$rev,$fh) or do { + print "... $rev $path ...\n" if $opt_v; + eval { $self->{'svn'}->get_file($path,$rev,$fh); }; + if (defined $@ and $@ !~ /Attempted to get checksum/) { # retry $self->conn(); - $self->{'svn'}->get_file($path,$rev,$fh) - or die "$rev: No file $path at $rev\n"; + eval { $self->{'svn'}->get_file($path,$rev,$fh); }; }; + return () if defined $@ and $@ !~ /Attempted to get checksum/; + die $@ if $@; close ($fh); return ($name, $res); @@ -308,7 +311,8 @@ sub get_file($$$) { } # now get it - my ($name, $res) = $svn->file($svnpath,$rev); + my ($name, $res) = eval { $svn->file($svnpath,$rev); }; + return () unless defined $name; open my $F, '-|', "git-hash-object -w $name" or die "Cannot create object: $!\n"; @@ -343,7 +347,9 @@ sub commit { my($author_name,$author_email,$dest); my(@old,@new); - if ($author =~ /^(.*?)\s+<(.*)>$/) { + if (not defined $author) { + $author_name = $author_email = "unknown"; + } elsif ($author =~ /^(.*?)\s+<(.*)>$/) { ($author_name, $author_email) = ($1, $2); } else { $author =~ s/^<(.*)>$/$1/; -- cgit v0.10.2-6-g49f6 From c015bf2bcbdc2021410753b4a024dd35dfef6a33 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 12:34:32 +0200 Subject: SVN import: No modes svn doesn't seem to save file modes: removed the code that analyzes them. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 920b23e..27d964c 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -149,30 +149,6 @@ sub pdate($) { return timegm($6||0,$5,$4,$3,$2-1,$y); } -sub pmode($) { - my($mode) = @_; - my $m = 0; - my $mm = 0; - my $um = 0; - for my $x(split(//,$mode)) { - if($x eq ",") { - $m |= $mm&$um; - $mm = 0; - $um = 0; - } elsif($x eq "u") { $um |= 0700; - } elsif($x eq "g") { $um |= 0070; - } elsif($x eq "o") { $um |= 0007; - } elsif($x eq "r") { $mm |= 0444; - } elsif($x eq "w") { $mm |= 0222; - } elsif($x eq "x") { $mm |= 0111; - } elsif($x eq "=") { # do nothing - } else { die "Unknown mode: $mode\n"; - } - } - $m |= $mm&$um; - return $m; -} - sub getwd() { my $pwd = `pwd`; chomp $pwd; @@ -319,7 +295,6 @@ sub get_file($$$) { my $sha = <$F>; chomp $sha; close $F; - # my $mode = pmode($cvs->{'mode'}); my $mode = "0644"; # SV does not seem to store any file modes return [$mode, $sha, $path]; } -- cgit v0.10.2-6-g49f6 From f0daa628a297819ed039e6b61d337fde02d8a6dd Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 12:41:15 +0200 Subject: svn import: copy path information Due to a bug in the SVN library, path information is freed as soon as the callback returns, even if it still refers to the data. Workaround: Copy it. (Also fix a wrong-method-name bug while we're at it.) Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 27d964c..3844cc5 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -346,9 +346,9 @@ sub commit { $dest = $parent; my $prev = $changed_paths->{"/"}; - if($prev and $prev->action eq "A") { + if($prev and $prev->[0] eq "A") { delete $changed_paths->{"/"}; - my $oldpath = $prev->copyfrom_path; + my $oldpath = $prev->[1]; my $rev; if(defined $oldpath) { my $p; @@ -385,7 +385,7 @@ sub commit { $rev = undef; } -# if($prev and $prev->action eq "A") { +# if($prev and $prev->[0] eq "A") { # if(not $tag) { # unless(open(H,"> $git_dir/refs/heads/$branch")) { # print STDERR "$revision: Could not create branch $branch: $!\n"; @@ -408,21 +408,21 @@ sub commit { } while(my($path,$action) = each %$changed_paths) { - if ($action->action eq "A") { + if ($action->[0] eq "A") { my $f = get_file($revision,$branch,$path); push(@new,$f) if $f; - } elsif ($action->action eq "D") { + } elsif ($action->[0] eq "D") { push(@old,$path); - } elsif ($action->action eq "M") { + } elsif ($action->[0] eq "M") { my $f = get_file($revision,$branch,$path); push(@new,$f) if $f; - } elsif ($action->action eq "R") { + } elsif ($action->[0] eq "R") { # refer to a file/tree in an earlier commit push(@old,$path); # remove any old stuff # ... and add any new stuff - my($b,$p) = split_path($revision,$action->oldpath); - open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->oldrev}, $p; + my($b,$p) = split_path($revision,$action->[1]); + open my $F,"-|","git-ls-tree","-r","-z", $branches{$b}{$action->[2]}, $p; local $/ = '\0'; while(<$F>) { chomp; @@ -432,7 +432,7 @@ sub commit { push(@new,[$mode,$sha1,$p]); } } else { - die "$revision: unknown action '".$action->action."' for $path\n"; + die "$revision: unknown action '".$action->[0]."' for $path\n"; } } @@ -596,7 +596,13 @@ sub commit { my ($changed_paths, $revision, $author, $date, $message, $pool) = @_; 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 ]; + } + $changed_paths = \%p; } + sub commit_all { my %done; my @col; -- cgit v0.10.2-6-g49f6 From 6d281217b930466717d0078285e5431c409b7aec Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 12:45:46 +0200 Subject: svn import: fixed two pipe open calls. Perl's magic "different semantics of open() based on the number of arguments" is really annoying at times... Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 3844cc5..415b50b 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -290,7 +290,7 @@ sub get_file($$$) { my ($name, $res) = eval { $svn->file($svnpath,$rev); }; return () unless defined $name; - open my $F, '-|', "git-hash-object -w $name" + open my $F, '-|', "git-hash-object", "-w", $name or die "Cannot create object: $!\n"; my $sha = <$F>; chomp $sha; @@ -437,14 +437,14 @@ sub commit { } if(@old) { - open F, "-│", "git-ls-files", "-z", @old or die $!; + open my $F, "-│", "git-ls-files", "-z", @old or die $!; @old = (); local $/ = '\0'; - while() { + while(<$F>) { chomp; push(@old,$_); } - close(F); + close($F); while(@old) { my @o2; -- cgit v0.10.2-6-g49f6 From c6582aba5230301fe826c06d1891a4a8a9d32074 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 13:10:01 +0200 Subject: svn import: add libsvn-core-perl to Debian's control file Added libsvn-core-perl to debian/control, "Recommends:" section. Signed-Off-By: Matthias Urlichs diff --git a/debian/control b/debian/control index 5d75c32..0ec8933 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,7 @@ Standards-Version: 3.6.1 Package: git-core Architecture: any Depends: ${shlibs:Depends}, ${perl:Depends}, ${misc:Depends}, patch, rcs -Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, python (>= 2.4.0), less +Recommends: rsync, curl, ssh, libmail-sendmail-perl, libemail-valid-perl, libsvn-core-perl (>= 1.2.1), python (>= 2.4.0), less Suggests: cogito Conflicts: git, cogito (<< 0.13) Description: The git content addressable filesystem -- cgit v0.10.2-6-g49f6 From 37dcf6de60498dfedb5d97ad96789b0527493bcd Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 13:42:48 +0200 Subject: svn improt needs SVN::Core 1.2.1 or better Die with a warning if Perl's svn module is too old. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 415b50b..ef73f36 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -26,6 +26,8 @@ use IPC::Open2; use SVN::Core; use SVN::Ra; +die "Need CVN:COre 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; + $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -- cgit v0.10.2-6-g49f6 From 8cd4177d5ef651c8acb9c1f113a076e6fae2e1c2 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 14:14:44 +0200 Subject: svn import: avoid reconnecting Perl's eval() sets $@ to empts, not undef, when it succeeds. That caused excessive reconnect attempts. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index ef73f36..ba9f818 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -100,8 +100,6 @@ sub new { $self->{'fullrep'} = $repo; $self->conn(); - $self->{'lines'} = undef; - return $self; } @@ -112,6 +110,7 @@ sub conn { die "SVN connection to $repo: $!\n" unless defined $s; $self->{'svn'} = $s; + print STDERR "*** SVN *** $s ***\n"; $self->{'repo'} = $repo; $self->{'maxrev'} = $s->get_latest_revnum(); } @@ -124,13 +123,15 @@ sub file { DIR => File::Spec->tmpdir(), UNLINK => 1); print "... $rev $path ...\n" if $opt_v; - eval { $self->{'svn'}->get_file($path,$rev,$fh); }; - if (defined $@ and $@ !~ /Attempted to get checksum/) { + my $s = $self->{'svn'}; + print STDERR "*** GET *** $s ***\n"; + eval { $s->get_file($path,$rev,$fh); }; + if ($@ and $@ !~ /Attempted to get checksum/) { # retry $self->conn(); eval { $self->{'svn'}->get_file($path,$rev,$fh); }; }; - return () if defined $@ and $@ !~ /Attempted to get checksum/; + return () if $@ and $@ !~ /Attempted to get checksum/; die $@ if $@; close ($fh); -- cgit v0.10.2-6-g49f6 From c7ff5f1d7d6f103802fd6d6b1d4dcdf095e95d5f Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 14:18:38 +0200 Subject: svn import: wrong file open mode There are multiple | characters in Unicode. Don't use the wrong one ... Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index ba9f818..2686f4a 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -440,7 +440,7 @@ sub commit { } if(@old) { - open my $F, "-│", "git-ls-files", "-z", @old or die $!; + open my $F, "-|", "git-ls-files", "-z", @old or die $!; @old = (); local $/ = '\0'; while(<$F>) { -- cgit v0.10.2-6-g49f6 From 62d72e4b707d6931787e91f611ed49aaabb14391 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 14:19:15 +0200 Subject: svn import: remove debugging Removed debugging output used to identify the too-many-connections problem. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 2686f4a..f7bf616 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -110,7 +110,6 @@ sub conn { die "SVN connection to $repo: $!\n" unless defined $s; $self->{'svn'} = $s; - print STDERR "*** SVN *** $s ***\n"; $self->{'repo'} = $repo; $self->{'maxrev'} = $s->get_latest_revnum(); } @@ -124,7 +123,6 @@ sub file { print "... $rev $path ...\n" if $opt_v; my $s = $self->{'svn'}; - print STDERR "*** GET *** $s ***\n"; eval { $s->get_file($path,$rev,$fh); }; if ($@ and $@ !~ /Attempted to get checksum/) { # retry -- cgit v0.10.2-6-g49f6 From f02b3eba7fc6e3fca25e0063dde6ff149aed2b45 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 14:42:59 +0200 Subject: svn import: Fix tagging. Tagging was 100% broken. :-/ Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index f7bf616..f977ed2 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -122,8 +122,7 @@ sub file { DIR => File::Spec->tmpdir(), UNLINK => 1); print "... $rev $path ...\n" if $opt_v; - my $s = $self->{'svn'}; - eval { $s->get_file($path,$rev,$fh); }; + eval { $self->{'svn'}->get_file($path,$rev,$fh); }; if ($@ and $@ !~ /Attempted to get checksum/) { # retry $self->conn(); @@ -544,14 +543,14 @@ sub commit { waitpid($pid,0); die "Error running git-commit-tree: $?\n" if $?; - if(defined $dest) { + if(not defined $dest) { + 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 print C ("$cid\n") and close(C) or die "Cannot write branch $dest for update: $!\n"; - } else { - print "... no known parent\n" if $opt_v; } $branches{$branch}{"LAST"} = $cid; $branches{$branch}{$revision} = $cid; @@ -564,33 +563,30 @@ sub commit { $last_rev = "-" if %$changed_paths; # the tag was 'complex', i.e. did not refer to a "real" revision - $tag =~ tr/_/\./ if $opt_u; + $dest =~ tr/_/\./ if $opt_u; my $pid = open2($in, $out, 'git-mktag'); print $out ("object $cid\n". "type commit\n". - "tag $tag\n". + "tag $dest\n". "tagger $author_name <$author_email>\n") and close($out) - or die "Cannot create tag object $tag: $!\n"; + or die "Cannot create tag object $dest: $!\n"; my $tagobj = <$in>; chomp $tagobj; if ( !close($in) or waitpid($pid, 0) != $pid or $? != 0 or $tagobj !~ /^[0123456789abcdef]{40}$/ ) { - die "Cannot create tag object $tag: $!\n"; + die "Cannot create tag object $dest: $!\n"; } - - open(C,">$git_dir/refs/tags/$tag") - or die "Cannot create tag $tag: $!\n"; - print C "$tagobj\n" - or die "Cannot write tag $tag: $!\n"; + open(C,">$git_dir/refs/tags/$dest") and + print C ("$tagobj\n") and close(C) - or die "Cannot write tag $tag: $!\n"; + or die "Cannot create tag $branch: $!\n"; - print "Created tag '$tag' on '$branch'\n" if $opt_v; + print "Created tag '$dest' on '$branch'\n" if $opt_v; } } -- cgit v0.10.2-6-g49f6 From bf267d99e88410a31452d4d1ccae0b9b4432b11e Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 14:51:13 +0200 Subject: svn import: Do not create empty tags If a tag is "clean", do not create a commit for it. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index f977ed2..10ffb54 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -407,141 +407,146 @@ sub commit { $last_rev = $rev; } - while(my($path,$action) = each %$changed_paths) { - if ($action->[0] eq "A") { - my $f = get_file($revision,$branch,$path); - push(@new,$f) if $f; - } elsif ($action->[0] eq "D") { - push(@old,$path); - } elsif ($action->[0] eq "M") { - my $f = get_file($revision,$branch,$path); - push(@new,$f) if $f; - } elsif ($action->[0] eq "R") { - # refer to a file/tree in an earlier 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; + my $cid; + if($tag and not %$changed_paths) { + $cid = $rev; + } else { + while(my($path,$action) = each %$changed_paths) { + if ($action->[0] eq "A") { + my $f = get_file($revision,$branch,$path); + push(@new,$f) if $f; + } elsif ($action->[0] eq "D") { + push(@old,$path); + } elsif ($action->[0] eq "M") { + my $f = get_file($revision,$branch,$path); + push(@new,$f) if $f; + } elsif ($action->[0] eq "R") { + # refer to a file/tree in an earlier 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'; + 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]); + } + } else { + die "$revision: unknown action '".$action->[0]."' for $path\n"; + } + } + + if(@old) { + open my $F, "-|", "git-ls-files", "-z", @old or die $!; + @old = (); 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]); + push(@old,$_); + } + close($F); + + while(@old) { + my @o2; + if(@old > 55) { + @o2 = splice(@old,0,50); + } else { + @o2 = @old; + @old = (); + } + system("git-update-index","--force-remove","--",@o2); + die "Cannot remove files: $?\n" if $?; } - } else { - die "$revision: unknown action '".$action->[0]."' for $path\n"; - } - } - - if(@old) { - open my $F, "-|", "git-ls-files", "-z", @old or die $!; - @old = (); - local $/ = '\0'; - while(<$F>) { - chomp; - push(@old,$_); } - close($F); - - while(@old) { - my @o2; - if(@old > 55) { - @o2 = splice(@old,0,50); + while(@new) { + my @n2; + if(@new > 12) { + @n2 = splice(@new,0,10); } else { - @o2 = @old; - @old = (); + @n2 = @new; + @new = (); } - system("git-update-index","--force-remove","--",@o2); - die "Cannot remove files: $?\n" if $?; - } - } - while(@new) { - my @n2; - if(@new > 12) { - @n2 = splice(@new,0,10); - } else { - @n2 = @new; - @new = (); + system("git-update-index","--add", + (map { ('--cacheinfo', @$_) } @n2)); + die "Cannot add files: $?\n" if $?; } - system("git-update-index","--add", - (map { ('--cacheinfo', @$_) } @n2)); - die "Cannot add files: $?\n" if $?; - } - - my $pid = open(C,"-|"); - die "Cannot fork: $!" unless defined $pid; - unless($pid) { - exec("git-write-tree"); - die "Cannot exec git-write-tree: $!\n"; - } - chomp(my $tree = ); - length($tree) == 40 - or die "Cannot get tree id ($tree): $!\n"; - close(C) - or die "Error running git-write-tree: $?\n"; - print "Tree ID $tree\n" if $opt_v; - - my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n"; - my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n"; - $pid = fork(); - die "Fork: $!\n" unless defined $pid; - unless($pid) { - $pr->writer(); - $pw->reader(); - open(OUT,">&STDOUT"); - dup2($pw->fileno(),0); - dup2($pr->fileno(),1); - $pr->close(); - $pw->close(); - my @par = (); - @par = ("-p",$rev) if defined $rev; - - # loose detection of merges - # based on the commit msg - foreach my $rx (@mergerx) { - if ($message =~ $rx) { - my $mparent = $1; - if ($mparent eq 'HEAD') { $mparent = $opt_o }; - if ( -e "$git_dir/refs/heads/$mparent") { - $mparent = get_headref($mparent, $git_dir); - push @par, '-p', $mparent; - print OUT "Merge parent branch: $mparent\n" if $opt_v; - } - } + my $pid = open(C,"-|"); + die "Cannot fork: $!" unless defined $pid; + unless($pid) { + exec("git-write-tree"); + die "Cannot exec git-write-tree: $!\n"; } + chomp(my $tree = ); + length($tree) == 40 + or die "Cannot get tree id ($tree): $!\n"; + close(C) + or die "Error running git-write-tree: $?\n"; + print "Tree ID $tree\n" if $opt_v; + + my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n"; + my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n"; + $pid = fork(); + die "Fork: $!\n" unless defined $pid; + unless($pid) { + $pr->writer(); + $pw->reader(); + open(OUT,">&STDOUT"); + dup2($pw->fileno(),0); + dup2($pr->fileno(),1); + $pr->close(); + $pw->close(); + + my @par = (); + @par = ("-p",$rev) if defined $rev; + + # loose detection of merges + # based on the commit msg + foreach my $rx (@mergerx) { + if ($message =~ $rx) { + my $mparent = $1; + if ($mparent eq 'HEAD') { $mparent = $opt_o }; + if ( -e "$git_dir/refs/heads/$mparent") { + $mparent = get_headref($mparent, $git_dir); + push @par, '-p', $mparent; + print OUT "Merge parent branch: $mparent\n" if $opt_v; + } + } + } - exec("env", - "GIT_AUTHOR_NAME=$author_name", - "GIT_AUTHOR_EMAIL=$author_email", - "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), - "GIT_COMMITTER_NAME=$author_name", - "GIT_COMMITTER_EMAIL=$author_email", - "GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), - "git-commit-tree", $tree,@par); - die "Cannot exec git-commit-tree: $!\n"; - } - $pw->writer(); - $pr->reader(); + exec("env", + "GIT_AUTHOR_NAME=$author_name", + "GIT_AUTHOR_EMAIL=$author_email", + "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), + "GIT_COMMITTER_NAME=$author_name", + "GIT_COMMITTER_EMAIL=$author_email", + "GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), + "git-commit-tree", $tree,@par); + die "Cannot exec git-commit-tree: $!\n"; + } + $pw->writer(); + $pr->reader(); - $message =~ s/[\s\n]+\z//; + $message =~ s/[\s\n]+\z//; - print $pw "$message\n" - or die "Error writing to git-commit-tree: $!\n"; - $pw->close(); + print $pw "$message\n" + or die "Error writing to git-commit-tree: $!\n"; + $pw->close(); - print "Committed change $revision:$branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v; - chomp(my $cid = <$pr>); - length($cid) == 40 - or die "Cannot get commit id ($cid): $!\n"; - print "Commit ID $cid\n" if $opt_v; - $pr->close(); + print "Committed change $revision:$branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v; + chomp($cid = <$pr>); + length($cid) == 40 + or die "Cannot get commit id ($cid): $!\n"; + print "Commit ID $cid\n" if $opt_v; + $pr->close(); - waitpid($pid,0); - die "Error running git-commit-tree: $?\n" if $?; + waitpid($pid,0); + die "Error running git-commit-tree: $?\n" if $?; + } if(not defined $dest) { print "... no known parent\n" if $opt_v; -- cgit v0.10.2-6-g49f6 From 7ee74a99b2b710b5f5adc22db2fe0aca8a74c809 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 15:14:21 +0200 Subject: svn import: skip initial revisions Add a flag to skip initial revisions: some SVN repositories have initial setup cruft in their logs which we might want to ignore. Signed-Off-By: Matthias Urlichs diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index be03a65..a144c6c 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -12,7 +12,7 @@ SYNOPSIS 'git-svnimport' [ -o ] [ -h ] [ -v ] [ -C ] [ -i ] [ -u ] [ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ] - [ -m ] [ -M regex ] [ ] + [ -s start_chg ] [ -m ] [ -M regex ] [ ] DESCRIPTION @@ -36,6 +36,11 @@ OPTIONS The GIT repository to import to. If the directory doesn't exist, it will be created. Default is the current directory. +-s :: + Start importing at this SVN change number. The default is 1. ++ +When importing incementally, you might need to edit the .git/svn2git file. + -i:: Import-only: don't perform a checkout after importing. This option ensures the working directory and cache remain untouched and will diff --git a/git-svnimport.perl b/git-svnimport.perl index 10ffb54..896222b 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -31,19 +31,19 @@ die "Need CVN:COre 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b); +our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s); sub usage() { print STDERR < $opt_s and defined $parent) { open(H,"git-rev-parse --verify $parent |"); $rev = ; close(H) or do { @@ -377,7 +377,7 @@ sub commit { return; } $rev = $branches{($parent eq $opt_o) ? "/" : $parent}{"LAST"}; - if($revision != 1 and not $rev) { + if($revision != $opt_s and not $rev) { print STDERR "$revision: do not know ancestor for '$parent'!\n"; return; } -- cgit v0.10.2-6-g49f6 From e7e477dfacecaf362f08a65644d806da5231a9f0 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 15:28:00 +0200 Subject: svn import: incremental imports Incremental imports skipped a revision. Also improve interrupt safety -- ^C while writing a tag caused the tag to be skipped. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 896222b..00f563d 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -244,7 +244,7 @@ EOM my($num,$branch,$ref) = split; $branches{$branch}{$num} = $ref; $branches{$branch}{"LAST"} = $ref; - $current_rev = $num+1 if $current_rev < $num+1; + $current_rev = $num if $current_rev < $num; } close($B); } @@ -557,11 +557,6 @@ sub commit { close(C) or die "Cannot write branch $dest for update: $!\n"; } - $branches{$branch}{"LAST"} = $cid; - $branches{$branch}{$revision} = $cid; - $last_rev = $cid; - print BRANCHES "$revision $branch $cid\n"; - print "DONE: $revision $dest $cid\n" if $opt_v; if($tag) { my($in, $out) = ('',''); @@ -593,6 +588,11 @@ sub commit { print "Created tag '$dest' on '$branch'\n" if $opt_v; } + $branches{$branch}{"LAST"} = $cid; + $branches{$branch}{$revision} = $cid; + $last_rev = $cid; + print BRANCHES "$revision $branch $cid\n"; + print "DONE: $revision $dest $cid\n" if $opt_v; } my ($changed_paths, $revision, $author, $date, $message, $pool) = @_; -- cgit v0.10.2-6-g49f6 From 3ef378a67b5b39441837700ab4dfb800eb443c5a Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 18:45:00 +0200 Subject: svn import: Add a loop limit option The svn library has a serious memory leak. Added a new option (-l NUM) which causes git-svnimport to exit cleanly after fetching that many changes, in order to . Signed-Off-By: Matthias Urlichs diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index a144c6c..047f8f3 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -10,7 +10,7 @@ git-svnimport - Import a SVN repository into git SYNOPSIS -------- 'git-svnimport' [ -o ] [ -h ] [ -v ] - [ -C ] [ -i ] [ -u ] + [ -C ] [ -i ] [ -u ] [-l limit_nr_changes] [ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ] [ -s start_chg ] [ -m ] [ -M regex ] [ ] @@ -70,6 +70,15 @@ When importing incementally, you might need to edit the .git/svn2git file. regex. It can be used with -m to also see the default regexes. You must escape forward slashes. +-l :: + Limit the number of SVN changesets we pull before quitting. + This option is necessary because the SVN library has serious memory + leaks; the recommended value for nontrivial imports is 100. + + git-svnimport will still exit with a zero exit code. You can check + the size of the file ".git/svn2git" to determine whether to call + the importer again. + -v:: Verbosity: let 'svnimport' report what it is doing. diff --git a/git-svnimport.perl b/git-svnimport.perl index 00f563d..b880297 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -31,19 +31,19 @@ die "Need CVN:COre 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s); +our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s,$opt_l); sub usage() { print STDERR <{'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"; + last; + } } @@ -637,7 +642,7 @@ if (defined $orig_git_index) { # Now switch back to the branch we were in before all of this happened if($orig_branch) { - print "DONE\n" if $opt_v; + print "DONE\n" if $opt_v and (not defined $opt_l or $opt_l > 0); system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") if $forward_master; unless ($opt_i) { @@ -646,7 +651,7 @@ if($orig_branch) { } } else { $orig_branch = "master"; - print "DONE; creating $orig_branch branch\n" if $opt_v; + print "DONE; creating $orig_branch branch\n" if $opt_v and (not defined $opt_l or $opt_l > 0); system("cp","$git_dir/refs/heads/$opt_o","$git_dir/refs/heads/master") unless -f "$git_dir/refs/heads/master"; unlink("$git_dir/HEAD"); -- cgit v0.10.2-6-g49f6 From 22dcbb75129b3124a9fd71ed449030b79093b634 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 18:54:53 +0200 Subject: svn import: unlink downlaoded files Actually removing the files that have been checked out of SVN, after checking them into git of course, is a good idea... Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index b880297..102fa6e 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -296,6 +296,7 @@ sub get_file($$$) { my $sha = <$F>; chomp $sha; close $F; + unlink $name; my $mode = "0644"; # SV does not seem to store any file modes return [$mode, $sha, $path]; } -- cgit v0.10.2-6-g49f6 From 8470b7f3a3cd5a70ff0b05486e335d351843890f Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Mon, 10 Oct 2005 20:10:48 +0200 Subject: svn import: get all revisions Not skipping the last revision is generally seen as Good Thing. ;-) Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 102fa6e..f9318c8 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -623,7 +623,7 @@ sub commit_all { } } -while(++$current_rev < $svn->{'maxrev'}) { +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) { -- cgit v0.10.2-6-g49f6 From 16e685967d638fd50860fa24bd5f2d06ab4f8e96 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 11 Oct 2005 14:18:01 +0200 Subject: svn import: typo fix Fixed a minor typo Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index f9318c8..821f51f 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -26,7 +26,7 @@ use IPC::Open2; use SVN::Core; use SVN::Ra; -die "Need CVN:COre 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; +die "Need CVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -- cgit v0.10.2-6-g49f6 From 2fa92046a8ae8548a8dff15abbf730506d49009e Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 11 Oct 2005 16:22:03 +0200 Subject: svn import: make -s option actually optional The -s option was accidentally not optional. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 821f51f..0462c31 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -53,6 +53,7 @@ my $branch_name = $opt_b || "branches"; @ARGV <= 1 or usage(); $opt_o ||= "origin"; +$opt_s ||= 1; $opt_l = 100 unless defined $opt_l; my $git_tree = $opt_C; $git_tree ||= "."; @@ -193,7 +194,7 @@ $ENV{GIT_INDEX_FILE} = $git_index; my $maxnum = 0; my $last_rev = ""; my $last_branch; -my $current_rev = $opt_s ? ($opt_s-1) : 0; +my $current_rev = $opt_s-1; unless(-d $git_dir) { system("git-init-db"); die "Cannot init the GIT db at $git_tree: $?\n" if $?; -- cgit v0.10.2-6-g49f6 From 4a91b796e3f48ad01d06cce46df28321b7a1500b Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 11 Oct 2005 17:02:45 +0200 Subject: svn import: remove some CVS cruft Some remains of CVS still lingered. Removed. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 0462c31..b976841 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -5,8 +5,7 @@ # # The basic idea is to pull and analyze SVN changes. # -# Checking out the files is done by a single long-running CVS connection -# / server process. +# Checking out the files is done by a single long-running SVN connection. # # The head revision is on branch "origin" by default. # You can change that with the '-o' option. @@ -50,7 +49,7 @@ my $tag_name = $opt_t || "tags"; my $trunk_name = $opt_T || "trunk"; my $branch_name = $opt_b || "branches"; -@ARGV <= 1 or usage(); +@ARGV == 1 or usage(); $opt_o ||= "origin"; $opt_s ||= 1; @@ -58,18 +57,7 @@ $opt_l = 100 unless defined $opt_l; my $git_tree = $opt_C; $git_tree ||= "."; -my $cvs_tree; -if ($#ARGV == 0) { - $cvs_tree = $ARGV[0]; -} elsif (-f 'CVS/Repository') { - open my $f, '<', 'CVS/Repository' or - die 'Failed to open CVS/Repository'; - $cvs_tree = <$f>; - chomp $cvs_tree; - close $f; -} else { - usage(); -} +my $svn_url = $ARGV[0]; our @mergerx = (); if ($opt_m) { @@ -140,7 +128,7 @@ sub file { package main; -my $svn = SVNconn->new($cvs_tree); +my $svn = SVNconn->new($svn_url); sub pdate($) { @@ -255,25 +243,6 @@ EOM open BRANCHES,">>", "$git_dir/svn2git"; - -## cvsps output: -#--------------------- -#PatchSet 314 -#Date: 1999/09/18 13:03:59 -#Author: wkoch -#Branch: STABLE-BRANCH-1-0 -#Ancestor branch: HEAD -#Tag: (none) -#Log: -# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch -#Members: -# README:1.57->1.57.2.1 -# VERSION:1.96->1.96.2.1 -# -#--------------------- - -my $state = 0; - sub get_file($$$) { my($rev,$branch,$path) = @_; -- cgit v0.10.2-6-g49f6 From 25f6f325d7a8f7cb686a9ffd9fa2c00b3aa85a60 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 11 Oct 2005 18:13:30 +0200 Subject: svn import: Add direct HTTP access Some SVN repositories that are accessible through HTTP don't like when I retrieve files using SVN methods ("internal server error"). Therefore, I added an option to get the contents using (persistent) HTTP directly. This also reduces round-trip time, from two or three requests down to one. Also corrected error handling a bit. Signed-Off-By: Matthias Urlichs diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt index 047f8f3..a27a835 100644 --- a/Documentation/git-svnimport.txt +++ b/Documentation/git-svnimport.txt @@ -9,10 +9,11 @@ git-svnimport - Import a SVN repository into git SYNOPSIS -------- -'git-svnimport' [ -o ] [ -h ] [ -v ] +'git-svnimport' [ -o ] [ -h ] [ -v ] [ -d | -D ] [ -C ] [ -i ] [ -u ] [-l limit_nr_changes] [ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ] - [ -s start_chg ] [ -m ] [ -M regex ] [ ] + [ -s start_chg ] [ -m ] [ -M regex ] + [ ] DESCRIPTION @@ -82,9 +83,32 @@ When importing incementally, you might need to edit the .git/svn2git file. -v:: Verbosity: let 'svnimport' report what it is doing. +-d:: + Use direct HTTP requests if possible. The "" argument is used + only for retrieving the SVN logs; the path to the contents is + included in the SVN log. + +-D:: + Use direct HTTP requests if possible. The "" argument is used + for retrieving the logs, as well as for the contents. ++ +There's no safe way to automatically find out which of these options to +use, so you need to try both. Usually, the one that's wrong will die +with a 40x error pretty quickly. + :: The URL of the SVN module you want to import. For local repositories, use "file:///absolute/path". ++ +If you're using the "-d" or "-D" option, this is the URL of the SVN +repository itself; it usually ends in "/svn". + +:: + The URL of the SVN module you want to import. For local + repositories, use "file:///absolute/path". + + + The path to the module you want to check out. -h:: Print a short usage message and exit. diff --git a/git-svnimport.perl b/git-svnimport.perl index b976841..2f89c31 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -30,26 +30,26 @@ die "Need CVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s,$opt_l); +our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s,$opt_l,$opt_d,$opt_D); sub usage() { print STDERR < File::Spec->tmpdir(), UNLINK => 1); print "... $rev $path ...\n" if $opt_v; eval { $self->{'svn'}->get_file($path,$rev,$fh); }; - if ($@ and $@ !~ /Attempted to get checksum/) { - # retry - $self->conn(); - eval { $self->{'svn'}->get_file($path,$rev,$fh); }; - }; - return () if $@ and $@ !~ /Attempted to get checksum/; - die $@ if $@; + if($@) { + return undef if $@ =~ /Attempted to get checksum/; + die $@; + } close ($fh); - return ($name, $res); + return $name; } - package main; +use URI; -my $svn = SVNconn->new($svn_url); +my $svn = $svn_url; +$svn .= "/$svn_dir" if defined $svn_dir; +$svn = SVNconn->new($svn); +my $lwp_ua; +if($opt_d or $opt_D) { + $svn_url = URI->new($svn_url)->canonical; + if($opt_D) { + $svn_dir =~ s#/*$#/#; + } else { + $svn_dir = ""; + } + if ($svn_url->scheme eq "http") { + use LWP::UserAgent; + $lwp_ua = LWP::UserAgent->new(keep_alive => 1, requests_redirectable => []); + } else { + print STDERR "Warning: not HTTP; turning off direct file access\n"; + $opt_d=0; + } +} sub pdate($) { my($d) = @_; @@ -258,8 +273,30 @@ sub get_file($$$) { } # now get it - my ($name, $res) = eval { $svn->file($svnpath,$rev); }; - return () unless defined $name; + my $name; + if($opt_d) { + my($req,$res); + + # /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; + $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); + print $fh $res->content; + close($fh) or die "Could not write $name: $!\n"; + } else { + return undef if $res->code == 301; # directory? + die $res->status_line." at $url\n"; + } + } else { + $name = $svn->file($svnpath,$rev); + return undef unless defined $name; + } open my $F, '-|', "git-hash-object", "-w", $name or die "Cannot create object: $!\n"; -- cgit v0.10.2-6-g49f6 From 0090a6185af18a199d5bc12781adf411177f1e1a Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 11 Oct 2005 19:42:27 +0200 Subject: svn import: copy directories Import SVN-copied and -referenced directories correctly. Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index 2f89c31..aa8fa40 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -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,7 +280,7 @@ 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) { @@ -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,$_); @@ -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; } -- cgit v0.10.2-6-g49f6 From f005dba7c15af5de74e05f8667da4e5d27cf6d1b Mon Sep 17 00:00:00 2001 From: Kalle Valo Date: Sun, 16 Oct 2005 19:37:25 +0200 Subject: Makefile entry for git-svnimport contained a small typo. Signed-Off-By: Matthias Urlichs diff --git a/Makefile b/Makefile index 30fda9e..13b949b 100644 --- a/Makefile +++ b/Makefile @@ -92,7 +92,7 @@ SCRIPT_SH = \ SCRIPT_PERL = \ git-archimport.perl git-cvsimport.perl git-relink.perl \ git-rename.perl git-shortlog.perl git-fmt-merge-msg.perl \ - git-svnimport-perl + git-svnimport.perl SCRIPT_PYTHON = \ git-merge-recursive.py -- cgit v0.10.2-6-g49f6 From 40dad96e41fcb96e31bdf11deec3c7bf6261adbe Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 16 Oct 2005 19:57:38 +0200 Subject: svn commit: re-word the exit-due-to-memory-leak message Reworded the exit message, as per Kalle Valo's suggestion (but shorter). Signed-Off-By: Matthias Urlichs diff --git a/git-svnimport.perl b/git-svnimport.perl index aa8fa40..45486a8 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -677,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; } } -- cgit v0.10.2-6-g49f6