Skip to content

Commit dff589e

Browse files
Sam VilainEric Wong
authored andcommitted
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>
1 parent ce62683 commit dff589e

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

git-svn.perl

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,93 @@ sub find_extra_svk_parents {
29182918
}
29192919
}
29202920

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+
29213008
sub make_log_entry {
29223009
my ($self, $rev, $parents, $ed) = @_;
29233010
my $untracked = $self->get_untracked($ed);
@@ -2930,6 +3017,12 @@ sub make_log_entry {
29303017
$self->find_extra_svk_parents
29313018
($ed, $props->{"svk:merge"}, \@parents);
29323019
}
3020+
if ( $props->{"svn:mergeinfo"} ) {
3021+
$self->find_extra_svn_parents
3022+
($ed,
3023+
$props->{"svn:mergeinfo"},
3024+
\@parents);
3025+
}
29333026
}
29343027

29353028
open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!;

t/t9151-svn-mergeinfo.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)