]> git.ipfire.org Git - thirdparty/git.git/blame - git-cvsimport.perl
Merge branch 'nd/index-doc' into maint
[thirdparty/git.git] / git-cvsimport.perl
CommitLineData
3328aced 1#!/usr/bin/perl
9718a00b 2
a57a9493
MU
3# This tool is copyright (c) 2005, Matthias Urlichs.
4# It is released under the Gnu Public License, version 2.
5#
6# The basic idea is to aggregate CVS check-ins into related changes.
7# Fortunately, "cvsps" does that for us; all we have to do is to parse
8# its output.
9#
10# Checking out the files is done by a single long-running CVS connection
11# / server process.
12#
13# The head revision is on branch "origin" by default.
14# You can change that with the '-o' option.
15
d48b2841 16use 5.008;
a57a9493
MU
17use strict;
18use warnings;
bc434e82 19use Getopt::Long;
79ee456c 20use File::Spec;
7ccd9009 21use File::Temp qw(tempfile tmpnam);
a57a9493
MU
22use File::Path qw(mkpath);
23use File::Basename qw(basename dirname);
24use Time::Local;
2a3e1a85
MU
25use IO::Socket;
26use IO::Pipe;
e49289df 27use POSIX qw(strftime dup2 ENOENT);
0d821d4d 28use IPC::Open2;
a57a9493
MU
29
30$SIG{'PIPE'}="IGNORE";
31$ENV{'TZ'}="UTC";
32
0455ec03 33our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R);
ffd97f3a 34my (%conv_author_name, %conv_author_email);
a57a9493 35
7bf77644
FL
36sub usage(;$) {
37 my $msg = shift;
38 print(STDERR "Error: $msg\n") if $msg;
a57a9493 39 print STDERR <<END;
1b1dd23f 40Usage: git cvsimport # fetch/update GIT from CVS
ffd97f3a 41 [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
edbe4466
FL
42 [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
43 [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
0455ec03 44 [-r remote] [-R] [CVS_module]
a57a9493
MU
45END
46 exit(1);
47}
48
ffd97f3a
AE
49sub read_author_info($) {
50 my ($file) = @_;
51 my $user;
52 open my $f, '<', "$file" or die("Failed to open $file: $!\n");
53
54 while (<$f>) {
8cd16211 55 # Expected format is this:
ffd97f3a 56 # exon=Andreas Ericsson <ae@op5.se>
8cd16211 57 if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
ffd97f3a 58 $user = $1;
8cd16211
JH
59 $conv_author_name{$user} = $2;
60 $conv_author_email{$user} = $3;
ffd97f3a 61 }
8cd16211
JH
62 # However, we also read from CVSROOT/users format
63 # to ease migration.
64 elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
65 my $mapped;
66 ($user, $mapped) = ($1, $3);
67 if ($mapped =~ /^\s*(.*?)\s*<(.*)>\s*$/) {
68 $conv_author_name{$user} = $1;
69 $conv_author_email{$user} = $2;
70 }
71 elsif ($mapped =~ /^<?(.*)>?$/) {
72 $conv_author_name{$user} = $user;
73 $conv_author_email{$user} = $1;
74 }
75 }
76 # NEEDSWORK: Maybe warn on unrecognized lines?
ffd97f3a
AE
77 }
78 close ($f);
79}
80
81sub write_author_info($) {
82 my ($file) = @_;
83 open my $f, '>', $file or
84 die("Failed to open $file for writing: $!");
85
86 foreach (keys %conv_author_name) {
8cd16211 87 print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
ffd97f3a
AE
88 }
89 close ($f);
90}
91
cfc44a12 92# convert getopts specs for use by git config
60d5985d
MG
93my %longmap = (
94 'A:' => 'authors-file',
95 'M:' => 'merge-regex',
96 'P:' => undef,
97 'R' => 'track-revisions',
98 'S:' => 'ignore-paths',
99);
100
ed35dece 101sub read_repo_config {
549ad6d2
MG
102 # Split the string between characters, unless there is a ':'
103 # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
ed35dece
JB
104 my @opts = split(/ *(?!:)/, shift);
105 foreach my $o (@opts) {
106 my $key = $o;
107 $key =~ s/://g;
cfc44a12 108 my $arg = 'git config';
ed35dece 109 $arg .= ' --bool' if ($o !~ /:$/);
60d5985d 110 my $ckey = $key;
ed35dece 111
60d5985d
MG
112 if (exists $longmap{$o}) {
113 # An uppercase option like -R cannot be
114 # expressed in the configuration, as the
115 # variable names are downcased.
116 $ckey = $longmap{$o};
117 next if (! defined $ckey);
118 $ckey =~ s/-//g;
119 }
120 chomp(my $tmp = `$arg --get cvsimport.$ckey`);
ed35dece 121 if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
549ad6d2
MG
122 no strict 'refs';
123 my $opt_name = "opt_" . $key;
124 if (!$$opt_name) {
125 $$opt_name = $tmp;
126 }
ed35dece
JB
127 }
128 }
ed35dece
JB
129}
130
0455ec03 131my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:R";
ed35dece 132read_repo_config($opts);
bc434e82
PB
133Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
134
135# turn the Getopt::Std specification in a Getopt::Long one,
136# with support for multiple -M options
137GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
138 or usage();
a57a9493
MU
139usage if $opt_h;
140
67d23242 141if (@ARGV == 0) {
cfc44a12 142 chomp(my $module = `git config --get cvsimport.module`);
67d23242
JK
143 push(@ARGV, $module) if $? == 0;
144}
7bf77644 145@ARGV <= 1 or usage("You can't specify more than one CVS module");
a57a9493 146
86d11cf2 147if ($opt_d) {
2a3e1a85 148 $ENV{"CVSROOT"} = $opt_d;
86d11cf2 149} elsif (-f 'CVS/Root') {
f9714a4a
SV
150 open my $f, '<', 'CVS/Root' or die 'Failed to open CVS/Root';
151 $opt_d = <$f>;
152 chomp $opt_d;
153 close $f;
154 $ENV{"CVSROOT"} = $opt_d;
86d11cf2 155} elsif ($ENV{"CVSROOT"}) {
2a3e1a85
MU
156 $opt_d = $ENV{"CVSROOT"};
157} else {
7bf77644 158 usage("CVSROOT needs to be set");
2a3e1a85 159}
fbfd60d6 160$opt_s ||= "-";
ded9f400
ML
161$opt_a ||= 0;
162
f9714a4a 163my $git_tree = $opt_C;
2a3e1a85
MU
164$git_tree ||= ".";
165
8b7f5fc1
AW
166my $remote;
167if (defined $opt_r) {
168 $remote = 'refs/remotes/' . $opt_r;
169 $opt_o ||= "master";
170} else {
171 $opt_o ||= "origin";
172 $remote = 'refs/heads';
173}
174
f9714a4a
SV
175my $cvs_tree;
176if ($#ARGV == 0) {
177 $cvs_tree = $ARGV[0];
178} elsif (-f 'CVS/Repository') {
a6080a0a 179 open my $f, '<', 'CVS/Repository' or
f9714a4a
SV
180 die 'Failed to open CVS/Repository';
181 $cvs_tree = <$f>;
182 chomp $cvs_tree;
db4b6582 183 close $f;
f9714a4a 184} else {
7bf77644 185 usage("CVS module has to be specified");
f9714a4a
SV
186}
187
db4b6582
ML
188our @mergerx = ();
189if ($opt_m) {
fbbbc362 190 @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
db4b6582 191}
bc434e82
PB
192if (@opt_M) {
193 push (@mergerx, map { qr/$_/ } @opt_M);
db4b6582
ML
194}
195
6211988f
ML
196# Remember UTC of our starting time
197# we'll want to avoid importing commits
198# that are too recent
199our $starttime = time();
200
a57a9493
MU
201select(STDERR); $|=1; select(STDOUT);
202
203
204package CVSconn;
205# Basic CVS dialog.
2a3e1a85 206# We're only interested in connecting and downloading, so ...
a57a9493 207
2eb6d82e
SV
208use File::Spec;
209use File::Temp qw(tempfile);
f65ae603
MU
210use POSIX qw(strftime dup2);
211
a57a9493 212sub new {
86d11cf2 213 my ($what,$repo,$subdir) = @_;
a57a9493
MU
214 $what=ref($what) if ref($what);
215
216 my $self = {};
217 $self->{'buffer'} = "";
218 bless($self,$what);
219
220 $repo =~ s#/+$##;
221 $self->{'fullrep'} = $repo;
222 $self->conn();
223
224 $self->{'subdir'} = $subdir;
225 $self->{'lines'} = undef;
226
227 return $self;
228}
229
230sub conn {
231 my $self = shift;
232 my $repo = $self->{'fullrep'};
86d11cf2
JH
233 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
234 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
73bcf533 235
86d11cf2
JH
236 my ($proxyhost,$proxyport);
237 if ($param && ($param =~ m/proxy=([^;]+)/)) {
73bcf533
IA
238 $proxyhost = $1;
239 # Default proxyport, if not specified, is 8080.
240 $proxyport = 8080;
86d11cf2 241 if ($ENV{"CVS_PROXY_PORT"}) {
73bcf533
IA
242 $proxyport = $ENV{"CVS_PROXY_PORT"};
243 }
86d11cf2 244 if ($param =~ m/proxyport=([^;]+)/) {
73bcf533
IA
245 $proxyport = $1;
246 }
247 }
8c372fb0 248 $repo ||= '/';
73bcf533 249
2e458e05
GH
250 # if username is not explicit in CVSROOT, then use current user, as cvs would
251 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
2a3e1a85 252 my $rr2 = "-";
86d11cf2 253 unless ($port) {
a57a9493
MU
254 $rr2 = ":pserver:$user\@$serv:$repo";
255 $port=2401;
256 }
257 my $rr = ":pserver:$user\@$serv:$port$repo";
258
3fb9d582
PO
259 if ($pass) {
260 $pass = $self->_scramble($pass);
261 } else {
a57a9493
MU
262 open(H,$ENV{'HOME'}."/.cvspass") and do {
263 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
86d11cf2 264 while (<H>) {
a57a9493
MU
265 chomp;
266 s/^\/\d+\s+//;
267 my ($w,$p) = split(/\s/,$_,2);
86d11cf2 268 if ($w eq $rr or $w eq $rr2) {
a57a9493
MU
269 $pass = $p;
270 last;
271 }
272 }
273 };
e481b1d8 274 $pass = "A" unless $pass;
a57a9493 275 }
b2139dbd 276
73bcf533 277 my ($s, $rep);
86d11cf2 278 if ($proxyhost) {
73bcf533
IA
279
280 # Use a HTTP Proxy. Only works for HTTP proxies that
281 # don't require user authentication
282 #
283 # See: http://www.ietf.org/rfc/rfc2817.txt
284
285 $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
286 die "Socket to $proxyhost: $!\n" unless defined $s;
287 $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
288 or die "Write to $proxyhost: $!\n";
289 $s->flush();
290
291 $rep = <$s>;
292
293 # The answer should look like 'HTTP/1.x 2yy ....'
86d11cf2 294 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
73bcf533
IA
295 die "Proxy connect: $rep\n";
296 }
297 # Skip up to the empty line of the proxy server output
298 # including the response headers.
299 while ($rep = <$s>) {
300 last if (!defined $rep ||
301 $rep eq "\n" ||
302 $rep eq "\r\n");
303 }
304 } else {
305 $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
306 die "Socket to $serv: $!\n" unless defined $s;
307 }
308
a57a9493
MU
309 $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
310 or die "Write to $serv: $!\n";
311 $s->flush();
312
73bcf533 313 $rep = <$s>;
a57a9493 314
86d11cf2 315 if ($rep ne "I LOVE YOU\n") {
a57a9493
MU
316 $rep="<unknown>" unless $rep;
317 die "AuthReply: $rep\n";
318 }
319 $self->{'socketo'} = $s;
320 $self->{'socketi'} = $s;
34155390 321 } else { # local or ext: Fork off our own cvs server.
a57a9493
MU
322 my $pr = IO::Pipe->new();
323 my $pw = IO::Pipe->new();
324 my $pid = fork();
325 die "Fork: $!\n" unless defined $pid;
8d0ea311
SV
326 my $cvs = 'cvs';
327 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
34155390
SV
328 my $rsh = 'rsh';
329 $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH};
330
331 my @cvs = ($cvs, 'server');
332 my ($local, $user, $host);
333 $local = $repo =~ s/:local://;
334 if (!$local) {
335 $repo =~ s/:ext://;
336 $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://);
337 ($user, $host) = ($1, $2);
338 }
339 if (!$local) {
340 if ($user) {
341 unshift @cvs, $rsh, '-l', $user, $host;
342 } else {
343 unshift @cvs, $rsh, $host;
344 }
345 }
346
86d11cf2 347 unless ($pid) {
a57a9493
MU
348 $pr->writer();
349 $pw->reader();
a57a9493
MU
350 dup2($pw->fileno(),0);
351 dup2($pr->fileno(),1);
352 $pr->close();
353 $pw->close();
34155390 354 exec(@cvs);
a57a9493
MU
355 }
356 $pw->writer();
357 $pr->reader();
358 $self->{'socketo'} = $pw;
359 $self->{'socketi'} = $pr;
360 }
361 $self->{'socketo'}->write("Root $repo\n");
362
363 # Trial and error says that this probably is the minimum set
b0921331 364 $self->{'socketo'}->write("Valid-responses ok error Valid-requests Mode M Mbinary E Checked-in Created Updated Merged Removed\n");
a57a9493
MU
365
366 $self->{'socketo'}->write("valid-requests\n");
367 $self->{'socketo'}->flush();
368
e7cad3cc
FK
369 my $rep=$self->readline();
370 die "Failed to read from server" unless defined $rep;
371 chomp($rep);
86d11cf2 372 if ($rep !~ s/^Valid-requests\s*//) {
a57a9493
MU
373 $rep="<unknown>" unless $rep;
374 die "Expected Valid-requests from server, but got: $rep\n";
375 }
376 chomp(my $res=$self->readline());
377 die "validReply: $res\n" if $res ne "ok";
378
379 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
380 $self->{'repo'} = $repo;
381}
382
383sub readline {
86d11cf2 384 my ($self) = @_;
a57a9493
MU
385 return $self->{'socketi'}->getline();
386}
387
388sub _file {
389 # Request a file with a given revision.
390 # Trial and error says this is a good way to do it. :-/
86d11cf2 391 my ($self,$fn,$rev) = @_;
a57a9493
MU
392 $self->{'socketo'}->write("Argument -N\n") or return undef;
393 $self->{'socketo'}->write("Argument -P\n") or return undef;
abe05822
ML
394 # -kk: Linus' version doesn't use it - defaults to off
395 if ($opt_k) {
396 $self->{'socketo'}->write("Argument -kk\n") or return undef;
397 }
a57a9493
MU
398 $self->{'socketo'}->write("Argument -r\n") or return undef;
399 $self->{'socketo'}->write("Argument $rev\n") or return undef;
400 $self->{'socketo'}->write("Argument --\n") or return undef;
401 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
402 $self->{'socketo'}->write("Directory .\n") or return undef;
403 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
4f7c0caa 404 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
a57a9493
MU
405 $self->{'socketo'}->write("co\n") or return undef;
406 $self->{'socketo'}->flush() or return undef;
407 $self->{'lines'} = 0;
408 return 1;
409}
410sub _line {
411 # Read a line from the server.
412 # ... except that 'line' may be an entire file. ;-)
86d11cf2 413 my ($self, $fh) = @_;
a57a9493
MU
414 die "Not in lines" unless defined $self->{'lines'};
415
416 my $line;
2eb6d82e 417 my $res=0;
86d11cf2 418 while (defined($line = $self->readline())) {
a57a9493
MU
419 # M U gnupg-cvs-rep/AUTHORS
420 # Updated gnupg-cvs-rep/
421 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
422 # /AUTHORS/1.1///T1.1
423 # u=rw,g=rw,o=rw
424 # 0
425 # ok
426
86d11cf2 427 if ($line =~ s/^(?:Created|Updated) //) {
a57a9493
MU
428 $line = $self->readline(); # path
429 $line = $self->readline(); # Entries line
430 my $mode = $self->readline(); chomp $mode;
431 $self->{'mode'} = $mode;
432 defined (my $cnt = $self->readline())
433 or die "EOF from server after 'Changed'\n";
434 chomp $cnt;
435 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
436 $line="";
55cad842 437 $res = $self->_fetchfile($fh, $cnt);
86d11cf2 438 } elsif ($line =~ s/^ //) {
2eb6d82e
SV
439 print $fh $line;
440 $res += length($line);
86d11cf2 441 } elsif ($line =~ /^M\b/) {
a57a9493 442 # output, do nothing
86d11cf2 443 } elsif ($line =~ /^Mbinary\b/) {
a57a9493
MU
444 my $cnt;
445 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
446 chomp $cnt;
447 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
448 $line="";
55cad842 449 $res += $self->_fetchfile($fh, $cnt);
a57a9493
MU
450 } else {
451 chomp $line;
86d11cf2 452 if ($line eq "ok") {
a57a9493
MU
453 # print STDERR "S: ok (".length($res).")\n";
454 return $res;
86d11cf2 455 } elsif ($line =~ s/^E //) {
a57a9493 456 # print STDERR "S: $line\n";
86d11cf2 457 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
8b8840e0
MU
458 $line = $self->readline(); # filename
459 $line = $self->readline(); # OK
460 chomp $line;
461 die "Unknown: $line" if $line ne "ok";
462 return -1;
a57a9493
MU
463 } else {
464 die "Unknown: $line\n";
465 }
466 }
467 }
39ba7d54 468 return undef;
a57a9493
MU
469}
470sub file {
86d11cf2 471 my ($self,$fn,$rev) = @_;
a57a9493
MU
472 my $res;
473
a6080a0a 474 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
2eb6d82e
SV
475 DIR => File::Spec->tmpdir(), UNLINK => 1);
476
477 $self->_file($fn,$rev) and $res = $self->_line($fh);
478
479 if (!defined $res) {
39ba7d54
MM
480 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
481 truncate $fh, 0;
2eb6d82e 482 $self->conn();
39ba7d54 483 $self->_file($fn,$rev) or die "No file command send";
2eb6d82e 484 $res = $self->_line($fh);
39ba7d54 485 die "Retry failed" unless defined $res;
a57a9493 486 }
c619ad51 487 close ($fh);
a57a9493 488
2eb6d82e 489 return ($name, $res);
a57a9493 490}
55cad842
ML
491sub _fetchfile {
492 my ($self, $fh, $cnt) = @_;
61efa5e3 493 my $res = 0;
55cad842 494 my $bufsize = 1024 * 1024;
86d11cf2 495 while ($cnt) {
55cad842
ML
496 if ($bufsize > $cnt) {
497 $bufsize = $cnt;
498 }
499 my $buf;
500 my $num = $self->{'socketi'}->read($buf,$bufsize);
501 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
502 print $fh $buf;
503 $res += $num;
504 $cnt -= $num;
505 }
506 return $res;
507}
a57a9493 508
b2139dbd
DH
509sub _scramble {
510 my ($self, $pass) = @_;
511 my $scrambled = "A";
512
513 return $scrambled unless $pass;
514
515 my $pass_len = length($pass);
516 my @pass_arr = split("", $pass);
517 my $i;
518
519 # from cvs/src/scramble.c
520 my @shifts = (
521 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
522 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
523 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
524 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
525 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
526 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
527 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
528 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
529 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
530 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
531 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
532 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
533 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
534 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
535 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
536 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
537 );
538
539 for ($i = 0; $i < $pass_len; $i++) {
540 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
541 }
542
543 return $scrambled;
544}
a57a9493
MU
545
546package main;
547
2a3e1a85 548my $cvs = CVSconn->new($opt_d, $cvs_tree);
a57a9493
MU
549
550
551sub pdate($) {
86d11cf2 552 my ($d) = @_;
a57a9493
MU
553 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
554 or die "Unparseable date: $d\n";
555 my $y=$1; $y-=1900 if $y>1900;
556 return timegm($6||0,$5,$4,$3,$2-1,$y);
9718a00b
TM
557}
558
a57a9493 559sub pmode($) {
86d11cf2 560 my ($mode) = @_;
a57a9493
MU
561 my $m = 0;
562 my $mm = 0;
563 my $um = 0;
564 for my $x(split(//,$mode)) {
86d11cf2 565 if ($x eq ",") {
a57a9493
MU
566 $m |= $mm&$um;
567 $mm = 0;
568 $um = 0;
86d11cf2
JH
569 } elsif ($x eq "u") { $um |= 0700;
570 } elsif ($x eq "g") { $um |= 0070;
571 } elsif ($x eq "o") { $um |= 0007;
572 } elsif ($x eq "r") { $mm |= 0444;
573 } elsif ($x eq "w") { $mm |= 0222;
574 } elsif ($x eq "x") { $mm |= 0111;
575 } elsif ($x eq "=") { # do nothing
a57a9493
MU
576 } else { die "Unknown mode: $mode\n";
577 }
578 }
579 $m |= $mm&$um;
580 return $m;
581}
d4f8b390 582
a57a9493
MU
583sub getwd() {
584 my $pwd = `pwd`;
585 chomp $pwd;
586 return $pwd;
d4f8b390
LT
587}
588
e73aefe4
JK
589sub is_sha1 {
590 my $s = shift;
591 return $s =~ /^[a-f0-9]{40}$/;
592}
db4b6582 593
9da0dabc
JK
594sub get_headref ($) {
595 my $name = shift;
596 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
597 return undef unless $? == 0;
598 chomp $r;
599 return $r;
db4b6582
ML
600}
601
f6fdbb68
JK
602my $user_filename_prepend = '';
603sub munge_user_filename {
604 my $name = shift;
605 return File::Spec->file_name_is_absolute($name) ?
606 $name :
607 $user_filename_prepend . $name;
608}
609
a57a9493
MU
610-d $git_tree
611 or mkdir($git_tree,0777)
612 or die "Could not create $git_tree: $!";
f6fdbb68
JK
613if ($git_tree ne '.') {
614 $user_filename_prepend = getwd() . '/';
615 chdir($git_tree);
616}
d4f8b390 617
a57a9493 618my $last_branch = "";
46541669 619my $orig_branch = "";
a57a9493 620my %branch_date;
8a5f2eac 621my $tip_at_start = undef;
a57a9493
MU
622
623my $git_dir = $ENV{"GIT_DIR"} || ".git";
624$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
625$ENV{"GIT_DIR"} = $git_dir;
79ee456c
SV
626my $orig_git_index;
627$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
8f732649
ML
628
629my %index; # holds filenames of one index per branch
061303f0 630
86d11cf2 631unless (-d $git_dir) {
91fe7324 632 system(qw(git init));
a57a9493 633 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
1bb28d87 634 system(qw(git read-tree --empty));
a57a9493
MU
635 die "Cannot init an empty tree: $?\n" if $?;
636
637 $last_branch = $opt_o;
46541669 638 $orig_branch = "";
a57a9493 639} else {
a12477db 640 open(F, "-|", qw(git symbolic-ref HEAD)) or
640d9d08 641 die "Cannot run git symbolic-ref: $!\n";
8366a10a
PR
642 chomp ($last_branch = <F>);
643 $last_branch = basename($last_branch);
644 close(F);
86d11cf2 645 unless ($last_branch) {
46541669
MU
646 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
647 $last_branch = "master";
648 }
649 $orig_branch = $last_branch;
640d9d08 650 $tip_at_start = `git rev-parse --verify HEAD`;
a57a9493
MU
651
652 # Get the last import timestamps
1f24c587 653 my $fmt = '($ref, $author) = (%(refname), %(author));';
a12477db
BW
654 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
655 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
86d11cf2 656 while (defined(my $entry = <H>)) {
1f24c587
AW
657 my ($ref, $author);
658 eval($entry) || die "cannot eval refs list: $@";
8b7f5fc1 659 my ($head) = ($ref =~ m|^$remote/(.*)|);
1f24c587
AW
660 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
661 $branch_date{$head} = $1;
a57a9493 662 }
1f24c587 663 close(H);
7ca055f7
SS
664 if (!exists $branch_date{$opt_o}) {
665 die "Branch '$opt_o' does not exist.\n".
666 "Either use the correct '-o branch' option,\n".
667 "or import to a new repository.\n";
668 }
a57a9493
MU
669}
670
671-d $git_dir
672 or die "Could not create git subdir ($git_dir).\n";
673
ffd97f3a
AE
674# now we read (and possibly save) author-info as well
675-f "$git_dir/cvs-authors" and
676 read_author_info("$git_dir/cvs-authors");
677if ($opt_A) {
f6fdbb68 678 read_author_info(munge_user_filename($opt_A));
ffd97f3a
AE
679 write_author_info("$git_dir/cvs-authors");
680}
681
0455ec03
AC
682# open .git/cvs-revisions, if requested
683open my $revision_map, '>>', "$git_dir/cvs-revisions"
684 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
685 if defined $opt_R;
686
2f57c697
ML
687
688#
689# run cvsps into a file unless we are getting
690# it passed as a file via $opt_P
691#
4083c2fc 692my $cvspsfile;
2f57c697
ML
693unless ($opt_P) {
694 print "Running cvsps...\n" if $opt_v;
695 my $pid = open(CVSPS,"-|");
4083c2fc 696 my $cvspsfh;
2f57c697 697 die "Cannot fork: $!\n" unless defined $pid;
86d11cf2 698 unless ($pid) {
2f57c697
ML
699 my @opt;
700 @opt = split(/,/,$opt_p) if defined $opt_p;
701 unshift @opt, '-z', $opt_z if defined $opt_z;
702 unshift @opt, '-q' unless defined $opt_v;
703 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
704 push @opt, '--cvs-direct';
705 }
706 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
707 die "Could not start cvsps: $!\n";
df73e9c6 708 }
4083c2fc
ML
709 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
710 DIR => File::Spec->tmpdir());
2f57c697
ML
711 while (<CVSPS>) {
712 print $cvspsfh $_;
211dcac6 713 }
2f57c697 714 close CVSPS;
640d9d08 715 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
2f57c697 716 close $cvspsfh;
4083c2fc 717} else {
f6fdbb68 718 $cvspsfile = munge_user_filename($opt_P);
a57a9493
MU
719}
720
4083c2fc 721open(CVS, "<$cvspsfile") or die $!;
2f57c697 722
a57a9493
MU
723## cvsps output:
724#---------------------
725#PatchSet 314
726#Date: 1999/09/18 13:03:59
727#Author: wkoch
728#Branch: STABLE-BRANCH-1-0
729#Ancestor branch: HEAD
730#Tag: (none)
731#Log:
732# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
733#Members:
734# README:1.57->1.57.2.1
735# VERSION:1.96->1.96.2.1
736#
737#---------------------
738
739my $state = 0;
740
e73aefe4
JK
741sub update_index (\@\@) {
742 my $old = shift;
743 my $new = shift;
640d9d08
BW
744 open(my $fh, '|-', qw(git update-index -z --index-info))
745 or die "unable to open git update-index: $!";
6a1871e1
JK
746 print $fh
747 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
e73aefe4 748 @$old),
6a1871e1 749 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
e73aefe4 750 @$new)
640d9d08 751 or die "unable to write to git update-index: $!";
6a1871e1 752 close $fh
640d9d08
BW
753 or die "unable to write to git update-index: $!";
754 $? and die "git update-index reported error: $?";
e73aefe4 755}
a57a9493 756
e73aefe4 757sub write_tree () {
a12477db 758 open(my $fh, '-|', qw(git write-tree))
640d9d08 759 or die "unable to open git write-tree: $!";
e73aefe4
JK
760 chomp(my $tree = <$fh>);
761 is_sha1($tree)
762 or die "Cannot get tree id ($tree): $!";
763 close($fh)
640d9d08 764 or die "Error running git write-tree: $?\n";
a57a9493 765 print "Tree ID $tree\n" if $opt_v;
e73aefe4
JK
766 return $tree;
767}
a57a9493 768
86d11cf2 769my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
0455ec03 770my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
71b08148
ML
771
772# commits that cvsps cannot place anywhere...
773$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
774
e73aefe4 775sub commit {
9da0dabc
JK
776 if ($branch eq $opt_o && !$index{branch} &&
777 !get_headref("$remote/$branch")) {
c5f448b0 778 # looks like an initial commit
640d9d08 779 # use the index primed by git init
23fcdc79
MM
780 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
781 $index{$branch} = "$git_dir/index";
c5f448b0
ML
782 } else {
783 # use an index per branch to speed up
784 # imports of projects with many branches
785 unless ($index{$branch}) {
786 $index{$branch} = tmpnam();
787 $ENV{GIT_INDEX_FILE} = $index{$branch};
788 if ($ancestor) {
640d9d08 789 system("git", "read-tree", "$remote/$ancestor");
c5f448b0 790 } else {
640d9d08 791 system("git", "read-tree", "$remote/$branch");
c5f448b0
ML
792 }
793 die "read-tree failed: $?\n" if $?;
794 }
795 }
796 $ENV{GIT_INDEX_FILE} = $index{$branch};
797
e73aefe4
JK
798 update_index(@old, @new);
799 @old = @new = ();
800 my $tree = write_tree();
9da0dabc 801 my $parent = get_headref("$remote/$last_branch");
e73aefe4
JK
802 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
803
804 my @commit_args;
805 push @commit_args, ("-p", $parent) if $parent;
806
807 # loose detection of merges
808 # based on the commit msg
809 foreach my $rx (@mergerx) {
810 next unless $logmsg =~ $rx && $1;
811 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
9da0dabc 812 if (my $sha1 = get_headref("$remote/$mparent")) {
c36c5b84 813 push @commit_args, '-p', "$remote/$mparent";
e73aefe4 814 print "Merge parent branch: $mparent\n" if $opt_v;
db4b6582 815 }
a57a9493 816 }
e73aefe4
JK
817
818 my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
62bf0d96
JK
819 $ENV{GIT_AUTHOR_NAME} = $author_name;
820 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
821 $ENV{GIT_AUTHOR_DATE} = $commit_date;
822 $ENV{GIT_COMMITTER_NAME} = $author_name;
823 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
824 $ENV{GIT_COMMITTER_DATE} = $commit_date;
e73aefe4 825 my $pid = open2(my $commit_read, my $commit_write,
640d9d08 826 'git', 'commit-tree', $tree, @commit_args);
e371046b
MU
827
828 # compatibility with git2cvs
829 substr($logmsg,32767) = "" if length($logmsg) > 32767;
830 $logmsg =~ s/[\s\n]+\z//;
831
5179c8a5
ML
832 if (@skipped) {
833 $logmsg .= "\n\n\nSKIPPED:\n\t";
834 $logmsg .= join("\n\t", @skipped) . "\n";
f396f01f 835 @skipped = ();
5179c8a5
ML
836 }
837
e73aefe4 838 print($commit_write "$logmsg\n") && close($commit_write)
640d9d08 839 or die "Error writing to git commit-tree: $!\n";
2a3e1a85 840
e73aefe4
JK
841 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
842 chomp(my $cid = <$commit_read>);
843 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
a57a9493 844 print "Commit ID $cid\n" if $opt_v;
e73aefe4 845 close($commit_read);
2a3e1a85
MU
846
847 waitpid($pid,0);
640d9d08 848 die "Error running git commit-tree: $?\n" if $?;
a57a9493 849
640d9d08 850 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
a57a9493
MU
851 or die "Cannot write branch $branch for update: $!\n";
852
0455ec03
AC
853 if ($revision_map) {
854 print $revision_map "@$_ $cid\n" for @commit_revisions;
855 }
856 @commit_revisions = ();
857
86d11cf2 858 if ($tag) {
86d11cf2 859 my ($xtag) = $tag;
0d821d4d
PA
860 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
861 $xtag =~ tr/_/\./ if ( $opt_u );
34c99da2 862 $xtag =~ s/[\/]/$opt_s/g;
509792b9 863 $xtag =~ s/\[//g;
a6080a0a 864
640d9d08 865 system('git' , 'tag', '-f', $xtag, $cid) == 0
0d821d4d 866 or die "Cannot create tag $xtag: $!\n";
0d821d4d
PA
867
868 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
a57a9493 869 }
a57a9493
MU
870};
871
06918348 872my $commitcount = 1;
86d11cf2 873while (<CVS>) {
a57a9493 874 chomp;
86d11cf2 875 if ($state == 0 and /^-+$/) {
a57a9493 876 $state = 1;
86d11cf2 877 } elsif ($state == 0) {
a57a9493
MU
878 $state = 1;
879 redo;
86d11cf2 880 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
a57a9493
MU
881 $patchset = 0+$_;
882 $state=2;
86d11cf2 883 } elsif ($state == 2 and s/^Date:\s+//) {
a57a9493 884 $date = pdate($_);
86d11cf2 885 unless ($date) {
a57a9493
MU
886 print STDERR "Could not parse date: $_\n";
887 $state=0;
888 next;
889 }
890 $state=3;
86d11cf2 891 } elsif ($state == 3 and s/^Author:\s+//) {
a57a9493 892 s/\s+$//;
94c23343
JH
893 if (/^(.*?)\s+<(.*)>/) {
894 ($author_name, $author_email) = ($1, $2);
ffd97f3a
AE
895 } elsif ($conv_author_name{$_}) {
896 $author_name = $conv_author_name{$_};
897 $author_email = $conv_author_email{$_};
94c23343
JH
898 } else {
899 $author_name = $author_email = $_;
900 }
a57a9493 901 $state = 4;
86d11cf2 902 } elsif ($state == 4 and s/^Branch:\s+//) {
a57a9493 903 s/\s+$//;
a0554224 904 tr/_/\./ if ( $opt_u );
fbfd60d6 905 s/[\/]/$opt_s/g;
a57a9493
MU
906 $branch = $_;
907 $state = 5;
86d11cf2 908 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
a57a9493
MU
909 s/\s+$//;
910 $ancestor = $_;
0fa2824f 911 $ancestor = $opt_o if $ancestor eq "HEAD";
a57a9493 912 $state = 6;
86d11cf2 913 } elsif ($state == 5) {
a57a9493
MU
914 $ancestor = undef;
915 $state = 6;
916 redo;
86d11cf2 917 } elsif ($state == 6 and s/^Tag:\s+//) {
a57a9493 918 s/\s+$//;
86d11cf2 919 if ($_ eq "(none)") {
a57a9493
MU
920 $tag = undef;
921 } else {
922 $tag = $_;
923 }
924 $state = 7;
86d11cf2 925 } elsif ($state == 7 and /^Log:/) {
a57a9493
MU
926 $logmsg = "";
927 $state = 8;
86d11cf2 928 } elsif ($state == 8 and /^Members:/) {
a57a9493 929 $branch = $opt_o if $branch eq "HEAD";
86d11cf2 930 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
a57a9493 931 # skip
9da07f34 932 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
a57a9493
MU
933 $state = 11;
934 next;
935 }
ded9f400 936 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
6211988f 937 # skip if the commit is too recent
77190eb9 938 # given that the cvsps default fuzz is 300s, we give ourselves another
6211988f
ML
939 # 300s just in case -- this also prevents skipping commits
940 # due to server clock drift
941 print "skip patchset $patchset: $date too recent\n" if $opt_v;
942 $state = 11;
943 next;
944 }
71b08148
ML
945 if (exists $ignorebranch{$branch}) {
946 print STDERR "Skipping $branch\n";
947 $state = 11;
948 next;
949 }
86d11cf2
JH
950 if ($ancestor) {
951 if ($ancestor eq $branch) {
71b08148
ML
952 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
953 $ancestor = $opt_o;
954 }
0750d751 955 if (defined get_headref("$remote/$branch")) {
a57a9493
MU
956 print STDERR "Branch $branch already exists!\n";
957 $state=11;
958 next;
959 }
0750d751
JK
960 my $id = get_headref("$remote/$ancestor");
961 if (!$id) {
a57a9493 962 print STDERR "Branch $ancestor does not exist!\n";
71b08148 963 $ignorebranch{$branch} = 1;
a57a9493
MU
964 $state=11;
965 next;
966 }
0750d751
JK
967
968 system(qw(git update-ref -m cvsimport),
969 "$remote/$branch", $id);
970 if($? != 0) {
971 print STDERR "Could not create branch $branch\n";
71b08148 972 $ignorebranch{$branch} = 1;
a57a9493
MU
973 $state=11;
974 next;
975 }
a57a9493 976 }
46e63efc 977 $last_branch = $branch if $branch ne $last_branch;
a57a9493 978 $state = 9;
86d11cf2 979 } elsif ($state == 8) {
a57a9493 980 $logmsg .= "$_\n";
86d11cf2 981 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
a57a9493 982# VERSION:1.96->1.96.2.1
2a3e1a85 983 my $init = ($2 eq "INITIAL");
a57a9493 984 my $fn = $1;
f65ae603
MU
985 my $rev = $3;
986 $fn =~ s#^/+##;
5179c8a5
ML
987 if ($opt_S && $fn =~ m/$opt_S/) {
988 print "SKIPPING $fn v $rev\n";
989 push(@skipped, $fn);
990 next;
991 }
0455ec03 992 push @commit_revisions, [$fn, $rev];
5179c8a5 993 print "Fetching $fn v $rev\n" if $opt_v;
2eb6d82e 994 my ($tmpname, $size) = $cvs->file($fn,$rev);
86d11cf2 995 if ($size == -1) {
8b8840e0
MU
996 push(@old,$fn);
997 print "Drop $fn\n" if $opt_v;
998 } else {
999 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
dd27478f
JH
1000 my $pid = open(my $F, '-|');
1001 die $! unless defined $pid;
1002 if (!$pid) {
640d9d08 1003 exec("git", "hash-object", "-w", $tmpname)
8b8840e0 1004 or die "Cannot create object: $!\n";
dd27478f 1005 }
8b8840e0
MU
1006 my $sha = <$F>;
1007 chomp $sha;
1008 close $F;
1009 my $mode = pmode($cvs->{'mode'});
1010 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1011 }
2eb6d82e 1012 unlink($tmpname);
86d11cf2 1013 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
f65ae603 1014 my $fn = $1;
0455ec03 1015 my $rev = $2;
f65ae603 1016 $fn =~ s#^/+##;
0455ec03 1017 push @commit_revisions, [$fn, $rev];
f65ae603 1018 push(@old,$fn);
8b8840e0 1019 print "Delete $fn\n" if $opt_v;
86d11cf2 1020 } elsif ($state == 9 and /^\s*$/) {
a57a9493 1021 $state = 10;
86d11cf2 1022 } elsif (($state == 9 or $state == 10) and /^-+$/) {
4adcea99
LT
1023 $commitcount++;
1024 if ($opt_L && $commitcount > $opt_L) {
06918348
ML
1025 last;
1026 }
c4b16f8d 1027 commit();
4adcea99 1028 if (($commitcount & 1023) == 0) {
91fe7324 1029 system(qw(git repack -a -d));
4adcea99 1030 }
a57a9493 1031 $state = 1;
86d11cf2 1032 } elsif ($state == 11 and /^-+$/) {
a57a9493 1033 $state = 1;
86d11cf2 1034 } elsif (/^-+$/) { # end of unknown-line processing
a57a9493 1035 $state = 1;
86d11cf2 1036 } elsif ($state != 11) { # ignore stuff when skipping
3be39998 1037 print STDERR "* UNKNOWN LINE * $_\n";
a57a9493
MU
1038 }
1039}
c4b16f8d 1040commit() if $branch and $state != 11;
d4f8b390 1041
4083c2fc
ML
1042unless ($opt_P) {
1043 unlink($cvspsfile);
1044}
1045
efe4abd1
JM
1046# The heuristic of repacking every 1024 commits can leave a
1047# lot of unpacked data. If there is more than 1MB worth of
1048# not-packed objects, repack once more.
640d9d08 1049my $line = `git count-objects`;
efe4abd1
JM
1050if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1051 my ($n_objects, $kb) = ($1, $2);
1052 1024 < $kb
91fe7324 1053 and system(qw(git repack -a -d));
efe4abd1
JM
1054}
1055
8f732649 1056foreach my $git_index (values %index) {
23fcdc79 1057 if ($git_index ne "$git_dir/index") {
c5f448b0
ML
1058 unlink($git_index);
1059 }
8f732649 1060}
79ee456c 1061
210569f9
SV
1062if (defined $orig_git_index) {
1063 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1064} else {
1065 delete $ENV{GIT_INDEX_FILE};
1066}
1067
46541669 1068# Now switch back to the branch we were in before all of this happened
86d11cf2 1069if ($orig_branch) {
8a5f2eac
JH
1070 print "DONE.\n" if $opt_v;
1071 if ($opt_i) {
1072 exit 0;
1073 }
640d9d08 1074 my $tip_at_end = `git rev-parse --verify HEAD`;
8a5f2eac 1075 if ($tip_at_start ne $tip_at_end) {
cb9594e2 1076 for ($tip_at_start, $tip_at_end) { chomp; }
8a5f2eac 1077 print "Fetched into the current branch.\n" if $opt_v;
640d9d08 1078 system(qw(git read-tree -u -m),
8a5f2eac
JH
1079 $tip_at_start, $tip_at_end);
1080 die "Fast-forward update failed: $?\n" if $?;
1081 }
1082 else {
640d9d08 1083 system(qw(git merge cvsimport HEAD), "$remote/$opt_o");
8a5f2eac
JH
1084 die "Could not merge $opt_o into the current branch.\n" if $?;
1085 }
46541669
MU
1086} else {
1087 $orig_branch = "master";
1088 print "DONE; creating $orig_branch branch\n" if $opt_v;
640d9d08 1089 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
0750d751 1090 unless defined get_headref('refs/heads/master');
640d9d08 1091 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
06baffd3 1092 if ($opt_r && $opt_o ne 'HEAD');
640d9d08 1093 system('git', 'update-ref', 'HEAD', "$orig_branch");
c1c774e7 1094 unless ($opt_i) {
91fe7324 1095 system(qw(git checkout -f));
c1c774e7
SV
1096 die "checkout failed: $?\n" if $?;
1097 }
46541669 1098}