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