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>
Adam Brewster committed
Aug 11, 2009 at 23:14 UTC
6f5748e14cc5bb0a836b649fb8e2d6a5eb166f1d
6 files changed
+96
-54
git-svn.perl
+48
-35
@@ -909,7 +909,7 @@ sub cmd_multi_init {
909
}
910
do_git_init_db();
911
if (defined $_trunk) {
912
- my $trunk_ref = $_prefix . 'trunk';
912
+ my $trunk_ref = 'refs/remotes/' . $_prefix . 'trunk';
913
# try both old-style and new-style lookups:
914
my $gs_trunk = eval { Git::SVN->new($trunk_ref) };
915
unless ($gs_trunk) {
@@ -1654,23 +1654,23 @@ sub resolve_local_globs {
1654
return unless defined $glob_spec;
1655
my $ref = $glob_spec->{ref};
1656
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}$#;
1659
my $p = $1;
1660
my $pathname = desanitize_refname($path->full_path($p));
1661
my $refname = desanitize_refname($ref->full_path($p));
1662
if (my $existing = $fetch->{$pathname}) {
1663
if ($existing ne $refname) {
1664
die "Refspec conflict:\n",
1665
- "existing: refs/remotes/$existing\n",
1666
- " globbed: refs/remotes/$refname\n";
1665
+ "existing: $existing\n",
1666
+ " globbed: $refname\n";
1667
}
1668
- my $u = (::cmt_metadata("refs/remotes/$refname"))[0];
1668
+ my $u = (::cmt_metadata("$refname"))[0];
1669
$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";
1671
if ($pathname ne $u) {
1672
warn "W: Refspec glob conflict ",
1673
- "(ref: refs/remotes/$refname):\n",
1673
+ "(ref: $refname):\n",
1674
"expected path: $pathname\n",
1675
" real path: $u\n",
1676
"Continuing ahead with $u\n";
@@ -1748,33 +1748,35 @@ sub read_all_remotes {
1748
my $use_svm_props = eval { command_oneline(qw/config --bool
1749
svn.useSvmProps/) };
1750
$use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
1751
+ my $svn_refspec = qr{\s*/?(.*?)\s*:\s*(.+?)\s*};
1752
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/};
1758
$r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
1759
$r->{$remote}->{svm} = {} if $use_svm_props;
1760
} elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
1761
$r->{$1}->{svm} = {};
1762
} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
1763
$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/};
1770
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) };
1775
if (length($rs->{ref}->{right}) != 0) {
1776
die "The '*' glob character must be the last ",
1775
- "character of '$g'\n";
1777
+ "character of '$remote_ref'\n";
1778
}
1777
- push @{ $r->{$1}->{$2} }, $rs;
1779
+ push @{ $r->{$remote}->{$t} }, $rs;
1780
}
1781
}
1782
@@ -1882,9 +1884,9 @@ sub init_remote_config {
1884
}
1885
}
1886
my ($xrepo_id, $xpath) = find_ref($self->refname);
1885
- if (defined $xpath) {
1887
+ if (!$no_write && defined $xpath) {
1888
die "svn-remote.$xrepo_id.fetch already set to track ",
1887
- "$xpath:refs/remotes/", $self->refname, "\n";
1889
+ "$xpath:", $self->refname, "\n";
1890
}
1891
unless ($no_write) {
1892
command_noisy('config',
@@ -1959,7 +1961,7 @@ sub find_ref {
1961
my ($ref_id) = @_;
1962
foreach (command(qw/config -l/)) {
1963
next unless m!^svn-remote\.(.+)\.fetch=
1962
- \s*(.*)\s*:\s*refs/remotes/(.+)\s*$!x;
1964
+ \s*/?(.*?)\s*:\s*(.+?)\s*$!x;
1965
my ($repo_id, $path, $ref) = ($1, $2, $3);
1966
if ($ref eq $ref_id) {
1967
$path = '' if ($path =~ m#^\./?#);
@@ -1976,16 +1978,16 @@ sub new {
1978
if (!defined $repo_id) {
1979
die "Could not find a \"svn-remote.*.fetch\" key ",
1980
"in the repository configuration matching: ",
1979
- "refs/remotes/$ref_id\n";
1981
+ "$ref_id\n";
1982
}
1983
}
1984
my $self = _new($class, $repo_id, $ref_id, $path);
1985
if (!defined $self->{path} || !length $self->{path}) {
1986
my $fetch = command_oneline('config', '--get',
1987
"svn-remote.$repo_id.fetch",
1986
- ":refs/remotes/$ref_id\$") or
1988
+ ":$ref_id\$") or
1989
die "Failed to read \"svn-remote.$repo_id.fetch\" ",
1988
- "\":refs/remotes/$ref_id\$\" in config\n";
1990
+ "\":$ref_id\$\" in config\n";
1991
($self->{path}, undef) = split(/\s*:\s*/, $fetch);
1992
}
1993
$self->{url} = command_oneline('config', '--get',
@@ -1996,7 +1998,7 @@ sub new {
1998
}
1999
2000
sub refname {
1999
- my ($refname) = "refs/remotes/$_[0]->{ref_id}" ;
2001
+ my ($refname) = $_[0]->{ref_id} ;
2002
2003
# It cannot end with a slash /, we'll throw up on this because
2004
# SVN can't have directories with a slash in their name, either:
@@ -3331,12 +3333,23 @@ sub _new {
3333
}
3334
unless (defined $ref_id && length $ref_id) {
3335
$_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";
3338
}
3339
$_[1] = $repo_id;
3340
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
+
3351
$_[3] = $path = '' unless (defined $path);
3339
- mkpath(["$ENV{GIT_DIR}/svn"]);
3352
+ mkpath([$dir]);
3353
bless {
3354
ref_id => $ref_id, dir => $dir, index => "$dir/index",
3355
path => $path, config => "$ENV{GIT_DIR}/svn/config",
@@ -5509,7 +5522,7 @@ sub minimize_connections {
5522
my $pfx = "svn-remote.$x->{old_repo_id}";
5523
5524
my $old_fetch = quotemeta("$x->{old_path}:".
5512
- "refs/remotes/$x->{ref_id}");
5525
+ "$x->{ref_id}");
5526
command_noisy(qw/config --unset/,
5527
"$pfx.fetch", '^'. $old_fetch . '$');
5528
delete $r->{$x->{old_repo_id}}->
@@ -5578,7 +5591,7 @@ sub new {
5591
my ($class, $glob) = @_;
5592
my $re = $glob;
5593
$re =~ s!/+$!!g; # no need for trailing slashes
5581
- $re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
5594
+ $re =~ m!^([^*]*)(\*(?:/\*)*)(.*)$!;
5595
my $temp = $re;
5596
my ($left, $right) = ($1, $3);
5597
$re = $2;
t/lib-git-svn.sh
+1
-1
@@ -14,7 +14,7 @@ if ! test_have_prereq PERL; then
14
fi
15
16
GIT_DIR=$PWD/.git
17
-GIT_SVN_DIR=$GIT_DIR/svn/git-svn
17
+GIT_SVN_DIR=$GIT_DIR/svn/refs/remotes/git-svn
18
SVN_TREE=$GIT_SVN_DIR/svn-tree
19
20
svn >/dev/null 2>&1
t/t9104-git-svn-follow-parent.sh
+5
-5
@@ -172,11 +172,11 @@ test_expect_success "follow-parent is atomic" '
172
git update-ref refs/remotes/flunk@18 refs/remotes/stunk~2 &&
173
git update-ref -d refs/remotes/stunk &&
174
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 &&
180
git svn init --minimize-url -i flunk "$svnrepo"/flunk &&
181
git svn fetch -i flunk &&
182
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
t/t9107-git-svn-migrate.sh
+6
-8
@@ -16,9 +16,7 @@ test_expect_success 'setup old-looking metadata' '
16
cd .. &&
17
git svn init "$svnrepo" &&
18
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 &&
20
git update-ref refs/heads/git-svn-HEAD refs/${remotes_git_svn} &&
21
git update-ref refs/heads/svn-HEAD refs/${remotes_git_svn} &&
22
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' '
85
rm -rf "$GIT_DIR"/svn &&
86
for i in `cat fetch.out`; do
87
path=`expr $i : "\([^:]*\):.*$"`
90
- ref=`expr $i : "[^:]*:refs/remotes/\(.*\)$"`
88
+ ref=`expr $i : "[^:]*:\(refs/remotes/.*\)$"`
89
if test -z "$ref"; then continue; fi
90
if test -n "$path"; then path="/$path"; fi
91
( mkdir -p "$GIT_DIR"/svn/$ref/info/ &&
@@ -107,16 +105,16 @@ test_expect_success 'migrate --minimize on old inited layout' '
105
106
test_expect_success ".rev_db auto-converted to .rev_map.UUID" '
107
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.*)" &&
110
test -n "$expect" &&
111
rev_db="$(echo $expect | sed -e "s,_map,_db,")" &&
112
convert_to_rev_db "$expect" "$rev_db" &&
113
rm -f "$expect" &&
114
test -f "$rev_db" &&
115
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 &&
118
test -f "$expect"
119
'
120
t/t9143-git-svn-gc.sh
+5
-5
@@ -28,26 +28,26 @@ test_expect_success 'Setup repo' 'git svn init "$svnrepo"'
28
test_expect_success 'Fetch repo' 'git svn fetch'
29
30
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
32
'
33
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'
35
36
test_expect_success 'git svn gc runs' 'git svn gc'
37
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'
39
40
if perl -MCompress::Zlib -e 0 2>/dev/null
41
then
42
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
44
'
45
else
46
say "Perl Compress::Zlib unavailable, skipping gunzip test"
47
fi
48
49
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
51
'
52
53
test_done
t/t9144-git-svn-old-rev_map.sh
new
+31
@@ -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