diff options
Diffstat (limited to 'git-svn.perl')
| -rwxr-xr-x | git-svn.perl | 149 | 
1 files changed, 146 insertions, 3 deletions
| diff --git a/git-svn.perl b/git-svn.perl index eb4b75aff3..6a3b501d24 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1765,7 +1765,7 @@ sub read_all_remotes {  	my $use_svm_props = eval { command_oneline(qw/config --bool  	    svn.useSvmProps/) };  	$use_svm_props = $use_svm_props eq 'true' if $use_svm_props; -	my $svn_refspec = qr{\s*/?(.*?)\s*:\s*(.+?)\s*}; +	my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*};  	foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {  		if (m!^(.+)\.fetch=$svn_refspec$!) {  			my ($remote, $local_ref, $remote_ref) = ($1, $2, $3); @@ -1979,7 +1979,7 @@ sub find_ref {  	my ($ref_id) = @_;  	foreach (command(qw/config -l/)) {  		next unless m!^svn-remote\.(.+)\.fetch= -		              \s*/?(.*?)\s*:\s*(.+?)\s*$!x; +		              \s*(.*?)\s*:\s*(.+?)\s*$!x;  		my ($repo_id, $path, $ref) = ($1, $2, $3);  		if ($ref eq $ref_id) {  			$path = '' if ($path =~ m#^\./?#); @@ -2878,14 +2878,157 @@ sub check_author {  	$author;  } +sub find_extra_svk_parents { +	my ($self, $ed, $tickets, $parents) = @_; +	# aha!  svk:merge property changed... +	my @tickets = split "\n", $tickets; +	my @known_parents; +	for my $ticket ( @tickets ) { +		my ($uuid, $path, $rev) = split /:/, $ticket; +		if ( $uuid eq $self->ra_uuid ) { +			my $url = $self->rewrite_root || $self->{url}; +			my $repos_root = $url; +			my $branch_from = $path; +			$branch_from =~ s{^/}{}; +			my $gs = $self->other_gs($repos_root."/".$branch_from, +			                         $url, +			                         $branch_from, +			                         $rev, +			                         $self->{ref_id}); +			if ( my $commit = $gs->rev_map_get($rev, $uuid) ) { +				# wahey!  we found it, but it might be +				# an old one (!) +				push @known_parents, $commit; +			} +		} +	} +	for my $parent ( @known_parents ) { +		my @cmd = ('rev-list', $parent, map { "^$_" } @$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 ) { +			print STDERR +			    "Found merge parent (svk:merge ticket): $parent\n"; +			push @$parents, $parent; +		} +	} +} + +# 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); +	my @parents = @$parents; +	my $ps = $ed->{path_strip} || ""; +	for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) { +		my $props = $ed->{dir_prop}{$path}; +		if ( $props->{"svk:merge"} ) { +			$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 $!;  	print $un "r$rev\n" or croak $!;  	print $un $_, "\n" foreach @$untracked; -	my %log_entry = ( parents => $parents || [], revision => $rev, +	my %log_entry = ( parents => \@parents, revision => $rev,  	                  log => '');  	my $headrev; | 
