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