Skip to content

Commit 0757620

Browse files
jaysoffianEric Wong
authored andcommitted
git-svn: allow subset of branches/tags to be specified in glob spec
For very large projects it is useful to be able to clone a subset of the upstream SVN repo's branches. Allow for this by letting the left-side of the branches and tags glob specs contain a brace-delineated comma-separated list of names. e.g.: branches = branches/{red,green}/src:refs/remotes/branches/* Signed-off-by: Jay Soffian <jaysoffian@gmail.com> Acked-by: Eric Wong <normalperson@yhbt.net>
1 parent 3e18ce1 commit 0757620

File tree

4 files changed

+320
-20
lines changed

4 files changed

+320
-20
lines changed

Documentation/git-svn.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,22 @@ independent path component (surrounded by '/' or EOL). This
838838
type of configuration is not automatically created by 'init' and
839839
should be manually entered with a text-editor or using 'git config'.
840840

841+
It is also possible to fetch a subset of branches or tags by using a
842+
comma-separated list of names within braces. For example:
843+
844+
------------------------------------------------------------------------
845+
[svn-remote "huge-project"]
846+
url = http://server.org/svn
847+
fetch = trunk/src:refs/remotes/trunk
848+
branches = branches/{red,green}/src:refs/remotes/branches/*
849+
tags = tags/{1.0,2.0}/src:refs/remotes/tags/*
850+
------------------------------------------------------------------------
851+
852+
Note that git-svn keeps track of the highest revision in which a branch
853+
or tag has appeared. If the subset of branches or tags is changed after
854+
fetching, then .git/svn/.metadata must be manually edited to remove (or
855+
reset) branches-maxRev and/or tags-maxRev as appropriate.
856+
841857
SEE ALSO
842858
--------
843859
linkgit:git-rebase[1]

git-svn.perl

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,8 +1825,8 @@ sub read_all_remotes {
18251825
my $rs = {
18261826
t => $t,
18271827
remote => $remote,
1828-
path => Git::SVN::GlobSpec->new($local_ref),
1829-
ref => Git::SVN::GlobSpec->new($remote_ref) };
1828+
path => Git::SVN::GlobSpec->new($local_ref, 1),
1829+
ref => Git::SVN::GlobSpec->new($remote_ref, 0) };
18301830
if (length($rs->{ref}->{right}) != 0) {
18311831
die "The '*' glob character must be the last ",
18321832
"character of '$remote_ref'\n";
@@ -5233,6 +5233,7 @@ sub match_globs {
52335233
next if (length $g->{path}->{right} &&
52345234
($self->check_path($p, $r) !=
52355235
$SVN::Node::dir));
5236+
next unless $p =~ /$g->{path}->{regex}/;
52365237
$exists->{$p} = Git::SVN->init($self->{url}, $p, undef,
52375238
$g->{ref}->full_path($de), 1);
52385239
}
@@ -6006,29 +6007,48 @@ package Git::SVN::GlobSpec;
60066007
use warnings;
60076008

60086009
sub new {
6009-
my ($class, $glob) = @_;
6010+
my ($class, $glob, $pattern_ok) = @_;
60106011
my $re = $glob;
60116012
$re =~ s!/+$!!g; # no need for trailing slashes
6012-
$re =~ m!^([^*]*)(\*(?:/\*)*)(.*)$!;
6013-
my $temp = $re;
6014-
my ($left, $right) = ($1, $3);
6015-
$re = $2;
6016-
my $depth = $re =~ tr/*/*/;
6017-
if ($depth != $temp =~ tr/*/*/) {
6018-
die "Only one set of wildcard directories " .
6019-
"(e.g. '*' or '*/*/*') is supported: '$glob'\n";
6013+
my (@left, @right, @patterns);
6014+
my $state = "left";
6015+
my $die_msg = "Only one set of wildcard directories " .
6016+
"(e.g. '*' or '*/*/*') is supported: '$glob'\n";
6017+
for my $part (split(m|/|, $glob)) {
6018+
if ($part =~ /\*/ && $part ne "*") {
6019+
die "Invalid pattern in '$glob': $part\n";
6020+
} elsif ($pattern_ok && $part =~ /[{}]/ &&
6021+
$part !~ /^\{[^{}]+\}/) {
6022+
die "Invalid pattern in '$glob': $part\n";
6023+
}
6024+
if ($part eq "*") {
6025+
die $die_msg if $state eq "right";
6026+
$state = "pattern";
6027+
push(@patterns, "[^/]*");
6028+
} elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) {
6029+
die $die_msg if $state eq "right";
6030+
$state = "pattern";
6031+
my $p = quotemeta($1);
6032+
$p =~ s/\\,/|/g;
6033+
push(@patterns, "(?:$p)");
6034+
} else {
6035+
if ($state eq "left") {
6036+
push(@left, $part);
6037+
} else {
6038+
push(@right, $part);
6039+
$state = "right";
6040+
}
6041+
}
60206042
}
6043+
my $depth = @patterns;
60216044
if ($depth == 0) {
6022-
die "One '*' is needed for glob: '$glob'\n";
6023-
}
6024-
$re =~ s!\*!\[^/\]*!g;
6025-
$re = quotemeta($left) . "($re)" . quotemeta($right);
6026-
if (length $left && !($left =~ s!/+$!!g)) {
6027-
die "Missing trailing '/' on left side of: '$glob' ($left)\n";
6028-
}
6029-
if (length $right && !($right =~ s!^/+!!g)) {
6030-
die "Missing leading '/' on right side of: '$glob' ($right)\n";
6045+
die "One '*' is needed in glob: '$glob'\n";
60316046
}
6047+
my $left = join('/', @left);
6048+
my $right = join('/', @right);
6049+
$re = join('/', @patterns);
6050+
$re = join('\/',
6051+
grep(length, quotemeta($left), "($re)", quotemeta($right)));
60326052
my $left_re = qr/^\/\Q$left\E(\/|$)/;
60336053
bless { left => $left, right => $right, left_regex => $left_re,
60346054
regex => qr/$re/, glob => $glob, depth => $depth }, $class;

