git-svn.perl: fix a false-positive in the "already exists" test
open_or_add_dir checks to see if the directory already exists or not. If it already exists and is not a directory, then we fail. However, open_or_add_dir did not previously account for the possibility that the path did exist as a file, but is deleted in the current commit. In order to prevent this legitimate case from failing, open_or_add_dir needs to know what files are deleted in the current commit. Unfortunately that information has to be plumbed through a couple of layers. Signed-off-by: Steven Walter <stevenrwalter@gmail.com> Acked-by: Eric Wong <normalperson@yhbt.net>
Steven Walter committed
Feb 20, 2012 at 09:17 UTC
379862ec5a413e636d977a6ea3d618f0b3eafceb
2 files changed
+44
-32
git-svn.perl
+26
-17
@@ -5137,7 +5137,7 @@ sub rmdirs {
5137
}
5138
5139
sub open_or_add_dir {
5140
- my ($self, $full_path, $baton) = @_;
5140
+ my ($self, $full_path, $baton, $deletions) = @_;
5141
my $t = $self->{types}->{$full_path};
5142
if (!defined $t) {
5143
die "$full_path not known in r$self->{r} or we have a bug!\n";
@@ -5146,7 +5146,7 @@ sub open_or_add_dir {
5146
no warnings 'once';
5147
# SVN::Node::none and SVN::Node::file are used only once,
5148
# so we're shutting up Perl's warnings about them.
5149
- if ($t == $SVN::Node::none) {
5149
+ if ($t == $SVN::Node::none || defined($deletions->{$full_path})) {
5150
return $self->add_directory($full_path, $baton,
5151
undef, -1, $self->{pool});
5152
} elsif ($t == $SVN::Node::dir) {
@@ -5161,17 +5161,18 @@ sub open_or_add_dir {
5161
}
5162
5163
sub ensure_path {
5164
- my ($self, $path) = @_;
5164
+ my ($self, $path, $deletions) = @_;
5165
my $bat = $self->{bat};
5166
my $repo_path = $self->repo_path($path);
5167
return $bat->{''} unless (length $repo_path);
5168
+
5169
my @p = split m#/+#, $repo_path;
5170
my $c = shift @p;
5170
- $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''});
5171
+ $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}, $deletions);
5172
while (@p) {
5173
my $c0 = $c;
5174
$c .= '/' . shift @p;
5174
- $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0});
5175
+ $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}, $deletions);
5176
}
5177
return $bat->{$c};
5178
}
@@ -5228,9 +5229,9 @@ sub apply_autoprops {
5229
}
5230
5231
sub A {
5231
- my ($self, $m) = @_;
5232
+ my ($self, $m, $deletions) = @_;
5233
my ($dir, $file) = split_path($m->{file_b});
5233
- my $pbat = $self->ensure_path($dir);
5234
+ my $pbat = $self->ensure_path($dir, $deletions);
5235
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
5236
undef, -1);
5237
print "\tA\t$m->{file_b}\n" unless $::_q;
@@ -5240,9 +5241,9 @@ sub A {
5241
}
5242
5243
sub C {
5243
- my ($self, $m) = @_;
5244
+ my ($self, $m, $deletions) = @_;
5245
my ($dir, $file) = split_path($m->{file_b});
5245
- my $pbat = $self->ensure_path($dir);
5246
+ my $pbat = $self->ensure_path($dir, $deletions);
5247
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
5248
$self->url_path($m->{file_a}), $self->{r});
5249
print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
@@ -5259,9 +5260,9 @@ sub delete_entry {
5260
}
5261
5262
sub R {
5262
- my ($self, $m) = @_;
5263
+ my ($self, $m, $deletions) = @_;
5264
my ($dir, $file) = split_path($m->{file_b});
5264
- my $pbat = $self->ensure_path($dir);
5265
+ my $pbat = $self->ensure_path($dir, $deletions);
5266
my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
5267
$self->url_path($m->{file_a}), $self->{r});
5268
print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
@@ -5270,14 +5271,14 @@ sub R {
5271
$self->close_file($fbat,undef,$self->{pool});
5272
5273
($dir, $file) = split_path($m->{file_a});
5273
- $pbat = $self->ensure_path($dir);
5274
+ $pbat = $self->ensure_path($dir, $deletions);
5275
$self->delete_entry($m->{file_a}, $pbat);
5276
}
5277
5278
sub M {
5278
- my ($self, $m) = @_;
5279
+ my ($self, $m, $deletions) = @_;
5280
my ($dir, $file) = split_path($m->{file_b});
5280
- my $pbat = $self->ensure_path($dir);
5281
+ my $pbat = $self->ensure_path($dir, $deletions);
5282
my $fbat = $self->open_file($self->repo_path($m->{file_b}),
5283
$pbat,$self->{r},$self->{pool});
5284
print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
@@ -5347,9 +5348,9 @@ sub chg_file {
5348
}
5349
5350
sub D {
5350
- my ($self, $m) = @_;
5351
+ my ($self, $m, $deletions) = @_;
5352
my ($dir, $file) = split_path($m->{file_b});
5352
- my $pbat = $self->ensure_path($dir);
5353
+ my $pbat = $self->ensure_path($dir, $deletions);
5354
print "\tD\t$m->{file_b}\n" unless $::_q;
5355
$self->delete_entry($m->{file_b}, $pbat);
5356
}
@@ -5382,10 +5383,18 @@ sub apply_diff {
5383
my ($self) = @_;
5384
my $mods = $self->{mods};
5385
my %o = ( D => 0, C => 1, R => 2, A => 3, M => 4, T => 5 );
5386
+ my %deletions;
5387
+
5388
+ foreach my $m (@$mods) {
5389
+ if ($m->{chg} eq "D") {
5390
+ $deletions{$m->{file_b}} = 1;
5391
+ }
5392
+ }
5393
+
5394
foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) {
5395
my $f = $m->{chg};
5396
if (defined $o{$f}) {
5388
- $self->$f($m);
5397
+ $self->$f($m, \%deletions);
5398
} else {
5399
fatal("Invalid change type: $f");
5400
}
t/t9100-git-svn-basic.sh
+18
-15
@@ -92,9 +92,11 @@ test_expect_success "$name" '
92
echo yyy > bar/zzz/yyy &&
93
git update-index --add bar/zzz/yyy &&
94
git commit -m "$name" &&
95
- test_must_fail git svn set-tree --find-copies-harder --rmdir \
96
- ${remotes_git_svn}..mybranch3' || true
97
-
95
+ git svn set-tree --find-copies-harder --rmdir \
96
+ ${remotes_git_svn}..mybranch3 &&
97
+ svn_cmd up "$SVN_TREE" &&
98
+ test -d "$SVN_TREE"/bar/zzz &&
99
+ test -e "$SVN_TREE"/bar/zzz/yyy ' || true
100
101
name='detect node change from directory to file #2'
102
test_expect_success "$name" '
@@ -134,10 +136,10 @@ test_expect_success "$name" '
136
test -x "$SVN_TREE"/exec.sh'
137
138
137
-name='executable file becomes a symlink to bar/zzz (file)'
139
+name='executable file becomes a symlink to file'
140
test_expect_success "$name" '
141
rm exec.sh &&
140
- ln -s bar/zzz exec.sh &&
142
+ ln -s file exec.sh &&
143
git update-index exec.sh &&
144
git commit -m "$name" &&
145
git svn set-tree --find-copies-harder --rmdir \
@@ -148,14 +150,14 @@ test_expect_success "$name" '
150
name='new symlink is added to a file that was also just made executable'
151
152
test_expect_success "$name" '
151
- chmod +x bar/zzz &&
152
- ln -s bar/zzz exec-2.sh &&
153
- git update-index --add bar/zzz exec-2.sh &&
153
+ chmod +x file &&
154
+ ln -s file exec-2.sh &&
155
+ git update-index --add file exec-2.sh &&
156
git commit -m "$name" &&
157
git svn set-tree --find-copies-harder --rmdir \
158
${remotes_git_svn}..mybranch5 &&
159
svn_cmd up "$SVN_TREE" &&
158
- test -x "$SVN_TREE"/bar/zzz &&
160
+ test -x "$SVN_TREE"/file &&
161
test -h "$SVN_TREE"/exec-2.sh'
162
163
name='modify a symlink to become a file'
@@ -195,14 +197,15 @@ name='check imported tree checksums expected tree checksums'
197
rm -f expected
198
if test_have_prereq UTF8
199
then
198
- echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected
200
+ echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected
201
fi
202
cat >> expected <<\EOF
201
-tree 83654bb36f019ae4fe77a0171f81075972087624
202
-tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1
203
-tree 0b094cbff17168f24c302e297f55bfac65eb8bd3
204
-tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
205
-tree 56a30b966619b863674f5978696f4a3594f2fca9
203
+tree c3322890dcf74901f32d216f05c5044f670ce632
204
+tree d3ccd5035feafd17b030c5732e7808cc49122853
205
+tree d03e1630363d4881e68929d532746b20b0986b83
206
+tree 149d63cd5878155c846e8c55d7d8487de283f89e
207
+tree 312b76e4f64ce14893aeac8591eb3960b065e247
208
+tree 149d63cd5878155c846e8c55d7d8487de283f89e
209
tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e
210
tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4
211
EOF