aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2006-03-03 01:20:07 -0800
committerJunio C Hamano <junkio@cox.net>2006-03-03 11:27:10 -0800
commit69f0d91e49dbf3c3942bae125c07ad17f6027f83 (patch)
treeea9a298863f655f495245d6b9dfbb2a0099d14b3
parenta41c175d6f3e903844131b6dc39da986248c7585 (diff)
downloadgit-69f0d91e49dbf3c3942bae125c07ad17f6027f83.tar.gz
git-69f0d91e49dbf3c3942bae125c07ad17f6027f83.tar.xz
contrib/git-svn: add -b/--branch switch for branch detection
I've said I don't like branches in Subversion, and I still don't. This is a bit more flexible, though, as the argument for -b is any arbitrary git head/tag reference. This makes some things easier: * Importing git history into a brand new SVN branch. * Tracking multiple SVN branches via GIT_SVN_ID, even from multiple repositories. * Adding tags from SVN (still need to use GIT_SVN_ID, though). * Even merge tracking is supported, if and only the heads end up with 100% equivalent tree objects. This is more stricter but more robust and foolproof than parsing commit messages, imho. Signed-off-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <junkio@cox.net>
-rwxr-xr-xcontrib/git-svn/git-svn.perl38
-rw-r--r--contrib/git-svn/git-svn.txt17
2 files changed, 54 insertions, 1 deletions
diff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl
index 0e092c5d3..1f9a470f0 100755
--- a/contrib/git-svn/git-svn.perl
+++ b/contrib/git-svn/git-svn.perl
@@ -35,6 +35,7 @@ my $sha1 = qr/[a-f\d]{40}/;
my $sha1_short = qr/[a-f\d]{6,40}/;
my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
$_find_copies_harder, $_l, $_version, $_upgrade);
+my (@_branch_from, %tree_map);
GetOptions( 'revision|r=s' => \$_revision,
'no-ignore-externals' => \$_no_ignore_ext,
@@ -43,6 +44,7 @@ GetOptions( 'revision|r=s' => \$_revision,
'rmdir' => \$_rmdir,
'upgrade' => \$_upgrade,
'help|H|h' => \$_help,
+ 'branch|b=s' => \@_branch_from,
'find-copies-harder' => \$_find_copies_harder,
'l=i' => \$_l,
'version|V' => \$_version,
@@ -831,6 +833,8 @@ sub git_commit {
my $uuid = $info->{'Repository UUID'};
defined $uuid or croak "Unable to get Repository UUID\n";
+ map_tree_joins() if (@_branch_from && !%tree_map);
+
# commit parents can be conditionally bound to a particular
# svn revision via: "svn_revno=commit_sha1", filter them out here:
my @exec_parents;
@@ -852,6 +856,17 @@ sub git_commit {
git_addremove();
chomp(my $tree = `git-write-tree`);
croak if $?;
+ if (exists $tree_map{$tree}) {
+ my %seen_parent = map { $_ => 1 } @exec_parents;
+ foreach (@{$tree_map{$tree}}) {
+ # MAXPARENT is defined to 16 in commit-tree.c:
+ if ($seen_parent{$_} || @exec_parents > 16) {
+ next;
+ }
+ push @exec_parents, $_;
+ $seen_parent{$_} = 1;
+ }
+ }
my $msg_fh = IO::File->new_tmpfile or croak $!;
print $msg_fh $log_msg->{msg}, "\ngit-svn-id: ",
"$SVN_URL\@$log_msg->{revision}",
@@ -975,6 +990,29 @@ sub check_upgrade_needed {
}
}
+# fills %tree_map with a reverse mapping of trees to commits. Useful
+# for finding parents to commit on.
+sub map_tree_joins {
+ foreach my $br (@_branch_from) {
+ my $pid = open my $pipe, '-|';
+ defined $pid or croak $!;
+ if ($pid == 0) {
+ exec(qw(git-rev-list --pretty=raw), $br) or croak $?;
+ }
+ while (<$pipe>) {
+ if (/^commit ($sha1)$/o) {
+ my $commit = $1;
+ my ($tree) = (<$pipe> =~ /^tree ($sha1)$/o);
+ unless (defined $tree) {
+ die "Failed to parse commit $commit\n";
+ }
+ push @{$tree_map{$tree}}, $commit;
+ }
+ }
+ close $pipe or croak $?;
+ }
+}
+
__END__
Data structures:
diff --git a/contrib/git-svn/git-svn.txt b/contrib/git-svn/git-svn.txt
index 4102deb38..7306048bf 100644
--- a/contrib/git-svn/git-svn.txt
+++ b/contrib/git-svn/git-svn.txt
@@ -27,7 +27,7 @@ For importing svn, git-svnimport is potentially more powerful when
operating on repositories organized under the recommended
trunk/branch/tags structure, and should be faster, too.
-git-svn completely ignores the very limited view of branching that
+git-svn mostly ignores the very limited view of branching that
Subversion has. This allows git-svn to be much easier to use,
especially on repositories that are not organized in a manner that
git-svnimport is designed for.
@@ -116,6 +116,21 @@ OPTIONS
They are both passed directly to git-diff-tree see
git-diff-tree(1) for more information.
+-b<refname>::
+--branch <refname>::
+ Used with 'fetch' or 'commit'.
+
+ This can be used to join arbitrary git branches to remotes/git-svn
+ on new commits where the tree object is equivalent.
+
+ When used with different GIT_SVN_ID values, tags and branches in
+ SVN can be tracked this way, as can some merges where the heads
+ end up having completely equivalent content. This can even be
+ used to track branches across multiple SVN _repositories_.
+
+ This option may be specified multiple times, once for each
+ branch.
+
COMPATIBILITY OPTIONS
---------------------
--no-ignore-externals::