Skip to content

Commit 1fd81ef

Browse files
committed
Merge branch 'ew/svn'
* ew/svn: git-svn: allow dcommit to retain local merge information
2 parents 7425dcc + 733a65a commit 1fd81ef

File tree

2 files changed

+152
-9
lines changed

2 files changed

+152
-9
lines changed

git-svn.perl

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -374,16 +374,9 @@ sub cmd_dcommit {
374374
die "Unable to determine upstream SVN information from ",
375375
"$head history\n";
376376
}
377-
my $c = $refs[-1];
378377
my $last_rev;
379-
foreach my $d (@refs) {
380-
if (!verify_ref("$d~1")) {
381-
fatal "Commit $d\n",
382-
"has no parent commit, and therefore ",
383-
"nothing to diff against.\n",
384-
"You should be working from a repository ",
385-
"originally created by git-svn\n";
386-
}
378+
my ($linear_refs, $parents) = linearize_history($gs, \@refs);
379+
foreach my $d (@$linear_refs) {
387380
unless (defined $last_rev) {
388381
(undef, $last_rev, undef) = cmt_metadata("$d~1");
389382
unless (defined $last_rev) {
@@ -405,6 +398,9 @@ sub cmd_dcommit {
405398
svn_path => '');
406399
if (!SVN::Git::Editor->new(\%ed_opts)->apply_diff) {
407400
print "No changes\n$d~1 == $d\n";
401+
} elsif ($parents->{$d} && @{$parents->{$d}}) {
402+
$gs->{inject_parents_dcommit}->{$last_rev} =
403+
$parents->{$d};
408404
}
409405
}
410406
}
@@ -831,6 +827,59 @@ sub working_head_info {
831827
(undef, undef, undef, undef);
832828
}
833829

830+
sub read_commit_parents {
831+
my ($parents, $c) = @_;
832+
my ($fh, $ctx) = command_output_pipe(qw/cat-file commit/, $c);
833+
while (<$fh>) {
834+
chomp;
835+
last if '';
836+
/^parent ($sha1)/ or next;
837+
push @{$parents->{$c}}, $1;
838+
}
839+
close $fh; # break the pipe
840+
}
841+
842+
sub linearize_history {
843+
my ($gs, $refs) = @_;
844+
my %parents;
845+
foreach my $c (@$refs) {
846+
read_commit_parents(\%parents, $c);
847+
}
848+
849+
my @linear_refs;
850+
my %skip = ();
851+
my $last_svn_commit = $gs->last_commit;
852+
foreach my $c (reverse @$refs) {
853+
next if $c eq $last_svn_commit;
854+
last if $skip{$c};
855+
856+
unshift @linear_refs, $c;
857+
$skip{$c} = 1;
858+
859+
# we only want the first parent to diff against for linear
860+
# history, we save the rest to inject when we finalize the
861+
# svn commit
862+
my $fp_a = verify_ref("$c~1");
863+
my $fp_b = shift @{$parents{$c}} if $parents{$c};
864+
if (!$fp_a || !$fp_b) {
865+
die "Commit $c\n",
866+
"has no parent commit, and therefore ",
867+
"nothing to diff against.\n",
868+
"You should be working from a repository ",
869+
"originally created by git-svn\n";
870+
}
871+
if ($fp_a ne $fp_b) {
872+
die "$c~1 = $fp_a, however parsing commit $c ",
873+
"revealed that:\n$c~1 = $fp_b\nBUG!\n";
874+
}
875+
876+
foreach my $p (@{$parents{$c}}) {
877+
$skip{$p} = 1;
878+
}
879+
}
880+
(\@linear_refs, \%parents);
881+
}
882+
834883
package Git::SVN;
835884
use strict;
836885
use warnings;
@@ -1551,6 +1600,11 @@ sub get_commit_parents {
15511600
if (my $cur = ::verify_ref($self->refname.'^0')) {
15521601
push @tmp, $cur;
15531602
}
1603+
if (my $ipd = $self->{inject_parents_dcommit}) {
1604+
if (my $commit = delete $ipd->{$log_entry->{revision}}) {
1605+
push @tmp, @$commit;
1606+
}
1607+
}
15541608
push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
15551609
while (my $p = shift @tmp) {
15561610
next if $seen{$p};

t/t9114-git-svn-dcommit-merge.sh

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2007 Eric Wong
4+
# Based on a script by Joakim Tjernlund <[email protected]>
5+
6+
test_description='git-svn dcommit handles merges'
7+
8+
. ./lib-git-svn.sh
9+
10+
big_text_block () {
11+
cat << EOF
12+
#
13+
# (C) Copyright 2000 - 2005
14+
# Wolfgang Denk, DENX Software Engineering, [email protected].
15+
#
16+
# See file CREDITS for list of people who contributed to this
17+
# project.
18+
#
19+
# This program is free software; you can redistribute it and/or
20+
# modify it under the terms of the GNU General Public License as
21+
# published by the Free Software Foundation; either version 2 of
22+
# the License, or (at your option) any later version.
23+
#
24+
# This program is distributed in the hope that it will be useful,
25+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
26+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+
# GNU General Public License for more details.
28+
#
29+
# You should have received a copy of the GNU General Public License
30+
# along with this program; if not, write to the Free Software
31+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32+
# MA 02111-1307 USA
33+
#
34+
EOF
35+
}
36+
37+
test_expect_success 'setup svn repository' "
38+
svn co $svnrepo mysvnwork &&
39+
mkdir -p mysvnwork/trunk &&
40+
cd mysvnwork &&
41+
big_text_block >> trunk/README &&
42+
svn add trunk &&
43+
svn ci -m 'first commit' trunk &&
44+
cd ..
45+
"
46+
47+
test_expect_success 'setup git mirror and merge' "
48+
git svn init $svnrepo -t tags -T trunk -b branches &&
49+
git svn fetch &&
50+
git checkout --track -b svn remotes/trunk &&
51+
git checkout -b merge &&
52+
echo new file > new_file &&
53+
git add new_file &&
54+
git commit -a -m 'New file' &&
55+
echo hello >> README &&
56+
git commit -a -m 'hello' &&
57+
echo add some stuff >> new_file &&
58+
git commit -a -m 'add some stuff' &&
59+
git checkout svn &&
60+
mv -f README tmp &&
61+
echo friend > README &&
62+
cat tmp >> README &&
63+
git commit -a -m 'friend' &&
64+
git pull . merge
65+
"
66+
67+
test_debug 'gitk --all & sleep 1'
68+
69+
test_expect_success 'verify pre-merge ancestry' "
70+
test x\`git rev-parse --verify refs/heads/svn^2\` = \
71+
x\`git rev-parse --verify refs/heads/merge\` &&
72+
git cat-file commit refs/heads/svn^ | grep '^friend$'
73+
"
74+
75+
test_expect_success 'git svn dcommit merges' "
76+
git svn dcommit
77+
"
78+
79+
test_debug 'gitk --all & sleep 1'
80+
81+
test_expect_success 'verify post-merge ancestry' "
82+
test x\`git rev-parse --verify refs/heads/svn\` = \
83+
x\`git rev-parse --verify refs/remotes/trunk \` &&
84+
test x\`git rev-parse --verify refs/heads/svn^2\` = \
85+
x\`git rev-parse --verify refs/heads/merge\` &&
86+
git cat-file commit refs/heads/svn^ | grep '^friend$'
87+
"
88+
89+
test_done

0 commit comments

Comments
 (0)