git-svn: introduce --parents parameter for commands branch and tag

This parameter is equivalent to the parameter --parents on svn cp commands
and is useful for non-standard repository layouts.

Signed-off-by: Tobias Schulte <tobias.schulte@gliderpilot.de>
Signed-off-by: Eric Wong <normalperson@yhbt.net>
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 68c706d..aad452f 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -300,6 +300,11 @@
 	git config --get-all svn-remote.<name>.commiturl
 +
 
+--parents;;
+	Create parent folders. This parameter is equivalent to the parameter
+	--parents on svn cp commands and is useful for non-standard repository
+	layouts.
+
 'tag'::
 	Create a tag in the SVN repository. This is a shorthand for
 	'branch -t'.
diff --git a/git-svn.perl b/git-svn.perl
index ccabe06..d070de0 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -113,7 +113,7 @@
 	$_template, $_shared,
 	$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
 	$_before, $_after,
-	$_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
+	$_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
 	$_prefix, $_no_checkout, $_url, $_verbose,
 	$_commit_url, $_tag, $_merge_info, $_interactive);
 
@@ -203,6 +203,7 @@
 	            { 'message|m=s' => \$_message,
 	              'destination|d=s' => \$_branch_dest,
 	              'dry-run|n' => \$_dry_run,
+	              'parents' => \$_parents,
 	              'tag|t' => \$_tag,
 	              'username=s' => \$Git::SVN::Prompt::_username,
 	              'commit-url=s' => \$_commit_url } ],
@@ -211,6 +212,7 @@
 	         { 'message|m=s' => \$_message,
 	           'destination|d=s' => \$_branch_dest,
 	           'dry-run|n' => \$_dry_run,
+	           'parents' => \$_parents,
 	           'username=s' => \$Git::SVN::Prompt::_username,
 	           'commit-url=s' => \$_commit_url } ],
 	'set-tree' => [ \&cmd_set_tree,
@@ -1172,6 +1174,10 @@
 		$ctx->ls($dst, 'HEAD', 0);
 	} and die "branch ${branch_name} already exists\n";
 
+	if ($_parents) {
+		mk_parent_dirs($ctx, $dst);
+	}
+
 	print "Copying ${src} at r${rev} to ${dst}...\n";
 	$ctx->copy($src, $rev, $dst)
 		unless $_dry_run;
@@ -1179,6 +1185,17 @@
 	$gs->fetch_all;
 }
 
+sub mk_parent_dirs {
+	my ($ctx, $parent) = @_;
+	$parent =~ s{/[^/]*$}{};
+
+	if (!eval{$ctx->ls($parent, 'HEAD', 0)}) {
+		mk_parent_dirs($ctx, $parent);
+		print "Creating parent folder ${parent} ...\n";
+		$ctx->mkdir($parent) unless $_dry_run;
+	}
+}
+
 sub cmd_find_rev {
 	my $revision_or_hash = shift or die "SVN or git revision required ",
 	                                    "as a command-line argument\n";
diff --git a/t/t9167-git-svn-cmd-branch-subproject.sh b/t/t9167-git-svn-cmd-branch-subproject.sh
new file mode 100755
index 0000000..53def87
--- /dev/null
+++ b/t/t9167-git-svn-cmd-branch-subproject.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+#
+# Copyright (c) 2013 Tobias Schulte
+#
+
+test_description='git svn branch for subproject clones'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize svnrepo' '
+	mkdir import &&
+	(
+		cd import &&
+		mkdir -p trunk/project branches tags &&
+		(
+			cd trunk/project &&
+			echo foo > foo
+		) &&
+		svn_cmd import -m "import for git-svn" . "$svnrepo" >/dev/null
+	) &&
+	rm -rf import &&
+	svn_cmd co "$svnrepo"/trunk/project trunk/project &&
+	(
+		cd trunk/project &&
+		echo bar >> foo &&
+		svn_cmd ci -m "updated trunk"
+	) &&
+	rm -rf trunk
+'
+
+test_expect_success 'import into git' '
+	git svn init --trunk=trunk/project --branches=branches/*/project \
+		--tags=tags/*/project "$svnrepo" &&
+	git svn fetch &&
+	git checkout remotes/trunk
+'
+
+test_expect_success 'git svn branch tests' '
+	test_must_fail git svn branch a &&
+	git svn branch --parents a &&
+	test_must_fail git svn branch -t tag1 &&
+	git svn branch --parents -t tag1 &&
+	test_must_fail git svn branch --tag tag2 &&
+	git svn branch --parents --tag tag2 &&
+	test_must_fail git svn tag tag3 &&
+	git svn tag --parents tag3
+'
+
+test_done