Skip to content

Commit 6f5748e

Browse files
adambrewsterEric Wong
authored andcommitted
svn: allow branches outside of refs/remotes
It may be convenient for some users to store svn remote tracking branches outside of the refs/remotes/ heirarchy. To accomplish this feat, this patch includes the entire path to the ref in $r->{'refname'} in &read_all_remotes and tries to change references to this entry so the new value makes sense. [ew: fixed backwards compatibility, long lines] Signed-off-by: Adam Brewster <adambrewster@gmail.com> Signed-off-by: Eric Wong <normalperson@yhbt.net>
1 parent b186a26 commit 6f5748e

File tree

6 files changed

+96
-54
lines changed

6 files changed

+96
-54
lines changed

git-svn.perl

Lines changed: 48 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ sub cmd_multi_init {
909909
}
910910
do_git_init_db();
911911
if (defined $_trunk) {
912-
my $trunk_ref = $_prefix . 'trunk';
912+
my $trunk_ref = 'refs/remotes/' . $_prefix . 'trunk';
913913
# try both old-style and new-style lookups:
914914
my $gs_trunk = eval { Git::SVN->new($trunk_ref) };
915915
unless ($gs_trunk) {
@@ -1654,23 +1654,23 @@ sub resolve_local_globs {
16541654
return unless defined $glob_spec;
16551655
my $ref = $glob_spec->{ref};
16561656
my $path = $glob_spec->{path};
1657-
foreach (command(qw#for-each-ref --format=%(refname) refs/remotes#)) {
1658-
next unless m#^refs/remotes/$ref->{regex}$#;
1657+
foreach (command(qw#for-each-ref --format=%(refname) refs/#)) {
1658+
next unless m#^$ref->{regex}$#;
16591659
my $p = $1;
16601660
my $pathname = desanitize_refname($path->full_path($p));
16611661
my $refname = desanitize_refname($ref->full_path($p));
16621662
if (my $existing = $fetch->{$pathname}) {
16631663
if ($existing ne $refname) {
16641664
die "Refspec conflict:\n",
1665-
"existing: refs/remotes/$existing\n",
1666-
" globbed: refs/remotes/$refname\n";
1665+
"existing: $existing\n",
1666+
" globbed: $refname\n";
16671667
}
1668-
my $u = (::cmt_metadata("refs/remotes/$refname"))[0];
1668+
my $u = (::cmt_metadata("$refname"))[0];
16691669
$u =~ s!^\Q$url\E(/|$)!! or die
1670-
"refs/remotes/$refname: '$url' not found in '$u'\n";
1670+
"$refname: '$url' not found in '$u'\n";
16711671
if ($pathname ne $u) {
16721672
warn "W: Refspec glob conflict ",
1673-
"(ref: refs/remotes/$refname):\n",
1673+
"(ref: $refname):\n",
16741674
"expected path: $pathname\n",
16751675
" real path: $u\n",
16761676
"Continuing ahead with $u\n";
@@ -1748,33 +1748,35 @@ sub read_all_remotes {
17481748
my $use_svm_props = eval { command_oneline(qw/config --bool
17491749
svn.useSvmProps/) };
17501750
$use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
1751+
my $svn_refspec = qr{\s*/?(.*?)\s*:\s*(.+?)\s*};
17511752
foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
1752-
if (m!^(.+)\.fetch=\s*(.*)\s*:\s*(.+)\s*$!) {
1753-
my ($remote, $local_ref, $_remote_ref) = ($1, $2, $3);
1754-
die("svn-remote.$remote: remote ref '$_remote_ref' "
1755-
. "must start with 'refs/remotes/'\n")
1756-
unless $_remote_ref =~ m{^refs/remotes/(.+)};
1757-
my $remote_ref = $1;
1758-
$local_ref =~ s{^/}{};
1753+
if (m!^(.+)\.fetch=$svn_refspec$!) {
1754+
my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
1755+
die("svn-remote.$remote: remote ref '$remote_ref' "
1756+
. "must start with 'refs/'\n")
1757+
unless $remote_ref =~ m{^refs/};
17591758
$r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
17601759
$r->{$remote}->{svm} = {} if $use_svm_props;
17611760
} elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
17621761
$r->{$1}->{svm} = {};
17631762
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
17641763
$r->{$1}->{url} = $2;
1765-
} elsif (m!^(.+)\.(branches|tags)=
1766-
(.*):refs/remotes/(.+)\s*$/!x) {
1767-
my ($p, $g) = ($3, $4);
1764+
} elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
1765+
my ($remote, $t, $local_ref, $remote_ref) =
1766+
($1, $2, $3, $4);
1767+
die("svn-remote.$remote: remote ref '$remote_ref' ($t) "
1768+
. "must start with 'refs/'\n")
1769+
unless $remote_ref =~ m{^refs/};
17681770
my $rs = {
1769-
t => $2,
1770-
remote => $1,
1771-
path => Git::SVN::GlobSpec->new($p),
1772-
ref => Git::SVN::GlobSpec->new($g) };
1771+
t => $t,
1772+
remote => $remote,
1773+
path => Git::SVN::GlobSpec->new($local_ref),
1774+
ref => Git::SVN::GlobSpec->new($remote_ref) };
17731775
if (length($rs->{ref}->{right}) != 0) {
17741776
die "The '*' glob character must be the last ",
1775-
"character of '$g'\n";
1777+
"character of '$remote_ref'\n";
17761778
}
1777-
push @{ $r->{$1}->{$2} }, $rs;
1779+
push @{ $r->{$remote}->{$t} }, $rs;
17781780
}
17791781
}
17801782

@@ -1882,9 +1884,9 @@ sub init_remote_config {
18821884
}
18831885
}
18841886
my ($xrepo_id, $xpath) = find_ref($self->refname);
1885-
if (defined $xpath) {
1887+
if (!$no_write && defined $xpath) {
18861888
die "svn-remote.$xrepo_id.fetch already set to track ",
1887-
"$xpath:refs/remotes/", $self->refname, "\n";
1889+
"$xpath:", $self->refname, "\n";
18881890
}
18891891
unless ($no_write) {
18901892
command_noisy('config',
@@ -1959,7 +1961,7 @@ sub find_ref {
19591961
my ($ref_id) = @_;
19601962
foreach (command(qw/config -l/)) {
19611963
next unless m!^svn-remote\.(.+)\.fetch=
1962-
\s*(.*)\s*:\s*refs/remotes/(.+)\s*$!x;
1964+
\s*/?(.*?)\s*:\s*(.+?)\s*$!x;
19631965
my ($repo_id, $path, $ref) = ($1, $2, $3);
19641966
if ($ref eq $ref_id) {
19651967
$path = '' if ($path =~ m#^\./?#);
@@ -1976,16 +1978,16 @@ sub new {
19761978
if (!defined $repo_id) {
19771979
die "Could not find a \"svn-remote.*.fetch\" key ",
19781980
"in the repository configuration matching: ",
1979-
"refs/remotes/$ref_id\n";
1981+
"$ref_id\n";
19801982
}
19811983
}
19821984
my $self = _new($class, $repo_id, $ref_id, $path);
19831985
if (!defined $self->{path} || !length $self->{path}) {
19841986
my $fetch = command_oneline('config', '--get',
19851987
"svn-remote.$repo_id.fetch",
1986-
":refs/remotes/$ref_id\$") or
1988+
":$ref_id\$") or
19871989
die "Failed to read \"svn-remote.$repo_id.fetch\" ",
1988-
"\":refs/remotes/$ref_id\$\" in config\n";
1990+
"\":$ref_id\$\" in config\n";
19891991
($self->{path}, undef) = split(/\s*:\s*/, $fetch);
19901992
}
19911993
$self->{url} = command_oneline('config', '--get',
@@ -1996,7 +1998,7 @@ sub new {
19961998
}
19971999

19982000
sub refname {
1999-
my ($refname) = "refs/remotes/$_[0]->{ref_id}" ;
2001+
my ($refname) = $_[0]->{ref_id} ;
20002002

20012003
# It cannot end with a slash /, we'll throw up on this because
20022004
# SVN can't have directories with a slash in their name, either:
@@ -3331,12 +3333,23 @@ sub _new {
33313333
}
33323334
unless (defined $ref_id && length $ref_id) {
33333335
$_prefix = '' unless defined($_prefix);
3334-
$_[2] = $ref_id = $_prefix . $Git::SVN::default_ref_id;
3336+
$_[2] = $ref_id =
3337+
"refs/remotes/$_prefix$Git::SVN::default_ref_id";
33353338
}
33363339
$_[1] = $repo_id;
33373340
my $dir = "$ENV{GIT_DIR}/svn/$ref_id";
3341+
3342+
# Older repos imported by us used $GIT_DIR/svn/foo instead of
3343+
# $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo
3344+
if ($ref_id =~ m{^refs/remotes/(.*)}) {
3345+
my $old_dir = "$ENV{GIT_DIR}/svn/$1";
3346+
if (-d $old_dir && ! -d $dir) {
3347+
$dir = $old_dir;
3348+
}
3349+
}
3350+
33383351
$_[3] = $path = '' unless (defined $path);
3339-
mkpath(["$ENV{GIT_DIR}/svn"]);
3352+
mkpath([$dir]);
33403353
bless {
33413354
ref_id => $ref_id, dir => $dir, index => "$dir/index",
33423355
path => $path, config => "$ENV{GIT_DIR}/svn/config",
@@ -5509,7 +5522,7 @@ sub minimize_connections {
55095522
my $pfx = "svn-remote.$x->{old_repo_id}";
55105523

55115524
my $old_fetch = quotemeta("$x->{old_path}:".
5512-
"refs/remotes/$x->{ref_id}");
5525+
"$x->{ref_id}");
55135526
command_noisy(qw/config --unset/,
55145527
"$pfx.fetch", '^'. $old_fetch . '$');
55155528
delete $r->{$x->{old_repo_id}}->
@@ -5578,7 +5591,7 @@ sub new {
55785591
my ($class, $glob) = @_;
55795592
my $re = $glob;
55805593
$re =~ s!/+$!!g; # no need for trailing slashes
5581-
$re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
5594+
$re =~ m!^([^*]*)(\*(?:/\*)*)(.*)$!;
55825595
my $temp = $re;
55835596
my ($left, $right) = ($1, $3);
55845597
$re = $2;

t/lib-git-svn.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ if ! test_have_prereq PERL; then
1414
fi
1515

1616
GIT_DIR=$PWD/.git
17-
GIT_SVN_DIR=$GIT_DIR/svn/git-svn
17+
GIT_SVN_DIR=$GIT_DIR/svn/refs/remotes/git-svn
1818
SVN_TREE=$GIT_SVN_DIR/svn-tree
1919

2020
svn >/dev/null 2>&1

t/t9104-git-svn-follow-parent.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ test_expect_success "follow-parent is atomic" '
172172
git update-ref refs/remotes/flunk@18 refs/remotes/stunk~2 &&
173173
git update-ref -d refs/remotes/stunk &&
174174
git config --unset svn-remote.svn.fetch stunk &&
175-
mkdir -p "$GIT_DIR"/svn/flunk@18 &&
176-
rev_map=$(cd "$GIT_DIR"/svn/stunk && ls .rev_map*) &&
177-
dd if="$GIT_DIR"/svn/stunk/$rev_map \
178-
of="$GIT_DIR"/svn/flunk@18/$rev_map bs=24 count=1 &&
179-
rm -rf "$GIT_DIR"/svn/stunk &&
175+
mkdir -p "$GIT_DIR"/svn/refs/remotes/flunk@18 &&
176+
rev_map=$(cd "$GIT_DIR"/svn/refs/remotes/stunk && ls .rev_map*) &&
177+
dd if="$GIT_DIR"/svn/refs/remotes/stunk/$rev_map \
178+
of="$GIT_DIR"/svn/refs/remotes/flunk@18/$rev_map bs=24 count=1 &&
179+
rm -rf "$GIT_DIR"/svn/refs/remotes/stunk &&
180180
git svn init --minimize-url -i flunk "$svnrepo"/flunk &&
181181
git svn fetch -i flunk &&
182182
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&

t/t9107-git-svn-migrate.sh

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ test_expect_success 'setup old-looking metadata' '
1616
cd .. &&
1717
git svn init "$svnrepo" &&
1818
git svn fetch &&
19-
mv "$GIT_DIR"/svn/* "$GIT_DIR"/ &&
20-
mv "$GIT_DIR"/svn/.metadata "$GIT_DIR"/ &&
21-
rmdir "$GIT_DIR"/svn &&
19+
rm -rf "$GIT_DIR"/svn &&
2220
git update-ref refs/heads/git-svn-HEAD refs/${remotes_git_svn} &&
2321
git update-ref refs/heads/svn-HEAD refs/${remotes_git_svn} &&
2422
git update-ref -d refs/${remotes_git_svn} refs/${remotes_git_svn}
@@ -87,7 +85,7 @@ test_expect_success 'migrate --minimize on old inited layout' '
8785
rm -rf "$GIT_DIR"/svn &&
8886
for i in `cat fetch.out`; do
8987
path=`expr $i : "\([^:]*\):.*$"`
90-
ref=`expr $i : "[^:]*:refs/remotes/\(.*\)$"`
88+
ref=`expr $i : "[^:]*:\(refs/remotes/.*\)$"`
9189
if test -z "$ref"; then continue; fi
9290
if test -n "$path"; then path="/$path"; fi
9391
( mkdir -p "$GIT_DIR"/svn/$ref/info/ &&
@@ -107,16 +105,16 @@ test_expect_success 'migrate --minimize on old inited layout' '
107105

108106
test_expect_success ".rev_db auto-converted to .rev_map.UUID" '
109107
git svn fetch -i trunk &&
110-
test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
111-
expect="$(ls "$GIT_DIR"/svn/trunk/.rev_map.*)" &&
108+
test -z "$(ls "$GIT_DIR"/svn/refs/remotes/trunk/.rev_db.* 2>/dev/null)" &&
109+
expect="$(ls "$GIT_DIR"/svn/refs/remotes/trunk/.rev_map.*)" &&
112110
test -n "$expect" &&
113111
rev_db="$(echo $expect | sed -e "s,_map,_db,")" &&
114112
convert_to_rev_db "$expect" "$rev_db" &&
115113
rm -f "$expect" &&
116114
test -f "$rev_db" &&
117115
git svn fetch -i trunk &&
118-
test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
119-
test ! -e "$GIT_DIR"/svn/trunk/.rev_db &&
116+
test -z "$(ls "$GIT_DIR"/svn/refs/remotes/trunk/.rev_db.* 2>/dev/null)" &&
117+
test ! -e "$GIT_DIR"/svn/refs/remotes/trunk/.rev_db &&
120118
test -f "$expect"
121119
'
122120

t/t9143-git-svn-gc.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,26 +28,26 @@ test_expect_success 'Setup repo' 'git svn init "$svnrepo"'
2828
test_expect_success 'Fetch repo' 'git svn fetch'
2929

3030
test_expect_success 'make backup copy of unhandled.log' '
31-
cp .git/svn/git-svn/unhandled.log tmp
31+
cp .git/svn/refs/remotes/git-svn/unhandled.log tmp
3232
'
3333

34-
test_expect_success 'create leftover index' '> .git/svn/git-svn/index'
34+
test_expect_success 'create leftover index' '> .git/svn/refs/remotes/git-svn/index'
3535

3636
test_expect_success 'git svn gc runs' 'git svn gc'
3737

38-
test_expect_success 'git svn index removed' '! test -f .git/svn/git-svn/index'
38+
test_expect_success 'git svn index removed' '! test -f .git/svn/refs/remotes/git-svn/index'
3939

4040
if perl -MCompress::Zlib -e 0 2>/dev/null
4141
then
4242
test_expect_success 'git svn gc produces a valid gzip file' '
43-
gunzip .git/svn/git-svn/unhandled.log.gz
43+
gunzip .git/svn/refs/remotes/git-svn/unhandled.log.gz
4444
'
4545
else
4646
say "Perl Compress::Zlib unavailable, skipping gunzip test"
4747
fi
4848

4949
test_expect_success 'git svn gc does not change unhandled.log files' '
50-
test_cmp .git/svn/git-svn/unhandled.log tmp/unhandled.log
50+
test_cmp .git/svn/refs/remotes/git-svn/unhandled.log tmp/unhandled.log
5151
'
5252

5353
test_done

t/t9144-git-svn-old-rev_map.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2009 Eric Wong
4+
5+
test_description='git svn old rev_map preservd'
6+
. ./lib-git-svn.sh
7+
8+
test_expect_success 'setup test repository with old layout' '
9+
mkdir i &&
10+
(cd i && > a) &&
11+
svn_cmd import -m- i "$svnrepo" &&
12+
git svn init "$svnrepo" &&
13+
git svn fetch &&
14+
test -d .git/svn/refs/remotes/git-svn/ &&
15+
! test -e .git/svn/git-svn/ &&
16+
mv .git/svn/refs/remotes/git-svn .git/svn/ &&
17+
rm -r .git/svn/refs
18+
'
19+
20+
test_expect_success 'old layout continues to work' '
21+
svn_cmd import -m- i "$svnrepo/b" &&
22+
git svn rebase &&
23+
echo a >> b/a &&
24+
git add b/a &&
25+
git commit -m- -a &&
26+
git svn dcommit &&
27+
! test -d .git/svn/refs/ &&
28+
test -e .git/svn/git-svn/
29+
'
30+
31+
test_done

0 commit comments

Comments
 (0)