提交 4f2b15ce 编写于 作者: J Junio C Hamano

Merge git://git.bogomips.org/git-svn

* git://git.bogomips.org/git-svn:
  git svn: Doc update for multiple branch and tag paths
  git svn: cleanup t9138-multiple-branches
  git-svn: Canonicalize svn urls to prevent libsvn assertion
  t9138: remove stray dot in test which broke bash
  git-svn: convert globs to regexps for branch destinations
  git svn: Support multiple branch and tag paths in the svn repository.
  Add 'git svn reset' to unwind 'git svn fetch'
  git-svn: speed up find_rev_before
  Add 'git svn help [cmd]' which works outside a repo.
  git-svn: let 'dcommit $rev' work on $rev instead of HEAD
......@@ -3,7 +3,7 @@ git-svn(1)
NAME
----
git-svn - Bidirectional operation between a single Subversion branch and git
git-svn - Bidirectional operation between a Subversion repository and git
SYNOPSIS
--------
......@@ -15,13 +15,12 @@ DESCRIPTION
It provides a bidirectional flow of changes between a Subversion and a git
repository.
'git-svn' can track a single Subversion branch simply by using a
URL to the branch, follow branches laid out in the Subversion recommended
method (trunk, branches, tags directories) with the --stdlayout option, or
follow branches in any layout with the -T/-t/-b options (see options to
'init' below, and also the 'clone' command).
'git-svn' can track a standard Subversion repository,
following the common "trunk/branches/tags" layout, with the --stdlayout option.
It can also follow branches and tags in any layout with the -T/-t/-b options
(see options to 'init' below, and also the 'clone' command).
Once tracking a Subversion branch (with any of the above methods), the git
Once tracking a Subversion repository (with any of the above methods), the git
repository can be updated from Subversion by the 'fetch' command and
Subversion updated from git by the 'dcommit' command.
......@@ -48,8 +47,11 @@ COMMANDS
--stdlayout;;
These are optional command-line options for init. Each of
these flags can point to a relative repository path
(--tags=project/tags') or a full url
(--tags=https://foo.org/project/tags). The option --stdlayout is
(--tags=project/tags) or a full url
(--tags=https://foo.org/project/tags).
You can specify more than one --tags and/or --branches options, in case
your Subversion repository places tags or branches under multiple paths.
The option --stdlayout is
a shorthand way of setting trunk,tags,branches as the relative paths,
which is the Subversion default. If any of the other options are given
as well, they take precedence.
......@@ -170,8 +172,9 @@ and have no uncommitted changes.
It is recommended that you run 'git-svn' fetch and rebase (not
pull or merge) your commits against the latest changes in the
SVN repository.
An optional command-line argument may be specified as an
alternative to HEAD.
An optional revision or branch argument may be specified, and
causes 'git-svn' to do all work on that revision/branch
instead of HEAD.
This is advantageous over 'set-tree' (below) because it produces
cleaner, more linear history.
+
......@@ -204,6 +207,20 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
Create a tag by using the tags_subdir instead of the branches_subdir
specified during git svn init.
-d;;
--destination;;
If more than one --branches (or --tags) option was given to the 'init'
or 'clone' command, you must provide the location of the branch (or
tag) you wish to create in the SVN repository. The value of this
option must match one of the paths specified by a --branches (or
--tags) option. You can see these paths with the commands
+
git config --get-all svn-remote.<name>.branches
git config --get-all svn-remote.<name>.tags
+
where <name> is the name of the SVN repository as specified by the -R option to
'init' (or "svn" by default).
'tag'::
Create a tag in the SVN repository. This is a shorthand for
'branch -t'.
......@@ -215,7 +232,7 @@ config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
The following features from `svn log' are supported:
+
--
--revision=<n>[:<n>];;
-r/--revision=<n>[:<n>];;
is supported, non-numeric args are not:
HEAD, NEXT, BASE, PREV, etc ...
-v/--verbose;;
......@@ -313,6 +330,63 @@ Any other arguments are passed directly to 'git-log'
Shows the Subversion externals. Use -r/--revision to specify a
specific revision.
'reset'::
Undoes the effects of 'fetch' back to the specified revision.
This allows you to re-'fetch' an SVN revision. Normally the
contents of an SVN revision should never change and 'reset'
should not be necessary. However, if SVN permissions change,
or if you alter your --ignore-paths option, a 'fetch' may fail
with "not found in commit" (file not previously visible) or
"checksum mismatch" (missed a modification). If the problem
file cannot be ignored forever (with --ignore-paths) the only
way to repair the repo is to use 'reset'.
Only the rev_map and refs/remotes/git-svn are changed. Follow 'reset'
with a 'fetch' and then 'git-reset' or 'git-rebase' to move local
branches onto the new tree.
-r/--revision=<n>;;
Specify the most recent revision to keep. All later revisions
are discarded.
-p/--parent;;
Discard the specified revision as well, keeping the nearest
parent instead.
Example:;;
Assume you have local changes in "master", but you need to refetch "r2".
------------
r1---r2---r3 remotes/git-svn
\
A---B master
------------
Fix the ignore-paths or SVN permissions problem that caused "r2" to
be incomplete in the first place. Then:
[verse]
git svn reset -r2 -p
git svn fetch
------------
r1---r2'--r3' remotes/git-svn
\
r2---r3---A---B master
------------
Then fixup "master" with 'git-rebase'.
Do NOT use 'git-merge' or your history will not be compatible with a
future 'dcommit'!
[verse]
git rebase --onto remotes/git-svn A^ master
------------
r1---r2'--r3' remotes/git-svn
\
A'--B' master
------------
--
OPTIONS
......@@ -669,6 +743,16 @@ already dcommitted. It is considered bad practice to --amend commits
you've already pushed to a remote repository for other users, and
dcommit with SVN is analogous to that.
When using multiple --branches or --tags, 'git-svn' does not automatically
handle name collisions (for example, if two branches from different paths have
the same name, or if a branch and a tag have the same name). In these cases,
use 'init' to set up your git repository then, before your first 'fetch', edit
the .git/config file so that the branches and tags are associated with
different name spaces. For example:
branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*
BUGS
----
......
......@@ -63,7 +63,7 @@ BEGIN
$sha1 = qr/[a-f\d]{40}/;
$sha1_short = qr/[a-f\d]{4,40}/;
my ($_stdin, $_help, $_edit,
$_message, $_file,
$_message, $_file, $_branch_dest,
$_template, $_shared,
$_version, $_fetch_all, $_no_rebase, $_fetch_parent,
$_merge, $_strategy, $_dry_run, $_local,
......@@ -92,11 +92,11 @@ BEGIN
'localtime' => \$Git::SVN::_localtime,
%remote_opts );
my ($_trunk, $_tags, $_branches, $_stdlayout);
my ($_trunk, @_tags, @_branches, $_stdlayout);
my %icv;
my %init_opts = ( 'template=s' => \$_template, 'shared:s' => \$_shared,
'trunk|T=s' => \$_trunk, 'tags|t=s' => \$_tags,
'branches|b=s' => \$_branches, 'prefix=s' => \$_prefix,
'trunk|T=s' => \$_trunk, 'tags|t=s@' => \@_tags,
'branches|b=s@' => \@_branches, 'prefix=s' => \$_prefix,
'stdlayout|s' => \$_stdlayout,
'minimize-url|m' => \$Git::SVN::_minimize_url,
'no-metadata' => sub { $icv{noMetadata} = 1 },
......@@ -141,11 +141,13 @@ BEGIN
branch => [ \&cmd_branch,
'Create a branch in the SVN repository',
{ 'message|m=s' => \$_message,
'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run,
'tag|t' => \$_tag } ],
tag => [ sub { $_tag = 1; cmd_branch(@_) },
'Create a tag in the SVN repository',
{ 'message|m=s' => \$_message,
'destination|d=s' => \$_branch_dest,
'dry-run|n' => \$_dry_run } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
......@@ -211,6 +213,10 @@ BEGIN
'blame' => [ \&Git::SVN::Log::cmd_blame,
"Show what revision and author last modified each line of a file",
{ 'git-format' => \$_git_format } ],
'reset' => [ \&cmd_reset,
"Undo fetches back to the specified SVN revision",
{ 'revision|r=s' => \$_revision,
'parent|p' => \$_fetch_parent } ],
);
my $cmd;
......@@ -219,6 +225,9 @@ BEGIN
$cmd = $ARGV[$i];
splice @ARGV, $i, 1;
last;
} elsif ($ARGV[$i] eq 'help') {
$cmd = $ARGV[$i+1];
usage(0);
}
};
......@@ -358,7 +367,7 @@ sub init_subdir {
sub cmd_clone {
my ($url, $path) = @_;
if (!defined $path &&
(defined $_trunk || defined $_branches || defined $_tags ||
(defined $_trunk || @_branches || @_tags ||
defined $_stdlayout) &&
$url !~ m#^[a-z\+]+://#) {
$path = $url;
......@@ -372,14 +381,15 @@ sub cmd_clone {
sub cmd_init {
if (defined $_stdlayout) {
$_trunk = 'trunk' if (!defined $_trunk);
$_tags = 'tags' if (!defined $_tags);
$_branches = 'branches' if (!defined $_branches);
@_tags = 'tags' if (! @_tags);
@_branches = 'branches' if (! @_branches);
}
if (defined $_trunk || defined $_branches || defined $_tags) {
if (defined $_trunk || @_branches || @_tags) {
return cmd_multi_init(@_);
}
my $url = shift or die "SVN repository location required ",
"as a command-line argument\n";
$url = canonicalize_url($url);
init_subdir(@_);
do_git_init_db();
......@@ -454,8 +464,22 @@ sub cmd_dcommit {
'Cannot dcommit with a dirty index. Commit your changes first, '
. "or stash them with `git stash'.\n";
$head ||= 'HEAD';
my $old_head;
if ($head ne 'HEAD') {
$old_head = eval {
command_oneline([qw/symbolic-ref -q HEAD/])
};
if ($old_head) {
$old_head =~ s{^refs/heads/}{};
} else {
$old_head = eval { command_oneline(qw/rev-parse HEAD/) };
}
command(['checkout', $head], STDERR => 0);
}
my @refs;
my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD', \@refs);
unless ($gs) {
die "Unable to determine upstream SVN information from ",
"$head history.\nPerhaps the repository is empty.";
......@@ -541,7 +565,7 @@ sub cmd_dcommit {
if (@diff) {
@refs = ();
my ($url_, $rev_, $uuid_, $gs_) =
working_head_info($head, \@refs);
working_head_info('HEAD', \@refs);
my ($linear_refs_, $parents_) =
linearize_history($gs_, \@refs);
if (scalar(@$linear_refs) !=
......@@ -579,6 +603,22 @@ sub cmd_dcommit {
}
}
}
if ($old_head) {
my $new_head = command_oneline(qw/rev-parse HEAD/);
my $new_is_symbolic = eval {
command_oneline(qw/symbolic-ref -q HEAD/);
};
if ($new_is_symbolic) {
print "dcommitted the branch ", $head, "\n";
} else {
print "dcommitted on a detached HEAD because you gave ",
"a revision argument.\n",
"The rewritten commit is: ", $new_head, "\n";
}
command(['checkout', $old_head], STDERR => 0);
}
unlink $gs->{index};
}
......@@ -593,7 +633,33 @@ sub cmd_branch {
my ($src, $rev, undef, $gs) = working_head_info($head);
my $remote = Git::SVN::read_all_remotes()->{$gs->{repo_id}};
my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
my $allglobs = $remote->{ $_tag ? 'tags' : 'branches' };
my $glob;
if ($#{$allglobs} == 0) {
$glob = $allglobs->[0];
} else {
unless(defined $_branch_dest) {
die "Multiple ",
$_tag ? "tag" : "branch",
" paths defined for Subversion repository.\n",
"You must specify where you want to create the ",
$_tag ? "tag" : "branch",
" with the --destination argument.\n";
}
foreach my $g (@{$allglobs}) {
# SVN::Git::Editor could probably be moved to Git.pm..
my $re = SVN::Git::Editor::glob2pat($g->{path}->{left});
if ($_branch_dest =~ /$re/) {
$glob = $g;
last;
}
}
unless (defined $glob) {
die "Unknown ",
$_tag ? "tag" : "branch",
" destination $_branch_dest\n";
}
}
my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
......@@ -741,6 +807,12 @@ sub canonicalize_path {
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.
......@@ -800,7 +872,7 @@ sub cmd_proplist {
sub cmd_multi_init {
my $url = shift;
unless (defined $_trunk || defined $_branches || defined $_tags) {
unless (defined $_trunk || @_branches || @_tags) {
usage(1);
}
......@@ -810,7 +882,7 @@ sub cmd_multi_init {
$_prefix = '' unless defined $_prefix;
if (defined $url) {
$url =~ s#/+$##;
$url = canonicalize_url($url);
init_subdir(@_);
}
do_git_init_db();
......@@ -825,10 +897,14 @@ sub cmd_multi_init {
undef, $trunk_ref);
}
}
return unless defined $_branches || defined $_tags;
return unless @_branches || @_tags;
my $ra = $url ? Git::SVN::Ra->new($url) : undef;
complete_url_ls_init($ra, $_branches, '--branches/-b', $_prefix);
complete_url_ls_init($ra, $_tags, '--tags/-t', $_prefix . 'tags/');
foreach my $path (@_branches) {
complete_url_ls_init($ra, $path, '--branches/-b', $_prefix);
}
foreach my $path (@_tags) {
complete_url_ls_init($ra, $path, '--tags/-t', $_prefix.'tags/');
}
}
sub cmd_multi_fetch {
......@@ -1021,6 +1097,20 @@ sub cmd_info {
print $result, "\n";
}
sub cmd_reset {
my $target = shift || $_revision or die "SVN revision required\n";
$target = $1 if $target =~ /^r(\d+)$/;
$target =~ /^\d+$/ or die "Numeric SVN revision expected\n";
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
unless ($gs) {
die "Unable to determine upstream SVN information from ".
"history\n";
}
my ($r, $c) = $gs->find_rev_before($target, not $_fetch_parent);
$gs->rev_map_set($r, $c, 'reset', $uuid);
print "r$r = $c ($gs->{ref_id})\n";
}
########################### utility functions #########################
sub rebase_cmd {
......@@ -1099,6 +1189,7 @@ sub complete_url_ls_init {
die "--prefix='$pfx' must have a trailing slash '/'\n";
}
command_noisy('config',
'--add',
"svn-remote.$gs->{repo_id}.$n",
"$remote_path:refs/remotes/$pfx*" .
('/*' x (($remote_path =~ tr/*/*/) - 1)) );
......@@ -1565,7 +1656,8 @@ sub fetch_all {
# read the max revs for wildcard expansion (branches/*, tags/*)
foreach my $t (qw/branches tags/) {
defined $remote->{$t} or next;
push @globs, $remote->{$t};
push @globs, @{$remote->{$t}};
my $max_rev = eval { tmp_config(qw/--int --get/,
"svn-remote.$repo_id.${t}-maxRev") };
if (defined $max_rev && ($max_rev < $base)) {
......@@ -1612,15 +1704,16 @@ sub read_all_remotes {
} elsif (m!^(.+)\.(branches|tags)=
(.*):refs/remotes/(.+)\s*$/!x) {
my ($p, $g) = ($3, $4);
my $rs = $r->{$1}->{$2} = {
t => $2,
remote => $1,
path => Git::SVN::GlobSpec->new($p),
ref => Git::SVN::GlobSpec->new($g) };
my $rs = {
t => $2,
remote => $1,
path => Git::SVN::GlobSpec->new($p),
ref => Git::SVN::GlobSpec->new($g) };
if (length($rs->{ref}->{right}) != 0) {
die "The '*' glob character must be the last ",
"character of '$g'\n";
}
push @{ $r->{$1}->{$2} }, $rs;
}
}
......@@ -1760,9 +1853,10 @@ sub find_by_url { # repos_root and, path are optional
next if defined $repos_root && $repos_root ne $u;
my $fetch = $remotes->{$repo_id}->{fetch} || {};
foreach (qw/branches tags/) {
resolve_local_globs($u, $fetch,
$remotes->{$repo_id}->{$_});
foreach my $t (qw/branches tags/) {
foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) {
resolve_local_globs($u, $fetch, $globspec);
}
}
my $p = $path;
my $rwr = rewrite_root({repo_id => $repo_id});
......@@ -2990,6 +3084,14 @@ sub _rev_map_set {
croak "write: $!";
}
sub _rev_map_reset {
my ($fh, $rev, $commit) = @_;
my $c = _rev_map_get($fh, $rev);
$c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n";
my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!";
truncate $fh, $offset or croak "truncate: $!";
}
sub mkfile {
my ($path) = @_;
unless (-e $path) {
......@@ -3006,6 +3108,7 @@ sub rev_map_set {
my $db = $self->map_path($uuid);
my $db_lock = "$db.lock";
my $sig;
$update_ref ||= 0;
if ($update_ref) {
$SIG{INT} = $SIG{HUP} = $SIG{TERM} = $SIG{ALRM} = $SIG{PIPE} =
$SIG{USR1} = $SIG{USR2} = sub { $sig = $_[0] };
......@@ -3029,7 +3132,8 @@ sub rev_map_set {
sysopen(my $fh, $db_lock, O_RDWR | O_CREAT)
or croak "Couldn't open $db_lock: $!\n";
_rev_map_set($fh, $rev, $commit);
$update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) :
_rev_map_set($fh, $rev, $commit);
if ($sync) {
$fh->flush or die "Couldn't flush $db_lock: $!\n";
$fh->sync or die "Couldn't sync $db_lock: $!\n";
......@@ -3037,7 +3141,9 @@ sub rev_map_set {
close $fh or croak $!;
if ($update_ref) {
$_head = $self;
command_noisy('update-ref', '-m', "r$rev",
my $note = "";
$note = " ($update_ref)" if ($update_ref !~ /^\d*$/);
command_noisy('update-ref', '-m', "r$rev$note",
$self->refname, $commit);
}
rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ",
......@@ -3099,12 +3205,19 @@ sub rev_map_get {
return undef unless -e $map_path;
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";
my $c = _rev_map_get($fh, $rev);
close($fh) or croak "close: $!";
$c
}
sub _rev_map_get {
my ($fh, $rev) = @_;
binmode $fh or croak "binmode: $!";
my $size = (stat($fh))[7];
($size % 24) == 0 or croak "inconsistent size: $size";
if ($size == 0) {
close $fh or croak "close: $fh";
return undef;
}
......@@ -3122,11 +3235,9 @@ sub rev_map_get {
} elsif ($r > $rev) {
$u = $i - 24;
} else { # $r == $rev
close($fh) or croak "close: $!";
return $c eq ('0' x 40) ? undef : $c;
}
}
close($fh) or croak "close: $!";
undef;
}
......@@ -3138,6 +3249,8 @@ sub find_rev_before {
my ($self, $rev, $eq_ok, $min_rev) = @_;
--$rev unless $eq_ok;
$min_rev ||= 1;
my $max_rev = $self->rev_map_max;
$rev = $max_rev if ($rev > $max_rev);
while ($rev >= $min_rev) {
if (my $c = $self->rev_map_get($rev)) {
return ($rev, $c);
......
......@@ -231,6 +231,25 @@ test_expect_success \
"^:refs/${remotes_git_svn}$"
'
test_expect_success 'dcommit $rev does not clobber current branch' '
git svn fetch -i bar &&
git checkout -b my-bar refs/remotes/bar &&
echo 1 > foo &&
git add foo &&
git commit -m "change 1" &&
echo 2 > foo &&
git add foo &&
git commit -m "change 2" &&
old_head=$(git rev-parse HEAD) &&
git svn dcommit -i bar HEAD^ &&
test $old_head = $(git rev-parse HEAD) &&
test refs/heads/my-bar = $(git symbolic-ref HEAD) &&
git log refs/remotes/bar | grep "change 1" &&
! git log refs/remotes/bar | grep "change 2" &&
git checkout master &&
git branch -D my-bar
'
test_expect_success 'able to dcommit to a subdirectory' "
git svn fetch -i bar &&
git checkout -b my-bar refs/remotes/bar &&
......
#!/bin/sh
#
# Copyright (c) 2009 Marc Branchaud
#
test_description='git svn multiple branch and tag paths in the svn repo'
. ./lib-git-svn.sh
test_expect_success 'setup svnrepo' '
mkdir project \
project/trunk \
project/b_one \
project/b_two \
project/tags_A \
project/tags_B &&
echo 1 > project/trunk/a.file &&
svn_cmd import -m "$test_description" project "$svnrepo/project" &&
rm -rf project &&
svn_cmd cp -m "Branch 1" "$svnrepo/project/trunk" \
"$svnrepo/project/b_one/first" &&
svn_cmd cp -m "Tag 1" "$svnrepo/project/trunk" \
"$svnrepo/project/tags_A/1.0" &&
svn_cmd co "$svnrepo/project" svn_project &&
( cd svn_project &&
echo 2 > trunk/a.file &&
svn_cmd ci -m "Change 1" trunk/a.file &&
svn_cmd cp -m "Branch 2" "$svnrepo/project/trunk" \
"$svnrepo/project/b_one/second" &&
svn_cmd cp -m "Tag 2" "$svnrepo/project/trunk" \
"$svnrepo/project/tags_A/2.0" &&
echo 3 > trunk/a.file &&
svn_cmd ci -m "Change 2" trunk/a.file &&
svn_cmd cp -m "Branch 3" "$svnrepo/project/trunk" \
"$svnrepo/project/b_two/1" &&
svn_cmd cp -m "Tag 3" "$svnrepo/project/trunk" \
"$svnrepo/project/tags_A/3.0" &&
echo 4 > trunk/a.file &&
svn_cmd ci -m "Change 3" trunk/a.file &&
svn_cmd cp -m "Branch 4" "$svnrepo/project/trunk" \
"$svnrepo/project/b_two/2" &&
svn_cmd cp -m "Tag 4" "$svnrepo/project/trunk" \
"$svnrepo/project/tags_A/4.0" &&
svn_cmd up &&
echo 5 > b_one/first/a.file &&
svn_cmd ci -m "Change 4" b_one/first/a.file &&
svn_cmd cp -m "Tag 5" "$svnrepo/project/b_one/first" \
"$svnrepo/project/tags_B/v5" &&
echo 6 > b_one/second/a.file &&
svn_cmd ci -m "Change 5" b_one/second/a.file &&
svn_cmd cp -m "Tag 6" "$svnrepo/project/b_one/second" \
"$svnrepo/project/tags_B/v6" &&
echo 7 > b_two/1/a.file &&
svn_cmd ci -m "Change 6" b_two/1/a.file &&
svn_cmd cp -m "Tag 7" "$svnrepo/project/b_two/1" \
"$svnrepo/project/tags_B/v7" &&
echo 8 > b_two/2/a.file &&
svn_cmd ci -m "Change 7" b_two/2/a.file &&
svn_cmd cp -m "Tag 8" "$svnrepo/project/b_two/2" \
"$svnrepo/project/tags_B/v8"
)
'
test_expect_success 'clone multiple branch and tag paths' '
git svn clone -T trunk \
-b b_one/* --branches b_two/* \
-t tags_A/* --tags tags_B \
"$svnrepo/project" git_project &&
( cd git_project &&
git rev-parse refs/remotes/first &&
git rev-parse refs/remotes/second &&
git rev-parse refs/remotes/1 &&
git rev-parse refs/remotes/2 &&
git rev-parse refs/remotes/tags/1.0 &&
git rev-parse refs/remotes/tags/2.0 &&
git rev-parse refs/remotes/tags/3.0 &&
git rev-parse refs/remotes/tags/4.0 &&
git rev-parse refs/remotes/tags/v5 &&
git rev-parse refs/remotes/tags/v6 &&
git rev-parse refs/remotes/tags/v7 &&
git rev-parse refs/remotes/tags/v8
)
'
test_expect_success 'Multiple branch or tag paths require -d' '
( cd git_project &&
test_must_fail git svn branch -m "No new branch" Nope &&
test_must_fail git svn tag -m "No new tag" Tagless &&
test_must_fail git rev-parse refs/remotes/Nope &&
test_must_fail git rev-parse refs/remotes/tags/Tagless
) &&
( cd svn_project &&
svn_cmd up &&
test_must_fail test -d b_one/Nope &&
test_must_fail test -d b_two/Nope &&
test_must_fail test -d tags_A/Tagless &&
test_must_fail test -d tags_B/Tagless
)
'
test_expect_success 'create new branches and tags' '
( cd git_project &&
git svn branch -m "New branch 1" -d project/b_one New1 ) &&
( cd svn_project &&
svn_cmd up && test -e b_one/New1/a.file ) &&
( cd git_project &&
git svn branch -m "New branch 2" -d project/b_two New2 ) &&
( cd svn_project &&
svn_cmd up && test -e b_two/New2/a.file ) &&
( cd git_project &&
git svn branch -t -m "New tag 1" -d project/tags_A Tag1 ) &&
( cd svn_project &&
svn_cmd up && test -e tags_A/Tag1/a.file ) &&
( cd git_project &&
git svn tag -m "New tag 2" -d project/tags_B Tag2 ) &&
( cd svn_project &&
svn_cmd up && test -e tags_B/Tag2/a.file )
'
test_done
#!/bin/sh
#
# Copyright (c) 2009 Ben Jackson
#
test_description='git svn reset'
. ./lib-git-svn.sh
test_expect_success 'setup test repository' '
svn_cmd co "$svnrepo" s &&
(
cd s &&
mkdir vis &&
echo always visible > vis/vis.txt &&
svn_cmd add vis &&
svn_cmd commit -m "create visible files" &&
mkdir hid &&
echo initially hidden > hid/hid.txt &&
svn_cmd add hid &&
svn_cmd commit -m "create initially hidden files" &&
svn_cmd up &&
echo mod >> vis/vis.txt &&
svn_cmd commit -m "modify vis" &&
svn_cmd up
)
'
test_expect_success 'clone SVN repository with hidden directory' '
git svn init "$svnrepo" g &&
( cd g && git svn fetch --ignore-paths="^hid" )
'
test_expect_success 'modify hidden file in SVN repo' '
( cd s &&
echo mod hidden >> hid/hid.txt &&
svn_cmd commit -m "modify hid" &&
svn_cmd up
)
'
test_expect_success 'fetch fails on modified hidden file' '
( cd g &&
git svn find-rev refs/remotes/git-svn > ../expect &&
! git svn fetch 2> ../errors &&
git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
fgrep "not found in commit" errors &&
test_cmp expect expect2
'
test_expect_success 'reset unwinds back to r1' '
( cd g &&
git svn reset -r1 &&
git svn find-rev refs/remotes/git-svn > ../expect2 ) &&
echo 1 >expect &&
test_cmp expect expect2
'
test_expect_success 'refetch succeeds not ignoring any files' '
( cd g &&
git svn fetch &&
git svn rebase &&
fgrep "mod hidden" hid/hid.txt
)
'
test_done
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册