blob: 8d41610bcf260545bcc5b6a8c30b43d427c70491 [file] [log] [blame]
Ævar Arnfjörð Bjarmason3328ace2010-09-24 20:00:53 +00001#!/usr/bin/perl
Tommy M. McGuire9718a002005-06-10 01:38:32 -05002
Matthias Urlichsa57a9492005-06-28 16:48:40 +02003# 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
Ævar Arnfjörð Bjarmasond48b2842010-09-24 20:00:52 +000016use 5.008;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020017use strict;
18use warnings;
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +010019use Getopt::Long;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +020020use File::Spec;
Martin Langhoff7ccd9002006-06-24 23:13:08 +120021use File::Temp qw(tempfile tmpnam);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020022use File::Path qw(mkpath);
23use File::Basename qw(basename dirname);
24use Time::Local;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +020025use IO::Socket;
26use IO::Pipe;
Jeff Kinge49289d2006-05-24 09:58:28 -040027use POSIX qw(strftime dup2 ENOENT);
H. Peter Anvin0d821d42005-09-06 10:36:01 -070028use IPC::Open2;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020029
30$SIG{'PIPE'}="IGNORE";
31$ENV{'TZ'}="UTC";
32
Aaron Crane0455ec02010-02-06 18:26:24 +000033our ($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);
Andreas Ericssonffd97f32006-01-13 00:38:59 +010034my (%conv_author_name, %conv_author_email);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020035
Frank Lichtenheld7bf77642007-04-06 23:52:41 +020036sub usage(;$) {
37 my $msg = shift;
38 print(STDERR "Error: $msg\n") if $msg;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020039 print STDERR <<END;
Stephan Beyer1b1dd232008-07-13 15:36:15 +020040Usage: git cvsimport # fetch/update GIT from CVS
Andreas Ericssonffd97f32006-01-13 00:38:59 +010041 [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
Frank Lichtenheldedbe4462007-04-06 23:52:39 +020042 [-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]
Aaron Crane0455ec02010-02-06 18:26:24 +000044 [-r remote] [-R] [CVS_module]
Matthias Urlichsa57a9492005-06-28 16:48:40 +020045END
46 exit(1);
Tommy M. McGuire9718a002005-06-10 01:38:32 -050047}
48
Andreas Ericssonffd97f32006-01-13 00:38:59 +010049sub 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>) {
Junio C Hamano8cd16212006-01-15 03:30:30 -080055 # Expected format is this:
Andreas Ericssonffd97f32006-01-13 00:38:59 +010056 # exon=Andreas Ericsson <ae@op5.se>
Junio C Hamano8cd16212006-01-15 03:30:30 -080057 if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
Andreas Ericssonffd97f32006-01-13 00:38:59 +010058 $user = $1;
Junio C Hamano8cd16212006-01-15 03:30:30 -080059 $conv_author_name{$user} = $2;
60 $conv_author_email{$user} = $3;
Andreas Ericssonffd97f32006-01-13 00:38:59 +010061 }
Junio C Hamano8cd16212006-01-15 03:30:30 -080062 # 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?
Andreas Ericssonffd97f32006-01-13 00:38:59 +010077 }
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) {
Junio C Hamano8cd16212006-01-15 03:30:30 -080087 print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
Andreas Ericssonffd97f32006-01-13 00:38:59 +010088 }
89 close ($f);
90}
91
Dan McGeecfc44a12008-01-13 22:51:10 -060092# convert getopts specs for use by git config
Michael J Gruber60d59852010-12-29 22:55:34 +010093my %longmap = (
94 'A:' => 'authors-file',
95 'M:' => 'merge-regex',
96 'P:' => undef,
97 'R' => 'track-revisions',
98 'S:' => 'ignore-paths',
99);
100
James Bowesed35dec2007-02-07 17:57:43 -0500101sub read_repo_config {
Michael J Gruber549ad6d2010-11-28 20:39:45 +0100102 # Split the string between characters, unless there is a ':'
103 # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
James Bowesed35dec2007-02-07 17:57:43 -0500104 my @opts = split(/ *(?!:)/, shift);
105 foreach my $o (@opts) {
106 my $key = $o;
107 $key =~ s/://g;
Dan McGeecfc44a12008-01-13 22:51:10 -0600108 my $arg = 'git config';
James Bowesed35dec2007-02-07 17:57:43 -0500109 $arg .= ' --bool' if ($o !~ /:$/);
Michael J Gruber60d59852010-12-29 22:55:34 +0100110 my $ckey = $key;
James Bowesed35dec2007-02-07 17:57:43 -0500111
Michael J Gruber60d59852010-12-29 22:55:34 +0100112 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`);
James Bowesed35dec2007-02-07 17:57:43 -0500121 if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
Michael J Gruber549ad6d2010-11-28 20:39:45 +0100122 no strict 'refs';
123 my $opt_name = "opt_" . $key;
124 if (!$$opt_name) {
125 $$opt_name = $tmp;
126 }
James Bowesed35dec2007-02-07 17:57:43 -0500127 }
128 }
James Bowesed35dec2007-02-07 17:57:43 -0500129}
130
Aaron Crane0455ec02010-02-06 18:26:24 +0000131my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:R";
James Bowesed35dec2007-02-07 17:57:43 -0500132read_repo_config($opts);
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100133Getopt::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();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200139usage if $opt_h;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700140
Jeff King67d23242007-11-30 17:22:12 -0500141if (@ARGV == 0) {
Dan McGeecfc44a12008-01-13 22:51:10 -0600142 chomp(my $module = `git config --get cvsimport.module`);
Jeff King67d23242007-11-30 17:22:12 -0500143 push(@ARGV, $module) if $? == 0;
144}
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200145@ARGV <= 1 or usage("You can't specify more than one CVS module");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200146
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800147if ($opt_d) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200148 $ENV{"CVSROOT"} = $opt_d;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800149} elsif (-f 'CVS/Root') {
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200150 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;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800155} elsif ($ENV{"CVSROOT"}) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200156 $opt_d = $ENV{"CVSROOT"};
157} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200158 usage("CVSROOT needs to be set");
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200159}
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200160$opt_s ||= "-";
Martin Langhoffded9f402007-01-08 19:43:39 +1300161$opt_a ||= 0;
162
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200163my $git_tree = $opt_C;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200164$git_tree ||= ".";
165
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100166my $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
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200175my $cvs_tree;
176if ($#ARGV == 0) {
177 $cvs_tree = $ARGV[0];
178} elsif (-f 'CVS/Repository') {
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700179 open my $f, '<', 'CVS/Repository' or
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200180 die 'Failed to open CVS/Repository';
181 $cvs_tree = <$f>;
182 chomp $cvs_tree;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200183 close $f;
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200184} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200185 usage("CVS module has to be specified");
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200186}
187
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200188our @mergerx = ();
189if ($opt_m) {
Philippe Bruhat (BooKfbbbc362008-02-28 11:18:21 +0100190 @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200191}
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100192if (@opt_M) {
193 push (@mergerx, map { qr/$_/ } @opt_M);
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200194}
195
Martin Langhoff62119882007-01-08 14:11:23 +1300196# Remember UTC of our starting time
197# we'll want to avoid importing commits
198# that are too recent
199our $starttime = time();
200
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200201select(STDERR); $|=1; select(STDOUT);
202
203
204package CVSconn;
205# Basic CVS dialog.
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200206# We're only interested in connecting and downloading, so ...
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200207
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200208use File::Spec;
209use File::Temp qw(tempfile);
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200210use POSIX qw(strftime dup2);
211
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200212sub new {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800213 my ($what,$repo,$subdir) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200214 $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;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700228}
229
Guy Rouillier58fdef02011-05-01 01:33:52 -0400230sub find_password_entry {
231 my ($cvspass, @cvsroot) = @_;
232 my ($file, $delim) = @$cvspass;
233 my $pass;
234 local ($_);
235
236 if (open(my $fh, $file)) {
237 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
238 CVSPASSFILE:
239 while (<$fh>) {
240 chomp;
241 s/^\/\d+\s+//;
242 my ($w, $p) = split($delim,$_,2);
243 for my $cvsroot (@cvsroot) {
244 if ($w eq $cvsroot) {
245 $pass = $p;
246 last CVSPASSFILE;
247 }
248 }
249 }
250 close($fh);
251 }
252 return $pass;
253}
254
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200255sub conn {
256 my $self = shift;
257 my $repo = $self->{'fullrep'};
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800258 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
259 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100260
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800261 my ($proxyhost,$proxyport);
262 if ($param && ($param =~ m/proxy=([^;]+)/)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100263 $proxyhost = $1;
264 # Default proxyport, if not specified, is 8080.
265 $proxyport = 8080;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800266 if ($ENV{"CVS_PROXY_PORT"}) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100267 $proxyport = $ENV{"CVS_PROXY_PORT"};
268 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800269 if ($param =~ m/proxyport=([^;]+)/) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100270 $proxyport = $1;
271 }
272 }
Philippe Bruhat (BooK)8c372fb2008-06-10 14:32:06 +0200273 $repo ||= '/';
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100274
Gordon Hopper2e458e02007-11-08 13:15:20 -0700275 # if username is not explicit in CVSROOT, then use current user, as cvs would
276 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200277 my $rr2 = "-";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800278 unless ($port) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200279 $rr2 = ":pserver:$user\@$serv:$repo";
280 $port=2401;
281 }
282 my $rr = ":pserver:$user\@$serv:$port$repo";
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700283
Pascal Obry3fb9d582009-09-04 13:58:32 +0200284 if ($pass) {
285 $pass = $self->_scramble($pass);
286 } else {
Guy Rouillier58fdef02011-05-01 01:33:52 -0400287 my @cvspass = ([$ENV{'HOME'}."/.cvspass", qr/\s/],
288 [$ENV{'HOME'}."/.cvs/cvspass", qr/=/]);
289 my @loc = ();
290 foreach my $cvspass (@cvspass) {
291 my $p = find_password_entry($cvspass, $rr, $rr2);
292 if ($p) {
293 push @loc, $cvspass->[0];
294 $pass = $p;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200295 }
Guy Rouillier58fdef02011-05-01 01:33:52 -0400296 }
297
298 if (1 < @loc) {
299 die("Multiple cvs password files have ".
300 "entries for CVSROOT $opt_d: @loc");
301 } elsif (!$pass) {
302 $pass = "A";
303 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200304 }
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200305
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100306 my ($s, $rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800307 if ($proxyhost) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100308
309 # Use a HTTP Proxy. Only works for HTTP proxies that
310 # don't require user authentication
311 #
312 # See: http://www.ietf.org/rfc/rfc2817.txt
313
314 $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
315 die "Socket to $proxyhost: $!\n" unless defined $s;
316 $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
317 or die "Write to $proxyhost: $!\n";
318 $s->flush();
319
320 $rep = <$s>;
321
322 # The answer should look like 'HTTP/1.x 2yy ....'
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800323 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100324 die "Proxy connect: $rep\n";
325 }
326 # Skip up to the empty line of the proxy server output
327 # including the response headers.
328 while ($rep = <$s>) {
329 last if (!defined $rep ||
330 $rep eq "\n" ||
331 $rep eq "\r\n");
332 }
333 } else {
334 $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
335 die "Socket to $serv: $!\n" unless defined $s;
336 }
337
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200338 $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
339 or die "Write to $serv: $!\n";
340 $s->flush();
341
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100342 $rep = <$s>;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200343
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800344 if ($rep ne "I LOVE YOU\n") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200345 $rep="<unknown>" unless $rep;
346 die "AuthReply: $rep\n";
347 }
348 $self->{'socketo'} = $s;
349 $self->{'socketi'} = $s;
Sven Verdoolaege34155392005-07-03 13:02:06 +0200350 } else { # local or ext: Fork off our own cvs server.
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200351 my $pr = IO::Pipe->new();
352 my $pw = IO::Pipe->new();
353 my $pid = fork();
354 die "Fork: $!\n" unless defined $pid;
Sven Verdoolaege8d0ea312005-07-03 12:26:51 +0200355 my $cvs = 'cvs';
356 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
Sven Verdoolaege34155392005-07-03 13:02:06 +0200357 my $rsh = 'rsh';
358 $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH};
359
360 my @cvs = ($cvs, 'server');
361 my ($local, $user, $host);
362 $local = $repo =~ s/:local://;
363 if (!$local) {
364 $repo =~ s/:ext://;
365 $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://);
366 ($user, $host) = ($1, $2);
367 }
368 if (!$local) {
369 if ($user) {
370 unshift @cvs, $rsh, '-l', $user, $host;
371 } else {
372 unshift @cvs, $rsh, $host;
373 }
374 }
375
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800376 unless ($pid) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200377 $pr->writer();
378 $pw->reader();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200379 dup2($pw->fileno(),0);
380 dup2($pr->fileno(),1);
381 $pr->close();
382 $pw->close();
Sven Verdoolaege34155392005-07-03 13:02:06 +0200383 exec(@cvs);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200384 }
385 $pw->writer();
386 $pr->reader();
387 $self->{'socketo'} = $pw;
388 $self->{'socketi'} = $pr;
389 }
390 $self->{'socketo'}->write("Root $repo\n");
391
392 # Trial and error says that this probably is the minimum set
iso-8859-1?Q?David_K=E5gedalb0921332005-08-15 20:18:25 +0200393 $self->{'socketo'}->write("Valid-responses ok error Valid-requests Mode M Mbinary E Checked-in Created Updated Merged Removed\n");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200394
395 $self->{'socketo'}->write("valid-requests\n");
396 $self->{'socketo'}->flush();
397
Fabian Keile7cad3c2011-01-31 20:29:46 +0100398 my $rep=$self->readline();
399 die "Failed to read from server" unless defined $rep;
400 chomp($rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800401 if ($rep !~ s/^Valid-requests\s*//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200402 $rep="<unknown>" unless $rep;
403 die "Expected Valid-requests from server, but got: $rep\n";
404 }
405 chomp(my $res=$self->readline());
406 die "validReply: $res\n" if $res ne "ok";
407
408 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
409 $self->{'repo'} = $repo;
410}
411
412sub readline {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800413 my ($self) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200414 return $self->{'socketi'}->getline();
415}
416
417sub _file {
418 # Request a file with a given revision.
419 # Trial and error says this is a good way to do it. :-/
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800420 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200421 $self->{'socketo'}->write("Argument -N\n") or return undef;
422 $self->{'socketo'}->write("Argument -P\n") or return undef;
Martin Langhoffabe05822005-08-16 17:39:29 +1200423 # -kk: Linus' version doesn't use it - defaults to off
424 if ($opt_k) {
425 $self->{'socketo'}->write("Argument -kk\n") or return undef;
426 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200427 $self->{'socketo'}->write("Argument -r\n") or return undef;
428 $self->{'socketo'}->write("Argument $rev\n") or return undef;
429 $self->{'socketo'}->write("Argument --\n") or return undef;
430 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
431 $self->{'socketo'}->write("Directory .\n") or return undef;
432 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
Matthias Urlichs4f7c0ca2005-06-30 12:19:48 +0200433 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200434 $self->{'socketo'}->write("co\n") or return undef;
435 $self->{'socketo'}->flush() or return undef;
436 $self->{'lines'} = 0;
437 return 1;
438}
439sub _line {
440 # Read a line from the server.
441 # ... except that 'line' may be an entire file. ;-)
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800442 my ($self, $fh) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200443 die "Not in lines" unless defined $self->{'lines'};
444
445 my $line;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200446 my $res=0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800447 while (defined($line = $self->readline())) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200448 # M U gnupg-cvs-rep/AUTHORS
449 # Updated gnupg-cvs-rep/
450 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
451 # /AUTHORS/1.1///T1.1
452 # u=rw,g=rw,o=rw
453 # 0
454 # ok
455
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800456 if ($line =~ s/^(?:Created|Updated) //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200457 $line = $self->readline(); # path
458 $line = $self->readline(); # Entries line
459 my $mode = $self->readline(); chomp $mode;
460 $self->{'mode'} = $mode;
461 defined (my $cnt = $self->readline())
462 or die "EOF from server after 'Changed'\n";
463 chomp $cnt;
464 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
465 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200466 $res = $self->_fetchfile($fh, $cnt);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800467 } elsif ($line =~ s/^ //) {
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200468 print $fh $line;
469 $res += length($line);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800470 } elsif ($line =~ /^M\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200471 # output, do nothing
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800472 } elsif ($line =~ /^Mbinary\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200473 my $cnt;
474 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
475 chomp $cnt;
476 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
477 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200478 $res += $self->_fetchfile($fh, $cnt);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200479 } else {
480 chomp $line;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800481 if ($line eq "ok") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200482 # print STDERR "S: ok (".length($res).")\n";
483 return $res;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800484 } elsif ($line =~ s/^E //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200485 # print STDERR "S: $line\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800486 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200487 $line = $self->readline(); # filename
488 $line = $self->readline(); # OK
489 chomp $line;
490 die "Unknown: $line" if $line ne "ok";
491 return -1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200492 } else {
493 die "Unknown: $line\n";
494 }
495 }
496 }
Martin Mares39ba7d52006-02-18 21:44:20 +0100497 return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200498}
499sub file {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800500 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200501 my $res;
502
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700503 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200504 DIR => File::Spec->tmpdir(), UNLINK => 1);
505
506 $self->_file($fn,$rev) and $res = $self->_line($fh);
507
508 if (!defined $res) {
Martin Mares39ba7d52006-02-18 21:44:20 +0100509 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
510 truncate $fh, 0;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200511 $self->conn();
Martin Mares39ba7d52006-02-18 21:44:20 +0100512 $self->_file($fn,$rev) or die "No file command send";
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200513 $res = $self->_line($fh);
Martin Mares39ba7d52006-02-18 21:44:20 +0100514 die "Retry failed" unless defined $res;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200515 }
Sven Verdoolaegec619ad52005-07-06 08:37:12 +0200516 close ($fh);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200517
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200518 return ($name, $res);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200519}
Martin Langhoff55cad842006-05-23 20:08:58 +1200520sub _fetchfile {
521 my ($self, $fh, $cnt) = @_;
Junio C Hamano61efa5e2006-05-23 16:30:39 -0700522 my $res = 0;
Martin Langhoff55cad842006-05-23 20:08:58 +1200523 my $bufsize = 1024 * 1024;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800524 while ($cnt) {
Martin Langhoff55cad842006-05-23 20:08:58 +1200525 if ($bufsize > $cnt) {
526 $bufsize = $cnt;
527 }
528 my $buf;
529 my $num = $self->{'socketi'}->read($buf,$bufsize);
530 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
531 print $fh $buf;
532 $res += $num;
533 $cnt -= $num;
534 }
535 return $res;
536}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200537
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200538sub _scramble {
539 my ($self, $pass) = @_;
540 my $scrambled = "A";
541
542 return $scrambled unless $pass;
543
544 my $pass_len = length($pass);
545 my @pass_arr = split("", $pass);
546 my $i;
547
548 # from cvs/src/scramble.c
549 my @shifts = (
550 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
551 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
552 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
553 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
554 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
555 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
556 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
557 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
558 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
559 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
560 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
561 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
562 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
563 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
564 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
565 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
566 );
567
568 for ($i = 0; $i < $pass_len; $i++) {
569 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
570 }
571
572 return $scrambled;
573}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200574
575package main;
576
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200577my $cvs = CVSconn->new($opt_d, $cvs_tree);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200578
579
580sub pdate($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800581 my ($d) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200582 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
583 or die "Unparseable date: $d\n";
584 my $y=$1; $y-=1900 if $y>1900;
585 return timegm($6||0,$5,$4,$3,$2-1,$y);
586}
587
588sub pmode($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800589 my ($mode) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200590 my $m = 0;
591 my $mm = 0;
592 my $um = 0;
593 for my $x(split(//,$mode)) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800594 if ($x eq ",") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200595 $m |= $mm&$um;
596 $mm = 0;
597 $um = 0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800598 } elsif ($x eq "u") { $um |= 0700;
599 } elsif ($x eq "g") { $um |= 0070;
600 } elsif ($x eq "o") { $um |= 0007;
601 } elsif ($x eq "r") { $mm |= 0444;
602 } elsif ($x eq "w") { $mm |= 0222;
603 } elsif ($x eq "x") { $mm |= 0111;
604 } elsif ($x eq "=") { # do nothing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200605 } else { die "Unknown mode: $mode\n";
606 }
607 }
608 $m |= $mm&$um;
609 return $m;
610}
611
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200612sub getwd() {
613 my $pwd = `pwd`;
614 chomp $pwd;
615 return $pwd;
616}
617
Jeff Kinge73aefe2006-05-23 03:27:46 -0400618sub is_sha1 {
619 my $s = shift;
620 return $s =~ /^[a-f0-9]{40}$/;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200621}
622
Jeff King9da0dab2007-11-28 13:56:11 -0500623sub get_headref ($) {
624 my $name = shift;
625 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
626 return undef unless $? == 0;
627 chomp $r;
628 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400629}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200630
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400631my $user_filename_prepend = '';
632sub munge_user_filename {
633 my $name = shift;
634 return File::Spec->file_name_is_absolute($name) ?
635 $name :
636 $user_filename_prepend . $name;
637}
638
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200639-d $git_tree
640 or mkdir($git_tree,0777)
641 or die "Could not create $git_tree: $!";
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400642if ($git_tree ne '.') {
643 $user_filename_prepend = getwd() . '/';
644 chdir($git_tree);
645}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200646
647my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200648my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200649my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800650my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200651
652my $git_dir = $ENV{"GIT_DIR"} || ".git";
653$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
654$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200655my $orig_git_index;
656$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200657
658my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200659
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800660unless (-d $git_dir) {
Ben Walton91fe7322010-01-19 14:03:10 -0500661 system(qw(git init));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200662 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
Thomas Rast1bb28d82010-10-18 15:11:25 +0200663 system(qw(git read-tree --empty));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200664 die "Cannot init an empty tree: $?\n" if $?;
665
666 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200667 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200668} else {
Ben Waltona12477d2010-01-19 14:03:09 -0500669 open(F, "-|", qw(git symbolic-ref HEAD)) or
Ben Walton640d9d02010-01-19 14:03:08 -0500670 die "Cannot run git symbolic-ref: $!\n";
Pavel Roskin8366a102005-11-16 13:27:28 -0500671 chomp ($last_branch = <F>);
672 $last_branch = basename($last_branch);
673 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800674 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200675 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
676 $last_branch = "master";
677 }
678 $orig_branch = $last_branch;
Ben Walton640d9d02010-01-19 14:03:08 -0500679 $tip_at_start = `git rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200680
681 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100682 my $fmt = '($ref, $author) = (%(refname), %(author));';
Ben Waltona12477d2010-01-19 14:03:09 -0500683 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
684 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800685 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100686 my ($ref, $author);
687 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100688 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100689 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
690 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200691 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100692 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100693 if (!exists $branch_date{$opt_o}) {
694 die "Branch '$opt_o' does not exist.\n".
695 "Either use the correct '-o branch' option,\n".
696 "or import to a new repository.\n";
697 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200698}
699
700-d $git_dir
701 or die "Could not create git subdir ($git_dir).\n";
702
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100703# now we read (and possibly save) author-info as well
704-f "$git_dir/cvs-authors" and
705 read_author_info("$git_dir/cvs-authors");
706if ($opt_A) {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400707 read_author_info(munge_user_filename($opt_A));
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100708 write_author_info("$git_dir/cvs-authors");
709}
710
Aaron Crane0455ec02010-02-06 18:26:24 +0000711# open .git/cvs-revisions, if requested
712open my $revision_map, '>>', "$git_dir/cvs-revisions"
713 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
714 if defined $opt_R;
715
Martin Langhoff2f57c692006-06-11 20:12:20 +1200716
717#
718# run cvsps into a file unless we are getting
719# it passed as a file via $opt_P
720#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300721my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200722unless ($opt_P) {
723 print "Running cvsps...\n" if $opt_v;
724 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300725 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200726 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800727 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200728 my @opt;
729 @opt = split(/,/,$opt_p) if defined $opt_p;
730 unshift @opt, '-z', $opt_z if defined $opt_z;
731 unshift @opt, '-q' unless defined $opt_v;
732 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
733 push @opt, '--cvs-direct';
734 }
735 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
736 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700737 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300738 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
739 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200740 while (<CVSPS>) {
741 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300742 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200743 close CVSPS;
Ben Walton640d9d02010-01-19 14:03:08 -0500744 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200745 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300746} else {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400747 $cvspsfile = munge_user_filename($opt_P);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200748}
749
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300750open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200751
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200752## cvsps output:
753#---------------------
754#PatchSet 314
755#Date: 1999/09/18 13:03:59
756#Author: wkoch
757#Branch: STABLE-BRANCH-1-0
758#Ancestor branch: HEAD
759#Tag: (none)
760#Log:
761# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
762#Members:
763# README:1.57->1.57.2.1
764# VERSION:1.96->1.96.2.1
765#
766#---------------------
767
768my $state = 0;
769
Jeff Kinge73aefe2006-05-23 03:27:46 -0400770sub update_index (\@\@) {
771 my $old = shift;
772 my $new = shift;
Ben Walton640d9d02010-01-19 14:03:08 -0500773 open(my $fh, '|-', qw(git update-index -z --index-info))
774 or die "unable to open git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400775 print $fh
776 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400777 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400778 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400779 @$new)
Ben Walton640d9d02010-01-19 14:03:08 -0500780 or die "unable to write to git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400781 close $fh
Ben Walton640d9d02010-01-19 14:03:08 -0500782 or die "unable to write to git update-index: $!";
783 $? and die "git update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400784}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200785
Jeff Kinge73aefe2006-05-23 03:27:46 -0400786sub write_tree () {
Ben Waltona12477d2010-01-19 14:03:09 -0500787 open(my $fh, '-|', qw(git write-tree))
Ben Walton640d9d02010-01-19 14:03:08 -0500788 or die "unable to open git write-tree: $!";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400789 chomp(my $tree = <$fh>);
790 is_sha1($tree)
791 or die "Cannot get tree id ($tree): $!";
792 close($fh)
Ben Walton640d9d02010-01-19 14:03:08 -0500793 or die "Error running git write-tree: $?\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200794 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400795 return $tree;
796}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200797
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800798my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
Aaron Crane0455ec02010-02-06 18:26:24 +0000799my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
Martin Langhoff71b08142006-06-11 20:12:09 +1200800
801# commits that cvsps cannot place anywhere...
802$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
803
Jeff Kinge73aefe2006-05-23 03:27:46 -0400804sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500805 if ($branch eq $opt_o && !$index{branch} &&
806 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200807 # looks like an initial commit
Ben Walton640d9d02010-01-19 14:03:08 -0500808 # use the index primed by git init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600809 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
810 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200811 } else {
812 # use an index per branch to speed up
813 # imports of projects with many branches
814 unless ($index{$branch}) {
815 $index{$branch} = tmpnam();
816 $ENV{GIT_INDEX_FILE} = $index{$branch};
817 if ($ancestor) {
Ben Walton640d9d02010-01-19 14:03:08 -0500818 system("git", "read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200819 } else {
Ben Walton640d9d02010-01-19 14:03:08 -0500820 system("git", "read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200821 }
822 die "read-tree failed: $?\n" if $?;
823 }
824 }
825 $ENV{GIT_INDEX_FILE} = $index{$branch};
826
Jeff Kinge73aefe2006-05-23 03:27:46 -0400827 update_index(@old, @new);
828 @old = @new = ();
829 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500830 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400831 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200832
Jeff Kinge73aefe2006-05-23 03:27:46 -0400833 my @commit_args;
834 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200835
Jeff Kinge73aefe2006-05-23 03:27:46 -0400836 # loose detection of merges
837 # based on the commit msg
838 foreach my $rx (@mergerx) {
839 next unless $logmsg =~ $rx && $1;
840 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500841 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200842 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400843 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200844 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200845 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400846
847 my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
Jeff King62bf0d92006-05-23 16:59:44 -0400848 $ENV{GIT_AUTHOR_NAME} = $author_name;
849 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
850 $ENV{GIT_AUTHOR_DATE} = $commit_date;
851 $ENV{GIT_COMMITTER_NAME} = $author_name;
852 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
853 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400854 my $pid = open2(my $commit_read, my $commit_write,
Ben Walton640d9d02010-01-19 14:03:08 -0500855 'git', 'commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200856
857 # compatibility with git2cvs
858 substr($logmsg,32767) = "" if length($logmsg) > 32767;
859 $logmsg =~ s/[\s\n]+\z//;
860
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300861 if (@skipped) {
862 $logmsg .= "\n\n\nSKIPPED:\n\t";
863 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200864 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300865 }
866
Jeff Kinge73aefe2006-05-23 03:27:46 -0400867 print($commit_write "$logmsg\n") && close($commit_write)
Ben Walton640d9d02010-01-19 14:03:08 -0500868 or die "Error writing to git commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200869
Jeff Kinge73aefe2006-05-23 03:27:46 -0400870 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
871 chomp(my $cid = <$commit_read>);
872 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200873 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400874 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200875
876 waitpid($pid,0);
Ben Walton640d9d02010-01-19 14:03:08 -0500877 die "Error running git commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200878
Ben Walton640d9d02010-01-19 14:03:08 -0500879 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200880 or die "Cannot write branch $branch for update: $!\n";
881
Aaron Crane0455ec02010-02-06 18:26:24 +0000882 if ($revision_map) {
883 print $revision_map "@$_ $cid\n" for @commit_revisions;
884 }
885 @commit_revisions = ();
886
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800887 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800888 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700889 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
890 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800891 $xtag =~ s/[\/]/$opt_s/g;
Paul Oliver509792b2008-05-23 19:29:22 +0100892 $xtag =~ s/\[//g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700893
Ben Walton640d9d02010-01-19 14:03:08 -0500894 system('git' , 'tag', '-f', $xtag, $cid) == 0
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700895 or die "Cannot create tag $xtag: $!\n";
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700896
897 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200898 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200899};
900
Martin Langhoff06918342006-05-22 23:38:08 +1200901my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800902while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200903 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800904 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200905 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800906 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200907 $state = 1;
908 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800909 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200910 $patchset = 0+$_;
911 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800912 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200913 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800914 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200915 print STDERR "Could not parse date: $_\n";
916 $state=0;
917 next;
918 }
919 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800920 } elsif ($state == 3 and s/^Author:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200921 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700922 if (/^(.*?)\s+<(.*)>/) {
923 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100924 } elsif ($conv_author_name{$_}) {
925 $author_name = $conv_author_name{$_};
926 $author_email = $conv_author_email{$_};
Junio C Hamano94c23342005-09-30 01:48:57 -0700927 } else {
928 $author_name = $author_email = $_;
929 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200930 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800931 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200932 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000933 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200934 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200935 $branch = $_;
936 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800937 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200938 s/\s+$//;
939 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200940 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200941 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800942 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200943 $ancestor = undef;
944 $state = 6;
945 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800946 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200947 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800948 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200949 $tag = undef;
950 } else {
951 $tag = $_;
952 }
953 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800954 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200955 $logmsg = "";
956 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800957 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200958 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800959 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200960 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +0200961 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200962 $state = 11;
963 next;
964 }
Martin Langhoffded9f402007-01-08 19:43:39 +1300965 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +1300966 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +0100967 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +1300968 # 300s just in case -- this also prevents skipping commits
969 # due to server clock drift
970 print "skip patchset $patchset: $date too recent\n" if $opt_v;
971 $state = 11;
972 next;
973 }
Martin Langhoff71b08142006-06-11 20:12:09 +1200974 if (exists $ignorebranch{$branch}) {
975 print STDERR "Skipping $branch\n";
976 $state = 11;
977 next;
978 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800979 if ($ancestor) {
980 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +1200981 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
982 $ancestor = $opt_o;
983 }
Jeff King0750d752007-11-28 13:56:28 -0500984 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200985 print STDERR "Branch $branch already exists!\n";
986 $state=11;
987 next;
988 }
Jeff King0750d752007-11-28 13:56:28 -0500989 my $id = get_headref("$remote/$ancestor");
990 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200991 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +1200992 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200993 $state=11;
994 next;
995 }
Jeff King0750d752007-11-28 13:56:28 -0500996
997 system(qw(git update-ref -m cvsimport),
998 "$remote/$branch", $id);
999 if($? != 0) {
1000 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001001 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001002 $state=11;
1003 next;
1004 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001005 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +02001006 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001007 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001008 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001009 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001010 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001011# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +02001012 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001013 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001014 my $rev = $3;
1015 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001016 if ($opt_S && $fn =~ m/$opt_S/) {
1017 print "SKIPPING $fn v $rev\n";
1018 push(@skipped, $fn);
1019 next;
1020 }
Aaron Crane0455ec02010-02-06 18:26:24 +00001021 push @commit_revisions, [$fn, $rev];
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001022 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001023 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001024 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001025 push(@old,$fn);
1026 print "Drop $fn\n" if $opt_v;
1027 } else {
1028 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -08001029 my $pid = open(my $F, '-|');
1030 die $! unless defined $pid;
1031 if (!$pid) {
Ben Walton640d9d02010-01-19 14:03:08 -05001032 exec("git", "hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001033 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -08001034 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001035 my $sha = <$F>;
1036 chomp $sha;
1037 close $F;
1038 my $mode = pmode($cvs->{'mode'});
1039 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1040 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001041 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001042 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001043 my $fn = $1;
Aaron Crane0455ec02010-02-06 18:26:24 +00001044 my $rev = $2;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001045 $fn =~ s#^/+##;
Aaron Crane0455ec02010-02-06 18:26:24 +00001046 push @commit_revisions, [$fn, $rev];
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001047 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001048 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001049 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001050 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001051 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -07001052 $commitcount++;
1053 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +12001054 last;
1055 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001056 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -07001057 if (($commitcount & 1023) == 0) {
Ben Walton91fe7322010-01-19 14:03:10 -05001058 system(qw(git repack -a -d));
Linus Torvalds4adcea92006-05-22 19:28:37 -07001059 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001060 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001061 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001062 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001063 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001064 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001065 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +02001066 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001067 }
1068}
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001069commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001070
Martin Langhoff4083c2f2007-01-08 21:08:46 +13001071unless ($opt_P) {
1072 unlink($cvspsfile);
1073}
1074
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001075# The heuristic of repacking every 1024 commits can leave a
1076# lot of unpacked data. If there is more than 1MB worth of
1077# not-packed objects, repack once more.
Ben Walton640d9d02010-01-19 14:03:08 -05001078my $line = `git count-objects`;
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001079if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1080 my ($n_objects, $kb) = ($1, $2);
1081 1024 < $kb
Ben Walton91fe7322010-01-19 14:03:10 -05001082 and system(qw(git repack -a -d));
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001083}
1084
Martin Langhoff8f732642006-06-12 23:50:49 +12001085foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001086 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001087 unlink($git_index);
1088 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001089}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001090
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001091if (defined $orig_git_index) {
1092 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1093} else {
1094 delete $ENV{GIT_INDEX_FILE};
1095}
1096
Matthias Urlichs46541662005-06-28 21:08:15 +02001097# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001098if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001099 print "DONE.\n" if $opt_v;
1100 if ($opt_i) {
1101 exit 0;
1102 }
Ben Walton640d9d02010-01-19 14:03:08 -05001103 my $tip_at_end = `git rev-parse --verify HEAD`;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001104 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001105 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001106 print "Fetched into the current branch.\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001107 system(qw(git read-tree -u -m),
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001108 $tip_at_start, $tip_at_end);
1109 die "Fast-forward update failed: $?\n" if $?;
1110 }
1111 else {
Ben Walton640d9d02010-01-19 14:03:08 -05001112 system(qw(git merge cvsimport HEAD), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001113 die "Could not merge $opt_o into the current branch.\n" if $?;
1114 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001115} else {
1116 $orig_branch = "master";
1117 print "DONE; creating $orig_branch branch\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001118 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001119 unless defined get_headref('refs/heads/master');
Ben Walton640d9d02010-01-19 14:03:08 -05001120 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001121 if ($opt_r && $opt_o ne 'HEAD');
Ben Walton640d9d02010-01-19 14:03:08 -05001122 system('git', 'update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001123 unless ($opt_i) {
Ben Walton91fe7322010-01-19 14:03:10 -05001124 system(qw(git checkout -f));
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001125 die "checkout failed: $?\n" if $?;
1126 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001127}