[PATCH/RFC] git-svn: Allow multiple branch and tag patterns

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This change allows multiple branch and tag patterns to be specified in
.git/config for git-svn projects.  This is useful for fetching several
different parts out of the namespace of an svn repository.
Additionally, a new repeatable directive called "skip" has been added
to specify a specific tag or branch to ignore.

Signed-off-by: Michael W. Olson <mwolson@xxxxxxx>
---
I've been using this patch regularly for over a year on a very large
svn repository.

This patch is known to work on git 1.6.3.3 specifically.  Once I get a
few responses about whether or not it is useful, I'll rebase it
against the git.git master branch.  Some further documentation
(perhaps just a relevant example or two) would also need to be added
to the git-svn manpage.

Here is an example ~/.git/config file which works with these changes.
The example upstream svn repository has branches in tags in 2
different namespaces.  Originally all tags/branches were directly
under /root/mod/branches and /root/mod/tags.  Later on, they created
new branches and tags in subdirectories such as
/root/mod/branches/myorg/bugs/BUGID.  This config file forces
old-style branches and tags into the "old/" namespace in git, and puts
new-style branches and tags into (for example) "myorg/bugs/BUGID".
The "skip" directives prevent the first level of the new namespace
("myorg", in particular) from being replicated underneath "old/" in
git, which is for cosmetic purposes.

[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
[svn-remote "svn"]
	url = https://svn.my.org/svn/root
	fetch = mod/trunk:refs/remotes/trunk
	branches = mod/branches/*:refs/remotes/old/*
        skip = branches:old/myorg
	tags = mod/tags/*:refs/remotes/tags/old/*
        skip = tags:old/myorg
	branches = mod/branches/myorg/bugs/*:refs/remotes/myorg/bugs/*
	tags = mod/tags/myorg/bugs/*:refs/remotes/tags/myorg/bugs/*
	branches = mod/branches/myorg/projects/*:refs/remotes/myorg/projects/*
	tags = mod/tags/myorg/projects/*:refs/remotes/tags/myorg/projects/*
	branches = mod/branches/myorg/releases/*:refs/remotes/myorg/releases/*
	tags = mod/tags/myorg/releases/*:refs/remotes/tags/myorg/releases/*

 git-svn.perl |   25 ++++++++++++++++++++-----
 1 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index ef1d30d..f7ec70c 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1548,7 +1548,7 @@ 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)) {
@@ -1592,14 +1592,17 @@ sub read_all_remotes {
 			$r->{$1}->{svm} = {};
 		} elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
 			$r->{$1}->{url} = $2;
+		} elsif (m!^(.+)\.skip=(branches|tags):\s*(.*)\s*$!) {
+			push @{$r->{$1}->{skip}->{$2}}, $3;
 		} elsif (m!^(.+)\.(branches|tags)=
 		           (.*):refs/remotes/(.+)\s*$/!x) {
 			my ($p, $g) = ($3, $4);
-			my $rs = $r->{$1}->{$2} = {
+			my $rs = {
 			                  t => $2,
 					  remote => $1,
 			                  path => Git::SVN::GlobSpec->new($p),
 			                  ref => Git::SVN::GlobSpec->new($g) };
+			push @{$r->{$1}->{$2}}, $rs;
 			if (length($rs->{ref}->{right}) != 0) {
 				die "The '*' glob character must be the last ",
 				    "character of '$g'\n";
@@ -1623,6 +1626,14 @@ sub read_all_remotes {
 		}
 	} keys %$r;

+	for my $rname (keys %$r) {
+		map { $_->{skip} = $r->{$rname}->{skip}->{branches} }
+		    @{$r->{$rname}->{branches}};
+		map { $_->{skip} =
+			[ map { "tags/$_" } @{$r->{$rname}->{skip}->{tags}} ] }
+		    @{$r->{$rname}->{tags}};
+	}
+
 	$r;
 }

@@ -1744,8 +1755,9 @@ sub find_by_url { # repos_root and, path are optional

 		my $fetch = $remotes->{$repo_id}->{fetch} || {};
 		foreach (qw/branches tags/) {
-			resolve_local_globs($u, $fetch,
-			                    $remotes->{$repo_id}->{$_});
+			for my $p (@{$remotes->{$repo_id}->{$_}}) {
+				resolve_local_globs($u, $fetch, $p);
+			}
 		}
 		my $p = $path;
 		my $rwr = rewrite_root({repo_id => $repo_id});
@@ -4586,12 +4598,15 @@ sub match_globs {
 			next unless /$g->{path}->{regex}/;
 			my $p = $1;
 			my $pathname = $g->{path}->full_path($p);
+			my $refname = $g->{ref}->full_path($p);
+			next if $g->{skip} && grep { $refname eq $_ }
+						   @{$g->{skip}};
 			next if $exists->{$pathname};
 			next if ($self->check_path($pathname, $r) !=
 			         $SVN::Node::dir);
 			$exists->{$pathname} = Git::SVN->init(
 			                      $self->{url}, $pathname, undef,
-			                      $g->{ref}->full_path($p), 1);
+			                      $refname, 1);
 		}
 		my $c = '';
 		foreach (split m#/#, $g->{path}->{left}) {
-- 
1.6.3.3
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]