git-svn: convert SVN 1.5+ / svnmerge.py svn:mergeinfo props to parents
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@catalyst.net.nz> Acked-by: Eric Wong <normalperson@yhbt.net>
Sam Vilain committed
Oct 20, 2009 at 15:42 UTC
dff589ef949e97cbec5363b105ba27f6e85594fb
2 files changed
+114
git-svn.perl
+93
@@ -2918,6 +2918,93 @@ sub find_extra_svk_parents {
2918
}
2919
}
2920
2921
+# note: this function should only be called if the various dirprops
2922
+# have actually changed
2923
+sub find_extra_svn_parents {
2924
+ my ($self, $ed, $mergeinfo, $parents) = @_;
2925
+ # aha! svk:merge property changed...
2926
+
2927
+ # We first search for merged tips which are not in our
2928
+ # history. Then, we figure out which git revisions are in
2929
+ # that tip, but not this revision. If all of those revisions
2930
+ # are now marked as merge, we can add the tip as a parent.
2931
+ my @merges = split "\n", $mergeinfo;
2932
+ my @merge_tips;
2933
+ my @merged_commit_ranges;
2934
+ my $url = $self->rewrite_root || $self->{url};
2935
+ for my $merge ( @merges ) {
2936
+ my ($source, $revs) = split ":", $merge;
2937
+ my $path = $source;
2938
+ $path =~ s{^/}{};
2939
+ my $gs = Git::SVN->find_by_url($url.$source, $url, $path);
2940
+ if ( !$gs ) {
2941
+ warn "Couldn't find revmap for $url$source\n";
2942
+ next;
2943
+ }
2944
+ my @ranges = split ",", $revs;
2945
+ my ($tip, $tip_commit);
2946
+ # find the tip
2947
+ for my $range ( @ranges ) {
2948
+ my ($bottom, $top) = split "-", $range;
2949
+ $top ||= $bottom;
2950
+ my $bottom_commit =
2951
+ $gs->rev_map_get($bottom, $self->ra_uuid) ||
2952
+ $gs->rev_map_get($bottom+1, $self->ra_uuid);
2953
+ my $top_commit =
2954
+ $gs->rev_map_get($top, $self->ra_uuid);
2955
+
2956
+ unless ($top_commit and $bottom_commit) {
2957
+ warn "W:unknown path/rev in svn:mergeinfo "
2958
+ ."dirprop: $source:$range\n";
2959
+ next;
2960
+ }
2961
+
2962
+ push @merged_commit_ranges,
2963
+ "$bottom_commit..$top_commit";
2964
+
2965
+ if ( !defined $tip or $top > $tip ) {
2966
+ $tip = $top;
2967
+ $tip_commit = $top_commit;
2968
+ }
2969
+ }
2970
+ unless (!$tip_commit or
2971
+ grep { $_ eq $tip_commit } @$parents ) {
2972
+ push @merge_tips, $tip_commit;
2973
+ } else {
2974
+ push @merge_tips, undef;
2975
+ }
2976
+ }
2977
+ for my $merge_tip ( @merge_tips ) {
2978
+ my $spec = shift @merges;
2979
+ next unless $merge_tip;
2980
+ my @cmd = ('rev-list', "-1", $merge_tip,
2981
+ "--not", @$parents );
2982
+ my ($msg_fh, $ctx) = command_output_pipe(@cmd);
2983
+ my $new;
2984
+ while ( <$msg_fh> ) {
2985
+ $new=1;last;
2986
+ }
2987
+ command_close_pipe($msg_fh, $ctx);
2988
+ if ( $new ) {
2989
+ push @cmd, @merged_commit_ranges;
2990
+ my ($msg_fh, $ctx) = command_output_pipe(@cmd);
2991
+ my $unmerged;
2992
+ while ( <$msg_fh> ) {
2993
+ $unmerged=1;last;
2994
+ }
2995
+ command_close_pipe($msg_fh, $ctx);
2996
+ if ( $unmerged ) {
2997
+ warn "W:svn cherry-pick ignored ($spec)\n";
2998
+ } else {
2999
+ warn
3000
+ "Found merge parent (svn:mergeinfo prop): ",
3001
+ $merge_tip, "\n";
3002
+ push @$parents, $merge_tip;
3003
+ }
3004
+ }
3005
+ }
3006
+}
3007
+
3008
sub make_log_entry {
3009
my ($self, $rev, $parents, $ed) = @_;
3010
my $untracked = $self->get_untracked($ed);
@@ -2930,6 +3017,12 @@ sub make_log_entry {
3017
$self->find_extra_svk_parents
3018
($ed, $props->{"svk:merge"}, \@parents);
3019
}
3020
+ if ( $props->{"svn:mergeinfo"} ) {
3021
+ $self->find_extra_svn_parents
3022
+ ($ed,
3023
+ $props->{"svn:mergeinfo"},
3024
+ \@parents);
3025
+ }
3026
}
3027
3028
open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;
t/t9151-svn-mergeinfo.sh
new
+21
@@ -0,0 +1,21 @@
1
+#!/bin/sh
2
+#
3
+# Copyright (c) 2007, 2009 Sam Vilain
4
+#
5
+
6
+test_description='git-svn svn mergeinfo properties'
7
+
8
+. ./lib-git-svn.sh
9
+
10
+test_expect_success 'load svn dump' "
11
+ svnadmin load -q '$rawsvnrepo' < '../t9151/svn-mergeinfo.dump' &&
12
+ git svn init --minimize-url -R svnmerge \
13
+ -T trunk -b branches '$svnrepo' &&
14
+ git svn fetch --all
15
+ "
16
+
17
+test_expect_success 'svn merges were represented coming in' "
18
+ [ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
19
+ "
20
+
21
+test_done