Skip to content

Commit

Permalink
contrib/git-svn: fix svn compat and fetch args
Browse files Browse the repository at this point in the history
'svn info' doesn't work with URLs in svn <= 1.1.  Now we
only run svn info in local directories.

As a side effect, this should also work better for 'init' off
directories that are no longer in the latest revision of the
repository.

svn checkout -r<revision> arguments are fixed.
Newer versions of svn (1.2.x) seem to need URL@REV as well as
-rREV to checkout a particular revision...

Add an example in the manpage of how to track directory that has
been moved since its initial revision.

A huge thanks to Yann Dirson for the bug reporting and testing
my original patch.  Thanks also to Junio C Hamano for suggesting
a safer way to use git-rev-parse.

Signed-off-by: Eric Wong <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
Eric Wong authored and Junio C Hamano committed Mar 9, 2006
1 parent d2c4af7 commit 1d52aba
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 20 deletions.
63 changes: 45 additions & 18 deletions contrib/git-svn/git-svn.perl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,
$_find_copies_harder, $_l, $_version, $_upgrade, $_authors);
my (@_branch_from, %tree_map, %users);
my $_svn_co_url_revs;

my %fc_opts = ( 'no-ignore-externals' => \$_no_ignore_ext,
'branch|b=s' => \@_branch_from,
Expand Down Expand Up @@ -77,7 +78,7 @@
version() if $_version;
usage(1) unless defined $cmd;
load_authors() if $_authors;
svn_check_ignore_externals();
svn_compat_check();
$cmd{$cmd}->[0]->(@ARGV);
exit 0;

Expand Down Expand Up @@ -162,7 +163,8 @@ sub rebuild {
croak "SVN repository location required: $url\n";
}
$SVN_URL ||= $url;
$SVN_UUID ||= setup_git_svn();
$SVN_UUID ||= $uuid;
setup_git_svn();
$latest = $rev;
}
assert_revision_eq_or_unknown($rev, $c);
Expand All @@ -171,9 +173,7 @@ sub rebuild {
}
close $rev_list or croak $?;
if (!chdir $SVN_WC) {
my @svn_co = ('svn','co',"-r$latest");
push @svn_co, '--ignore-externals' unless $_no_ignore_ext;
sys(@svn_co, $SVN_URL, $SVN_WC);
svn_cmd_checkout($SVN_URL, $latest, $SVN_WC);
chdir $SVN_WC or croak $!;
}

