@matheusbsbs / matheus-bagliano / commits / 6f5748e14c
Fork 0

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