aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2007-02-16 03:22:40 -0800
committerEric Wong <normalperson@yhbt.net>2007-02-23 00:57:13 -0800
commit905f8b7dfc2c520b91f418ab0f2aecb1c371fbe4 (patch)
tree095d25cdf6c55f35e6ba414cfe6630183d2ca6f3
parent1e889ef36c45b5554f7e317493ed3f4f901f8d9f (diff)
downloadgit-905f8b7dfc2c520b91f418ab0f2aecb1c371fbe4.tar.gz
git-905f8b7dfc2c520b91f418ab0f2aecb1c371fbe4.tar.xz
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>
-rwxr-xr-xgit-svn.perl91
1 files changed, 63 insertions, 28 deletions
diff --git a/git-svn.perl b/git-svn.perl
index 7ffbf6413..eca08bdd3 100755
--- a/git-svn.perl
+++ b/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);