blob: bbf327f3e891cacdd14c0b18b51702ce14b2b6df [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
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200230sub conn {
231 my $self = shift;
232 my $repo = $self->{'fullrep'};
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800233 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
234 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100235
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800236 my ($proxyhost,$proxyport);
237 if ($param && ($param =~ m/proxy=([^;]+)/)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100238 $proxyhost = $1;
239 # Default proxyport, if not specified, is 8080.
240 $proxyport = 8080;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800241 if ($ENV{"CVS_PROXY_PORT"}) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100242 $proxyport = $ENV{"CVS_PROXY_PORT"};
243 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800244 if ($param =~ m/proxyport=([^;]+)/) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100245 $proxyport = $1;
246 }
247 }
Philippe Bruhat (BooK)8c372fb2008-06-10 14:32:06 +0200248 $repo ||= '/';
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100249
Gordon Hopper2e458e02007-11-08 13:15:20 -0700250 # if username is not explicit in CVSROOT, then use current user, as cvs would
251 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200252 my $rr2 = "-";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800253 unless ($port) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200254 $rr2 = ":pserver:$user\@$serv:$repo";
255 $port=2401;
256 }
257 my $rr = ":pserver:$user\@$serv:$port$repo";
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700258
Pascal Obry3fb9d582009-09-04 13:58:32 +0200259 if ($pass) {
260 $pass = $self->_scramble($pass);
261 } else {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200262 open(H,$ENV{'HOME'}."/.cvspass") and do {
263 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800264 while (<H>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200265 chomp;
266 s/^\/\d+\s+//;
267 my ($w,$p) = split(/\s/,$_,2);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800268 if ($w eq $rr or $w eq $rr2) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200269 $pass = $p;
270 last;
271 }
272 }
273 };
Clemens Buchachere481b1d2009-09-17 09:21:02 +0200274 $pass = "A" unless $pass;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200275 }
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200276
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100277 my ($s, $rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800278 if ($proxyhost) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100279
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 ....'
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800294 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100295 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
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200309 $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
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100313 $rep = <$s>;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200314
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800315 if ($rep ne "I LOVE YOU\n") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200316 $rep="<unknown>" unless $rep;
317 die "AuthReply: $rep\n";
318 }
319 $self->{'socketo'} = $s;
320 $self->{'socketi'} = $s;
Sven Verdoolaege34155392005-07-03 13:02:06 +0200321 } else { # local or ext: Fork off our own cvs server.
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200322 my $pr = IO::Pipe->new();
323 my $pw = IO::Pipe->new();
324 my $pid = fork();
325 die "Fork: $!\n" unless defined $pid;
Sven Verdoolaege8d0ea312005-07-03 12:26:51 +0200326 my $cvs = 'cvs';
327 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
Sven Verdoolaege34155392005-07-03 13:02:06 +0200328 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
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800347 unless ($pid) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200348 $pr->writer();
349 $pw->reader();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200350 dup2($pw->fileno(),0);
351 dup2($pr->fileno(),1);
352 $pr->close();
353 $pw->close();
Sven Verdoolaege34155392005-07-03 13:02:06 +0200354 exec(@cvs);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200355 }
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
iso-8859-1?Q?David_K=E5gedalb0921332005-08-15 20:18:25 +0200364 $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 +0200365
366 $self->{'socketo'}->write("valid-requests\n");
367 $self->{'socketo'}->flush();
368
Fabian Keile7cad3c2011-01-31 20:29:46 +0100369 my $rep=$self->readline();
370 die "Failed to read from server" unless defined $rep;
371 chomp($rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800372 if ($rep !~ s/^Valid-requests\s*//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200373 $rep="<unknown>" unless $rep;
374 die "Expected Valid-requests from server, but got: $rep\n";
375 }
376 chomp(my $res=$self->readline());
377 die "validReply: $res\n" if $res ne "ok";
378
379 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
380 $self->{'repo'} = $repo;
381}
382
383sub readline {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800384 my ($self) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200385 return $self->{'socketi'}->getline();
386}
387
388sub _file {
389 # Request a file with a given revision.
390 # Trial and error says this is a good way to do it. :-/
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800391 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200392 $self->{'socketo'}->write("Argument -N\n") or return undef;
393 $self->{'socketo'}->write("Argument -P\n") or return undef;
Martin Langhoffabe05822005-08-16 17:39:29 +1200394 # -kk: Linus' version doesn't use it - defaults to off
395 if ($opt_k) {
396 $self->{'socketo'}->write("Argument -kk\n") or return undef;
397 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200398 $self->{'socketo'}->write("Argument -r\n") or return undef;
399 $self->{'socketo'}->write("Argument $rev\n") or return undef;
400 $self->{'socketo'}->write("Argument --\n") or return undef;
401 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
402 $self->{'socketo'}->write("Directory .\n") or return undef;
403 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
Matthias Urlichs4f7c0ca2005-06-30 12:19:48 +0200404 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200405 $self->{'socketo'}->write("co\n") or return undef;
406 $self->{'socketo'}->flush() or return undef;
407 $self->{'lines'} = 0;
408 return 1;
409}
410sub _line {
411 # Read a line from the server.
412 # ... except that 'line' may be an entire file. ;-)
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800413 my ($self, $fh) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200414 die "Not in lines" unless defined $self->{'lines'};
415
416 my $line;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200417 my $res=0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800418 while (defined($line = $self->readline())) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200419 # M U gnupg-cvs-rep/AUTHORS
420 # Updated gnupg-cvs-rep/
421 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
422 # /AUTHORS/1.1///T1.1
423 # u=rw,g=rw,o=rw
424 # 0
425 # ok
426
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800427 if ($line =~ s/^(?:Created|Updated) //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200428 $line = $self->readline(); # path
429 $line = $self->readline(); # Entries line
430 my $mode = $self->readline(); chomp $mode;
431 $self->{'mode'} = $mode;
432 defined (my $cnt = $self->readline())
433 or die "EOF from server after 'Changed'\n";
434 chomp $cnt;
435 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
436 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200437 $res = $self->_fetchfile($fh, $cnt);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800438 } elsif ($line =~ s/^ //) {
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200439 print $fh $line;
440 $res += length($line);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800441 } elsif ($line =~ /^M\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200442 # output, do nothing
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800443 } elsif ($line =~ /^Mbinary\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200444 my $cnt;
445 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
446 chomp $cnt;
447 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
448 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200449 $res += $self->_fetchfile($fh, $cnt);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200450 } else {
451 chomp $line;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800452 if ($line eq "ok") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200453 # print STDERR "S: ok (".length($res).")\n";
454 return $res;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800455 } elsif ($line =~ s/^E //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200456 # print STDERR "S: $line\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800457 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200458 $line = $self->readline(); # filename
459 $line = $self->readline(); # OK
460 chomp $line;
461 die "Unknown: $line" if $line ne "ok";
462 return -1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200463 } else {
464 die "Unknown: $line\n";
465 }
466 }
467 }
Martin Mares39ba7d52006-02-18 21:44:20 +0100468 return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200469}
470sub file {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800471 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200472 my $res;
473
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700474 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200475 DIR => File::Spec->tmpdir(), UNLINK => 1);
476
477 $self->_file($fn,$rev) and $res = $self->_line($fh);
478
479 if (!defined $res) {
Martin Mares39ba7d52006-02-18 21:44:20 +0100480 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
481 truncate $fh, 0;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200482 $self->conn();
Martin Mares39ba7d52006-02-18 21:44:20 +0100483 $self->_file($fn,$rev) or die "No file command send";
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200484 $res = $self->_line($fh);
Martin Mares39ba7d52006-02-18 21:44:20 +0100485 die "Retry failed" unless defined $res;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200486 }
Sven Verdoolaegec619ad52005-07-06 08:37:12 +0200487 close ($fh);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200488
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200489 return ($name, $res);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200490}
Martin Langhoff55cad842006-05-23 20:08:58 +1200491sub _fetchfile {
492 my ($self, $fh, $cnt) = @_;
Junio C Hamano61efa5e2006-05-23 16:30:39 -0700493 my $res = 0;
Martin Langhoff55cad842006-05-23 20:08:58 +1200494 my $bufsize = 1024 * 1024;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800495 while ($cnt) {
Martin Langhoff55cad842006-05-23 20:08:58 +1200496 if ($bufsize > $cnt) {
497 $bufsize = $cnt;
498 }
499 my $buf;
500 my $num = $self->{'socketi'}->read($buf,$bufsize);
501 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
502 print $fh $buf;
503 $res += $num;
504 $cnt -= $num;
505 }
506 return $res;
507}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200508
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200509sub _scramble {
510 my ($self, $pass) = @_;
511 my $scrambled = "A";
512
513 return $scrambled unless $pass;
514
515 my $pass_len = length($pass);
516 my @pass_arr = split("", $pass);
517 my $i;
518
519 # from cvs/src/scramble.c
520 my @shifts = (
521 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
522 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
523 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
524 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
525 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
526 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
527 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
528 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
529 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
530 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
531 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
532 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
533 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
534 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
535 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
536 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
537 );
538
539 for ($i = 0; $i < $pass_len; $i++) {
540 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
541 }
542
543 return $scrambled;
544}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200545
546package main;
547
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200548my $cvs = CVSconn->new($opt_d, $cvs_tree);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200549
550
551sub pdate($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800552 my ($d) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200553 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
554 or die "Unparseable date: $d\n";
555 my $y=$1; $y-=1900 if $y>1900;
556 return timegm($6||0,$5,$4,$3,$2-1,$y);
557}
558
559sub pmode($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800560 my ($mode) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200561 my $m = 0;
562 my $mm = 0;
563 my $um = 0;
564 for my $x(split(//,$mode)) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800565 if ($x eq ",") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200566 $m |= $mm&$um;
567 $mm = 0;
568 $um = 0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800569 } elsif ($x eq "u") { $um |= 0700;
570 } elsif ($x eq "g") { $um |= 0070;
571 } elsif ($x eq "o") { $um |= 0007;
572 } elsif ($x eq "r") { $mm |= 0444;
573 } elsif ($x eq "w") { $mm |= 0222;
574 } elsif ($x eq "x") { $mm |= 0111;
575 } elsif ($x eq "=") { # do nothing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200576 } else { die "Unknown mode: $mode\n";
577 }
578 }
579 $m |= $mm&$um;
580 return $m;
581}
582
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200583sub getwd() {
584 my $pwd = `pwd`;
585 chomp $pwd;
586 return $pwd;
587}
588
Jeff Kinge73aefe2006-05-23 03:27:46 -0400589sub is_sha1 {
590 my $s = shift;
591 return $s =~ /^[a-f0-9]{40}$/;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200592}
593
Jeff King9da0dab2007-11-28 13:56:11 -0500594sub get_headref ($) {
595 my $name = shift;
596 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
597 return undef unless $? == 0;
598 chomp $r;
599 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400600}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200601
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400602my $user_filename_prepend = '';
603sub munge_user_filename {
604 my $name = shift;
605 return File::Spec->file_name_is_absolute($name) ?
606 $name :
607 $user_filename_prepend . $name;
608}
609
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200610-d $git_tree
611 or mkdir($git_tree,0777)
612 or die "Could not create $git_tree: $!";
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400613if ($git_tree ne '.') {
614 $user_filename_prepend = getwd() . '/';
615 chdir($git_tree);
616}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200617
618my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200619my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200620my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800621my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200622
623my $git_dir = $ENV{"GIT_DIR"} || ".git";
624$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
625$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200626my $orig_git_index;
627$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200628
629my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200630
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800631unless (-d $git_dir) {
Ben Walton91fe7322010-01-19 14:03:10 -0500632 system(qw(git init));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200633 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
Thomas Rast1bb28d82010-10-18 15:11:25 +0200634 system(qw(git read-tree --empty));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200635 die "Cannot init an empty tree: $?\n" if $?;
636
637 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200638 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200639} else {
Ben Waltona12477d2010-01-19 14:03:09 -0500640 open(F, "-|", qw(git symbolic-ref HEAD)) or
Ben Walton640d9d02010-01-19 14:03:08 -0500641 die "Cannot run git symbolic-ref: $!\n";
Pavel Roskin8366a102005-11-16 13:27:28 -0500642 chomp ($last_branch = <F>);
643 $last_branch = basename($last_branch);
644 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800645 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200646 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
647 $last_branch = "master";
648 }
649 $orig_branch = $last_branch;
Ben Walton640d9d02010-01-19 14:03:08 -0500650 $tip_at_start = `git rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200651
652 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100653 my $fmt = '($ref, $author) = (%(refname), %(author));';
Ben Waltona12477d2010-01-19 14:03:09 -0500654 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
655 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800656 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100657 my ($ref, $author);
658 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100659 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100660 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
661 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200662 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100663 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100664 if (!exists $branch_date{$opt_o}) {
665 die "Branch '$opt_o' does not exist.\n".
666 "Either use the correct '-o branch' option,\n".
667 "or import to a new repository.\n";
668 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200669}
670
671-d $git_dir
672 or die "Could not create git subdir ($git_dir).\n";
673
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100674# now we read (and possibly save) author-info as well
675-f "$git_dir/cvs-authors" and
676 read_author_info("$git_dir/cvs-authors");
677if ($opt_A) {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400678 read_author_info(munge_user_filename($opt_A));
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100679 write_author_info("$git_dir/cvs-authors");
680}
681
Aaron Crane0455ec02010-02-06 18:26:24 +0000682# open .git/cvs-revisions, if requested
683open my $revision_map, '>>', "$git_dir/cvs-revisions"
684 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
685 if defined $opt_R;
686
Martin Langhoff2f57c692006-06-11 20:12:20 +1200687
688#
689# run cvsps into a file unless we are getting
690# it passed as a file via $opt_P
691#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300692my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200693unless ($opt_P) {
694 print "Running cvsps...\n" if $opt_v;
695 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300696 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200697 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800698 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200699 my @opt;
700 @opt = split(/,/,$opt_p) if defined $opt_p;
701 unshift @opt, '-z', $opt_z if defined $opt_z;
702 unshift @opt, '-q' unless defined $opt_v;
703 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
704 push @opt, '--cvs-direct';
705 }
706 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
707 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700708 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300709 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
710 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200711 while (<CVSPS>) {
712 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300713 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200714 close CVSPS;
Ben Walton640d9d02010-01-19 14:03:08 -0500715 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200716 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300717} else {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400718 $cvspsfile = munge_user_filename($opt_P);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200719}
720
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300721open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200722
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200723## cvsps output:
724#---------------------
725#PatchSet 314
726#Date: 1999/09/18 13:03:59
727#Author: wkoch
728#Branch: STABLE-BRANCH-1-0
729#Ancestor branch: HEAD
730#Tag: (none)
731#Log:
732# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
733#Members:
734# README:1.57->1.57.2.1
735# VERSION:1.96->1.96.2.1
736#
737#---------------------
738
739my $state = 0;
740
Jeff Kinge73aefe2006-05-23 03:27:46 -0400741sub update_index (\@\@) {
742 my $old = shift;
743 my $new = shift;
Ben Walton640d9d02010-01-19 14:03:08 -0500744 open(my $fh, '|-', qw(git update-index -z --index-info))
745 or die "unable to open git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400746 print $fh
747 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400748 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400749 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400750 @$new)
Ben Walton640d9d02010-01-19 14:03:08 -0500751 or die "unable to write to git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400752 close $fh
Ben Walton640d9d02010-01-19 14:03:08 -0500753 or die "unable to write to git update-index: $!";
754 $? and die "git update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400755}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200756
Jeff Kinge73aefe2006-05-23 03:27:46 -0400757sub write_tree () {
Ben Waltona12477d2010-01-19 14:03:09 -0500758 open(my $fh, '-|', qw(git write-tree))
Ben Walton640d9d02010-01-19 14:03:08 -0500759 or die "unable to open git write-tree: $!";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400760 chomp(my $tree = <$fh>);
761 is_sha1($tree)
762 or die "Cannot get tree id ($tree): $!";
763 close($fh)
Ben Walton640d9d02010-01-19 14:03:08 -0500764 or die "Error running git write-tree: $?\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200765 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400766 return $tree;
767}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200768
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800769my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
Aaron Crane0455ec02010-02-06 18:26:24 +0000770my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
Martin Langhoff71b08142006-06-11 20:12:09 +1200771
772# commits that cvsps cannot place anywhere...
773$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
774
Jeff Kinge73aefe2006-05-23 03:27:46 -0400775sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500776 if ($branch eq $opt_o && !$index{branch} &&
777 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200778 # looks like an initial commit
Ben Walton640d9d02010-01-19 14:03:08 -0500779 # use the index primed by git init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600780 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
781 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200782 } else {
783 # use an index per branch to speed up
784 # imports of projects with many branches
785 unless ($index{$branch}) {
786 $index{$branch} = tmpnam();
787 $ENV{GIT_INDEX_FILE} = $index{$branch};
788 if ($ancestor) {
Ben Walton640d9d02010-01-19 14:03:08 -0500789 system("git", "read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200790 } else {
Ben Walton640d9d02010-01-19 14:03:08 -0500791 system("git", "read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200792 }
793 die "read-tree failed: $?\n" if $?;
794 }
795 }
796 $ENV{GIT_INDEX_FILE} = $index{$branch};
797
Jeff Kinge73aefe2006-05-23 03:27:46 -0400798 update_index(@old, @new);
799 @old = @new = ();
800 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500801 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400802 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200803
Jeff Kinge73aefe2006-05-23 03:27:46 -0400804 my @commit_args;
805 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200806
Jeff Kinge73aefe2006-05-23 03:27:46 -0400807 # loose detection of merges
808 # based on the commit msg
809 foreach my $rx (@mergerx) {
810 next unless $logmsg =~ $rx && $1;
811 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500812 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200813 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400814 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200815 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200816 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400817
818 my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
Jeff King62bf0d92006-05-23 16:59:44 -0400819 $ENV{GIT_AUTHOR_NAME} = $author_name;
820 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
821 $ENV{GIT_AUTHOR_DATE} = $commit_date;
822 $ENV{GIT_COMMITTER_NAME} = $author_name;
823 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
824 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400825 my $pid = open2(my $commit_read, my $commit_write,
Ben Walton640d9d02010-01-19 14:03:08 -0500826 'git', 'commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200827
828 # compatibility with git2cvs
829 substr($logmsg,32767) = "" if length($logmsg) > 32767;
830 $logmsg =~ s/[\s\n]+\z//;
831
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300832 if (@skipped) {
833 $logmsg .= "\n\n\nSKIPPED:\n\t";
834 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200835 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300836 }
837
Jeff Kinge73aefe2006-05-23 03:27:46 -0400838 print($commit_write "$logmsg\n") && close($commit_write)
Ben Walton640d9d02010-01-19 14:03:08 -0500839 or die "Error writing to git commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200840
Jeff Kinge73aefe2006-05-23 03:27:46 -0400841 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
842 chomp(my $cid = <$commit_read>);
843 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200844 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400845 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200846
847 waitpid($pid,0);
Ben Walton640d9d02010-01-19 14:03:08 -0500848 die "Error running git commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200849
Ben Walton640d9d02010-01-19 14:03:08 -0500850 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200851 or die "Cannot write branch $branch for update: $!\n";
852
Aaron Crane0455ec02010-02-06 18:26:24 +0000853 if ($revision_map) {
854 print $revision_map "@$_ $cid\n" for @commit_revisions;
855 }
856 @commit_revisions = ();
857
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800858 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800859 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700860 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
861 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800862 $xtag =~ s/[\/]/$opt_s/g;
Paul Oliver509792b2008-05-23 19:29:22 +0100863 $xtag =~ s/\[//g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700864
Ben Walton640d9d02010-01-19 14:03:08 -0500865 system('git' , 'tag', '-f', $xtag, $cid) == 0
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700866 or die "Cannot create tag $xtag: $!\n";
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700867
868 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200869 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200870};
871
Martin Langhoff06918342006-05-22 23:38:08 +1200872my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800873while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200874 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800875 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200876 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800877 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200878 $state = 1;
879 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800880 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200881 $patchset = 0+$_;
882 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800883 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200884 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800885 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200886 print STDERR "Could not parse date: $_\n";
887 $state=0;
888 next;
889 }
890 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800891 } elsif ($state == 3 and s/^Author:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200892 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700893 if (/^(.*?)\s+<(.*)>/) {
894 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100895 } elsif ($conv_author_name{$_}) {
896 $author_name = $conv_author_name{$_};
897 $author_email = $conv_author_email{$_};
Junio C Hamano94c23342005-09-30 01:48:57 -0700898 } else {
899 $author_name = $author_email = $_;
900 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200901 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800902 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200903 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000904 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200905 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200906 $branch = $_;
907 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800908 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200909 s/\s+$//;
910 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200911 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200912 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800913 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200914 $ancestor = undef;
915 $state = 6;
916 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800917 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200918 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800919 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200920 $tag = undef;
921 } else {
922 $tag = $_;
923 }
924 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800925 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200926 $logmsg = "";
927 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800928 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200929 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800930 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200931 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +0200932 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200933 $state = 11;
934 next;
935 }
Martin Langhoffded9f402007-01-08 19:43:39 +1300936 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +1300937 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +0100938 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +1300939 # 300s just in case -- this also prevents skipping commits
940 # due to server clock drift
941 print "skip patchset $patchset: $date too recent\n" if $opt_v;
942 $state = 11;
943 next;
944 }
Martin Langhoff71b08142006-06-11 20:12:09 +1200945 if (exists $ignorebranch{$branch}) {
946 print STDERR "Skipping $branch\n";
947 $state = 11;
948 next;
949 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800950 if ($ancestor) {
951 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +1200952 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
953 $ancestor = $opt_o;
954 }
Jeff King0750d752007-11-28 13:56:28 -0500955 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200956 print STDERR "Branch $branch already exists!\n";
957 $state=11;
958 next;
959 }
Jeff King0750d752007-11-28 13:56:28 -0500960 my $id = get_headref("$remote/$ancestor");
961 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200962 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +1200963 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200964 $state=11;
965 next;
966 }
Jeff King0750d752007-11-28 13:56:28 -0500967
968 system(qw(git update-ref -m cvsimport),
969 "$remote/$branch", $id);
970 if($? != 0) {
971 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +1200972 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200973 $state=11;
974 next;
975 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200976 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +0200977 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200978 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800979 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200980 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800981 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200982# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200983 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200984 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200985 my $rev = $3;
986 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300987 if ($opt_S && $fn =~ m/$opt_S/) {
988 print "SKIPPING $fn v $rev\n";
989 push(@skipped, $fn);
990 next;
991 }
Aaron Crane0455ec02010-02-06 18:26:24 +0000992 push @commit_revisions, [$fn, $rev];
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300993 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200994 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800995 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200996 push(@old,$fn);
997 print "Drop $fn\n" if $opt_v;
998 } else {
999 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -08001000 my $pid = open(my $F, '-|');
1001 die $! unless defined $pid;
1002 if (!$pid) {
Ben Walton640d9d02010-01-19 14:03:08 -05001003 exec("git", "hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001004 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -08001005 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001006 my $sha = <$F>;
1007 chomp $sha;
1008 close $F;
1009 my $mode = pmode($cvs->{'mode'});
1010 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1011 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001012 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001013 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001014 my $fn = $1;
Aaron Crane0455ec02010-02-06 18:26:24 +00001015 my $rev = $2;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001016 $fn =~ s#^/+##;
Aaron Crane0455ec02010-02-06 18:26:24 +00001017 push @commit_revisions, [$fn, $rev];
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001018 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001019 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001020 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001021 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001022 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -07001023 $commitcount++;
1024 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +12001025 last;
1026 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001027 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -07001028 if (($commitcount & 1023) == 0) {
Ben Walton91fe7322010-01-19 14:03:10 -05001029 system(qw(git repack -a -d));
Linus Torvalds4adcea92006-05-22 19:28:37 -07001030 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001031 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001032 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001033 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001034 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001035 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001036 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +02001037 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001038 }
1039}
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001040commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001041
Martin Langhoff4083c2f2007-01-08 21:08:46 +13001042unless ($opt_P) {
1043 unlink($cvspsfile);
1044}
1045
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001046# The heuristic of repacking every 1024 commits can leave a
1047# lot of unpacked data. If there is more than 1MB worth of
1048# not-packed objects, repack once more.
Ben Walton640d9d02010-01-19 14:03:08 -05001049my $line = `git count-objects`;
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001050if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1051 my ($n_objects, $kb) = ($1, $2);
1052 1024 < $kb
Ben Walton91fe7322010-01-19 14:03:10 -05001053 and system(qw(git repack -a -d));
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001054}
1055
Martin Langhoff8f732642006-06-12 23:50:49 +12001056foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001057 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001058 unlink($git_index);
1059 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001060}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001061
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001062if (defined $orig_git_index) {
1063 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1064} else {
1065 delete $ENV{GIT_INDEX_FILE};
1066}
1067
Matthias Urlichs46541662005-06-28 21:08:15 +02001068# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001069if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001070 print "DONE.\n" if $opt_v;
1071 if ($opt_i) {
1072 exit 0;
1073 }
Ben Walton640d9d02010-01-19 14:03:08 -05001074 my $tip_at_end = `git rev-parse --verify HEAD`;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001075 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001076 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001077 print "Fetched into the current branch.\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001078 system(qw(git read-tree -u -m),
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001079 $tip_at_start, $tip_at_end);
1080 die "Fast-forward update failed: $?\n" if $?;
1081 }
1082 else {
Ben Walton640d9d02010-01-19 14:03:08 -05001083 system(qw(git merge cvsimport HEAD), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001084 die "Could not merge $opt_o into the current branch.\n" if $?;
1085 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001086} else {
1087 $orig_branch = "master";
1088 print "DONE; creating $orig_branch branch\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001089 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001090 unless defined get_headref('refs/heads/master');
Ben Walton640d9d02010-01-19 14:03:08 -05001091 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001092 if ($opt_r && $opt_o ne 'HEAD');
Ben Walton640d9d02010-01-19 14:03:08 -05001093 system('git', 'update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001094 unless ($opt_i) {
Ben Walton91fe7322010-01-19 14:03:10 -05001095 system(qw(git checkout -f));
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001096 die "checkout failed: $?\n" if $?;
1097 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001098}