Skip to content

Instantly share code, notes, and snippets.

@bsuh
Last active March 29, 2016 16:28
Show Gist options
  • Save bsuh/c358ccd9da982a30a966 to your computer and use it in GitHub Desktop.
Save bsuh/c358ccd9da982a30a966 to your computer and use it in GitHub Desktop.
diff --git a/git-svn.perl b/git-svn.perl
index 05eced0..6127314 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -703,17 +703,19 @@ sub merge_merge_info {
}
sub populate_merge_info {
- my ($d, $gs, $uuid, $linear_refs, $rewritten_parent) = @_;
+ my ($d, $gs, $uuid, $linear_refs, $rewritten_parent, $merge_info_path) = @_;
my %parentshash;
read_commit_parents(\%parentshash, $d);
my @parents = @{$parentshash{$d}};
+
+ my $rooturl = $gs->repos_root;
+ my ($target_branch) = $gs->full_pushurl =~ /^\Q$rooturl\E(.*)/;
+
if ($#parents > 0) {
# Merge commit
my $all_parents_ok = 1;
my $aggregate_mergeinfo = '';
- my $rooturl = $gs->repos_root;
- my ($target_branch) = $gs->full_pushurl =~ /^\Q$rooturl\E(.*)/;
if (defined($rewritten_parent)) {
# Replace first parent with newly-rewritten version
@@ -737,7 +739,7 @@ sub populate_merge_info {
my $ra = Git::SVN::Ra->new($branchurl);
my (undef, undef, $props) =
- $ra->get_dir(canonicalize_path("."), $svnrev);
+ $ra->get_dir(canonicalize_path($merge_info_path), $svnrev);
my $par_mergeinfo = $props->{'svn:mergeinfo'};
unless (defined $par_mergeinfo) {
$par_mergeinfo = '';
@@ -786,7 +788,8 @@ sub populate_merge_info {
# We now have a list of all SVN revnos which are
# merged by this particular parent. Integrate them.
next if $#revsin == -1;
- my $newmergeinfo = "$branchpath:" . join(',', @revsin);
+ my $newmergeinfo = canonicalize_path("$branchpath/$merge_info_path")
+ . ":" . join(',', @revsin);
$aggregate_mergeinfo =
merge_merge_info($aggregate_mergeinfo,
$newmergeinfo,
@@ -795,6 +798,52 @@ sub populate_merge_info {
if ($all_parents_ok and $aggregate_mergeinfo) {
return $aggregate_mergeinfo;
}
+ } elsif ($#parents == 0) {
+ # cherry-pick merge
+ my ($cherry_branchurl, $cherry_svnrev, $cherry_paruuid) =
+ cmt_metadata($d);
+
+ if(defined $cherry_branchurl && defined $cherry_svnrev && defined $cherry_paruuid)
+ {
+ if (defined($rewritten_parent)) {
+ # Replace first parent with newly-rewritten version
+ shift @parents;
+ unshift @parents, $rewritten_parent;
+ }
+
+ my $aggregate_mergeinfo = '';
+
+ # parent mergeinfo
+ my ($branchurl, $svnrev, $paruuid) =
+ cmt_metadata($parents[0]);
+
+ my $ra = Git::SVN::Ra->new($branchurl);
+ my (undef, undef, $props) =
+ $ra->get_dir(canonicalize_path($merge_info_path), $svnrev);
+ my $parent_mergeinfo = $props->{'svn:mergeinfo'};
+ unless (defined $parent_mergeinfo) {
+ $parent_mergeinfo = '';
+ }
+
+ $aggregate_mergeinfo = merge_merge_info($aggregate_mergeinfo,
+ $parent_mergeinfo,
+ $target_branch);
+
+ # cherry-pick mergeinfo
+ unless ($cherry_branchurl =~ /^\Q$rooturl\E(.*)/) {
+ fatal "commit $d git-svn metadata changed mid-run!";
+ }
+ my $cherry_branchpath = $1;
+
+ my $cherry_pick_mergeinfo = canonicalize_path("$cherry_branchpath/$merge_info_path")
+ . ":$cherry_svnrev";
+
+ $aggregate_mergeinfo = merge_merge_info($aggregate_mergeinfo,
+ $cherry_pick_mergeinfo,
+ $target_branch);
+
+ return $aggregate_mergeinfo;
+ }
}
return undef;
@@ -970,6 +1019,12 @@ sub cmd_dcommit {
if (defined($_merge_info)) {
$_merge_info =~ tr{ }{\n};
}
+ my $merge_info_path = eval {
+ command_oneline(qw/config --get svn.mergeinfopath/)
+ };
+ if (not defined($merge_info_path)) {
+ $merge_info_path = "";
+ }
while (1) {
my $d = shift @$linear_refs or last;
unless (defined $last_rev) {
@@ -984,11 +1039,16 @@ sub cmd_dcommit {
} else {
my $cmt_rev;
- unless (defined($_merge_info) || ! $push_merge_info) {
- $_merge_info = populate_merge_info($d, $gs,
+ my $rev_merge_info;
+ if (defined($_merge_info)) {
+ $rev_merge_info = $_merge_info;
+ }
+ unless (defined($rev_merge_info) || ! $push_merge_info) {
+ $rev_merge_info = populate_merge_info($d, $gs,
$uuid,
$linear_refs,
- $rewritten_parent);
+ $rewritten_parent,
+ $merge_info_path);
}
my %ed_opts = ( r => $last_rev,
@@ -1003,7 +1063,8 @@ sub cmd_dcommit {
print "Committed r$_[0]\n";
$cmt_rev = $_[0];
},
- mergeinfo => $_merge_info,
+ mergeinfo => $rev_merge_info,
+ mergeinfopath => $merge_info_path,
svn_path => '');
my $err_handler = $SVN::Error::handler;
diff --git a/perl/Git/SVN/Editor.pm b/perl/Git/SVN/Editor.pm
index 4c4199a..8f8e5e4 100644
--- a/perl/Git/SVN/Editor.pm
+++ b/perl/Git/SVN/Editor.pm
@@ -41,6 +41,7 @@ sub new {
"$self->{svn_path}/" : '';
$self->{config} = $opts->{config};
$self->{mergeinfo} = $opts->{mergeinfo};
+ $self->{mergeinfopath} = $opts->{mergeinfopath};
$self->{pathnameencoding} = Git::config('svn.pathnameencoding');
return $self;
}
@@ -529,7 +530,9 @@ sub apply_diff {
}
if (defined($self->{mergeinfo})) {
- $self->change_dir_prop($self->{bat}{''}, "svn:mergeinfo",
+ my $pbat = $self->ensure_path($self->{mergeinfopath}, \%deletions);
+ $self->change_dir_prop($pbat,
+ "svn:mergeinfo",
$self->{mergeinfo});
}
$self->rmdirs if $_rmdir;
diff --git a/t/t9161-git-svn-mergeinfo-push.sh b/t/t9161-git-svn-mergeinfo-push.sh
index f113aca..38b4595 100755
--- a/t/t9161-git-svn-mergeinfo-push.sh
+++ b/t/t9161-git-svn-mergeinfo-push.sh
@@ -91,6 +91,73 @@ test_expect_success 'check reintegration mergeinfo' '
/branches/svnb5:6,11"
'
+test_expect_success 'make further commits to branch' '
+ git checkout svnb2 &&
+ touch newb2file-3 &&
+ git add newb2file-3 &&
+ git commit -m "later b2 commit 3" &&
+ touch newb2file-4 &&
+ git add newb2file-4 &&
+ git commit -m "later b2 commit 4" &&
+ touch newb2file-5 &&
+ git add newb2file-5 &&
+ git commit -m "later b2 commit 5" &&
+ git svn dcommit
+ '
+
+test_expect_success 'cherry-pick merge' '
+ git checkout svnb1 &&
+ git cherry-pick svnb2 &&
+ git cherry-pick svnb2^ &&
+ git cherry-pick svnb2^^ &&
+ git svn dcommit
+ '
+
+test_expect_success 'check cherry-pick mergeinfo' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8,16-17,20-22
+/branches/svnb3:4,9
+/branches/svnb4:5-6,10-12
+/branches/svnb5:6,11"
+ '
+
+test_expect_success 'make further commits to branch' '
+ git checkout svnb1 &&
+ mkdir sub_directory &&
+ touch sub_directory/newb1file &&
+ git add sub_directory/newb1file &&
+ git commit -m "sub directory b1 commit" &&
+ git svn dcommit &&
+ git checkout svnb2 &&
+ mkdir sub_directory &&
+ touch sub_directory/newb2file &&
+ git add sub_directory/newb2file &&
+ git commit -m "sub directory b2 commit" &&
+ touch sub_directory/newb2file2 &&
+ git add sub_directory/newb2file2 &&
+ git commit -m "sub directory b2 commit 2" &&
+ git svn dcommit
+ '
+
+test_expect_success 'cherry-pick mergeinfo sub directory' '
+ git config svn.mergeinfopath sub_directory &&
+ git checkout svnb1 &&
+ git cherry-pick svnb2 &&
+ git cherry-pick svnb2^ &&
+ git svn dcommit &&
+ git config --unset svn.mergeinfopath
+ '
+
+test_expect_success 'check cherry-pick mergeinfo sub directory' '
+ mergeinfo=$(svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1)
+ test "$mergeinfo" = "/branches/svnb2:3,8,16-17,20-22
+/branches/svnb3:4,9
+/branches/svnb4:5-6,10-12
+/branches/svnb5:6,11" &&
+ mergeinfo=$(cd sub_directory && svn_cmd propget svn:mergeinfo "$svnrepo"/branches/svnb1/sub_directory) &&
+ test "$mergeinfo" = "/branches/svnb2/sub_directory:27-28"
+ '
+
test_expect_success 'dcommit a merge at the top of a stack' '
git checkout origin/svnb1 &&
touch anotherfile &&
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment