From a57a9493df00b6fbb3699fda8ceedf4ac0783ac6 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 16:48:40 +0200 Subject: [PATCH 01/30] Added Perl git-cvsimport-script --- Makefile | 3 +- cvs2git.c | 329 ----------------------- git-cvsimport-script | 604 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 576 insertions(+), 360 deletions(-) delete mode 100644 cvs2git.c diff --git a/Makefile b/Makefile index 1736980d09..9379e16bb1 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ PROG= git-update-cache git-diff-files git-init-db git-write-tree \ git-http-pull git-ssh-push git-ssh-pull git-rev-list git-mktag \ git-diff-helper git-tar-tree git-local-pull git-write-blob \ git-get-tar-commit-id git-apply git-stripspace \ - git-cvs2git git-diff-stages git-rev-parse git-patch-id \ + git-diff-stages git-rev-parse git-patch-id \ git-pack-objects git-unpack-objects all: $(PROG) @@ -118,7 +118,6 @@ git-diff-helper: diff-helper.c git-tar-tree: tar-tree.c git-write-blob: write-blob.c git-stripspace: stripspace.c -git-cvs2git: cvs2git.c git-diff-stages: diff-stages.c git-rev-parse: rev-parse.c git-patch-id: patch-id.c diff --git a/cvs2git.c b/cvs2git.c deleted file mode 100644 index ab0590872e..0000000000 --- a/cvs2git.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * cvs2git - * - * Copyright (C) Linus Torvalds 2005 - */ - -#include -#include -#include -#include -#include - -static int verbose = 0; - -/* - * This is a really stupid program that takes cvsps output, and - * generates a a long _shell_script_ that will create the GIT archive - * from it. - * - * You've been warned. I told you it was stupid. - * - * NOTE NOTE NOTE! In order to do branches correctly, this needs - * the fixed cvsps that has the "Ancestor branch" tag output. - * Hopefully David Mansfield will update his distribution soon - * enough (he's the one who wrote the patch, so at least we don't - * have to figt maintainer issues ;) - * - * Usage: - * - * TZ=UTC cvsps -A | - * git-cvs2git --cvsroot=[root] --module=[module] > script - * - * Creates a shell script that will generate the .git archive of - * the names CVS repository. - * - * TZ=UTC cvsps -s 1234- -A | - * git-cvs2git -u --cvsroot=[root] --module=[module] > script - * - * Creates a shell script that will update the .git archive with - * CVS changes from patchset 1234 until the last one. - * - * IMPORTANT NOTE ABOUT "cvsps"! This requires version 2.1 or better, - * and the "TZ=UTC" and the "-A" flag is required for sane results! - */ -enum state { - Header, - Log, - Members -}; - -static const char *cvsroot; -static const char *cvsmodule; - -static char date[100]; -static char author[100]; -static char branch[100]; -static char ancestor[100]; -static char tag[100]; -static char log[32768]; -static int loglen = 0; -static int initial_commit = 1; - -static void lookup_author(char *n, char **name, char **email) -{ - /* - * FIXME!!! I'm lazy and stupid. - * - * This could be something like - * - * printf("lookup_author '%s'\n", n); - * *name = "$author_name"; - * *email = "$author_email"; - * - * and that would allow the script to do its own - * lookups at run-time. - */ - *name = n; - *email = n; -} - -static void prepare_commit(void) -{ - char *author_name, *author_email; - char *src_branch; - - lookup_author(author, &author_name, &author_email); - - printf("export GIT_COMMITTER_NAME=%s\n", author_name); - printf("export GIT_COMMITTER_EMAIL=%s\n", author_email); - printf("export GIT_COMMITTER_DATE='+0000 %s'\n", date); - - printf("export GIT_AUTHOR_NAME=%s\n", author_name); - printf("export GIT_AUTHOR_EMAIL=%s\n", author_email); - printf("export GIT_AUTHOR_DATE='+0000 %s'\n", date); - - if (initial_commit) - return; - - src_branch = *ancestor ? ancestor : branch; - if (!strcmp(src_branch, "HEAD")) - src_branch = "master"; - printf("ln -sf refs/heads/'%s' .git/HEAD\n", src_branch); - - /* - * Even if cvsps claims an ancestor, we'll let the new - * branch name take precedence if it already exists - */ - if (*ancestor) { - src_branch = branch; - if (!strcmp(src_branch, "HEAD")) - src_branch = "master"; - printf("[ -e .git/refs/heads/'%s' ] && ln -sf refs/heads/'%s' .git/HEAD\n", - src_branch, src_branch); - } - - printf("git-read-tree -m HEAD || exit 1\n"); - printf("git-checkout-cache -f -u -a\n"); -} - -static void commit(void) -{ - const char *cmit_parent = initial_commit ? "" : "-p HEAD"; - const char *dst_branch; - char *space; - int i; - - printf("tree=$(git-write-tree)\n"); - printf("cat > .cmitmsg < .git/refs/heads/'%s'\n", dst_branch); - - space = strchr(tag, ' '); - if (space) - *space = 0; - if (strcmp(tag, "(none)")) - printf("echo $commit > .git/refs/tags/'%s'\n", tag); - - printf("echo 'Committed (to %s):' ; cat .cmitmsg; echo\n", dst_branch); - - *date = 0; - *author = 0; - *branch = 0; - *ancestor = 0; - *tag = 0; - loglen = 0; - - initial_commit = 0; -} - -static void update_file(char *line) -{ - char *name, *version; - char *dir; - - while (isspace(*line)) - line++; - name = line; - line = strchr(line, ':'); - if (!line) - return; - *line++ = 0; - line = strchr(line, '>'); - if (!line) - return; - *line++ = 0; - version = line; - line = strchr(line, '('); - if (line) { /* "(DEAD)" */ - printf("git-update-cache --force-remove '%s'\n", name); - return; - } - - dir = strrchr(name, '/'); - if (dir) - printf("mkdir -p %.*s\n", (int)(dir - name), name); - - printf("cvs -q -d %s checkout -d .git-tmp -r%s '%s/%s'\n", - cvsroot, version, cvsmodule, name); - printf("mv -f .git-tmp/%s %s\n", dir ? dir+1 : name, name); - printf("rm -rf .git-tmp\n"); - printf("git-update-cache --add -- '%s'\n", name); -} - -struct hdrentry { - const char *name; - char *dest; -} hdrs[] = { - { "Date:", date }, - { "Author:", author }, - { "Branch:", branch }, - { "Ancestor branch:", ancestor }, - { "Tag:", tag }, - { "Log:", NULL }, - { NULL, NULL } -}; - -int main(int argc, char **argv) -{ - static char line[1000]; - enum state state = Header; - int i; - - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - if (!memcmp(arg, "--cvsroot=", 10)) { - cvsroot = arg + 10; - continue; - } - if (!memcmp(arg, "--module=", 9)) { - cvsmodule = arg+9; - continue; - } - if (!strcmp(arg, "-v")) { - verbose = 1; - continue; - } - if (!strcmp(arg, "-u")) { - initial_commit = 0; - continue; - } - } - - - if (!cvsroot) - cvsroot = getenv("CVSROOT"); - - if (!cvsmodule || !cvsroot) { - fprintf(stderr, "I need a CVSROOT and module name\n"); - exit(1); - } - - if (initial_commit) { - printf("[ -d .git ] && exit 1\n"); - printf("git-init-db\n"); - printf("mkdir -p .git/refs/heads\n"); - printf("mkdir -p .git/refs/tags\n"); - printf("ln -sf refs/heads/master .git/HEAD\n"); - } - - while (fgets(line, sizeof(line), stdin) != NULL) { - int linelen = strlen(line); - - while (linelen && isspace(line[linelen-1])) - line[--linelen] = 0; - - switch (state) { - struct hdrentry *entry; - - case Header: - if (verbose) - printf("# H: %s\n", line); - for (entry = hdrs ; entry->name ; entry++) { - int len = strlen(entry->name); - char *val; - - if (memcmp(entry->name, line, len)) - continue; - if (!entry->dest) { - state = Log; - break; - } - val = line + len; - linelen -= len; - while (isspace(*val)) { - val++; - linelen--; - } - memcpy(entry->dest, val, linelen+1); - break; - } - continue; - - case Log: - if (verbose) - printf("# L: %s\n", line); - if (!strcmp(line, "Members:")) { - while (loglen && isspace(log[loglen-1])) - log[--loglen] = 0; - prepare_commit(); - state = Members; - continue; - } - - if (loglen + linelen + 5 > sizeof(log)) - continue; - memcpy(log + loglen, line, linelen); - loglen += linelen; - log[loglen++] = '\n'; - continue; - - case Members: - if (verbose) - printf("# M: %s\n", line); - if (!linelen) { - commit(); - state = Header; - continue; - } - update_file(line); - continue; - } - } - return 0; -} diff --git a/git-cvsimport-script b/git-cvsimport-script index 0ba67461da..e480a50f48 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -1,38 +1,584 @@ -#!/bin/sh +#!/usr/bin/perl -w -usage () { - echo "Usage: git cvsimport [-v] [-z fuzz] " - exit 1 +# This tool is copyright (c) 2005, Matthias Urlichs. +# It is released under the Gnu Public License, version 2. +# +# The basic idea is to aggregate CVS check-ins into related changes. +# Fortunately, "cvsps" does that for us; all we have to do is to parse +# its output. +# +# 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. + +use strict; +use warnings; +use Getopt::Std; +use File::Path qw(mkpath); +use File::Basename qw(basename dirname); +use Time::Local; +use POSIX qw(strftime); + +$SIG{'PIPE'}="IGNORE"; +$ENV{'TZ'}="UTC"; + +our($opt_h,$opt_o,$opt_v); + +sub usage() { + print STDERR <&1 | grep -q "cvsps version 2.1" >& /dev/null || { - echo "I need cvsps version 2.1" - exit 1 +my($cvs_tree, $git_tree) = @ARGV; + +select(STDERR); $|=1; select(STDOUT); + + +package CVSconn; +# Basic CVS dialog. +# We're only interested in downloading files. + +sub new { + my($what,$repo,$subdir) = @_; + $what=ref($what) if ref($what); + + my $self = {}; + $self->{'buffer'} = ""; + bless($self,$what); + + $repo =~ s#/+$##; + $self->{'fullrep'} = $repo; + $self->conn(); + + $self->{'subdir'} = $subdir; + $self->{'lines'} = undef; + + return $self; } -mkdir "$MODULE" || exit 1 -cd "$MODULE" +sub conn { + my $self = shift; + my $repo = $self->{'fullrep'}; + if($repo =~ s/^:pserver:(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) { + my($user,$pass,$serv,$port) = ($1,$2,$3,$4); + $user="anonymous" unless defined $user; + my $rr2; + unless($port) { + $rr2 = ":pserver:$user\@$serv:$repo"; + $port=2401; + } + my $rr = ":pserver:$user\@$serv:$port$repo"; -TZ=UTC cvsps $CVSPS $MODULE > .git-cvsps-result -[ -s .git-cvsps-result ] || exit 1 -git-cvs2git $CVS2GIT --cvsroot="$CVSROOT" --module="$MODULE" < .git-cvsps-result > .git-create-script || exit 1 -sh .git-create-script + unless($pass) { + open(H,$ENV{'HOME'}."/.cvspass") and do { + # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah) { + chomp; + s/^\/\d+\s+//; + my ($w,$p) = split(/\s/,$_,2); + if($w eq $rr or $w eq $rr2) { + $pass = $p; + last; + } + } + }; + } + $pass="A" unless $pass; + use IO::Socket; + my $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port); + die "Socket to $serv: $!\n" unless defined $s; + $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n") + or die "Write to $serv: $!\n"; + $s->flush(); + + my $rep = <$s>; + + if($rep ne "I LOVE YOU\n") { + $rep="" unless $rep; + die "AuthReply: $rep\n"; + } + $self->{'socketo'} = $s; + $self->{'socketi'} = $s; + } else { # local: Fork off our own cvs server. + use IO::Pipe; + my $pr = IO::Pipe->new(); + my $pw = IO::Pipe->new(); + my $pid = fork(); + die "Fork: $!\n" unless defined $pid; + unless($pid) { + $pr->writer(); + $pw->reader(); + use POSIX qw(dup2); + dup2($pw->fileno(),0); + dup2($pr->fileno(),1); + $pr->close(); + $pw->close(); + exec("cvs","server"); + } + $pw->writer(); + $pr->reader(); + $self->{'socketo'} = $pw; + $self->{'socketi'} = $pr; + } + $self->{'socketo'}->write("Root $repo\n"); + + # Trial and error says that this probably is the minimum set + $self->{'socketo'}->write("Valid-responses ok error Valid-requests Mode M Mbinary E F Checked-in Created Updated Merged Removed\n"); + + $self->{'socketo'}->write("valid-requests\n"); + $self->{'socketo'}->flush(); + + chomp(my $rep=$self->readline()); + if($rep !~ s/^Valid-requests\s*//) { + $rep="" unless $rep; + die "Expected Valid-requests from server, but got: $rep\n"; + } + chomp(my $res=$self->readline()); + die "validReply: $res\n" if $res ne "ok"; + + $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/; + $self->{'repo'} = $repo; +} + +sub readline { + my($self) = @_; + return $self->{'socketi'}->getline(); +} + +sub _file { + # Request a file with a given revision. + # Trial and error says this is a good way to do it. :-/ + my($self,$fn,$rev) = @_; + $self->{'socketo'}->write("Argument -N\n") or return undef; + $self->{'socketo'}->write("Argument -P\n") or return undef; + # $self->{'socketo'}->write("Argument -ko\n") or return undef; + # -ko: Linus' version doesn't use it + $self->{'socketo'}->write("Argument -r\n") or return undef; + $self->{'socketo'}->write("Argument $rev\n") or return undef; + $self->{'socketo'}->write("Argument --\n") or return undef; + $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef; + $self->{'socketo'}->write("Directory .\n") or return undef; + $self->{'socketo'}->write("$self->{'repo'}\n") or return undef; + $self->{'socketo'}->write("Sticky T1.1\n") or return undef; + $self->{'socketo'}->write("co\n") or return undef; + $self->{'socketo'}->flush() or return undef; + $self->{'lines'} = 0; + return 1; +} +sub _line { + # Read a line from the server. + # ... except that 'line' may be an entire file. ;-) + my($self) = @_; + die "Not in lines" unless defined $self->{'lines'}; + + my $line; + my $res=""; + while(defined($line = $self->readline())) { + # M U gnupg-cvs-rep/AUTHORS + # Updated gnupg-cvs-rep/ + # /daten/src/rsync/gnupg-cvs-rep/AUTHORS + # /AUTHORS/1.1///T1.1 + # u=rw,g=rw,o=rw + # 0 + # ok + + if($line =~ s/^(?:Created|Updated) //) { + $line = $self->readline(); # path + $line = $self->readline(); # Entries line + my $mode = $self->readline(); chomp $mode; + $self->{'mode'} = $mode; + defined (my $cnt = $self->readline()) + or die "EOF from server after 'Changed'\n"; + chomp $cnt; + die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/; + $line=""; + $res=""; + while($cnt) { + my $buf; + my $num = $self->{'socketi'}->read($buf,$cnt); + die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0; + $res .= $buf; + $cnt -= $num; + } + } elsif($line =~ s/^ //) { + $res .= $line; + } elsif($line =~ /^M\b/) { + # output, do nothing + } elsif($line =~ /^Mbinary\b/) { + my $cnt; + die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline()); + chomp $cnt; + die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1; + $line=""; + while($cnt) { + my $buf; + my $num = $self->{'socketi'}->read($buf,$cnt); + die "S: Mbinary $cnt: $num: $!\n" if not defined $num or $num<=0; + $res .= $buf; + $cnt -= $num; + } + } else { + chomp $line; + if($line eq "ok") { + # print STDERR "S: ok (".length($res).")\n"; + return $res; + } elsif($line =~ s/^E //) { + # print STDERR "S: $line\n"; + } else { + die "Unknown: $line\n"; + } + } + } +} +sub file { + my($self,$fn,$rev) = @_; + my $res; + + if ($self->_file($fn,$rev)) { + $res = $self->_line(); + return $res if defined $res; + } + + # retry + $self->conn(); + $self->_file($fn,$rev) + or die "No file command send\n"; + $res = $self->_line(); + die "No input: $fn $rev\n" unless defined $res; + return $res; +} + + +package main; + +my $cvs = CVSconn->new(dirname($cvs_tree), basename($cvs_tree)); + + +sub pdate($) { + my($d) = @_; + m#(\d{2,4})/(\d\d)/(\d\d)\s(\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; +} + +my $tmpcv = "/var/cache/cvs"; + +sub getwd() { + my $pwd = `pwd`; + chomp $pwd; + return $pwd; +} + +-d $git_tree + or mkdir($git_tree,0777) + or die "Could not create $git_tree: $!"; +chdir($git_tree); + +my $last_branch = ""; +my %branch_date; + +my $git_dir = $ENV{"GIT_DIR"} || ".git"; +$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#; +$ENV{"GIT_DIR"} = $git_dir; +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; +} else { + $last_branch = basename(readlink("$git_dir/HEAD")); + die "Cannot read the last branch name: $!\n" unless $last_branch; + + # Get the last import timestamps + opendir(D,"$git_dir/refs/heads"); + while(defined(my $head = readdir(D))) { + next if $head =~ /^\./; + open(F,"$git_dir/refs/heads/$head") + or die "Bad head branch: $head: $!\n"; + chomp(my $ftag = ); + close(F); + open(F,"git-cat-file commit $ftag |"); + while() { + next unless /^author\s.*\s(\d+)\s[-+]\d{4}$/; + $branch_date{$head} = $1; + last; + } + close(F); + } + closedir(D); +} + +-d $git_dir + or die "Could not create git subdir ($git_dir).\n"; + +my $pid = open(CVS,"-|"); +die "Cannot fork: $!\n" unless defined $pid; +unless($pid) { + exec("cvsps","-A","--cvs-direct",$cvs_tree); + die "Could not start cvsps: $!\n"; +} + + +## 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; + +my($patchset,$date,$author,$branch,$ancestor,$tag,$logmsg); +my(@old,@new); +my $commit = sub { + my $pid; + system("git-update-cache","--force-remove","--",@old) if @old; + die "Cannot remove files: $?\n" if $?; + system("git-update-cache","--add","--",@new) if @new; + die "Cannot add files: $?\n" if $?; + + $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 $parent = ""; + if(open(C,"$git_dir/refs/heads/$last_branch")) { + chomp($parent = ); + close(C); + length($parent) == 40 + or die "Cannot get parent id ($parent): $!\n"; + print "Parent ID $parent\n" if $opt_v; + } + + pipe(I,O) + or die "No pipe: $!\n"; + $pid = open(C,"|-"); + die "Cannot fork: $!" unless defined $pid; + unless($pid) { + close(I); + open(STDOUT,">&O"); + my @par = (); + @par = ("-p",$parent) if $parent; + exec("env", + "GIT_AUTHOR_NAME=$author", + "GIT_AUTHOR_EMAIL=$author", + "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)), + "GIT_COMMITTER_NAME=$author", + "GIT_COMMITTER_EMAIL=$author", + "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"; + } + close(O); + print C $logmsg + or die "Error writing to git-commit-tree: $!\n"; + close(C) + or die "Error running git-commit-tree: $?\n"; + print "Committed patch $patchset ($branch)\n" if $opt_v; + chomp(my $cid = ); + length($cid) == 40 + or die "Cannot get commit id ($cid): $!\n"; + print "Commit ID $cid\n" if $opt_v; + close(I); + + open(C,">$git_dir/refs/heads/$branch") + or die "Cannot open branch $branch for update: $!\n"; + print C "$cid\n" + or die "Cannot write branch $branch for update: $!\n"; + close(C) + or die "Cannot write branch $branch for update: $!\n"; + + if($tag) { + open(C,">$git_dir/refs/tags/$tag") + or die "Cannot create tag $tag: $!\n"; + print C "$cid\n" + or die "Cannot write tag $branch: $!\n"; + close(C) + or die "Cannot write tag $branch: $!\n"; + print "Created tag '$tag' on '$branch'\n" if $opt_v; + } + + @old = (); + @new = (); +}; + +while() { + chomp; + if($state == 0 and /^-+$/) { + $state = 1; + } elsif($state == 0) { + $state = 1; + redo; + } elsif(($state==0 or $state==1) and s/^PatchSet\s+//) { + $patchset = 0+$_; + $state=2; + } elsif($state == 2 and s/^Date:\s+//) { + $date = pdate($_); + unless($date) { + print STDERR "Could not parse date: $_\n"; + $state=0; + next; + } + $state=3; + } elsif($state == 3 and s/^Author:\s+//) { + s/\s+$//; + $author = $_; + $state = 4; + } elsif($state == 4 and s/^Branch:\s+//) { + s/\s+$//; + $branch = $_; + $state = 5; + } elsif($state == 5 and s/^Ancestor branch:\s+//) { + s/\s+$//; + $ancestor = $_; + $ancestor = $opt_o if $ancestor == "HEAD"; + $state = 6; + } elsif($state == 5) { + $ancestor = undef; + $state = 6; + redo; + } elsif($state == 6 and s/^Tag:\s+//) { + s/\s+$//; + if($_ eq "(none)") { + $tag = undef; + } else { + $tag = $_; + } + $state = 7; + } elsif($state == 7 and /^Log:/) { + $logmsg = ""; + $state = 8; + } elsif($state == 8 and /^Members:/) { + $branch = $opt_o if $branch eq "HEAD"; + if(defined $branch_date{$branch} and $branch_date{$branch} >= $date) { + # skip + print "skip patchset $patchset: $date before $branch_date{$branch}\n"; + $state = 11; + next; + } + if($ancestor) { + if(-f "$git_dir/refs/heads/$branch") { + print STDERR "Branch $branch already exists!\n"; + $state=11; + next; + } + unless(open(H,"$git_dir/refs/heads/$ancestor")) { + print STDERR "Branch $ancestor does not exist!\n"; + $state=11; + next; + } + chomp(my $id = ); + close(H); + unless(open(H,"> $git_dir/refs/heads/$branch")) { + print STDERR "Could not create branch $branch: $!\n"; + $state=11; + next; + } + print H "$id\n" + or die "Could not write branch $branch: $!"; + close(H) + or die "Could not write branch $branch: $!"; + } + if(($ancestor || $branch) ne $last_branch) { + system("git-read-tree -m -u $last_branch $branch"); + die "read-tree $branch failed at $branch: $?\n" if $?; + } + if($branch ne $last_branch) { + unlink("$git_dir/HEAD"); + symlink("refs/heads/$branch","$git_dir/HEAD"); + $last_branch = $branch; + } + $state = 9; + } elsif($state == 8) { + $logmsg .= "$_\n"; + } elsif($state == 9 and /^\s+(\S+):(?:INITIAL|\d(?:\.\d+)+)->(\d(?:\.\d+)+)\s*$/) { +# VERSION:1.96->1.96.2.1 + my $fn = $1; + my $data = $cvs->file($fn,$2); + print "Update $fn: ".length($data)." bytes.\n"; + mkpath(dirname($fn),$opt_v); + open(F,"> ./$fn") + or die "Cannot create '$fn': $!\n"; + print F $data + or die "Cannot write to '$fn': $!\n"; + close(F) + or die "Cannot write to '$fn': $!\n"; + chmod(pmode($cvs->{'mode'}), $fn); + push(@new,$fn); # may be resurrected! + } elsif($state == 9 and /^\s+(\S+):\d(?:\.\d+)+->(\d(?:\.\d+)+)\(DEAD\)\s*$/) { + push(@old,$1); + } elsif($state == 9 and /^\s*$/) { + $state = 10; + } elsif(($state == 9 or $state == 10) and /^-+$/) { + &$commit(); + $state = 1; + } elsif($state == 11 and /^-+$/) { + $state = 1; + } elsif(/^-+$/) { # end of unknown-line processing + $state = 1; + } elsif($state != 11) { # ignore stuff when skipping + print "* UNKNOWN LINE * $_\n"; + } +} +&$commit() if $branch and $state != 11; + +print "DONE\n" if $opt_v; From 2a3e1a85b5432b94499db7d7fbe4ec9b65b6c88d Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 19:49:19 +0200 Subject: [PATCH 02/30] Fix remote CVS import. --- git-cvsimport-script | 78 +++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index e480a50f48..d61175613d 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -19,37 +19,47 @@ use Getopt::Std; use File::Path qw(mkpath); use File::Basename qw(basename dirname); use Time::Local; -use POSIX qw(strftime); +use IO::Socket; +use IO::Pipe; +use POSIX qw(strftime dup2); $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v); +our($opt_h,$opt_o,$opt_v,$opt_d); sub usage() { print STDERR <new(PeerHost => $serv, PeerPort => $port); die "Socket to $serv: $!\n" unless defined $s; $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n") @@ -114,7 +123,6 @@ sub conn { $self->{'socketo'} = $s; $self->{'socketi'} = $s; } else { # local: Fork off our own cvs server. - use IO::Pipe; my $pr = IO::Pipe->new(); my $pw = IO::Pipe->new(); my $pid = fork(); @@ -122,7 +130,6 @@ sub conn { unless($pid) { $pr->writer(); $pw->reader(); - use POSIX qw(dup2); dup2($pw->fileno(),0); dup2($pr->fileno(),1); $pr->close(); @@ -265,7 +272,7 @@ sub file { package main; -my $cvs = CVSconn->new(dirname($cvs_tree), basename($cvs_tree)); +my $cvs = CVSconn->new($opt_d, $cvs_tree); sub pdate($) { @@ -409,13 +416,18 @@ my $commit = sub { print "Parent ID $parent\n" if $opt_v; } - pipe(I,O) - or die "No pipe: $!\n"; - $pid = open(C,"|-"); - die "Cannot fork: $!" unless defined $pid; + my $pr = IO::Pipe->new(); + my $pw = IO::Pipe->new(); + $pid = fork(); + die "Fork: $!\n" unless defined $pid; unless($pid) { - close(I); - open(STDOUT,">&O"); + $pr->writer(); + $pw->reader(); + dup2($pw->fileno(),0); + dup2($pr->fileno(),1); + $pr->close(); + $pw->close(); + my @par = (); @par = ("-p",$parent) if $parent; exec("env", @@ -428,17 +440,21 @@ my $commit = sub { "git-commit-tree", $tree,@par); die "Cannot exec git-commit-tree: $!\n"; } - close(O); - print C $logmsg + $pw->writer(); + $pr->reader(); + print $pw $logmsg or die "Error writing to git-commit-tree: $!\n"; - close(C) - or die "Error running git-commit-tree: $?\n"; + $pw->close(); + print "Committed patch $patchset ($branch)\n" if $opt_v; - chomp(my $cid = ); + chomp(my $cid = <$pr>); length($cid) == 40 or die "Cannot get commit id ($cid): $!\n"; print "Commit ID $cid\n" if $opt_v; - close(I); + $pr->close(); + + waitpid($pid,0); + die "Error running git-commit-tree: $?\n" if $?; open(C,">$git_dir/refs/heads/$branch") or die "Cannot open branch $branch for update: $!\n"; @@ -539,6 +555,7 @@ while() { or die "Could not write branch $branch: $!"; } if(($ancestor || $branch) ne $last_branch) { + print "Switching from $last_branch to $branch\n" if $opt_v; system("git-read-tree -m -u $last_branch $branch"); die "read-tree $branch failed at $branch: $?\n" if $?; } @@ -550,11 +567,12 @@ while() { $state = 9; } elsif($state == 8) { $logmsg .= "$_\n"; - } elsif($state == 9 and /^\s+(\S+):(?:INITIAL|\d(?:\.\d+)+)->(\d(?:\.\d+)+)\s*$/) { + } elsif($state == 9 and /^\s+(\S+):(INITIAL|\d(?:\.\d+)+)->(\d(?:\.\d+)+)\s*$/) { # VERSION:1.96->1.96.2.1 + my $init = ($2 eq "INITIAL"); my $fn = $1; - my $data = $cvs->file($fn,$2); - print "Update $fn: ".length($data)." bytes.\n"; + my $data = $cvs->file($fn,$3); + print "".($init ? "New" : "Update")." $fn: ".length($data)." bytes.\n"; mkpath(dirname($fn),$opt_v); open(F,"> ./$fn") or die "Cannot create '$fn': $!\n"; From f65ae603db8ffc36e25cc835eeffcfe4909c3148 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 19:58:40 +0200 Subject: [PATCH 03/30] Local cvsimport fixups --- git-cvsimport-script | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index d61175613d..58ded8a989 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -61,6 +61,8 @@ package CVSconn; # Basic CVS dialog. # We're only interested in connecting and downloading, so ... +use POSIX qw(strftime dup2); + sub new { my($what,$repo,$subdir) = @_; $what=ref($what) if ref($what); @@ -571,7 +573,9 @@ while() { # VERSION:1.96->1.96.2.1 my $init = ($2 eq "INITIAL"); my $fn = $1; - my $data = $cvs->file($fn,$3); + my $rev = $3; + $fn =~ s#^/+##; + my $data = $cvs->file($fn,$rev); print "".($init ? "New" : "Update")." $fn: ".length($data)." bytes.\n"; mkpath(dirname($fn),$opt_v); open(F,"> ./$fn") @@ -583,7 +587,9 @@ while() { chmod(pmode($cvs->{'mode'}), $fn); push(@new,$fn); # may be resurrected! } elsif($state == 9 and /^\s+(\S+):\d(?:\.\d+)+->(\d(?:\.\d+)+)\(DEAD\)\s*$/) { - push(@old,$1); + my $fn = $1; + $fn =~ s#^/+##; + push(@old,$fn); } elsif($state == 9 and /^\s*$/) { $state = 10; } elsif(($state == 9 or $state == 10) and /^-+$/) { From 465416694a98a8f071abf6290c9a2a48d9789a98 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 21:08:15 +0200 Subject: [PATCH 04/30] Rollbak to the original branch after importing --- git-cvsimport-script | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 58ded8a989..0d205c55aa 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -323,6 +323,7 @@ sub getwd() { chdir($git_tree); my $last_branch = ""; +my $orig_branch = ""; my %branch_date; my $git_dir = $ENV{"GIT_DIR"} || ".git"; @@ -335,9 +336,14 @@ unless(-d $git_dir) { die "Cannot init an empty tree: $?\n" if $?; $last_branch = $opt_o; + $orig_branch = ""; } else { $last_branch = basename(readlink("$git_dir/HEAD")); - die "Cannot read the last branch name: $!\n" unless $last_branch; + unless($last_branch) { + warn "Cannot read the last branch name: $! -- assuming 'master'\n"; + $last_branch = "master"; + } + $orig_branch = $last_branch; # Get the last import timestamps opendir(D,"$git_dir/refs/heads"); @@ -558,8 +564,8 @@ while() { } if(($ancestor || $branch) ne $last_branch) { print "Switching from $last_branch to $branch\n" if $opt_v; - system("git-read-tree -m -u $last_branch $branch"); - die "read-tree $branch failed at $branch: $?\n" if $?; + system("git-read-tree","-m","-u","$last_branch","$branch"); + die "read-tree failed: $?\n" if $?; } if($branch ne $last_branch) { unlink("$git_dir/HEAD"); @@ -605,4 +611,19 @@ while() { } &$commit() if $branch and $state != 11; -print "DONE\n" if $opt_v; +# Now switch back to the branch we were in before all of this happened +if($orig_branch) { + print "DONE; switching back to $orig_branch\n" if $opt_v; +} 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"; +} + +system("git-read-tree","-m","-u","$last_branch","$orig_branch"); +die "read-tree failed: $?\n" if $?; + +unlink("$git_dir/HEAD"); +symlink("refs/heads/$orig_branch","$git_dir/HEAD"); + From e694dbabbfdb847d6adb33c33ea188b5a8f0c175 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 21:11:23 +0200 Subject: [PATCH 05/30] Document the new migration tool --- Documentation/cvs-migration.txt | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index 4e2c452034..da9d63e410 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -63,19 +63,35 @@ Once you've gotten (and installed) cvsps, you may or may not want to get any more familiar with it, but make sure it is in your path. After that, the magic command line is - git cvsimport + git cvsimport -d which will do exactly what you'd think it does: it will create a git -archive of the named CVS module. The new archive will be created in a -subdirectory named . +archive of the named CVS module. The new archive will be created in the +subdirectory named ; it'll be created if it doesn't exist. +Default is the local directory. It can take some time to actually do the conversion for a large archive since it involves checking out from CVS every revision of every file, and the conversion script can be reasonably chatty, but on some not very -scientific tests it averaged about eight revisions per second, so a +scientific tests it averaged about twenty revisions per second, so a medium-sized project should not take more than a couple of minutes. For larger projects or remote repositories, the process may take longer. +After the import is done, do this: + + cp .git/refs/heads/ .git/refs/heads/master + git-read-tree + git-checkout-cache -q -f -u -a + +The head branch is named "origin" by default; you can change that using +the '-o' option to "git cvsimport". + +The import is incremental, i.e. if you call it again next month it'll +fetch any CVS updates that have been happening in the meantime. You can +then merge those updates into your main branch: + + cg-merge + Emulating CVS behaviour ----------------------- From 6c9a0dc2b5fffdb67593ee6bb828fcc578b84207 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 28 Jun 2005 21:21:33 +0200 Subject: [PATCH 06/30] More doc --- Documentation/cvs-migration.txt | 34 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt index da9d63e410..e39b82938a 100644 --- a/Documentation/cvs-migration.txt +++ b/Documentation/cvs-migration.txt @@ -63,7 +63,7 @@ Once you've gotten (and installed) cvsps, you may or may not want to get any more familiar with it, but make sure it is in your path. After that, the magic command line is - git cvsimport -d + git cvsimport -v -d which will do exactly what you'd think it does: it will create a git archive of the named CVS module. The new archive will be created in the @@ -72,26 +72,30 @@ Default is the local directory. It can take some time to actually do the conversion for a large archive since it involves checking out from CVS every revision of every file, -and the conversion script can be reasonably chatty, but on some not very -scientific tests it averaged about twenty revisions per second, so a -medium-sized project should not take more than a couple of minutes. For -larger projects or remote repositories, the process may take longer. +and the conversion script is reasonably chatty unless you omit the '-v' +option, but on some not very scientific tests it averaged about twenty +revisions per second, so a medium-sized project should not take more +than a couple of minutes. For larger projects or remote repositories, +the process may take longer. -After the import is done, do this: - - cp .git/refs/heads/ .git/refs/heads/master - git-read-tree - git-checkout-cache -q -f -u -a - -The head branch is named "origin" by default; you can change that using -the '-o' option to "git cvsimport". +After the (initial) import is done, the CVS archive's current head +revision will be checked out -- thus, you can start adding your own +changes right away. The import is incremental, i.e. if you call it again next month it'll -fetch any CVS updates that have been happening in the meantime. You can -then merge those updates into your main branch: +fetch any CVS updates that have been happening in the meantime. The +cut-off is date-based, so don't change the branches that were imported +from CVS. + +You can merge those updates (or, in fact, a different CVS branch) into +your main branch: cg-merge +The HEAD revision from CVS is named "origin", not "HEAD", because git +already uses "HEAD". (If you don't like 'origin', use cvsimport's +'-o' option to change it.) + Emulating CVS behaviour ----------------------- From 4abdecbf85151b4881aed4840e84823a112f96a5 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 11:55:57 +0200 Subject: [PATCH 07/30] cvs import: Call git-update-cache multiple times instead of with a too-long argument list. --- git-cvsimport-script | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 0d205c55aa..f3e2a49e04 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -397,10 +397,28 @@ my($patchset,$date,$author,$branch,$ancestor,$tag,$logmsg); my(@old,@new); my $commit = sub { my $pid; - system("git-update-cache","--force-remove","--",@old) if @old; - die "Cannot remove files: $?\n" if $?; - system("git-update-cache","--add","--",@new) if @new; - die "Cannot add files: $?\n" if $?; + while(@old) { + my @o2; + if(@old > 55) { + @o2 = splice(@old,0,50); + } else { + @o2 = @old; + @old = (); + } + system("git-update-cache","--force-remove","--",@o2); + die "Cannot remove files: $?\n" if $?; + } + while(@new) { + my @n2; + if(@new > 55) { + @n2 = splice(@new,0,50); + } else { + @n2 = @new; + @new = (); + } + system("git-update-cache","--add","--",@n2); + die "Cannot add files: $?\n" if $?; + } $pid = open(C,"-|"); die "Cannot fork: $!" unless defined $pid; From 4f7c0caa8f37934fa05f22a48a987a6e14dd0e07 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 12:19:48 +0200 Subject: [PATCH 08/30] git-cvsimport-script: Remove setting Sticky; it may cause problems --- git-cvsimport-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index f3e2a49e04..9b23d1f016 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -182,7 +182,7 @@ sub _file { $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef; $self->{'socketo'}->write("Directory .\n") or return undef; $self->{'socketo'}->write("$self->{'repo'}\n") or return undef; - $self->{'socketo'}->write("Sticky T1.1\n") or return undef; + # $self->{'socketo'}->write("Sticky T1.0\n") or return undef; $self->{'socketo'}->write("co\n") or return undef; $self->{'socketo'}->flush() or return undef; $self->{'lines'} = 0; From dbc1aeace608ebd9422d86efde000dc11a1563be Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 12:28:31 +0200 Subject: [PATCH 09/30] git-cvsimport-script: Removed redundant @old and @new clear. --- git-cvsimport-script | 3 --- 1 file changed, 3 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 9b23d1f016..6ac31a7160 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -498,9 +498,6 @@ my $commit = sub { or die "Cannot write tag $branch: $!\n"; print "Created tag '$tag' on '$branch'\n" if $opt_v; } - - @old = (); - @new = (); }; while() { From 0fa2824f358febe306861f0cab73d25815372ee4 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Thu, 30 Jun 2005 17:23:22 +0200 Subject: [PATCH 10/30] cvsimport: perform string comparison on "HEAD" --- git-cvsimport-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 6ac31a7160..8e0e4ac4b2 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -529,7 +529,7 @@ while() { } elsif($state == 5 and s/^Ancestor branch:\s+//) { s/\s+$//; $ancestor = $_; - $ancestor = $opt_o if $ancestor == "HEAD"; + $ancestor = $opt_o if $ancestor eq "HEAD"; $state = 6; } elsif($state == 5) { $ancestor = undef; From e371046b6473907aa6d62b7862a3afe9d33561e1 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 22:09:42 +0200 Subject: [PATCH 11/30] cvs import: Strip whitespace at the end of the log entry for compatibility with old cvs2git. --- git-cvsimport-script | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 8e0e4ac4b2..3f157725c8 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -468,7 +468,12 @@ my $commit = sub { } $pw->writer(); $pr->reader(); - print $pw $logmsg + + # compatibility with git2cvs + substr($logmsg,32767) = "" if length($logmsg) > 32767; + $logmsg =~ s/[\s\n]+\z//; + + print $pw "$logmsg\n" or die "Error writing to git-commit-tree: $!\n"; $pw->close(); From 4c24e089a33d27e9f15dc746c43a816fabcc060c Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 22:10:32 +0200 Subject: [PATCH 12/30] cvsimport: Exit if an existing repository doesn't have the right branch. --- git-cvsimport-script | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/git-cvsimport-script b/git-cvsimport-script index 3f157725c8..1151fb8c0d 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -338,6 +338,11 @@ unless(-d $git_dir) { $last_branch = $opt_o; $orig_branch = ""; } else { + -f "$git_dir/refs/head/$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"; + $last_branch = basename(readlink("$git_dir/HEAD")); unless($last_branch) { warn "Cannot read the last branch name: $! -- assuming 'master'\n"; From 2be4fcc345b03910d1a7bf96f640cde4dcacbd6e Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Thu, 30 Jun 2005 22:54:01 +0200 Subject: [PATCH 13/30] cvsimport: Added option '-p': pass options to cvsps Added option '-x' to cvsps call --- git-cvsimport-script | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 1151fb8c0d..7ee8845a3d 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -26,18 +26,19 @@ use POSIX qw(strftime dup2); $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_d); +our($opt_h,$opt_o,$opt_v,$opt_d,$opt_p); sub usage() { print STDERR < Date: Thu, 30 Jun 2005 22:54:33 +0200 Subject: [PATCH 14/30] cvsimport: add documentation. --- Documentation/git-cvsimport-script.txt | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 Documentation/git-cvsimport-script.txt diff --git a/Documentation/git-cvsimport-script.txt b/Documentation/git-cvsimport-script.txt new file mode 100644 index 0000000000..c257d87097 --- /dev/null +++ b/Documentation/git-cvsimport-script.txt @@ -0,0 +1,82 @@ +git-cvsimport-script(1) +======================= +v0.1, July 2005 + +NAME +---- +git-cvsimport-script - Import a CVS repository into git + + +SYNOPSIS +-------- +'git-cvsimport-script' [ -o ] [ -h ] [ -v ] + [ -d ] [ -p ] + [ ] + + +DESCRIPTION +----------- +Imports a CVS repository into git. It will either create a new +repository, or incrementally import into an existing one. + +Spitting the CVS log into patch sets is done by 'cvsps'. +At least version 2.1 is required. + +OPTIONS +------- +-d :: + The root of the CVS archive. May be local (a simple path) or remote; + currently, only the :pserver: access method is supported. + +-o :: + The 'HEAD' branch from CVS is imported to the 'origin' branch within + the git repository, as 'HEAD' already has a special meaning for git. + Use this option if you want to import into a different branch. + + Use '-o master' for continuing an import that was initially done by + the old cvs2git tool. + +-p :: + Additional options for cvsps. + The options '-x' and '-A' are implicit and should not be used here. + + If you need to pass multiple options, separate them with a comma. + +-v:: + Verbosity: let 'cvsimport' report what it is doing. + +:: + The CVS module you want to import. Relative to . + +:: + Typically this matches the real type of but asking + for a type that can trivially dereferenced from the given + is also permitted. An example is to ask for a + "tree" with being a commit object that contains it, + or to ask for a "blob" with being a tag object that + points at it. + +-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 . + +Documentation +-------------- +Documentation by Matthias Urlichs . + +GIT +--- +Part of the link:git.html[git] suite + From 1cd3674add10d1e511446f3034a1d233a3da7eab Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 09:43:00 +0200 Subject: [PATCH 15/30] Fixed a typo in Documentation/git-cvsimport-script.txt. --- Documentation/git-cvsimport-script.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-cvsimport-script.txt b/Documentation/git-cvsimport-script.txt index c257d87097..8e170cdc1f 100644 --- a/Documentation/git-cvsimport-script.txt +++ b/Documentation/git-cvsimport-script.txt @@ -19,7 +19,7 @@ DESCRIPTION Imports a CVS repository into git. It will either create a new repository, or incrementally import into an existing one. -Spitting the CVS log into patch sets is done by 'cvsps'. +Splitting the CVS log into patch sets is done by 'cvsps'. At least version 2.1 is required. OPTIONS From f9714a4a0cd4ed0ccca3833743d98ea874a2232d Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 11:34:59 +0200 Subject: [PATCH 16/30] Make specification of CVS module to convert optional. If we're inside a checked out CVS repository, there is no need to explicitly specify the module as it is available in CVS/Repository. Also read CVS/Root if it's available and -d is not specified. Finally, explicitly pass root to cvsps as CVS/Root takes precedence over CVSROOT. Signed-off-by: Sven Verdoolaege --- Documentation/git-cvsimport-script.txt | 2 +- git-cvsimport-script | 34 ++++++++++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Documentation/git-cvsimport-script.txt b/Documentation/git-cvsimport-script.txt index 8e170cdc1f..2fefe89906 100644 --- a/Documentation/git-cvsimport-script.txt +++ b/Documentation/git-cvsimport-script.txt @@ -11,7 +11,7 @@ SYNOPSIS -------- 'git-cvsimport-script' [ -o ] [ -h ] [ -v ] [ -d ] [ -p ] - [ ] + [ -C ] [ ] DESCRIPTION diff --git a/git-cvsimport-script b/git-cvsimport-script index 7ee8845a3d..dffd134e63 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -26,35 +26,53 @@ use POSIX qw(strftime dup2); $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_d,$opt_p); +our($opt_h,$opt_o,$opt_v,$opt_d,$opt_p,$opt_C); sub usage() { print STDERR <; + chomp $opt_d; + close $f; + $ENV{"CVSROOT"} = $opt_d; } elsif($ENV{"CVSROOT"}) { $opt_d = $ENV{"CVSROOT"}; } else { die "CVSROOT needs to be set"; } $opt_o ||= "origin"; +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(); +} + select(STDERR); $|=1; select(STDOUT); @@ -378,7 +396,7 @@ die "Cannot fork: $!\n" unless defined $pid; unless($pid) { my @opt; @opt = split(/,/,$opt_p) if defined $opt_p; - exec("cvsps",@opt,"-x","-A","--cvs-direct",$cvs_tree); + exec("cvsps",@opt,"-x","-A","--cvs-direct",'--root',$opt_d,$cvs_tree); die "Could not start cvsps: $!\n"; } From a92bebe6978edaea2885a627e7bef6f7f8b208c2 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 11:38:06 +0200 Subject: [PATCH 17/30] git-cvsimport-script: clean up documentation Remove documentation of irrelevant "type" option. Signed-off-by: Sven Verdoolaege --- Documentation/git-cvsimport-script.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Documentation/git-cvsimport-script.txt b/Documentation/git-cvsimport-script.txt index 2fefe89906..23a79059f5 100644 --- a/Documentation/git-cvsimport-script.txt +++ b/Documentation/git-cvsimport-script.txt @@ -48,14 +48,6 @@ OPTIONS :: The CVS module you want to import. Relative to . -:: - Typically this matches the real type of but asking - for a type that can trivially dereferenced from the given - is also permitted. An example is to ask for a - "tree" with being a commit object that contains it, - or to ask for a "blob" with being a tag object that - points at it. - -h:: Print a short usage message and exit. From 8d0ea3117597933610e02907d14b443f8996ca3b Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 12:26:51 +0200 Subject: [PATCH 18/30] Honour CVS_SERVER. --- git-cvsimport-script | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index dffd134e63..c514d14c3f 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -148,6 +148,8 @@ sub conn { my $pw = IO::Pipe->new(); my $pid = fork(); die "Fork: $!\n" unless defined $pid; + my $cvs = 'cvs'; + $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER}; unless($pid) { $pr->writer(); $pw->reader(); @@ -155,7 +157,7 @@ sub conn { dup2($pr->fileno(),1); $pr->close(); $pw->close(); - exec("cvs","server"); + exec($cvs,"server"); } $pw->writer(); $pr->reader(); From 34155390a576d8124e0adc864aaf2f11bbf5168b Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 13:02:06 +0200 Subject: [PATCH 19/30] Support :ext: access method. --- Documentation/git-cvsimport-script.txt | 3 ++- git-cvsimport-script | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Documentation/git-cvsimport-script.txt b/Documentation/git-cvsimport-script.txt index 23a79059f5..4eb0f43246 100644 --- a/Documentation/git-cvsimport-script.txt +++ b/Documentation/git-cvsimport-script.txt @@ -26,7 +26,8 @@ OPTIONS ------- -d :: The root of the CVS archive. May be local (a simple path) or remote; - currently, only the :pserver: access method is supported. + currently, only the :local:, :ext: and :pserver: access methods + are supported. -o :: The 'HEAD' branch from CVS is imported to the 'origin' branch within diff --git a/git-cvsimport-script b/git-cvsimport-script index c514d14c3f..cdd4963695 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -143,13 +143,32 @@ sub conn { } $self->{'socketo'} = $s; $self->{'socketi'} = $s; - } else { # local: Fork off our own cvs server. + } else { # local or ext: Fork off our own cvs server. my $pr = IO::Pipe->new(); my $pw = IO::Pipe->new(); my $pid = fork(); die "Fork: $!\n" unless defined $pid; my $cvs = 'cvs'; $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER}; + my $rsh = 'rsh'; + $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH}; + + my @cvs = ($cvs, 'server'); + my ($local, $user, $host); + $local = $repo =~ s/:local://; + if (!$local) { + $repo =~ s/:ext://; + $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://); + ($user, $host) = ($1, $2); + } + if (!$local) { + if ($user) { + unshift @cvs, $rsh, '-l', $user, $host; + } else { + unshift @cvs, $rsh, $host; + } + } + unless($pid) { $pr->writer(); $pw->reader(); @@ -157,7 +176,7 @@ sub conn { dup2($pr->fileno(),1); $pr->close(); $pw->close(); - exec($cvs,"server"); + exec(@cvs); } $pw->writer(); $pr->reader(); From 9da07f34931f175402cce70dae9499fa67b84cbc Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Sun, 3 Jul 2005 19:03:30 +0200 Subject: [PATCH 20/30] cvsimport: Missing tests for verbosity flag. --- git-cvsimport-script | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index cdd4963695..6dd8c371d0 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -602,7 +602,7 @@ while() { $branch = $opt_o if $branch eq "HEAD"; if(defined $branch_date{$branch} and $branch_date{$branch} >= $date) { # skip - print "skip patchset $patchset: $date before $branch_date{$branch}\n"; + print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v; $state = 11; next; } @@ -649,7 +649,7 @@ while() { my $rev = $3; $fn =~ s#^/+##; my $data = $cvs->file($fn,$rev); - print "".($init ? "New" : "Update")." $fn: ".length($data)." bytes.\n"; + print "".($init ? "New" : "Update")." $fn: ".length($data)." bytes.\n" if $opt_v; mkpath(dirname($fn),$opt_v); open(F,"> ./$fn") or die "Cannot create '$fn': $!\n"; From 866d13108e969773347828daa9b7f3476ec70cb8 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Sun, 3 Jul 2005 23:40:48 +0200 Subject: [PATCH 21/30] git-cvsimport-script: typo head -> heads --- git-cvsimport-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 6dd8c371d0..f05fe10598 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -378,7 +378,7 @@ unless(-d $git_dir) { $last_branch = $opt_o; $orig_branch = ""; } else { - -f "$git_dir/refs/head/$opt_o" + -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"; From 2eb6d82eaa869a1faf4ba3326fd628f76f9f93a8 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 00:43:26 +0200 Subject: [PATCH 22/30] git-cvsimport-script: leave working directory alone. --- git-cvsimport-script | 81 ++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index f05fe10598..cc684602f3 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -80,6 +80,8 @@ package CVSconn; # Basic CVS dialog. # We're only interested in connecting and downloading, so ... +use File::Spec; +use File::Temp qw(tempfile); use POSIX qw(strftime dup2); sub new { @@ -231,11 +233,11 @@ sub _file { sub _line { # Read a line from the server. # ... except that 'line' may be an entire file. ;-) - my($self) = @_; + my($self, $fh) = @_; die "Not in lines" unless defined $self->{'lines'}; my $line; - my $res=""; + my $res=0; while(defined($line = $self->readline())) { # M U gnupg-cvs-rep/AUTHORS # Updated gnupg-cvs-rep/ @@ -255,16 +257,18 @@ sub _line { chomp $cnt; die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/; $line=""; - $res=""; + $res=0; while($cnt) { my $buf; my $num = $self->{'socketi'}->read($buf,$cnt); die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0; - $res .= $buf; + print $fh $buf; + $res += $num; $cnt -= $num; } } elsif($line =~ s/^ //) { - $res .= $line; + print $fh $line; + $res += length($line); } elsif($line =~ /^M\b/) { # output, do nothing } elsif($line =~ /^Mbinary\b/) { @@ -277,7 +281,8 @@ sub _line { my $buf; my $num = $self->{'socketi'}->read($buf,$cnt); die "S: Mbinary $cnt: $num: $!\n" if not defined $num or $num<=0; - $res .= $buf; + print $fh $buf; + $res += $num; $cnt -= $num; } } else { @@ -297,18 +302,21 @@ sub file { my($self,$fn,$rev) = @_; my $res; - if ($self->_file($fn,$rev)) { - $res = $self->_line(); - return $res if defined $res; + my ($fh, $name) = tempfile('gitcvs.XXXXXX', + DIR => File::Spec->tmpdir(), UNLINK => 1); + + $self->_file($fn,$rev) and $res = $self->_line($fh); + + if (!defined $res) { + # retry + $self->conn(); + $self->_file($fn,$rev) + or die "No file command send\n"; + $res = $self->_line($fh); + die "No input: $fn $rev\n" unless defined $res; } - # retry - $self->conn(); - $self->_file($fn,$rev) - or die "No file command send\n"; - $res = $self->_line(); - die "No input: $fn $rev\n" unless defined $res; - return $res; + return ($name, $res); } @@ -457,13 +465,14 @@ my $commit = sub { } while(@new) { my @n2; - if(@new > 55) { - @n2 = splice(@new,0,50); + if(@new > 12) { + @n2 = splice(@new,0,10); } else { @n2 = @new; @new = (); } - system("git-update-cache","--add","--",@n2); + system("git-update-cache","--add", + (map { ('--cacheinfo', @$_) } @n2)); die "Cannot add files: $?\n" if $?; } @@ -631,7 +640,7 @@ while() { } if(($ancestor || $branch) ne $last_branch) { print "Switching from $last_branch to $branch\n" if $opt_v; - system("git-read-tree","-m","-u","$last_branch","$branch"); + system("git-read-tree","-m","$last_branch","$branch"); die "read-tree failed: $?\n" if $?; } if($branch ne $last_branch) { @@ -648,17 +657,16 @@ while() { my $fn = $1; my $rev = $3; $fn =~ s#^/+##; - my $data = $cvs->file($fn,$rev); - print "".($init ? "New" : "Update")." $fn: ".length($data)." bytes.\n" if $opt_v; - mkpath(dirname($fn),$opt_v); - open(F,"> ./$fn") - or die "Cannot create '$fn': $!\n"; - print F $data - or die "Cannot write to '$fn': $!\n"; - close(F) - or die "Cannot write to '$fn': $!\n"; - chmod(pmode($cvs->{'mode'}), $fn); - push(@new,$fn); # may be resurrected! + my ($tmpname, $size) = $cvs->file($fn,$rev); + print "".($init ? "New" : "Update")." $fn: $size bytes.\n" if $opt_v; + open my $F, '-|', "git-write-blob $tmpname" + or die "Cannot create object: $!\n"; + my $sha = <$F>; + chomp $sha; + close $F; + unlink($tmpname); + my $mode = pmode($cvs->{'mode'}); + push(@new,[$mode, $sha, $fn]); # may be resurrected! } elsif($state == 9 and /^\s+(\S+):\d(?:\.\d+)+->(\d(?:\.\d+)+)\(DEAD\)\s*$/) { my $fn = $1; $fn =~ s#^/+##; @@ -688,8 +696,15 @@ if($orig_branch) { unless -f "$git_dir/refs/heads/master"; } -system("git-read-tree","-m","-u","$last_branch","$orig_branch"); -die "read-tree failed: $?\n" if $?; +if ($orig_branch) { + system("git-read-tree",$last_branch); + die "read-tree failed: $?\n" if $?; +} else { + system('git-read-tree', $orig_branch); + die "read-tree failed: $?\n" if $?; + system('git-checkout-cache', '-a'); + die "checkout-cache failed: $?\n" if $?; +} unlink("$git_dir/HEAD"); symlink("refs/heads/$orig_branch","$git_dir/HEAD"); From 79ee456cf222982f7ee3f003440c57b5f7cffa8b Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 13:36:59 +0200 Subject: [PATCH 23/30] git-cvsimport-script: use private index. --- git-cvsimport-script | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index cc684602f3..0531af30aa 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -16,6 +16,8 @@ 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; @@ -377,6 +379,12 @@ my %branch_date; 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; unless(-d $git_dir) { system("git-init-db"); die "Cannot init the GIT db at $git_tree: $?\n" if $?; @@ -398,6 +406,9 @@ unless(-d $git_dir) { } $orig_branch = $last_branch; + # populate index + system('git-read-tree', $last_branch); + # Get the last import timestamps opendir(D,"$git_dir/refs/heads"); while(defined(my $head = readdir(D))) { @@ -643,11 +654,6 @@ while() { system("git-read-tree","-m","$last_branch","$branch"); die "read-tree failed: $?\n" if $?; } - if($branch ne $last_branch) { - unlink("$git_dir/HEAD"); - symlink("refs/heads/$branch","$git_dir/HEAD"); - $last_branch = $branch; - } $state = 9; } elsif($state == 8) { $logmsg .= "$_\n"; @@ -686,26 +692,23 @@ while() { } &$commit() if $branch and $state != 11; +unlink($git_index); + # Now switch back to the branch we were in before all of this happened if($orig_branch) { - print "DONE; switching back to $orig_branch\n" if $opt_v; + print "DONE\n" if $opt_v; } 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"); + if (defined $orig_git_index) { + $ENV{GIT_INDEX_FILE} = $orig_git_index; + } else { + delete $ENV{GIT_INDEX_FILE}; + } + system('git checkout'); + die "checkout failed: $?\n" if $?; } - -if ($orig_branch) { - system("git-read-tree",$last_branch); - die "read-tree failed: $?\n" if $?; -} else { - system('git-read-tree', $orig_branch); - die "read-tree failed: $?\n" if $?; - system('git-checkout-cache', '-a'); - die "checkout-cache failed: $?\n" if $?; -} - -unlink("$git_dir/HEAD"); -symlink("refs/heads/$orig_branch","$git_dir/HEAD"); - From 46e63efc072bc440e4c6aad33d3157b70f5172b6 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 15:28:36 +0200 Subject: [PATCH 24/30] git-cvsimport-script: fix branch switching Previous patch broke branch switching. --- git-cvsimport-script | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 0531af30aa..418c209c80 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -651,9 +651,10 @@ while() { } if(($ancestor || $branch) ne $last_branch) { print "Switching from $last_branch to $branch\n" if $opt_v; - system("git-read-tree","-m","$last_branch","$branch"); + system("git-read-tree", $branch); die "read-tree failed: $?\n" if $?; } + $last_branch = $branch if $branch ne $last_branch; $state = 9; } elsif($state == 8) { $logmsg .= "$_\n"; From 6e7e37b0bfc921aa1f0cb30560fc128e87a41966 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 15:35:30 +0200 Subject: [PATCH 25/30] git-cvsimport-script: update cvsps cache instead of rebuilding it Updating the cache is sufficient for most purposes. If users really want to rebuild the cache, they can specify the option themselves. --- git-cvsimport-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 418c209c80..62df91666e 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -436,7 +436,7 @@ die "Cannot fork: $!\n" unless defined $pid; unless($pid) { my @opt; @opt = split(/,/,$opt_p) if defined $opt_p; - exec("cvsps",@opt,"-x","-A","--cvs-direct",'--root',$opt_d,$cvs_tree); + exec("cvsps",@opt,"-u","-A","--cvs-direct",'--root',$opt_d,$cvs_tree); die "Could not start cvsps: $!\n"; } From 28537171e7ec23c8677ea6e77c208583f95caa28 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 17:10:06 +0200 Subject: [PATCH 26/30] git-cvsimport-script: provide direct support for cvsps -z option --- git-cvsimport-script | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 62df91666e..9773891b5d 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -28,19 +28,19 @@ use POSIX qw(strftime dup2); $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_d,$opt_p,$opt_C); +our($opt_h,$opt_o,$opt_v,$opt_d,$opt_p,$opt_C,$opt_z); sub usage() { print STDERR < Date: Mon, 4 Jul 2005 17:36:25 +0200 Subject: [PATCH 27/30] git-cvsimport-script: more error handling --- git-cvsimport-script | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 9773891b5d..7f93fb3cd7 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -408,6 +408,7 @@ unless(-d $git_dir) { # populate index system('git-read-tree', $last_branch); + die "read-tree failed: $?\n" if $?; # Get the last import timestamps opendir(D,"$git_dir/refs/heads"); @@ -510,8 +511,8 @@ my $commit = sub { print "Parent ID $parent\n" if $opt_v; } - my $pr = IO::Pipe->new(); - my $pw = IO::Pipe->new(); + 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) { From fc6e714c838846aad566528f6ada904651c514f9 Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Mon, 4 Jul 2005 23:18:35 +0200 Subject: [PATCH 28/30] git-cvsimport-script: remove unused variable --- git-cvsimport-script | 2 -- 1 file changed, 2 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 7f93fb3cd7..3e6d22e742 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -359,8 +359,6 @@ sub pmode($) { return $m; } -my $tmpcv = "/var/cache/cvs"; - sub getwd() { my $pwd = `pwd`; chomp $pwd; From 210569f9aecee4d41420b9d9c8780f5c6bbee3cc Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Tue, 5 Jul 2005 13:19:59 +0200 Subject: [PATCH 29/30] git-cvsimport-script: move working directory forward If HEAD happened to point to a cvs branch, move the working directory forward to the tip of the branch. Additionally, if master and "origin" are equal, move master forward to new origin first. --- git-cvsimport-script | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 3e6d22e742..cdf9891614 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -372,6 +372,7 @@ chdir($git_tree); my $last_branch = ""; my $orig_branch = ""; +my $forward_master = 0; my %branch_date; my $git_dir = $ENV{"GIT_DIR"} || ".git"; @@ -403,6 +404,21 @@ unless(-d $git_dir) { $last_branch = "master"; } $orig_branch = $last_branch; + if (-f "$git_dir/CVS2GIT_HEAD") { + die <) { 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; + system('git-read-tree', '-m', '-u', 'CVS2GIT_HEAD', 'HEAD'); + die "read-tree failed: $?\n" if $?; } else { $orig_branch = "master"; print "DONE; creating $orig_branch branch\n" if $opt_v; @@ -705,11 +731,7 @@ if($orig_branch) { unless -f "$git_dir/refs/heads/master"; unlink("$git_dir/HEAD"); symlink("refs/heads/$orig_branch","$git_dir/HEAD"); - if (defined $orig_git_index) { - $ENV{GIT_INDEX_FILE} = $orig_git_index; - } else { - delete $ENV{GIT_INDEX_FILE}; - } system('git checkout'); die "checkout failed: $?\n" if $?; } +unlink("$git_dir/CVS2GIT_HEAD"); From a9174a14fcdac48b23e43db83649847a931fb1d8 Mon Sep 17 00:00:00 2001 From: Matthias Urlichs Date: Tue, 5 Jul 2005 14:22:53 +0200 Subject: [PATCH 30/30] cvsimport: getopt accepted a -q option (undocumented and unused). Removed. --- git-cvsimport-script | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cvsimport-script b/git-cvsimport-script index 6dd8c371d0..f71da43c32 100755 --- a/git-cvsimport-script +++ b/git-cvsimport-script @@ -38,7 +38,7 @@ END exit(1); } -getopts("hqvo:d:p:C:") or usage(); +getopts("hvo:d:p:C:") or usage(); usage if $opt_h; @ARGV <= 1 or usage();