Subject: [BRAINFART PATCH] git-svn: support SVN 1.5+ merge attributes

From: Sam Vilain <[email-masked]>
Date: Wed, 28 May 2008 21:00:59 +1200

Alexey,

I had a look at how svnmerge.py merge tickets / SVN 1.5+ merge tickets
might be supported in current git-svn.  I think something along these
lines might work, but it needs completion - much of the code there is
psuedocode.  It doesn't address the issue of pushing git-land merges
back to SVN, but I think this is also a sorely missing feature, as it
could mean people could start pushing their nice git merges back to
SVN.

Subject: [PATCH] git-svn: sketch out support for SVN 1.5+ merge properties

They may not exist in the wild much yet, but it is probably about time
git-svn supported SVN 1.5+ merge tickets.  Sketch out where they might
go, for discussion's sake only.

Signed-off-but-disowned-by: Sam Vilain <[email-masked]>
---
 git-svn.perl |   45 +++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/git-svn.perl b/git-svn.perl
index 37976f2..acd9784 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -1907,11 +1907,12 @@ sub prop_walk {
 	foreach (keys %{$props}) {
 		# If it doesn't start with `svn:', it must be a
 		# user-defined property.
-		++$interesting_props and next if $_ !~ /^svn:/;
+		++$interesting_props and next if $_ !~ /^(svn:|svk:merge)/;
 		# FIXME: Fragile, if SVN adds new public properties,
 		# this needs to be updated.
 		++$interesting_props if /^svn:(?:ignore|keywords|executable
 		                                 |eol-style|mime-type
+						 |mergeinfo
 						 |externals|needs-lock)$/x;
 	}
 	&$sub($self, $p, $props) if $interesting_props;
@@ -2353,7 +2354,9 @@ sub get_untracked {
 		foreach my $path (sort keys %$h) {
 			my $ppath = $path eq '' ? '.' : $path;
 			foreach my $prop (sort keys %{$h->{$path}}) {
-				next if $SKIP_PROP{$prop};
+				next if $SKIP_PROP{$prop}
+					or ($t eq "dir_prop" and !$path
+					    and $prop eq "svn:mergeinfo");
 				my $v = $h->{$path}->{$prop};
 				my $t_ppath_prop = "$t: " .
 				                    uri_encode($ppath) . ' ' .
@@ -2403,6 +2406,44 @@ sub make_log_entry {
 	my ($self, $rev, $parents, $ed) = @_;
 	my $untracked = $self->get_untracked($ed);
 
+	if ( my $mergeinfo = $ed->{dir_prop}{""}{"svn:mergeinfo"} ) {
+		my %mergeinfo = map { m{^([^:]*):\s*([\d,\-]+)} }
+			split "\n", $mergeinfo;
+
+		# check if any new line introduces a new complete merge
+		foreach my $path ( sort keys %mergeinfo ) {
+			my @merged = split ",", $mergeinfo{$path};
+
+			my @untracked;
+			for my $merge ( @merged ) {
+				my ($first, $last) = ($merge =~ m{\d+(-\d+)?$});
+				$last ||= $first;
+
+				# this function doesn't exist yet
+				my $svn_rev = $self->find_rev_on_path($path, $rev);
+				# it is a complete new cross-merge if;
+
+				#  a) the first revision specified is NOT in
+				#  the history of the commit we are making
+				my @commits = `git rev-list -1 $svn_rev --not @$parents`;
+				next if @commits;
+
+				#  b) the parents of that revision are also in
+				#  our history.
+				@commits = `git rev-list -1 $svn_rev^ --not @$parents`;
+				if ( @commits ) {
+					push @untracked, $merge;
+					next;
+				}
+
+				# ok - go ahead and make it a parent
+				push @$parents, $svn_rev;
+			}
+			push @$untracked, "svn:mergeinfo ticket for $path: "
+				.join(",", @untracked);
+		}
+	}
+
 	open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
 	print $un "r$rev\n" or croak $!;
 	print $un $_, "\n" foreach @$untracked;
-- 
1.5.4.rc2.85.g7c8f5