Expand Down Expand Up @@ -222,14 +222,14 @@ sub fetch {
my $base = shift @$svn_log or croak "No base revision!\n";
my $last_commit = undef;
unless (-d $SVN_WC) {
my @svn_co = ('svn','co',"-r$base->{revision}");
push @svn_co,'--ignore-externals' unless $_no_ignore_ext;
sys(@svn_co, $SVN_URL, $SVN_WC);
svn_cmd_checkout($SVN_URL,$base->{revision},$SVN_WC);
chdir $SVN_WC or croak $!;
read_uuid();
$last_commit = git_commit($base, @parents);
assert_svn_wc_clean($base->{revision}, $last_commit);
} else {
chdir $SVN_WC or croak $!;
read_uuid();
$last_commit = file_to_s("$REV_DIR/$base->{revision}");
}
my @svn_up = qw(svn up);
Expand Down Expand Up @@ -275,7 +275,9 @@ sub commit {

fetch();
chdir $SVN_WC or croak $!;
my $svn_current_rev = svn_info('.')->{'Last Changed Rev'};
my $info = svn_info('.');
read_uuid($info);
my $svn_current_rev = $info->{'Last Changed Rev'};
foreach my $c (@revs) {
my $mods = svn_checkout_tree($svn_current_rev, $c);
if (scalar @$mods == 0) {
Expand Down Expand Up @@ -314,6 +316,14 @@ sub show_ignore {

########################### utility functions #########################

sub read_uuid {
return if $SVN_UUID;
my $info = shift || svn_info('.');
$SVN_UUID = $info->{'Repository UUID'} or
croak "Repository UUID unreadable\n";
s_to_file($SVN_UUID,"$GIT_DIR/$GIT_SVN/info/uuid");
}

sub setup_git_svn {
defined $SVN_URL or croak "SVN repository location required\n";
unless (-d $GIT_DIR) {
Expand All @@ -323,14 +333,10 @@ sub setup_git_svn {
mkpath(["$GIT_DIR/$GIT_SVN/info"]);
mkpath([$REV_DIR]);
s_to_file($SVN_URL,"$GIT_DIR/$GIT_SVN/info/url");
$SVN_UUID = svn_info($SVN_URL)->{'Repository UUID'} or
croak "Repository UUID unreadable\n";
s_to_file($SVN_UUID,"$GIT_DIR/$GIT_SVN/info/uuid");

open my $fd, '>>', "$GIT_DIR/$GIT_SVN/info/exclude" or croak $!;
print $fd '.svn',"\n";
close $fd or croak $!;
return $SVN_UUID;
}

sub assert_svn_wc_clean {
Expand Down Expand Up @@ -860,7 +866,6 @@ sub git_commit {
my ($log_msg, @parents) = @_;
assert_revision_unknown($log_msg->{revision});
my $out_fh = IO::File->new_tmpfile or croak $!;
$SVN_UUID ||= svn_info('.')->{'Repository UUID'};

map_tree_joins() if (@_branch_from && !%tree_map);

Expand Down Expand Up @@ -922,7 +927,16 @@ sub git_commit {
}
my @update_ref = ('git-update-ref',"refs/remotes/$GIT_SVN",$commit);
if (my $primary_parent = shift @exec_parents) {
push @update_ref, $primary_parent;
$pid = fork;
defined $pid or croak $!;
if (!$pid) {
close STDERR;
close STDOUT;
exec 'git-rev-parse','--verify',
"refs/remotes/$GIT_SVN^0";
}
waitpid $pid, 0;
push @update_ref, $primary_parent unless $?;
}
sys(@update_ref);
sys('git-update-ref',"$GIT_SVN/revs/$log_msg->{revision}",$commit);
Expand Down Expand Up @@ -995,13 +1009,26 @@ sub safe_qx {
return wantarray ? @ret : join('',@ret);
}

sub svn_check_ignore_externals {
return if $_no_ignore_ext;
unless (grep /ignore-externals/,(safe_qx(qw(svn co -h)))) {
sub svn_compat_check {
my @co_help = safe_qx(qw(svn co -h));
unless (grep /ignore-externals/,@co_help) {
print STDERR "W: Installed svn version does not support ",
"--ignore-externals\n";
$_no_ignore_ext = 1;
}
if (grep /usage: checkout URL\[\@REV\]/,@co_help) {
$_svn_co_url_revs = 1;
}
}

# *sigh*, new versions of svn won't honor -r<rev> without URL@<rev>,
# (and they won't honor URL@<rev> without -r<rev>, too!)
sub svn_cmd_checkout {
my ($url, $rev, $dir) = @_;
my @cmd = ('svn','co', "-r$rev");
push @cmd, '--ignore-externals' unless $_no_ignore_ext;
$url .= "\@$rev" if $_svn_co_url_revs;
sys(@cmd, $url, $dir);
}

sub check_upgrade_needed {
Expand Down
32 changes: 30 additions & 2 deletions contrib/git-svn/git-svn.txt
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ COMPATIBILITY OPTIONS
Do not use this flag unless you know exactly what you're getting
yourself into. You have been warned.

Examples
~~~~~~~~
Basic Examples
~~~~~~~~~~~~~~

Tracking and contributing to an Subversion managed-project:

Expand Down Expand Up @@ -234,6 +234,34 @@ This allows you to tie unfetched SVN revision 375 to your current HEAD::

git-svn fetch 375=$(git-rev-parse HEAD)

Advanced Example: Tracking a Reorganized Repository
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you're tracking a directory that has moved, or otherwise been
branched or tagged off of another directory in the repository and you
care about the full history of the project, then you can read this
section.

This is how Yann Dirson tracked the trunk of the ufoai directory when
the /trunk directory of his repository was moved to /ufoai/trunk and
he needed to continue tracking /ufoai/trunk where /trunk left off.

# This log message shows when the repository was reorganized::
r166 | ydirson | 2006-03-02 01:36:55 +0100 (Thu, 02 Mar 2006) | 1 line
Changed paths:
D /trunk
A /ufoai/trunk (from /trunk:165)

# First we start tracking the old revisions::
GIT_SVN_ID=git-oldsvn git-svn init \
https://svn.sourceforge.net/svnroot/ufoai/trunk
GIT_SVN_ID=git-oldsvn git-svn fetch -r1:165

# And now, we continue tracking the new revisions::
GIT_SVN_ID=git-newsvn git-svn init \
https://svn.sourceforge.net/svnroot/ufoai/ufoai/trunk
GIT_SVN_ID=git-newsvn git-svn fetch \
166=`git-rev-parse refs/remotes/git-oldsvn`

BUGS
----
If somebody commits a conflicting changeset to SVN at a bad moment
Expand Down

0 comments on commit 1d52aba

Please sign in to comment.