[PATCH 5/5] git-svn: convert SVN 1.5+ / svnmerge.py svn:mergeinfo props to parents

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

 



This feature is long overdue; convert SVN's merge representation to git's
as revisions are imported.  This works by converting the list of revisions
in each line of the svn:mergeinfo into git revision ranges, and then
checking the latest of each of these revision ranges for A) being new and
B) now being completely merged.

Signed-off-by: Sam Vilain <sam.vilain@xxxxxxxxxxxxxxx>
---
   There's much more implemented here than is tested...
 git-svn.perl             |   93 ++++++++++++++++++++++++++++++++++++++++++++++
 t/t9151-svn-mergeinfo.sh |   21 ++++++++++
 2 files changed, 114 insertions(+), 0 deletions(-)
 create mode 100644 t/t9151-svn-mergeinfo.sh

diff --git a/git-svn.perl b/git-svn.perl
index 3c2534c..244e40d 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -2916,6 +2916,93 @@ sub find_extra_svk_parents {
 	}
 }
 
+# note: this function should only be called if the various dirprops
+# have actually changed
+sub find_extra_svn_parents {
+	my ($self, $ed, $mergeinfo, $parents) = @_;
+	# aha!  svk:merge property changed...
+
+	# We first search for merged tips which are not in our
+	# history.  Then, we figure out which git revisions are in
+	# that tip, but not this revision.  If all of those revisions
+	# are now marked as merge, we can add the tip as a parent.
+	my @merges = split "\n", $mergeinfo;
+	my @merge_tips;
+	my @merged_commit_ranges;
+	my $url = $self->rewrite_root || $self->{url};
+	for my $merge ( @merges ) {
+		my ($source, $revs) = split ":", $merge;
+		my $path = $source;
+		$path =~ s{^/}{};
+		my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
+		if ( !$gs ) {
+			warn "Couldn't find revmap for $url$source\n";
+			next;
+		}
+		my @ranges = split ",", $revs;
+		my ($tip, $tip_commit);
+		# find the tip
+		for my $range ( @ranges ) {
+			my ($bottom, $top) = split "-", $range;
+			$top ||= $bottom;
+			my $bottom_commit =
+				$gs->rev_map_get($bottom, $self->ra_uuid) ||
+				$gs->rev_map_get($bottom+1, $self->ra_uuid);
+			my $top_commit =
+				$gs->rev_map_get($top, $self->ra_uuid);
+
+			unless ($top_commit and $bottom_commit) {
+				warn "W:unknown path/rev in svn:mergeinfo "
+					."dirprop: $source:$range\n";
+				next;
+			}
+
+			push @merged_commit_ranges,
+				"$bottom_commit..$top_commit";
+
+			if ( !defined $tip or $top > $tip ) {
+				$tip = $top;
+				$tip_commit = $top_commit;
+			}
+		}
+		unless (!$tip_commit or
+				grep { $_ eq $tip_commit } @$parents ) {
+			push @merge_tips, $tip_commit;
+		}
+		else {
+			push @merge_tips, undef;
+		}
+	}
+	for my $merge_tip ( @merge_tips ) {
+		my $spec = shift @merges;
+		next unless $merge_tip;
+		my @cmd = ('rev-list', "-1", $merge_tip,
+			   "--not", @$parents );
+		my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+		my $new;
+		while ( <$msg_fh> ) {
+			$new=1;last;
+		}
+		command_close_pipe($msg_fh, $ctx);
+		if ( $new ) {
+			push @cmd, @merged_commit_ranges;
+			my ($msg_fh, $ctx) = command_output_pipe(@cmd);
+			my $unmerged;
+			while ( <$msg_fh> ) {
+				$unmerged=1;last;
+			}
+			command_close_pipe($msg_fh, $ctx);
+			if ( $unmerged ) {
+				warn "W:svn cherry-pick ignored ($spec)\n";
+			}
+			else {
+				warn "Found merge parent (svn:mergeinfo prop): $merge_tip\n";
+				push @$parents, $merge_tip;
+			}
+		}
+	}
+}
+
 sub make_log_entry {
 	my ($self, $rev, $parents, $ed) = @_;
 	my $untracked = $self->get_untracked($ed);
@@ -2928,6 +3015,12 @@ sub make_log_entry {
 			$self->find_extra_svk_parents
 				($ed, $props->{"svk:merge"}, \@parents);
 		}
+		if ( $props->{"svn:mergeinfo"} ) {
+			$self->find_extra_svn_parents
+				($ed,
+				 $props->{"svn:mergeinfo"},
+				 \@parents);
+		}
 	}
 
 	open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
diff --git a/t/t9151-svn-mergeinfo.sh b/t/t9151-svn-mergeinfo.sh
new file mode 100644
index 0000000..7eb36e5
--- /dev/null
+++ b/t/t9151-svn-mergeinfo.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+#
+# Copyright (c) 2007, 2009 Sam Vilain
+#
+
+test_description='git-svn svn mergeinfo properties'
+
+. ./lib-git-svn.sh
+
+test_expect_success 'load svn dump' "
+	svnadmin load -q '$rawsvnrepo' < '../t9151/svn-mergeinfo.dump' &&
+	git svn init --minimize-url -R svnmerge \
+	  -T trunk -b branches '$svnrepo' &&
+	git svn fetch --all
+	"
+
+test_expect_success 'svn merges were represented coming in' "
+	[ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
+	"
+
+test_done
-- 
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]