Skip to content

Commit 2a54323

Browse files
author
Junio C Hamano
committed
Merge branch 'maint'
* maint: Rework cvsexportcommit to handle binary files for all cases. Catch errors when writing an index that contains invalid objects. test-lib.sh: A command dying due to a signal is an unexpected failure. git-update-index(1): fix use of quoting in section title
2 parents a74e60a + fe142b3 commit 2a54323

File tree

8 files changed

+222
-23
lines changed

8 files changed

+222
-23
lines changed

Documentation/git-update-index.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ $ git ls-files -s
216216
------------
217217

218218

219-
Using "assume unchanged" bit
220-
----------------------------
219+
Using ``assume unchanged'' bit
220+
------------------------------
221221

222222
Many operations in git depend on your filesystem to have an
223223
efficient `lstat(2)` implementation, so that `st_mtime`

cache-tree.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ static int update_one(struct cache_tree *it,
282282
baselen + sublen + 1,
283283
missing_ok,
284284
dryrun);
285+
if (subcnt < 0)
286+
return subcnt;
285287
i += subcnt - 1;
286288
sub->used = 1;
287289
}

git-cvsexportcommit.perl

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
#!/usr/bin/perl -w
22

33
# Known limitations:
4-
# - cannot add or remove binary files
54
# - does not propagate permissions
65
# - tells "ready for commit" even when things could not be completed
7-
# (eg addition of a binary file)
6+
# (not sure this is true anymore, more testing is needed)
7+
# - does not handle whitespace in pathnames at all.
88

