aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xgit-svn.perl78
-rwxr-xr-xt/t9138-git-svn-multiple-branches.sh114
2 files changed, 170 insertions, 22 deletions
diff --git a/git-svn.perl b/git-svn.perl
index b1245cbab..48e8aad00 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -63,7 +63,7 @@ my ($SVN);
$sha1 = qr/[a-f\d]{40}/;
$sha1_short = qr/[a-f\d]{4,40}/;
my ($_stdin, $_help, $_edit,
- $_message, $_file,
+ $_message, $_file, $_branch_dest,
$_template, $_shared,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_merge, $_strategy, $_dry_run, $_local,
@@ -92,11 +92,11 @@ my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
'localtime' => \$Git::SVN::_localtime,
%remote_opts );
-my ($_trunk, $_tags, $_branches, $_stdlayout);
+my ($_trunk, @_tags, @_branches, $_stdlayout);
my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
- 'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
- 'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
+ 'trunk|T=s' => \$_trunk, 'tags|t=s@' => \@_tags,
+ 'branches|b=s@' => \@_branches, 'prefix=s' => \$_prefix,
'stdlayout|s' => \$_stdlayout,
'minimize-url|m' => \$Git::SVN::_minimize_url,
'no-metadata' => sub { $icv{noMetadata} = 1 },
@@ -141,11 +141,13 @@ my %cmd = (
branch => [ \&cmd_branch,
'Create a branch in the SVN repository',
{ 'message|m=s' => \$_message,
+ 'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run,
'tag|t' => \$_tag } ],
tag => [ sub { $_tag = 1; cmd_branch(@_) },
'Create a tag in the SVN repository',
{ 'message|m=s' => \$_message,
+ 'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
@@ -365,7 +367,7 @@ sub init_subdir {
sub cmd_clone {
my ($url, $path) = @_;
if (!defined $path &&
- (defined $_trunk || defined $_branches || defined $_tags ||
+ (defined $_trunk || @_branches || @_tags ||
defined $_stdlayout) &&
$url !~ m#^[a-z\+]+://#) {
$path = $url;
@@ -379,10 +381,10 @@ sub cmd_clone {
sub cmd_init {
if (defined $_stdlayout) {
$_trunk = 'trunk' if (!defined $_trunk);
- $_tags = 'tags' if (!defined $_tags);
- $_branches = 'branches' if (!defined $_branches);
+ @_tags = 'tags' if (! @_tags);
+ @_branches = 'branches' if (! @_branches);
}
- if (defined $_trunk || defined $_branches || defined $_tags) {
+ if (defined $_trunk || @_branches || @_tags) {
return cmd_multi_init(@_);
}
my $url = shift or die "SVN repository location required ",
@@ -630,7 +632,31 @@ sub cmd_branch {
my ($src, $rev, undef, $gs) = working_head_info($head);
my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
- my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
+ my $allglobs = $remote->{ $_tag ? 'tags' : 'branches' };
+ my $glob;
+ if ($#{$allglobs} == 0) {
+ $glob = $allglobs->[0];
+ } else {
+ unless(defined $_branch_dest) {
+ die "Multiple ",
+ $_tag ? "tag" : "branch",
+ " paths defined for Subversion repository.\n",
+ "You must specify where you want to create the ",
+ $_tag ? "tag" : "branch",
+ " with the --destination argument.\n";
+ }
+ foreach my $g (@{$allglobs}) {
+ if ($_branch_dest eq $g->{path}->{left}) {
+ $glob = $g;
+ last;
+ }
+ }
+ unless (defined $glob) {
+ die "Unknown ",
+ $_tag ? "tag" : "branch",
+ " destination $_branch_dest\n";
+ }
+ }
my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
@@ -837,7 +863,7 @@ sub cmd_proplist {
sub cmd_multi_init {
my $url = shift;
- unless (defined $_trunk || defined $_branches || defined $_tags) {
+ unless (defined $_trunk || @_branches || @_tags) {
usage(1);
}
@@ -862,10 +888,14 @@ sub cmd_multi_init {
undef, $trunk_ref);
}
}
- return unless defined $_branches || defined $_tags;
+ return unless @_branches || @_tags;
my $ra = $url ? Git::SVN::Ra->new($url) : undef;
- complete_url_ls_init($ra, $_branches, '--branches/-b', $_prefix);
- complete_url_ls_init($ra, $_tags, '--tags/-t', $_prefix . 'tags/');
+ foreach my $path (@_branches) {
+ complete_url_ls_init($ra, $path, '--branches/-b', $_prefix);
+ }
+ foreach my $path (@_tags) {
+ complete_url_ls_init($ra, $path, '--tags/-t', $_prefix.'tags/');
+ }
}
sub cmd_multi_fetch {
@@ -1150,6 +1180,7 @@ sub complete_url_ls_init {
die "--prefix='$pfx' must have a trailing slash '/'\n";
}
command_noisy('config',
+ '--add',
"svn-remote.$gs->{repo_id}.$n",
"$remote_path:refs/remotes/$pfx*" .
('/*' x (($remote_path =~ tr/*/*/) - 1)) );
@@ -1616,7 +1647,8 @@ sub fetch_all {
# read the max revs for wildcard expansion (branches/*, tags/*)
foreach my $t (qw/branches tags/) {
defined $remote->{$t} or next;
- push @globs, $remote->{$t};
+ push @globs, @{$remote->{$t}};
+
my $max_rev = eval { tmp_config(qw/--int --get/,
"svn-remote.$repo_id.${t}-maxRev") };
if (defined $max_rev && ($max_rev < $base)) {
@@ -1663,15 +1695,16 @@ sub read_all_remotes {
} elsif (m!^(.+)\.(branches|tags)=
(.*):refs/remotes/(.+)\s*$/!x) {
my ($p, $g) = ($3, $4);
- my $rs = $r->{$1}->{$2} = {
- t => $2,
- remote => $1,
- path => Git::SVN::GlobSpec->new($p),
- ref => Git::SVN::GlobSpec->new($g) };
+ my $rs = {
+ t => $2,
+ remote => $1,
+ path => Git::SVN::GlobSpec->new($p),
+ ref => Git::SVN::GlobSpec->new($g) };
if (length($rs->{ref}->{right}) != 0) {
die "The '*' glob character must be the last ",
"character of '$g'\n";
}
+ push @{ $r->{$1}->{$2} }, $rs;
}
}
@@ -1811,9 +1844,10 @@ sub find_by_url { # repos_root and, path are optional
next if defined $repos_root && $repos_root ne $u;
my $fetch = $remotes->{$repo_id}->{fetch} || {};
- foreach (qw/branches tags/) {
- resolve_local_globs($u, $fetch,
- $remotes->{$repo_id}->{$_});
+ foreach my $t (qw/branches tags/) {
+ foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
+ resolve_local_globs($u, $fetch, $globspec);
+ }
}
my $p = $path;
my $rwr = rewrite_root({repo_id => $repo_id});
diff --git a/t/t9138-git-svn-multiple-branches.sh b/t/t9138-git-svn-multiple-branches.sh
new file mode 100755
index 000000000..9725ccf9d
--- /dev/null
+++ b/t/t9138-git-svn-multiple-branches.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+#
+# Copyright (c) 2009 Marc Branchaud
+#
+
+test_description='git svn multiple branch and tag paths in the svn repo'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup svnrepo' '
+ mkdir project \
+ project/trunk \
+ project/b_one \
+ project/b_two \
+ project/tags_A \
+ project/tags_B &&
+ echo 1 > project/trunk/a.file &&
+ svn import -m "$test_description" project "$svnrepo/project" &&
+ rm -rf project &&
+ svn cp -m "Branch 1" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_one/first" &&
+ svn cp -m "Tag 1" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/1.0" &&
+ svn co "$svnrepo/project" svn_project &&
+ cd svn_project &&
+ .
+ echo 2 > trunk/a.file &&
+ svn ci -m "Change 1" trunk/a.file &&
+ svn cp -m "Branch 2" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_one/second" &&
+ svn cp -m "Tag 2" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/2.0" &&
+ echo 3 > trunk/a.file &&
+ svn ci -m "Change 2" trunk/a.file &&
+ svn cp -m "Branch 3" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_two/1" &&
+ svn cp -m "Tag 3" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/3.0" &&
+ echo 4 > trunk/a.file &&
+ svn ci -m "Change 3" trunk/a.file &&
+ svn cp -m "Branch 4" "$svnrepo/project/trunk" \
+ "$svnrepo/project/b_two/2" &&
+ svn cp -m "Tag 4" "$svnrepo/project/trunk" \
+ "$svnrepo/project/tags_A/4.0" &&
+ svn up &&
+ echo 5 > b_one/first/a.file &&
+ svn ci -m "Change 4" b_one/first/a.file &&
+ svn cp -m "Tag 5" "$svnrepo/project/b_one/first" \
+ "$svnrepo/project/tags_B/v5" &&
+ echo 6 > b_one/second/a.file &&
+ svn ci -m "Change 5" b_one/second/a.file &&
+ svn cp -m "Tag 6" "$svnrepo/project/b_one/second" \
+ "$svnrepo/project/tags_B/v6" &&
+ echo 7 > b_two/1/a.file &&
+ svn ci -m "Change 6" b_two/1/a.file &&
+ svn cp -m "Tag 7" "$svnrepo/project/b_two/1" \
+ "$svnrepo/project/tags_B/v7" &&
+ echo 8 > b_two/2/a.file &&
+ svn ci -m "Change 7" b_two/2/a.file &&
+ svn cp -m "Tag 8" "$svnrepo/project/b_two/2" \
+ "$svnrepo/project/tags_B/v8" &&
+ cd ..
+ '
+
+test_expect_success 'clone multiple branch and tag paths' '
+ git svn clone -T trunk \
+ -b b_one/* --branches b_two/* \
+ -t tags_A/* --tags tags_B \
+ "$svnrepo/project" git_project &&
+ cd git_project &&
+ git rev-parse refs/remotes/first &&
+ git rev-parse refs/remotes/second &&
+ git rev-parse refs/remotes/1 &&
+ git rev-parse refs/remotes/2 &&
+ git rev-parse refs/remotes/tags/1.0 &&
+ git rev-parse refs/remotes/tags/2.0 &&
+ git rev-parse refs/remotes/tags/3.0 &&
+ git rev-parse refs/remotes/tags/4.0 &&
+ git rev-parse refs/remotes/tags/v5 &&
+ git rev-parse refs/remotes/tags/v6 &&
+ git rev-parse refs/remotes/tags/v7 &&
+ git rev-parse refs/remotes/tags/v8 &&
+ cd ..
+ '
+
+test_expect_success 'Multiple branch or tag paths require -d' '
+ cd git_project &&
+ test_must_fail git svn branch -m "No new branch" Nope &&
+ test_must_fail git svn tag -m "No new tag" Tagless &&
+ test_must_fail git rev-parse refs/remotes/Nope &&
+ test_must_fail git rev-parse refs/remotes/tags/Tagless &&
+ cd ../svn_project &&
+ svn up &&
+ test_must_fail test -d b_one/Nope &&
+ test_must_fail test -d b_two/Nope &&
+ test_must_fail test -d tags_A/Tagless &&
+ test_must_fail test -d tags_B/Tagless &&
+ cd ..
+ '
+
+test_expect_success 'create new branches and tags' '
+ ( cd git_project && git svn branch -m "New branch 1" -d project/b_one New1 ) &&
+ ( cd svn_project && svn up && test -e b_one/New1/a.file ) &&
+
+ ( cd git_project && git svn branch -m "New branch 2" -d project/b_two New2 ) &&
+ ( cd svn_project && svn up && test -e b_two/New2/a.file ) &&
+
+ ( cd git_project && git svn branch -t -m "New tag 1" -d project/tags_A Tag1 ) &&
+ ( cd svn_project && svn up && test -e tags_A/Tag1/a.file )
+
+ ( cd git_project && git svn tag -m "New tag 2" -d project/tags_B Tag2 ) &&
+ ( cd svn_project && svn up && test -e tags_B/Tag2/a.file )
+ '
+
+test_done