git-cvsexportcommit can't commit files which have been removed from CVS
If a file X is removed from CVS, it goes into the Attic directory, and CVS reports it as 'no file X' but with status 'Up-to-date'. cvsexportcommit misinterprets this as an existing file and tries to commit a file with the same name. Correctly identify these files, so that new files with the same name can be committed. Add a test to t9200-git-cvsexportcommit.sh, which tests that we can re-commit a removed filename which remains in CVS's attic. This adds a file 'attic_gremlin' in CVS, then "removes" it, then tries to commit a file with the same name from git. Signed-off-by: Nick Woolley <git.wu-lee@noodlefactory.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Nick Woolley committed
May 29, 2009 at 00:23 UTC
54d5cc0e126ed4b6cc4b186efd9faf7b93df570f
2 files changed
+53
-14
git-cvsexportcommit.perl
+35
-14
@@ -225,7 +225,14 @@ if (@canstatusfiles) {
225
foreach my $name (keys %todo) {
226
my $basename = basename($name);
227
228
- $basename = "no file " . $basename if (exists($added{$basename}));
228
+ # CVS reports files that don't exist in the current revision as
229
+ # "no file $basename" in its "status" output, so we should
230
+ # anticipate that. Totally unknown files will have a status
231
+ # "Unknown". However, if they exist in the Attic, their status
232
+ # will be "Up-to-date" (this means they were added once but have
233
+ # been removed).
234
+ $basename = "no file $basename" if $added{$basename};
235
+
236
$basename =~ s/^\s+//;
237
$basename =~ s/\s+$//;
238
@@ -233,31 +240,45 @@ if (@canstatusfiles) {
240
$fullname{$basename} = $name;
241
push (@canstatusfiles2, $name);
242
delete($todo{$name});
236
- }
243
+ }
244
}
245
my @cvsoutput;
246
@cvsoutput = xargs_safe_pipe_capture([@cvs, 'status'], @canstatusfiles2);
247
foreach my $l (@cvsoutput) {
241
- chomp $l;
242
- if ($l =~ /^File:\s+(.*\S)\s+Status: (.*)$/) {
243
- if (!exists($fullname{$1})) {
244
- print STDERR "Huh? Status reported for unexpected file '$1'\n";
245
- } else {
246
- $cvsstat{$fullname{$1}} = $2;
247
- }
248
- }
248
+ chomp $l;
249
+ next unless
250
+ my ($file, $status) = $l =~ /^File:\s+(.*\S)\s+Status: (.*)$/;
251
+
252
+ my $fullname = $fullname{$file};
253
+ print STDERR "Huh? Status '$status' reported for unexpected file '$file'\n"
254
+ unless defined $fullname;
255
+
256
+ # This response means the file does not exist except in
257
+ # CVS's attic, so set the status accordingly
258
+ $status = "In-attic"
259
+ if $file =~ /^no file /
260
+ && $status eq 'Up-to-date';
261
+
262
+ $cvsstat{$fullname{$file}} = $status;
263
}
264
}
265
}
266
253
-# ... validate new files,
267
+# ... Validate that new files have the correct status
268
foreach my $f (@afiles) {
255
- if (defined ($cvsstat{$f}) and $cvsstat{$f} ne "Unknown") {
256
- $dirty = 1;
269
+ next unless defined(my $stat = $cvsstat{$f});
270
+
271
+ # This means the file has never been seen before
272
+ next if $stat eq 'Unknown';
273
+
274
+ # This means the file has been seen before but was removed
275
+ next if $stat eq 'In-attic';
276
+
277
+ $dirty = 1;
278
warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n";
279
warn "Status was: $cvsstat{$f}\n";
259
- }
280
}
281
+
282
# ... validate known files.
283
foreach my $f (@files) {
284
next if grep { $_ eq $f } @afiles;
t/t9200-git-cvsexportcommit.sh
+18
@@ -317,4 +317,22 @@ test_expect_success 'use the same checkout for Git and CVS' '
317
318
'
319
320
+test_expect_success 're-commit a removed filename which remains in CVS attic' '
321
+
322
+ (cd "$CVSWORK" &&
323
+ echo >attic_gremlin &&
324
+ cvs -Q add attic_gremlin &&
325
+ cvs -Q ci -m "added attic_gremlin" &&
326
+ rm attic_gremlin &&
327
+ cvs -Q rm attic_gremlin &&
328
+ cvs -Q ci -m "removed attic_gremlin") &&
329
+
330
+ echo > attic_gremlin &&
331
+ git add attic_gremlin &&
332
+ git commit -m "Added attic_gremlin" &&
333
+ git cvsexportcommit -w "$CVSWORK" -c HEAD &&
334
+ (cd "$CVSWORK"; cvs -Q update -d) &&
335
+ test -f "$CVSWORK/attic_gremlin"
336
+'
337
+
338
test_done