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 <sam@vilain.net> Acked-by: Eric Wong <normalperson@yhbt.net>
Sam Vilain committed
Dec 20, 2009 at 05:25 UTC
ea020cbd6aeb769d95e5c2dbffee4c81d6f92796
1 file changed
+48
-4
git-svn.perl
+48
-4
@@ -3038,6 +3038,41 @@ BEGIN {
3038
memoize 'lookup_svn_merge';
3039
}
3040
3041
+sub parents_exclude {
3042
+ my $parents = shift;
3043
+ my @commits = @_;
3044
+ return unless @commits;
3045
+
3046
+ my @excluded;
3047
+ my $excluded;
3048
+ do {
3049
+ my @cmd = ('rev-list', "-1", @commits, "--not", @$parents );
3050
+ $excluded = command_oneline(@cmd);
3051
+ if ( $excluded ) {
3052
+ my @new;
3053
+ my $found;
3054
+ for my $commit ( @commits ) {
3055
+ if ( $commit eq $excluded ) {
3056
+ push @excluded, $commit;
3057
+ $found++;
3058
+ last;
3059
+ }
3060
+ else {
3061
+ push @new, $commit;
3062
+ }
3063
+ }
3064
+ die "saw commit '$excluded' in rev-list output, "
3065
+ ."but we didn't ask for that commit (wanted: @commits --not @$parents)"
3066
+ unless $found;
3067
+ @commits = @new;
3068
+ }
3069
+ }
3070
+ while ($excluded and @commits);
3071
+
3072
+ return @excluded;
3073
+}
3074
+
3075
+
3076
# note: this function should only be called if the various dirprops
3077
# have actually changed
3078
sub find_extra_svn_parents {
@@ -3050,23 +3085,32 @@ sub find_extra_svn_parents {
3085
# are now marked as merge, we can add the tip as a parent.
3086
my @merges = split "\n", $mergeinfo;
3087
my @merge_tips;
3053
- my @merged_commit_ranges;
3088
my $url = $self->rewrite_root || $self->{url};
3089
my $uuid = $self->ra_uuid;
3090
+ my %ranges;
3091
for my $merge ( @merges ) {
3092
my ($tip_commit, @ranges) =
3093
lookup_svn_merge( $uuid, $url, $merge );
3059
- push @merged_commit_ranges, @ranges;
3094
unless (!$tip_commit or
3095
grep { $_ eq $tip_commit } @$parents ) {
3096
push @merge_tips, $tip_commit;
3097
+ $ranges{$tip_commit} = \@ranges;
3098
} else {
3099
push @merge_tips, undef;
3100
}
3101
}
3102
+
3103
+ my %excluded = map { $_ => 1 }
3104
+ parents_exclude($parents, grep { defined } @merge_tips);
3105
+
3106
+ # check merge tips for new parents
3107
+ my @new_parents;
3108
for my $merge_tip ( @merge_tips ) {
3109
my $spec = shift @merges;
3069
- next unless $merge_tip;
3110
+ next unless $merge_tip and $excluded{$merge_tip};
3111
+
3112
+ my $ranges = $ranges{$merge_tip};
3113
+
3114
my @cmd = ('rev-list', "-1", $merge_tip,
3115
"--not", @$parents );
3116
my ($msg_fh, $ctx) = command_output_pipe(@cmd);
@@ -3076,7 +3120,7 @@ sub find_extra_svn_parents {
3120
}
3121
command_close_pipe($msg_fh, $ctx);
3122
if ( $new ) {
3079
- push @cmd, @merged_commit_ranges;
3123
+ push @cmd, @$ranges;
3124
my ($msg_fh, $ctx) = command_output_pipe(@cmd);
3125
my $unmerged;
3126
while ( <$msg_fh> ) {