Browse Source

git-svn: let 'dcommit $rev' work on $rev instead of HEAD

'git svn dcommit' takes an optional revision argument, but the meaning
of it was rather scary.  It completely ignored the current state of
the HEAD, only looking at the revisions between SVN and $rev.  If HEAD
was attached to $branch, the branch lost all commits $rev..$branch in
the process.

Considering that 'git svn dcommit HEAD^' has the intuitive meaning
"dcommit all changes on my branch except the last one", we change the
meaning of the revision argument.  git-svn temporarily checks out $rev
for its work, meaning that

* if a branch is specified, that branch (_not_ the HEAD) is rebased as
  part of the dcommit,

* if some other revision is specified, as in the example, all work
  happens on a detached HEAD and no branch is affected.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>
Acked-by: Eric Wong <normalperson@yhbt.net>
maint
Thomas Rast 16 years ago committed by Eric Wong
parent
commit
5eec27e35f
  1. 5
      Documentation/git-svn.txt
  2. 34
      git-svn.perl
  3. 19
      t/t9100-git-svn-basic.sh

5
Documentation/git-svn.txt

@ -170,8 +170,9 @@ and have no uncommitted changes. @@ -170,8 +170,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.
+

34
git-svn.perl

@ -454,8 +454,22 @@ sub cmd_dcommit { @@ -454,8 +454,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 +555,7 @@ sub cmd_dcommit { @@ -541,7 +555,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 +593,22 @@ sub cmd_dcommit { @@ -579,6 +593,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};
}


19
t/t9100-git-svn-basic.sh

@ -231,6 +231,25 @@ test_expect_success \ @@ -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 &&

Loading…
Cancel
Save