99
use strict;
1010
use Getopt::Std;
@@ -68,9 +68,9 @@
6868
if ($stage eq 'headers') {
6969
if ($line =~ m/^parent (\w{40})$/) { # found a parent
7070
push @parents, $1;
71-
} elsif ($line =~ m/^author (.+) \d+ \+\d+$/) {
71+
} elsif ($line =~ m/^author (.+) \d+ [-+]\d+$/) {
7272
$author = $1;
73-
} elsif ($line =~ m/^committer (.+) \d+ \+\d+$/) {
73+
} elsif ($line =~ m/^committer (.+) \d+ [-+]\d+$/) {
7474
$committer = $1;
7575
}
7676
} else {
@@ -139,6 +139,17 @@
139139
push @dfiles, $fields[5];
140140
}
141141
}
142+
my (@binfiles, @abfiles, @dbfiles, @bfiles, @mbfiles);
143+
@binfiles = grep m/^Binary files/, safe_pipe_capture('git-diff-tree', '-p', $parent, $commit);
144+
map { chomp } @binfiles;
145+
@abfiles = grep s/^Binary files \/dev\/null and b\/(.*) differ$/$1/, @binfiles;
146+
@dbfiles = grep s/^Binary files a\/(.*) and \/dev\/null differ$/$1/, @binfiles;
147+
@mbfiles = grep s/^Binary files a\/(.*) and b\/(.*) differ$/$1/, @binfiles;
148+
push @bfiles, @abfiles;
149+
push @bfiles, @dbfiles;
150+
push @bfiles, @mbfiles;
151+
push @mfiles, @mbfiles;
152+
142153
$opt_v && print "The commit affects:\n ";
143154
$opt_v && print join ("\n ", @afiles,@mfiles,@dfiles) . "\n\n";
144155
undef @files; # don't need it anymore
@@ -153,6 +164,10 @@
153164
}
154165
foreach my $f (@afiles) {
155166
# This should return only one value
167+
if ($f =~ m,(.*)/[^/]*$,) {
168+
my $p = $1;
169+
next if (grep { $_ eq $p } @dirs);
170+
}
156171
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
157172
if (@status > 1) { warn 'Strange! cvs status returned more than one line?'};
158173
if (-d dirname $f and $status[0] !~ m/Status: Unknown$/
@@ -162,6 +177,7 @@
162177
warn "Status was: $status[0]\n";
163178
}
164179
}
180+
165181
foreach my $f (@mfiles, @dfiles) {
166182
# TODO:we need to handle removed in cvs
167183
my @status = grep(m/^File/, safe_pipe_capture('cvs', '-q', 'status' ,$f));
@@ -200,24 +216,31 @@
200216

201217
print "'Patching' binary files\n";
202218

203-
my @bfiles = grep(m/^Binary/, safe_pipe_capture('git-diff-tree', '-p', $parent, $commit));
204-
@bfiles = map { chomp } @bfiles;
205219
foreach my $f (@bfiles) {
206220
# check that the file in cvs matches the "old" file
207221
# extract the file to $tmpdir and compare with cmp
208-
my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}");
209-
chomp $tree;
210-
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
211-
chomp $blob;
212-
`git-cat-file blob $blob > $tmpdir/blob`;
213-
if (system('cmp', '-s', $f, "$tmpdir/blob")) {
214-
warn "Binary file $f in CVS does not match parent.\n";
215-
$dirty = 1;
216-
next;
222+
if (not(grep { $_ eq $f } @afiles)) {
223+
my $tree = safe_pipe_capture('git-rev-parse', "$parent^{tree}");
224+
chomp $tree;
225+
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
226+
chomp $blob;
227+
`git-cat-file blob $blob > $tmpdir/blob`;
228+
if (system('cmp', '-s', $f, "$tmpdir/blob")) {
229+
warn "Binary file $f in CVS does not match parent.\n";
230+
if (not $opt_f) {
231+
$dirty = 1;
232+
next;
233+
}
234+
}
235+
}
236+
if (not(grep { $_ eq $f } @dfiles)) {
237+
my $tree = safe_pipe_capture('git-rev-parse', "$commit^{tree}");
238+
chomp $tree;
239+
my $blob = `git-ls-tree $tree "$f" | cut -f 1 | cut -d ' ' -f 3`;
240+
chomp $blob;
241+
# replace with the new file
242+
`git-cat-file blob $blob > $f`;
217243
}
218-
219-
# replace with the new file
220-
`git-cat-file blob $blob > $f`;
221244

222245
# TODO: something smart with file modes
223246

@@ -231,7 +254,10 @@
231254
my $fuzz = $opt_p ? 0 : 2;
232255

233256
print "Patching non-binary files\n";
234-
print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`;
257+
258+
if (scalar(@afiles)+scalar(@dfiles)+scalar(@mfiles) != scalar(@bfiles)) {
259+
print `(git-diff-tree -p $parent -p $commit | patch -p1 -F $fuzz ) 2>&1`;
260+
}
235261

236262
my $dirtypatch = 0;
237263
if (($? >> 8) == 2) {
@@ -242,7 +268,11 @@
242268
}
243269

244270
foreach my $f (@afiles) {
245-
system('cvs', 'add', $f);
271+
if (grep { $_ eq $f } @bfiles) {
272+
system('cvs', 'add','-kb',$f);
273+
} else {
274+
system('cvs', 'add', $f);
275+
}
246276
if ($?) {
247277
$dirty = 1;
248278
warn "Failed to cvs add $f -- you may need to do it manually";

t/t0000-basic.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,28 @@ test_expect_success \
209209
'validate object ID for a known tree.' \
210210
'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2'
211211

212+
cat >badobjects <<EOF
213+
100644 blob 1000000000000000000000000000000000000000 dir/file1
214+
100644 blob 2000000000000000000000000000000000000000 dir/file2
215+
100644 blob 3000000000000000000000000000000000000000 dir/file3
216+
100644 blob 4000000000000000000000000000000000000000 dir/file4
217+
100644 blob 5000000000000000000000000000000000000000 dir/file5
218+
EOF
219+
220+
rm .git/index
221+
test_expect_success \
222+
'put invalid objects into the index.' \
223+
'git-update-index --index-info < badobjects'
224+
225+
test_expect_failure \
226+
'writing this tree without --missing-ok.' \
227+
'git-write-tree'
228+
229+
test_expect_success \
230+
'writing this tree with --missing-ok.' \
231+
'git-write-tree --missing-ok'
232+
233+
212234
################################################################
213235
rm .git/index
214236
test_expect_success \

t/t9200-git-cvsexportcommit.sh

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (c) Robin Rosenberg
4+
#
5+
test_description='CVS export comit. '
6+
7+
. ./test-lib.sh
8+
9+
cvs >/dev/null 2>&1
10+
if test $? -ne 1
11+
then
12+
test_expect_success 'skipping git-cvsexportcommit tests, cvs not found' :
13+
test_done
14+
exit
15+
fi
16+
17+
export CVSROOT=$(pwd)/cvsroot
18+
export CVSWORK=$(pwd)/cvswork
19+
rm -rf "$CVSROOT" "$CVSWORK"
20+
mkdir "$CVSROOT" &&
21+
cvs init &&
22+
cvs -Q co -d "$CVSWORK" . &&
23+
export GIT_DIR=$(pwd)/.git &&
24+
echo >empty &&
25+
git add empty &&
26+
git commit -a -m "Initial" 2>/dev/null ||
27+
exit 1
28+
29+
test_expect_success \
30+
'New file' \
31+
'mkdir A B C D E F &&
32+
echo hello1 >A/newfile1.txt &&
33+
echo hello2 >B/newfile2.txt &&
34+
cp ../test9200a.png C/newfile3.png &&
35+
cp ../test9200a.png D/newfile4.png &&
36+
git add A/newfile1.txt &&
37+
git add B/newfile2.txt &&
38+
git add C/newfile3.png &&
39+
git add D/newfile4.png &&
40+
git commit -a -m "Test: New file" &&
41+
id=$(git rev-list --max-count=1 HEAD) &&
42+
(cd "$CVSWORK" &&
43+
git cvsexportcommit -c $id &&
44+
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.1/" &&
45+
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "newfile2.txt/1.1/" &&
46+
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "newfile3.png/1.1/-kb" &&
47+
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.1/-kb" &&
48+
diff A/newfile1.txt ../A/newfile1.txt &&
49+
diff B/newfile2.txt ../B/newfile2.txt &&
50+
diff C/newfile3.png ../C/newfile3.png &&
51+
diff D/newfile4.png ../D/newfile4.png
52+
)'
53+
54+
test_expect_success \
55+
'Remove two files, add two and update two' \
56+
'echo Hello1 >>A/newfile1.txt &&
57+
rm -f B/newfile2.txt &&
58+
rm -f C/newfile3.png &&
59+
echo Hello5 >E/newfile5.txt &&
60+
cp ../test9200b.png D/newfile4.png &&
61+
cp ../test9200a.png F/newfile6.png &&
62+
git add E/newfile5.txt &&
63+
git add F/newfile6.png &&
64+
git commit -a -m "Test: Remove, add and update" &&
65+
id=$(git rev-list --max-count=1 HEAD) &&
66+
(cd "$CVSWORK" &&
67+
git cvsexportcommit -c $id &&
68+
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" &&
69+
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
70+
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
71+
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "newfile4.png/1.2/-kb" &&
72+
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
73+
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
74+
diff A/newfile1.txt ../A/newfile1.txt &&
75+
diff D/newfile4.png ../D/newfile4.png &&
76+
diff E/newfile5.txt ../E/newfile5.txt &&
77+
diff F/newfile6.png ../F/newfile6.png
78+
)'
79+
80+
# Should fail (but only on the git-cvsexportcommit stage)
81+
test_expect_success \
82+
'Fail to change binary more than one generation old' \
83+
'cat F/newfile6.png >>D/newfile4.png &&
84+
git commit -a -m "generatiion 1" &&
85+
cat F/newfile6.png >>D/newfile4.png &&
86+
git commit -a -m "generation 2" &&
87+
id=$(git rev-list --max-count=1 HEAD) &&
88+
(cd "$CVSWORK" &&
89+
! git cvsexportcommit -c $id
90+
)'
91+
92+
# Should fail, but only on the git-cvsexportcommit stage
93+
test_expect_success \
94+
'Fail to remove binary file more than one generation old' \
95+
'git reset --hard HEAD^ &&
96+
cat F/newfile6.png >>D/newfile4.png &&
97+
git commit -a -m "generation 2 (again)" &&
98+
rm -f D/newfile4.png &&
99+
git commit -a -m "generation 3" &&
100+
id=$(git rev-list --max-count=1 HEAD) &&
101+
(cd "$CVSWORK" &&
102+
! git cvsexportcommit -c $id
103+
)'
104+
105+
# We reuse the state from two tests back here
106+
107+
# This test is here because a patch for only binary files will
108+
# fail with gnu patch, so cvsexportcommit must handle that.
109+
test_expect_success \
110+
'Remove only binary files' \
111+
'git reset --hard HEAD^^^ &&
112+
rm -f D/newfile4.png &&
113+
git commit -a -m "test: remove only a binary file" &&
114+
id=$(git rev-list --max-count=1 HEAD) &&
115+
(cd "$CVSWORK" &&
116+
git cvsexportcommit -c $id &&
117+
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "newfile1.txt/1.2/" &&
118+
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
119+
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
120+
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
121+
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
122+
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
123+
diff A/newfile1.txt ../A/newfile1.txt &&
124+
diff E/newfile5.txt ../E/newfile5.txt &&
125+
diff F/newfile6.png ../F/newfile6.png
126+
)'
127+
128+
test_expect_success \
129+
'Remove only a text file' \
130+
'rm -f A/newfile1.txt &&
131+
git commit -a -m "test: remove only a binary file" &&
132+
id=$(git rev-list --max-count=1 HEAD) &&
133+
(cd "$CVSWORK" &&
134+
git cvsexportcommit -c $id &&
135+
test "$(echo $(sort A/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
136+
test "$(echo $(sort B/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
137+
test "$(echo $(sort C/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
138+
test "$(echo $(sort D/CVS/Entries|cut -d/ -f2,3,5))" = "" &&
139+
test "$(echo $(sort E/CVS/Entries|cut -d/ -f2,3,5))" = "newfile5.txt/1.1/" &&
140+
test "$(echo $(sort F/CVS/Entries|cut -d/ -f2,3,5))" = "newfile6.png/1.1/-kb" &&
141+
diff E/newfile5.txt ../E/newfile5.txt &&
142+
diff F/newfile6.png ../F/newfile6.png
143+
)'
144+
145+
test_done

t/test-lib.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ test_expect_failure () {
129129
error "bug in the test script: not 2 parameters to test-expect-failure"
130130
say >&3 "expecting failure: $2"
131131
test_run_ "$2"
132-
if [ "$?" = 0 -a "$eval_ret" != 0 ]
132+
if [ "$?" = 0 -a "$eval_ret" != 0 -a "$eval_ret" -lt 129 ]
133133
then
134134
test_ok_ "$1"
135135
else

t/test9200a.png

5.53 KB
Loading

t/test9200b.png

275 Bytes
Loading

0 commit comments

Comments
 (0)