t/t9154-git-svn-fancy-glob.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2010 Jay Soffian
4+
#
5+
6+
test_description='git svn fancy glob test'
7+
8+
. ./lib-git-svn.sh
9+
10+
test_expect_success 'load svn repo' "
11+
svnadmin load -q '$rawsvnrepo' < '$TEST_DIRECTORY/t9154/svn.dump' &&
12+
git svn init --minimize-url -T trunk '$svnrepo' &&
13+
git svn fetch
14+
"
15+
16+
test_expect_success 'add red branch' "
17+
git config svn-remote.svn.branches 'branches/{red}:refs/remotes/*' &&
18+
git svn fetch &&
19+
git rev-parse refs/remotes/red &&
20+
test_must_fail git rev-parse refs/remotes/green &&
21+
test_must_fail git rev-parse refs/remotes/blue
22+
"
23+
24+
test_expect_success 'add green branch' "
25+
GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
26+
git config svn-remote.svn.branches 'branches/{red,green}:refs/remotes/*' &&
27+
git svn fetch &&
28+
git rev-parse refs/remotes/red &&
29+
git rev-parse refs/remotes/green &&
30+
test_must_fail git rev-parse refs/remotes/blue
31+
"
32+
33+
test_expect_success 'add all branches' "
34+
GIT_CONFIG=.git/svn/.metadata git config --unset svn-remote.svn.branches-maxRev &&
35+
git config svn-remote.svn.branches 'branches/*:refs/remotes/*' &&
36+
git svn fetch &&
37+
git rev-parse refs/remotes/red &&
38+
git rev-parse refs/remotes/green &&
39+
git rev-parse refs/remotes/blue
40+
"
41+
42+
test_done

