$_version, $_fetch_all, $_no_rebase,
$_merge, $_strategy, $_dry_run, $_local,
$_prefix, $_no_checkout, $_url, $_verbose,
- $_git_format, $_commit_url);
+ $_git_format, $_commit_url, $_tag);
$Git::SVN::_follow_parent = 1;
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
'config-dir=s' => \$Git::SVN::Ra::config_dir,
'revision|r=i' => \$_revision,
'no-rebase' => \$_no_rebase,
%cmt_opts, %fc_opts } ],
+ branch => [ \&cmd_branch,
+ 'Create a branch in the SVN repository',
+ { 'message|m=s' => \$_message,
+ '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,
+ 'dry-run|n' => \$_dry_run } ],
'set-tree' => [ \&cmd_set_tree,
"Set an SVN repository to a git tree-ish",
{ 'stdin|' => \$_stdin, %cmt_opts, %fc_opts, } ],
unlink $gs->{index};
}
+sub cmd_branch {
+ my ($branch_name, $head) = @_;
+
+ unless (defined $branch_name && length $branch_name) {
+ die(($_tag ? "tag" : "branch") . " name required\n");
+ }
+ $head ||= 'HEAD';
+
+ my ($src, $rev, undef, $gs) = working_head_info($head);
+
+ my $remote = Git::SVN::read_all_remotes()->{svn};
+ my $glob = $remote->{ $_tag ? 'tags' : 'branches' };
+ my ($lft, $rgt) = @{ $glob->{path} }{qw/left right/};
+ my $dst = join '/', $remote->{url}, $lft, $branch_name, ($rgt || ());
+
+ my $ctx = SVN::Client->new(
+ auth => Git::SVN::Ra::_auth_providers(),
+ log_msg => sub {
+ ${ $_[0] } = defined $_message
+ ? $_message
+ : 'Create ' . ($_tag ? 'tag ' : 'branch ' )
+ . $branch_name;
+ },
+ );
+
+ eval {
+ $ctx->ls($dst, 'HEAD', 0);
+ } and die "branch ${branch_name} already exists\n";
+
+ print "Copying ${src} at r${rev} to ${dst}...\n";
+ $ctx->copy($src, $rev, $dst)
+ unless $_dry_run;
+
+ $gs->fetch_all;
+}
+
sub cmd_find_rev {
my $revision_or_hash = shift or die "SVN or git revision required ",
"as a command-line argument\n";
my ($self, $tree) = (shift, shift);
my $log_entry = ::get_commit_entry($tree);
unless ($self->{last_rev}) {
- fatal("Must have an existing revision to commit");
+ ::fatal("Must have an existing revision to commit");
}
my %ed_opts = ( r => $self->{last_rev},
log => $log_entry->{log},
sub rebuild {
my ($self) = @_;
my $map_path = $self->map_path;
- return if (-e $map_path && ! -z $map_path);
+ my $partial = (-e $map_path && ! -z $map_path);
return unless ::verify_ref($self->refname.'^0');
- if ($self->use_svm_props || $self->no_metadata) {
+ if (!$partial && ($self->use_svm_props || $self->no_metadata)) {
my $rev_db = $self->rev_db_path;
$self->rebuild_from_rev_db($rev_db);
if ($self->use_svm_props) {
$self->unlink_rev_db_symlink;
return;
}
- print "Rebuilding $map_path ...\n";
+ print "Rebuilding $map_path ...\n" if (!$partial);
+ my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) :
+ (undef, undef));
my ($log, $ctx) =
command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/,
- $self->refname, '--');
+ ($head ? "$head.." : "") . $self->refname,
+ '--');
my $metadata_url = $self->metadata_url;
remove_username($metadata_url);
my $svn_uuid = $self->ra_uuid;
($metadata_url && $url && ($url ne $metadata_url))) {
next;
}
+ if ($partial && $head) {
+ print "Partial-rebuilding $map_path ...\n";
+ print "Currently at $base_rev = $head\n";
+ $head = undef;
+ }
$self->rev_map_set($rev, $c);
print "r$rev = $c\n";
}
command_close_pipe($log, $ctx);
- print "Done rebuilding $map_path\n";
+ print "Done rebuilding $map_path\n" if (!$partial || !$head);
my $rev_db_path = $self->rev_db_path;
if (-f $self->rev_db_path) {
unlink $self->rev_db_path or croak "unlink: $!";
sub rev_map_max {
my ($self, $want_commit) = @_;
$self->rebuild;
+ my ($r, $c) = $self->rev_map_max_norebuild($want_commit);
+ $want_commit ? ($r, $c) : $r;
+}
+
+sub rev_map_max_norebuild {
+ my ($self, $want_commit) = @_;
my $map_path = $self->map_path;
stat $map_path or return $want_commit ? (0, undef) : 0;
sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!";