Skip to content

Commit

Permalink
git-svn: Make following parents atomic
Browse files Browse the repository at this point in the history
find_parent_branch generates branch@rev type branches when one has to
look back through SVN history to properly get the history for a branch
copied from somewhere not already being tracked by git-svn.  If in the
process of fetching this history, git-svn is interrupted, then when one
fetches again, it will use whatever was last fetched as the parent
commit and fail to fetch any more history which it didn't get to before
being terminated.  This is especially troubling in that different
git-svn copies of the same SVN repository can end up with different
commit sha1s, incorrectly showing the history as divergent and
precluding easy collaboration using git push and fetch.

To fix this, when we initialise the Git::SVN object $gs to search for
and perhaps fetch history, we check if there are any commits in SVN in
the range between the current revision $gs is at, and the top revision
for which we were asked to fill history.  If there are commits we're
missing in that range, we continue the fetch from the current revision
to the top, properly getting all history before using it as the parent
for the branch we're trying to create.

Signed-off-by: Deskin Miller <deskinm@umich.edu>
Acked-by: Eric Wong <normalperson@yhbt.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Deskin Miller authored and Junio C Hamano committed Dec 9, 2008
1 parent 1c2ed59 commit 553589f
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
16 changes: 12 additions & 4 deletions git-svn.perl
Original file line number Diff line number Diff line change
Expand Up @@ -2318,12 +2318,20 @@ sub find_parent_branch {
$gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1);
}
my ($r0, $parent) = $gs->find_rev_before($r, 1);
if (!defined $r0 || !defined $parent) {
my ($base, $head) = parse_revision_argument(0, $r);
if ($base <= $r) {
{
my ($base, $head);
if (!defined $r0 || !defined $parent) {
($base, $head) = parse_revision_argument(0, $r);
} else {
if ($r0 < $r) {
$gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1,
0, 1, sub { $base = $_[1] - 1 });
}
}
if (defined $base && $base <= $r) {
$gs->fetch($base, $r);
}
($r0, $parent) = $gs->last_rev_commit;
($r0, $parent) = $gs->find_rev_before($r, 1);
}
if (defined $r0 && defined $parent) {
print STDERR "Found branch parent: ($self->{ref_id}) $parent\n";
Expand Down
42 changes: 42 additions & 0 deletions t/t9104-git-svn-follow-parent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,48 @@ test_expect_success "track initial change if it was only made to parent" '
"`git rev-parse r9270-d~1`"
'

test_expect_success "follow-parent is atomic" '
(
cd wc &&
svn up &&
svn mkdir stunk &&
echo "trunk stunk" > stunk/readme &&
svn add stunk/readme &&
svn ci -m "trunk stunk" &&
echo "stunk like junk" >> stunk/readme &&
svn ci -m "really stunk" &&
echo "stink stank stunk" >> stunk/readme &&
svn ci -m "even the grinch agrees"
) &&
svn copy -m "stunk flunked" "$svnrepo"/stunk "$svnrepo"/flunk &&
{ svn cp -m "early stunk flunked too" \
"$svnrepo"/stunk@17 "$svnrepo"/flunked ||
svn cp -m "early stunk flunked too" \
-r17 "$svnrepo"/stunk "$svnrepo"/flunked; } &&
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
git svn fetch -i stunk &&
git update-ref refs/remotes/flunk@18 refs/remotes/stunk~2 &&
git update-ref -d refs/remotes/stunk &&
git config --unset svn-remote.svn.fetch stunk &&
mkdir -p "$GIT_DIR"/svn/flunk@18 &&
rev_map=$(cd "$GIT_DIR"/svn/stunk && ls .rev_map*) &&
dd if="$GIT_DIR"/svn/stunk/$rev_map \
of="$GIT_DIR"/svn/flunk@18/$rev_map bs=24 count=1 &&
rm -rf "$GIT_DIR"/svn/stunk &&
git svn init --minimize-url -i flunk "$svnrepo"/flunk &&
git svn fetch -i flunk &&
git svn init --minimize-url -i stunk "$svnrepo"/stunk &&
git svn fetch -i stunk &&
git svn init --minimize-url -i flunked "$svnrepo"/flunked &&
git svn fetch -i flunked
test "`git rev-parse --verify refs/remotes/flunk@18`" \
= "`git rev-parse --verify refs/remotes/stunk`" &&
test "`git rev-parse --verify refs/remotes/flunk~1`" \
= "`git rev-parse --verify refs/remotes/stunk`" &&
test "`git rev-parse --verify refs/remotes/flunked~1`" \
= "`git rev-parse --verify refs/remotes/stunk~1`"
'

test_expect_success "track multi-parent paths" '
svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
git-svn multi-fetch &&
Expand Down

0 comments on commit 553589f

Please sign in to comment.