All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Sperling <stsp@elego.de>
To: git@vger.kernel.org
Cc: subversion@elego.de
Subject: [PATCH] Allow multiple tag and branch directories in git-svnimport
Date: Tue, 21 Aug 2007 19:08:58 +0200	[thread overview]
Message-ID: <20070821170858.GA1721@jack.stsp.lan> (raw)

[-- Attachment #1: Type: text/plain, Size: 8182 bytes --]

With this patch, users can specify colon-seperated lists of
directories containing tags and branches, respectively.

This makes git-svnimport much more usable in the real world
because there are Subversion repositories that use a deeper
tag and branch hierarchy than the recommended hierarchy of

	trunk/
	tags/
	branches/

The patch assumes my memleak fix patch from
http://marc.info/?l=git&m=118554191513822&w=2
but applies cleanly to current vanilla git head as well.

I'm not subscribed to the list so please Cc me in replies, thanks.


diff --git a/Documentation/git-svnimport.txt b/Documentation/git-svnimport.txt
index e97d15e..2cfc407 100644
--- a/Documentation/git-svnimport.txt
+++ b/Documentation/git-svnimport.txt
@@ -12,11 +12,11 @@ SYNOPSIS
 [verse]
 'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
 		[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
-		[ -b branch_subdir ] [ -T trunk_subdir ] [ -t tag_subdir ]
-		[ -s start_chg ] [ -m ] [ -r ] [ -M regex ]
-		[ -I <ignorefile_name> ] [ -A <author_file> ]
-		[ -R <repack_each_revs>] [ -P <path_from_trunk> ]
-		<SVN_repository_URL> [ <path> ]
+		[ -b branch_subdir[:branch_subdir:...] ] [ -T trunk_subdir ]
+		[ -t tag_subdir[:tag_subdir:...] ] [ -s start_chg ] [ -m ]
+		[ -r ] [ -M regex ] [ -I <ignorefile_name> ]
+		[ -A <author_file> ] [ -R <repack_each_revs>]
+		[ -P <path_from_trunk> ] <SVN_repository_URL> [ <path> ]
 
 
 DESCRIPTION
@@ -26,11 +26,6 @@ repository, or incrementally import into an existing one.
 
 SVN access is done by the SVN::Perl module.
 
-git-svnimport assumes that SVN repositories are organized into one
-"trunk" directory where the main development happens, "branches/FOO"
-directories for branches, and "/tags/FOO" directories for tags.
-Other subdirectories are ignored.
-
 git-svnimport creates a file ".git/svn2git", which is required for
 incremental SVN imports.
 
@@ -53,11 +48,13 @@ When importing incrementally, you might need to edit the .git/svn2git file.
 -T <trunk_subdir>::
 	Name the SVN trunk. Default "trunk".
 
--t <tag_subdir>::
-	Name the SVN subdirectory for tags. Default "tags".
+-t <tag_subdir[:tag_subdir:..]>::
+	Colon-seperated list of names of subdirectories containing tags.
+	Default "tags".
 
--b <branch_subdir>::
-	Name the SVN subdirectory for branches. Default "branches".
+-b <branch_subdir[:branch_subdir:...]>::
+	Colon-seperated list of names of subdirectories containing branches.
+	Default "branches".
 
 -o <branch-for-HEAD>::
 	The 'trunk' branch from SVN is imported to the 'origin' branch within
diff --git a/git-svnimport.perl b/git-svnimport.perl
index fc9ea71..96f0926 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -38,9 +38,10 @@ sub usage() {
 	print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from SVN
        [-o branch-for-HEAD] [-h] [-v] [-l max_rev] [-R repack_each_revs]
-       [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
-       [-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
-       [-m] [-M regex] [-A author_file] [-S] [-F] [-P project_name] [SVN_URL]
+       [-C GIT_repository] [-t tag_subdir[:tag_subdir:...]] [-T trunk_subdir]
+       [-b branch_subdir[:branch_subdir:...]] [-d|-D] [-i] [-u] [-r]
+       [-I ignorefilename] [-s start_chg] [-m] [-M regex]
+       [-A author_file] [-S] [-F] [-P project_name] [SVN_URL]
 END
 	exit(1);
 }
@@ -48,9 +49,9 @@ END
 getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:R:uv") or usage();
 usage if $opt_h;
 
-my $tag_name = $opt_t || "tags";
-my $trunk_name = defined $opt_T ? $opt_T : "trunk";
-my $branch_name = $opt_b || "branches";
+my @tag_dirs = defined $opt_t ? split /:/,$opt_t : "tags";
+my $trunk_dir = defined $opt_T ? $opt_T : "trunk";
+my @branch_dirs = defined $opt_b ? split /:/,$opt_b : "branches";
 my $project_name = $opt_P || "";
 $project_name = "/" . $project_name if ($project_name);
 my $repack_after = $opt_R || 1000;
@@ -68,14 +69,18 @@ my $svn_dir = $ARGV[1];
 
 our @mergerx = ();
 if ($opt_m) {
-	my $branch_esc = quotemeta ($branch_name);
-	my $trunk_esc  = quotemeta ($trunk_name);
-	@mergerx =
-	(
-		qr!\b(?:merg(?:ed?|ing))\b.*?\b((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i,
-		qr!\b(?:from|of)\W+((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i,
-		qr!\b(?:from|of)\W+(?:the )?([\w\.\-]+)[-\s]branch\b!i
-	);
+	my @branch_escs;
+	foreach (@branch_dirs) { push @branch_escs, quotemeta ($_); }
+	my $trunk_esc  = quotemeta ($trunk_dir);
+
+	foreach my $branch_esc (@branch_escs) {
+		push (@mergerx,
+		(
+			qr!\b(?:merg(?:ed?|ing))\b.*?\b((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i,
+			qr!\b(?:from|of)\W+((?:(?<=$branch_esc/)[\w\.\-]+)|(?:$trunk_esc))\b!i,
+			qr!\b(?:from|of)\W+(?:the )?([\w\.\-]+)[-\s]branch\b!i
+		));
+	}
 }
 if ($opt_M) {
 	unshift (@mergerx, qr/$opt_M/);
@@ -452,29 +457,39 @@ sub project_path($$)
 
 sub split_path($$) {
 	my($rev,$path) = @_;
-	my $branch;
+	my $dir; # tag or branch dir
+
+	OUTER: foreach my $tag_dir (@tag_dirs) {
+		foreach my $branch_dir (@branch_dirs) {
+			if ($path =~ s#^/\Q$tag_dir\E/([^/]+)/?##) {
+				$dir = "/$1";
+			} elsif ($path =~ s#^/\Q$trunk_dir\E/?##) {
+				$dir = "/";
+			} elsif ($path =~ s#^/\Q$branch_dir\E/([^/]+)/?##) {
+				$dir = $1;
+			}
+			last OUTER if $dir;
+		}
+	}
 
-	if($path =~ s#^/\Q$tag_name\E/([^/]+)/?##) {
-		$branch = "/$1";
-	} elsif($path =~ s#^/\Q$trunk_name\E/?##) {
-		$branch = "/";
-	} elsif($path =~ s#^/\Q$branch_name\E/([^/]+)/?##) {
-		$branch = $1;
-	} else {
-		my %no_error = (
-			"/" => 1,
-			"/$tag_name" => 1,
-			"/$branch_name" => 1
-		);
-		print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path});
-		return ()
+	if (! $dir) {
+		my %no_error = ( "/" => 1, "/tags" => 1, "/branches" => 1 );
+		foreach (@tag_dirs) {
+			$no_error{"/$_"} = 1;
+		}
+		foreach (@branch_dirs) {
+			$no_error{"/$_"} = 1;
+		}
+		print STDERR "$rev: Could not determine tag or branch ",
+			"directory for path '$path'\n",
+			unless (defined $no_error{$path});
 	}
 	if ($path eq "") {
 		$path = "/";
 	} elsif ($project_name) {
 		$path = project_path($path, $project_name);
 	}
-	return ($branch,$path);
+	return ($dir,$path);
 }
 
 sub branch_rev($$) {
@@ -874,9 +889,32 @@ sub commit {
 
 		$dest =~ tr/_/\./ if $opt_u;
 
-		system('git-tag', $dest, $cid) == 0
-			or die "Cannot create tag $dest: $!\n";
-
+		# Since we support multiple directories that host tags we
+		# must support repositories that contain the same tag name
+		# in different tag directories for whatever reason,
+		# e.g. tags/jim/1.0-rc3 and tags/huck/1.0-rc3
+		#
+		# Also, because in Subversion a given tag directory could
+		# exist in revision A, be deleted in revision B and later
+		# recreated under the same name in revision C, we
+		# cannot guarantee that a tag is unique simply by
+		# looking at the tag's path.
+		#
+		# So if we fail to create the tag the first time, we try
+		# to create the tag with the same name except with the
+		# revision number of the current commit appended.
+		# Users can rename tags again later after the repository
+		# has been converted if they don't like this.
+		# It's still much better than failing to convert the
+		# repository alltogether.
+		if (system('git-tag', $dest, $cid) != 0) {
+			print STDERR "Could not create tag $dest, ",
+				"trying to create tag $dest-r$revision ",
+				"instead\n";
+			$dest = "$dest-r$revision";
+			system('git-tag', $dest, $cid) == 0
+				or die "Cannot create tag $dest: $? $!\n";
+		}
 		print "Created tag '$dest' on '$branch'\n" if $opt_v;
 	}
 	$branches{$branch}{"LAST"} = $cid;

-- 
Stefan Sperling <stsp@elego.de>                 Software Developer
elego Software Solutions GmbH                            HRB 77719
Gustav-Meyer-Allee 25, Gebaeude 12        Tel:  +49 30 23 45 86 96 
13355 Berlin                              Fax:  +49 30 23 45 86 95
http://www.elego.de                 Geschaeftsfuehrer: Olaf Wagner

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

             reply	other threads:[~2007-08-21 17:16 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-21 17:08 Stefan Sperling [this message]
2007-08-21 17:38 ` [PATCH] Allow multiple tag and branch directories in git-svnimport Stefan Sperling
2007-08-21 17:46   ` Randal L. Schwartz
2007-08-22 10:24     ` Stefan Sperling

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070821170858.GA1721@jack.stsp.lan \
    --to=stsp@elego.de \
    --cc=git@vger.kernel.org \
    --cc=subversion@elego.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.