t/t9154/svn.dump

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
SVN-fs-dump-format-version: 2
2+
3+
UUID: a18093a0-5f0b-44e0-8d88-8911ac7078db
4+
5+
Revision-number: 0
6+
Prop-content-length: 56
7+
Content-length: 56
8+
9+
K 8
10+
svn:date
11+
V 27
12+
2010-01-23T07:40:25.660053Z
13+
PROPS-END
14+
15+
Revision-number: 1
16+
Prop-content-length: 104
17+
Content-length: 104
18+
19+
K 7
20+
svn:log
21+
V 7
22+
initial
23+
K 10
24+
svn:author
25+
V 3
26+
jay
27+
K 8
28+
svn:date
29+
V 27
30+
2010-01-23T07:41:33.636365Z
31+
PROPS-END
32+
33+
Node-path: trunk
34+
Node-kind: dir
35+
Node-action: add
36+
Prop-content-length: 10
37+
Content-length: 10
38+
39+
PROPS-END
40+
41+
42+
Node-path: trunk/foo
43+
Node-kind: file
44+
Node-action: add
45+
Prop-content-length: 10
46+
Text-content-length: 4
47+
Text-content-md5: d3b07384d113edec49eaa6238ad5ff00
48+
Text-content-sha1: f1d2d2f924e986ac86fdf7b36c94bcdf32beec15
49+
Content-length: 14
50+
51+
PROPS-END
52+
foo
53+
54+
55+
Revision-number: 2
56+
Prop-content-length: 110
57+
Content-length: 110
58+
59+
K 7
60+
svn:log
61+
V 12
62+
add branches
63+
K 10
64+
svn:author
65+
V 3
66+
jay
67+
K 8
68+
svn:date
69+
V 27
70+
2010-01-23T07:42:37.290694Z
71+
PROPS-END
72+
73+
Node-path: branches
74+
Node-kind: dir
75+
Node-action: add
76+
Prop-content-length: 10
77+
Content-length: 10
78+
79+
PROPS-END
80+
81+
82+
Node-path: branches/blue
83+
Node-kind: dir
84+
Node-action: add
85+
Node-copyfrom-rev: 1
86+
Node-copyfrom-path: trunk
87+
88+
89+
Node-path: branches/green
90+
Node-kind: dir
91+
Node-action: add
92+
Node-copyfrom-rev: 1
93+
Node-copyfrom-path: trunk
94+
95+
96+
Node-path: branches/red
97+
Node-kind: dir
98+
Node-action: add
99+
Node-copyfrom-rev: 1
100+
Node-copyfrom-path: trunk
101+
102+
103+
Revision-number: 3
104+
Prop-content-length: 108
105+
Content-length: 108
106+
107+
K 7
108+
svn:log
109+
V 10
110+
red change
111+
K 10
112+
svn:author
113+
V 3
114+
jay
115+
K 8
116+
svn:date
117+
V 27
118+
2010-01-23T07:43:02.208918Z
119+
PROPS-END
120+
121+
Node-path: branches/red/foo
122+
Node-kind: file
123+
Node-action: change
124+
Text-content-length: 8
125+
Text-content-md5: 64c3c8cf7d0233ab7627623a68888bd1
126+
Text-content-sha1: 95a0492027876adfd3891ec71ee37b79ee44d640
127+
Content-length: 8
128+
129+
foo
130+
red
131+
132+
133+
Revision-number: 4
134+
Prop-content-length: 110
135+
Content-length: 110
136+
137+
K 7
138+
svn:log
139+
V 12
140+
green change
141+
K 10
142+
svn:author
143+
V 3
144+
jay
145+
K 8
146+
svn:date
147+
V 27
148+
2010-01-23T07:43:15.746586Z
149+
PROPS-END
150+
151+
Node-path: branches/green/foo
152+
Node-kind: file
153+
Node-action: change
154+
Text-content-length: 10
155+
Text-content-md5: 0209b6450891abc033d5eaaa9d3a8023
156+
Text-content-sha1: 87fc3bef9faeec48c0cd61dfc9851db377fdccf7
157+
Content-length: 10
158+
159+
foo
160+
green
161+
162+
163+
Revision-number: 5
164+
Prop-content-length: 109
165+
Content-length: 109
166+
167+
K 7
168+
svn:log
169+
V 11
170+
blue change
171+
K 10
172+
svn:author
173+
V 3
174+
jay
175+
K 8
176+
svn:date
177+
V 27
178+
2010-01-23T07:43:29.364811Z
179+
PROPS-END
180+
181+
Node-path: branches/blue/foo
182+
Node-kind: file
183+
Node-action: change
184+
Text-content-length: 9
185+
Text-content-md5: 9fbe4c13d0bae86386ae5209b2e6b275
186+
Text-content-sha1: cc4575083459a16f9aaef796c4a2456d64691ba0
187+
Content-length: 9
188+
189+
foo
190+
blue
191+
192+
193+
Revision-number: 6
194+
Prop-content-length: 110
195+
Content-length: 110
196+
197+
K 7
198+
svn:log
199+
V 12
200+
trunk change
201+
K 10
202+
svn:author
203+
V 3
204+
jay
205+
K 8
206+
svn:date
207+
V 27
208+
2010-01-23T07:44:01.313130Z
209+
PROPS-END
210+
211+
Node-path: trunk/foo
212+
Node-kind: file
213+
Node-action: change
214+
Text-content-length: 10
215+
Text-content-md5: 1c4db977d7a57c3bae582aab87948516
216+
Text-content-sha1: 469c08df449e702cf2a1fe746244a9ef3f837fad
217+
Content-length: 10
218+
219+
foo
220+
trunk
221+
222+

0 commit comments

Comments
 (0)