git-svn: add a 'rebase' command
This works similarly to 'svn update' or 'git pull' except that it preserves linear history with 'git rebase' instead of 'git merge' for ease of dcommit-ing with git-svn. While we're at it, put the working_head_info() logic into its own function and allow --fetch-all/--all for dcommit and rebase (which will fetch all refs in the current [svn-remote] instead of just the working one). Note that the '-a' switch (short for --fetch-all/--all) has been removed as it conflicts with the non-svn 'git fetch' Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
parent
1e889ef36c
commit
905f8b7dfc
91
git-svn.perl
91
git-svn.perl
@ -56,7 +56,7 @@ my ($_stdin, $_help, $_edit,
|
||||
$_template, $_shared,
|
||||
$_version, $_fetch_all,
|
||||
$_merge, $_strategy, $_dry_run,
|
||||
$_prefix, $_no_checkout);
|
||||
$_prefix, $_no_checkout, $_verbose);
|
||||
$Git::SVN::_follow_parent = 1;
|
||||
my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
|
||||
'config-dir=s' => \$Git::SVN::Ra::config_dir,
|
||||
@ -88,7 +88,7 @@ my %cmt_opts = ( 'edit|e' => \$_edit,
|
||||
my %cmd = (
|
||||
fetch => [ \&cmd_fetch, "Download new revisions from SVN",
|
||||
{ 'revision|r=s' => \$_revision,
|
||||
'all|a' => \$_fetch_all,
|
||||
'fetch-all|all' => \$_fetch_all,
|
||||
%fc_opts } ],
|
||||
init => [ \&cmd_init, "Initialize a repo for tracking" .
|
||||
" (requires URL argument)",
|
||||
@ -101,7 +101,9 @@ my %cmd = (
|
||||
'Commit several diffs to merge with upstream',
|
||||
{ 'merge|m|M' => \$_merge,
|
||||
'strategy|s=s' => \$_strategy,
|
||||
'verbose|v' => \$_verbose,
|
||||
'dry-run|n' => \$_dry_run,
|
||||
'fetch-all|all' => \$_fetch_all,
|
||||
%cmt_opts, %fc_opts } ],
|
||||
'set-tree' => [ \&cmd_set_tree,
|
||||
"Set an SVN repository to a git tree-ish",
|
||||
@ -129,6 +131,12 @@ my %cmd = (
|
||||
'color' => \$Git::SVN::Log::color,
|
||||
'pager=s' => \$Git::SVN::Log::pager,
|
||||
} ],
|
||||
'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
|
||||
{ 'merge|m|M' => \$_merge,
|
||||
'verbose|v' => \$_verbose,
|
||||
'strategy|s=s' => \$_strategy,
|
||||
'fetch-all|all' => \$_fetch_all,
|
||||
%fc_opts } ],
|
||||
'commit-diff' => [ \&cmd_commit_diff,
|
||||
'Commit a diff between two trees',
|
||||
{ 'message|m=s' => \$_message,
|
||||
@ -248,7 +256,7 @@ sub cmd_fetch {
|
||||
}
|
||||
my ($remote) = @_;
|
||||
if (@_ > 1) {
|
||||
die "Usage: $0 fetch [--all|-a] [svn-remote]\n";
|
||||
die "Usage: $0 fetch [--all] [svn-remote]\n";
|
||||
}
|
||||
$remote ||= $Git::SVN::default_repo_id;
|
||||
if ($_fetch_all) {
|
||||
@ -296,21 +304,12 @@ sub cmd_set_tree {
|
||||
sub cmd_dcommit {
|
||||
my $head = shift;
|
||||
$head ||= 'HEAD';
|
||||
my ($url, $rev, $uuid);
|
||||
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
|
||||
my @refs;
|
||||
my $c;
|
||||
while (<$fh>) {
|
||||
$c = $_;
|
||||
chomp $c;
|
||||
($url, $rev, $uuid) = cmt_metadata($c);
|
||||
last if (defined $url && defined $rev && defined $uuid);
|
||||
unshift @refs, $c;
|
||||
}
|
||||
close $fh; # most likely breaking the pipe
|
||||
my ($url, $rev, $uuid) = working_head_info($head, \@refs);
|
||||
my $c = $refs[-1];
|
||||
unless (defined $url && defined $rev && defined $uuid) {
|
||||
die "Unable to determine upstream SVN information from ",
|
||||
"$head history:\n $ctx\n";
|
||||
"$head history\n";
|
||||
}
|
||||
my $gs = Git::SVN->find_by_url($url);
|
||||
my $last_rev;
|
||||
@ -354,15 +353,13 @@ sub cmd_dcommit {
|
||||
"now resync your SVN::Mirror repository.\n";
|
||||
return;
|
||||
}
|
||||
$gs->fetch;
|
||||
$_fetch_all ? $gs->fetch_all : $gs->fetch;
|
||||
# we always want to rebase against the current HEAD, not any
|
||||
# head that was passed to us
|
||||
my @diff = command('diff-tree', 'HEAD', $gs->refname, '--');
|
||||
my @finish;
|
||||
if (@diff) {
|
||||
@finish = qw/rebase/;
|
||||
push @finish, qw/--merge/ if $_merge;
|
||||
push @finish, "--strategy=$_strategy" if $_strategy;
|
||||
@finish = rebase_cmd();
|
||||
print STDERR "W: HEAD and ", $gs->refname, " differ, ",
|
||||
"using @finish:\n", "@diff";
|
||||
} else {
|
||||
@ -374,6 +371,24 @@ sub cmd_dcommit {
|
||||
command_noisy(@finish, $gs->refname);
|
||||
}
|
||||
|
||||
sub cmd_rebase {
|
||||
command_noisy(qw/update-index --refresh/);
|
||||
my $url = (working_head_info('HEAD'))[0];
|
||||
if (!defined $url) {
|
||||
die "Unable to determine upstream SVN information from ",
|
||||
"working tree history\n";
|
||||
}
|
||||
|
||||
my $gs = Git::SVN->find_by_url($url);
|
||||
if (command(qw/diff-index HEAD --/)) {
|
||||
print STDERR "Cannot rebase with uncommited changes:\n";
|
||||
command_noisy('status');
|
||||
exit 1;
|
||||
}
|
||||
$_fetch_all ? $gs->fetch_all : $gs->fetch;
|
||||
command_noisy(rebase_cmd(), $gs->refname);
|
||||
}
|
||||
|
||||
sub cmd_show_ignore {
|
||||
my $gs = Git::SVN->new;
|
||||
my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
|
||||
@ -468,6 +483,14 @@ sub cmd_commit_diff {
|
||||
|
||||
########################### utility functions #########################
|
||||
|
||||
sub rebase_cmd {
|
||||
my @cmd = qw/rebase/;
|
||||
push @cmd, '-v' if $_verbose;
|
||||
push @cmd, qw/--merge/ if $_merge;
|
||||
push @cmd, "--strategy=$_strategy" if $_strategy;
|
||||
@cmd;
|
||||
}
|
||||
|
||||
sub post_fetch_checkout {
|
||||
return if $_no_checkout;
|
||||
my $gs = $Git::SVN::_head or return;
|
||||
@ -687,6 +710,20 @@ sub cmt_metadata {
|
||||
command(qw/cat-file commit/, shift)))[-1]);
|
||||
}
|
||||
|
||||
sub working_head_info {
|
||||
my ($head, $refs) = @_;
|
||||
my ($url, $rev, $uuid);
|
||||
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
($url, $rev, $uuid) = cmt_metadata($_);
|
||||
last if (defined $url && defined $rev && defined $uuid);
|
||||
unshift @$refs, $_ if $refs;
|
||||
}
|
||||
close $fh; # break the pipe
|
||||
($url, $rev, $uuid);
|
||||
}
|
||||
|
||||
package Git::SVN;
|
||||
use strict;
|
||||
use warnings;
|
||||
@ -783,6 +820,12 @@ sub parse_revision_argument {
|
||||
|
||||
sub fetch_all {
|
||||
my ($repo_id, $remotes) = @_;
|
||||
if (ref $repo_id) {
|
||||
my $gs = $repo_id;
|
||||
$repo_id = undef;
|
||||
$repo_id = $gs->{repo_id};
|
||||
}
|
||||
$remotes ||= read_all_remotes();
|
||||
my $remote = $remotes->{$repo_id} or
|
||||
die "[svn-remote \"$repo_id\"] unknown\n";
|
||||
my $fetch = $remote->{fetch};
|
||||
@ -3085,15 +3128,7 @@ sub git_svn_log_cmd {
|
||||
last;
|
||||
}
|
||||
|
||||
my $url;
|
||||
my ($fh, $ctx) = command_output_pipe('rev-list', $head);
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
$url = (::cmt_metadata($_))[0];
|
||||
last if defined $url;
|
||||
}
|
||||
close $fh; # break the pipe
|
||||
|
||||
my $url = (::working_head_info($head))[0];
|
||||
my $gs = Git::SVN->find_by_url($url) || Git::SVN->_new;
|
||||
my @cmd = (qw/log --abbrev-commit --pretty=raw --default/,
|
||||
$gs->refname);
|
||||
|
Loading…
Reference in New Issue
Block a user