@matheusbsbs / matheus-bagliano / commits / baf5fa8a7f
Fork 0

git-svn: better attempt to handle broken symlink updates

This is a followup to 7fc35e0e94782bbbefb920875813519038659930, (workaround a for broken symlinks in SVN). Since broken SVN clients can commit svn:special files without the magic "link " prefix, this can affect delta application when we update the broken svn:special file. So now we fall back and retry the delta application on symlinks if having a "link " prefix fails. Our behavior differs from svn(1) (v1.5.1) slightly: When a svn:special file is created w/o a "link " prefix, svn will create a regular file (mode 100644 to git) with the contents of the blob as-is. Our behavior is to continue creating the symlink (mode 120000 to git) with the contents of the blob as-is. While this differs from current svn(1) behavior, this is easier and more efficient to implement (and the correctness of the svn(1) is debatable, since it's a workaround for a bug in the first place). More information on this SVN bug is described here: http://subversion.tigris.org/issues/show_bug.cgi?id=2692 Signed-off-by: Eric Wong <normalperson@yhbt.net>

Eric Wong committed Jan 11, 2009 at 16:51 UTC baf5fa8a7fdefc696fb1d79c95ae15a4cc779c1e
2 files changed +122 -4
git-svn.perl
+20 -4
@@ -3380,19 +3380,35 @@ sub apply_textdelta {
3380 open my $dup, '<&', $fh or croak $!;
3381 my $base = $::_repository->temp_acquire('git_blob');
3382 if ($fb->{blob}) {
3383 + my ($base_is_link, $size);
3384 +
3385 if ($fb->{mode_a} eq '120000' &&
3386 ! $self->{empty_symlinks}->{$fb->{path}}) {
3387 print $base 'link ' or die "print $!\n";
3388 + $base_is_link = 1;
3389 }
3387 - my $size = $::_repository->cat_blob($fb->{blob}, $base);
3390 + retry:
3391 + $size = $::_repository->cat_blob($fb->{blob}, $base);
3392 die "Failed to read object $fb->{blob}" if ($size < 0);
3393
3394 if (defined $exp) {
3395 seek $base, 0, 0 or croak $!;
3396 my $got = ::md5sum($base);
3393 - die "Checksum mismatch: $fb->{path} $fb->{blob}\n",
3394 - "expected: $exp\n",
3395 - " got: $got\n" if ($got ne $exp);
3397 + if ($got ne $exp) {
3398 + my $err = "Checksum mismatch: ".
3399 + "$fb->{path} $fb->{blob}\n" .
3400 + "expected: $exp\n" .
3401 + " got: $got\n";
3402 + if ($base_is_link) {
3403 + warn $err,
3404 + "Retrying... (possibly ",
3405 + "a bad symlink from SVN)\n";
3406 + $::_repository->temp_reset($base);
3407 + $base_is_link = 0;
3408 + goto retry;
3409 + }
3410 + die $err;
3411 + }
3412 }
3413 }
3414 seek $base, 0, 0 or croak $!;
t/t9132-git-svn-broken-symlink.sh new
+102
@@ -0,0 +1,102 @@
1 +#!/bin/sh
2 +
3 +test_description='test that git handles an svn repository with empty symlinks'
4 +
5 +. ./lib-git-svn.sh
6 +test_expect_success 'load svn dumpfile' '
7 + svnadmin load "$rawsvnrepo" <<EOF
8 +SVN-fs-dump-format-version: 2
9 +
10 +UUID: 60780f9a-7df5-43b4-83ab-60e2c0673ef7
11 +
12 +Revision-number: 0
13 +Prop-content-length: 56
14 +Content-length: 56
15 +
16 +K 8
17 +svn:date
18 +V 27
19 +2008-11-26T07:17:27.590577Z
20 +PROPS-END
21 +
22 +Revision-number: 1
23 +Prop-content-length: 111
24 +Content-length: 111
25 +
26 +K 7
27 +svn:log
28 +V 4
29 +test
30 +K 10
31 +svn:author
32 +V 12
33 +normalperson
34 +K 8
35 +svn:date
36 +V 27
37 +2008-11-26T07:18:03.511836Z
38 +PROPS-END
39 +
40 +Node-path: bar
41 +Node-kind: file
42 +Node-action: add
43 +Prop-content-length: 33
44 +Text-content-length: 4
45 +Text-content-md5: 912ec803b2ce49e4a541068d495ab570
46 +Content-length: 37
47 +
48 +K 11
49 +svn:special
50 +V 1
51 +*
52 +PROPS-END
53 +asdf
54 +
55 +Revision-number: 2
56 +Prop-content-length: 121
57 +Content-length: 121
58 +
59 +K 7
60 +svn:log
61 +V 13
62 +bar => doink
63 +
64 +K 10
65 +svn:author
66 +V 12
67 +normalperson
68 +K 8
69 +svn:date
70 +V 27
71 +2008-11-27T03:55:31.601672Z
72 +PROPS-END
73 +
74 +Node-path: bar
75 +Node-kind: file
76 +Node-action: change
77 +Text-content-length: 10
78 +Text-content-md5: 92ca4fe7a9721f877f765c252dcd66c9
79 +Content-length: 10
80 +
81 +link doink
82 +
83 +EOF
84 +'
85 +
86 +test_expect_success 'clone using git svn' 'git svn clone -r1 "$svnrepo" x'
87 +
88 +test_expect_success '"bar" is a symlink that points to "asdf"' '
89 + test -L x/bar &&
90 + (cd x && test xasdf = x"`git cat-file blob HEAD:bar`")
91 +'
92 +
93 +test_expect_success 'get "bar" => symlink fix from svn' '
94 + (cd x && git svn rebase)
95 +'
96 +
97 +test_expect_success '"bar" remains a proper symlink' '
98 + test -L x/bar &&
99 + (cd x && test xdoink = x"`git cat-file blob HEAD:bar`")
100 +'
101 +
102 +test_done