From ea020cbd6aeb769d95e5c2dbffee4c81d6f92796 Mon Sep 17 00:00:00 2001 From: Sam Vilain Date: Sun, 20 Dec 2009 05:25:31 +1300 Subject: git-svn: exclude already merged tips using one rev-list call The old function would have to check all mentioned merge tips, every time that the mergeinfo ticket changed. This involved 1-2 rev-list operation for each listed mergeinfo line. If there are a lot of feature branches being merged into a trunk, this makes for a very expensive operation for detecting the new parents on every merge. This new version first uses a single 'rev-list' to figure out which commit ranges are already reachable from the parents. This is used to eliminate the already merged branches from the list. Signed-off-by: Sam Vilain Acked-by: Eric Wong --- git-svn.perl | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'git-svn.perl') diff --git a/git-svn.perl b/git-svn.perl index a4a45ef398..07d40ba81f 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -3038,6 +3038,41 @@ BEGIN { memoize 'lookup_svn_merge'; } +sub parents_exclude { + my $parents = shift; + my @commits = @_; + return unless @commits; + + my @excluded; + my $excluded; + do { + my @cmd = ('rev-list', "-1", @commits, "--not", @$parents ); + $excluded = command_oneline(@cmd); + if ( $excluded ) { + my @new; + my $found; + for my $commit ( @commits ) { + if ( $commit eq $excluded ) { + push @excluded, $commit; + $found++; + last; + } + else { + push @new, $commit; + } + } + die "saw commit '$excluded' in rev-list output, " + ."but we didn't ask for that commit (wanted: @commits --not @$parents)" + unless $found; + @commits = @new; + } + } + while ($excluded and @commits); + + return @excluded; +} + + # note: this function should only be called if the various dirprops # have actually changed sub find_extra_svn_parents { @@ -3050,23 +3085,32 @@ sub find_extra_svn_parents { # 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}; my $uuid = $self->ra_uuid; + my %ranges; for my $merge ( @merges ) { my ($tip_commit, @ranges) = lookup_svn_merge( $uuid, $url, $merge ); - push @merged_commit_ranges, @ranges; unless (!$tip_commit or grep { $_ eq $tip_commit } @$parents ) { push @merge_tips, $tip_commit; + $ranges{$tip_commit} = \@ranges; } else { push @merge_tips, undef; } } + + my %excluded = map { $_ => 1 } + parents_exclude($parents, grep { defined } @merge_tips); + + # check merge tips for new parents + my @new_parents; for my $merge_tip ( @merge_tips ) { my $spec = shift @merges; - next unless $merge_tip; + next unless $merge_tip and $excluded{$merge_tip}; + + my $ranges = $ranges{$merge_tip}; + my @cmd = ('rev-list', "-1", $merge_tip, "--not", @$parents ); my ($msg_fh, $ctx) = command_output_pipe(@cmd); @@ -3076,7 +3120,7 @@ sub find_extra_svn_parents { } command_close_pipe($msg_fh, $ctx); if ( $new ) { - push @cmd, @merged_commit_ranges; + push @cmd, @$ranges; my ($msg_fh, $ctx) = command_output_pipe(@cmd); my $unmerged; while ( <$msg_fh> ) { -- cgit v1.2.1