aboutsummaryrefslogtreecommitdiff
path: root/git-svn.perl
diff options
context:
space:
mode:
Diffstat (limited to 'git-svn.perl')
-rwxr-xr-xgit-svn.perl147
1 files changed, 57 insertions, 90 deletions
diff --git a/git-svn.perl b/git-svn.perl
index 828b8f0c8..6c7bd9503 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -29,7 +29,16 @@ use Git::SVN::Prompt;
use Git::SVN::Log;
use Git::SVN::Migration;
-use Git::SVN::Utils qw(fatal can_compress);
+use Git::SVN::Utils qw(
+ fatal
+ can_compress
+ canonicalize_path
+ canonicalize_url
+ join_paths
+ add_path_to_url
+ join_paths
+);
+
use Git qw(
git_cmd_try
command
@@ -52,8 +61,6 @@ my $cmd_dir_prefix = eval {
command_oneline([qw/rev-parse --show-prefix/], STDERR => 0)
} || '';
-my $git_dir_user_set = 1 if defined $ENV{GIT_DIR};
-$ENV{GIT_DIR} ||= '.git';
$Git::SVN::Ra::_log_window_size = 100;
if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) {
@@ -105,6 +112,7 @@ my ($_stdin, $_help, $_edit,
$_message, $_file, $_branch_dest,
$_template, $_shared,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
+ $_before, $_after,
$_merge, $_strategy, $_preserve_merges, $_dry_run, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
$_commit_url, $_tag, $_merge_info, $_interactive);
@@ -249,7 +257,8 @@ my %cmd = (
} ],
'find-rev' => [ \&cmd_find_rev,
"Translate between SVN revision numbers and tree-ish",
- {} ],
+ { 'before' => \$_before,
+ 'after' => \$_after } ],
'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
{ 'merge|m|M' => \$_merge,
'verbose|v' => \$_verbose,
@@ -316,27 +325,20 @@ for (my $i = 0; $i < @ARGV; $i++) {
};
# make sure we're always running at the top-level working directory
-unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
- unless (-d $ENV{GIT_DIR}) {
- if ($git_dir_user_set) {
- die "GIT_DIR=$ENV{GIT_DIR} explicitly set, ",
- "but it is not a directory\n";
- }
- my $git_dir = delete $ENV{GIT_DIR};
- my $cdup = undef;
- git_cmd_try {
- $cdup = command_oneline(qw/rev-parse --show-cdup/);
- $git_dir = '.' unless ($cdup);
- chomp $cdup if ($cdup);
- $cdup = "." unless ($cdup && length $cdup);
- } "Already at toplevel, but $git_dir not found\n";
- chdir $cdup or die "Unable to chdir up to '$cdup'\n";
- unless (-d $git_dir) {
- die "$git_dir still not found after going to ",
- "'$cdup'\n";
- }
- $ENV{GIT_DIR} = $git_dir;
- }
+if ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {
+ $ENV{GIT_DIR} ||= ".git";
+} else {
+ my ($git_dir, $cdup);
+ git_cmd_try {
+ $git_dir = command_oneline([qw/rev-parse --git-dir/]);
+ } "Unable to find .git directory\n";
+ git_cmd_try {
+ $cdup = command_oneline(qw/rev-parse --show-cdup/);
+ chomp $cdup if ($cdup);
+ $cdup = "." unless ($cdup && length $cdup);
+ } "Already at toplevel, but $git_dir not found\n";
+ $ENV{GIT_DIR} = $git_dir;
+ chdir $cdup or die "Unable to chdir up to '$cdup'\n";
$_repository = Git->repository(Repository => $ENV{GIT_DIR});
}
@@ -380,7 +382,7 @@ sub usage {
my $fd = $exit ? \*STDERR : \*STDOUT;
print $fd <<"";
git-svn - bidirectional operations between a single Subversion tree and git
-Usage: git svn <command> [options] [arguments]\n
+usage: git svn <command> [options] [arguments]\n
print $fd "Available commands:\n" unless $cmd;
@@ -532,7 +534,7 @@ sub cmd_fetch {
}
my ($remote) = @_;
if (@_ > 1) {
- die "Usage: $0 fetch [--all] [--parent] [svn-remote]\n";
+ die "usage: $0 fetch [--all] [--parent] [svn-remote]\n";
}
$Git::SVN::no_reuse_existing = undef;
if ($_fetch_parent) {
@@ -1182,7 +1184,13 @@ sub cmd_find_rev {
"$head history\n";
}
my $desired_revision = substr($revision_or_hash, 1);
- $result = $gs->rev_map_get($desired_revision, $uuid);
+ if ($_before) {
+ $result = $gs->find_rev_before($desired_revision, 1);
+ } elsif ($_after) {
+ $result = $gs->find_rev_after($desired_revision, 1);
+ } else {
+ $result = $gs->rev_map_get($desired_revision, $uuid);
+ }
} else {
my (undef, $rev, undef) = cmt_metadata($revision_or_hash);
$result = $rev;
@@ -1231,7 +1239,7 @@ sub cmd_show_ignore {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:ignore'} or return;
@@ -1247,7 +1255,7 @@ sub cmd_show_externals {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
my $s = $props->{'svn:externals'} or return;
@@ -1262,7 +1270,7 @@ sub cmd_create_ignore {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
- $gs->prop_walk($gs->{path}, $r, sub {
+ $gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
# $path is of the form /path/to/dir/
$path = '.' . $path;
@@ -1292,31 +1300,6 @@ sub cmd_mkdirs {
$gs->mkemptydirs($_revision);
}
-sub canonicalize_path {
- my ($path) = @_;
- my $dot_slash_added = 0;
- if (substr($path, 0, 1) ne "/") {
- $path = "./" . $path;
- $dot_slash_added = 1;
- }
- # File::Spec->canonpath doesn't collapse x/../y into y (for a
- # good reason), so let's do this manually.
- $path =~ s#/+#/#g;
- $path =~ s#/\.(?:/|$)#/#g;
- $path =~ s#/[^/]+/\.\.##g;
- $path =~ s#/$##g;
- $path =~ s#^\./## if $dot_slash_added;
- $path =~ s#^/##;
- $path =~ s#^\.$##;
- return $path;
-}
-
-sub canonicalize_url {
- my ($url) = @_;
- $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
- return $url;
-}
-
# get_svnprops(PATH)
# ------------------
# Helper for cmd_propget and cmd_proplist below.
@@ -1330,7 +1313,7 @@ sub get_svnprops {
$path = $cmd_dir_prefix . $path;
fatal("No such file or directory: $path") unless -e $path;
my $is_dir = -d $path ? 1 : 0;
- $path = $gs->{path} . '/' . $path;
+ $path = join_paths($gs->path, $path);
# canonicalize the path (otherwise libsvn will abort or fail to
# find the file)
@@ -1421,7 +1404,7 @@ sub cmd_multi_fetch {
# this command is special because it requires no metadata
sub cmd_commit_diff {
my ($ta, $tb, $url) = @_;
- my $usage = "Usage: $0 commit-diff -r<revision> ".
+ my $usage = "usage: $0 commit-diff -r<revision> ".
"<tree-ish> <tree-ish> [<URL>]";
fatal($usage) if (!defined $ta || !defined $tb);
my $svn_path = '';
@@ -1431,8 +1414,8 @@ sub cmd_commit_diff {
fatal("Needed URL or usable git-svn --id in ",
"the command-line\n", $usage);
}
- $url = $gs->{url};
- $svn_path = $gs->{path};
+ $url = $gs->url;
+ $svn_path = $gs->path;
}
unless (defined $_revision) {
fatal("-r|--revision is a required argument\n", $usage);
@@ -1466,24 +1449,6 @@ sub cmd_commit_diff {
}
}
-sub escape_uri_only {
- my ($uri) = @_;
- my @tmp;
- foreach (split m{/}, $uri) {
- s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
- push @tmp, $_;
- }
- join('/', @tmp);
-}
-
-sub escape_url {
- my ($url) = @_;
- if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
- my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
- $url = "$scheme://$domain$uri";
- }
- $url;
-}
sub cmd_info {
my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
@@ -1508,21 +1473,21 @@ sub cmd_info {
# canonicalize_path() will return "" to make libsvn 1.5.x happy,
$path = "." if $path eq "";
- my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath");
+ my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
if ($_url) {
- print escape_url($full_url), "\n";
+ print "$full_url\n";
return;
}
my $result = "Path: $path\n";
$result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
- $result .= "URL: " . escape_url($full_url) . "\n";
+ $result .= "URL: $full_url\n";
eval {
my $repos_root = $gs->repos_root;
Git::SVN::remove_username($repos_root);
- $result .= "Repository Root: " . escape_url($repos_root) . "\n";
+ $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n";
};
if ($@) {
$result .= "Repository Root: (offline)\n";
@@ -1669,7 +1634,9 @@ sub post_fetch_checkout {
sub complete_svn_url {
my ($url, $path) = @_;
- $path =~ s#/+$##;
+ $path = canonicalize_path($path);
+
+ # If the path is not a URL...
if ($path !~ m#^[a-z\+]+://#) {
if (!defined $url || $url !~ m#^[a-z\+]+://#) {
fatal("E: '$path' is not a complete URL ",
@@ -1686,7 +1653,7 @@ sub complete_url_ls_init {
print STDERR "W: $switch not specified\n";
return;
}
- $repo_path =~ s#/+$##;
+ $repo_path = canonicalize_path($repo_path);
if ($repo_path =~ m#^[a-z\+]+://#) {
$ra = Git::SVN::Ra->new($repo_path);
$repo_path = '';
@@ -1697,18 +1664,18 @@ sub complete_url_ls_init {
"and a separate URL is not specified");
}
}
- my $url = $ra->{url};
+ my $url = $ra->url;
my $gs = Git::SVN->init($url, undef, undef, undef, 1);
my $k = "svn-remote.$gs->{repo_id}.url";
my $orig_url = eval { command_oneline(qw/config --get/, $k) };
- if ($orig_url && ($orig_url ne $gs->{url})) {
+ if ($orig_url && ($orig_url ne $gs->url)) {
die "$k already set: $orig_url\n",
- "wanted to set to: $gs->{url}\n";
+ "wanted to set to: $gs->url\n";
}
- command_oneline('config', $k, $gs->{url}) unless $orig_url;
- my $remote_path = "$gs->{path}/$repo_path";
+ command_oneline('config', $k, $gs->url) unless $orig_url;
+
+ my $remote_path = join_paths( $gs->path, $repo_path );
$remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
- $remote_path =~ s#/+#/#g;
$remote_path =~ s#^/##g;
$remote_path .= "/*" if $remote_path !~ /\*/;
my ($n) = ($switch =~ /^--(\w+)/);