Skip to content

Commit 5eec27e

Browse files
trastEric Wong
authored andcommitted
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 <[email protected]> Acked-by: Eric Wong <[email protected]>
1 parent 916e137 commit 5eec27e

File tree

3 files changed

+54
-4
lines changed

3 files changed

+54
-4
lines changed

Documentation/git-svn.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ and have no uncommitted changes.
170170
It is recommended that you run 'git-svn' fetch and rebase (not
171171
pull or merge) your commits against the latest changes in the
172172
SVN repository.
173-
An optional command-line argument may be specified as an
174-
alternative to HEAD.
173+
An optional revision or branch argument may be specified, and
174+
causes 'git-svn' to do all work on that revision/branch
175+
instead of HEAD.
175176
This is advantageous over 'set-tree' (below) because it produces
176177
cleaner, more linear history.
177178
+

git-svn.perl

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,22 @@ sub cmd_dcommit {
454454
'Cannot dcommit with a dirty index. Commit your changes first, '
455455
. "or stash them with `git stash'.\n";
456456
$head ||= 'HEAD';
457+
458+
my $old_head;
459+
if ($head ne 'HEAD') {
460+
$old_head = eval {
461+
command_oneline([qw/symbolic-ref -q HEAD/])
462+
};
463+
if ($old_head) {
464+
$old_head =~ s{^refs/heads/}{};
465+
} else {
466+
$old_head = eval { command_oneline(qw/rev-parse HEAD/) };
467+
}
468+
command(['checkout', $head], STDERR => 0);
469+
}
470+
457471
my @refs;
458-
my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
472+
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD', \@refs);
459473
unless ($gs) {
460474
die "Unable to determine upstream SVN information from ",
461475
"$head history.\nPerhaps the repository is empty.";
@@ -541,7 +555,7 @@ sub cmd_dcommit {
541555
if (@diff) {
542556
@refs = ();
543557
my ($url_, $rev_, $uuid_, $gs_) =
544-
working_head_info($head, \@refs);
558+
working_head_info('HEAD', \@refs);
545559
my ($linear_refs_, $parents_) =
546560
linearize_history($gs_, \@refs);
547561
if (scalar(@$linear_refs) !=
@@ -579,6 +593,22 @@ sub cmd_dcommit {
579593
}
580594
}
581595
}
596+
597+
if ($old_head) {
598+
my $new_head = command_oneline(qw/rev-parse HEAD/);
599+
my $new_is_symbolic = eval {
600+
command_oneline(qw/symbolic-ref -q HEAD/);
601+
};
602+
if ($new_is_symbolic) {
603+
print "dcommitted the branch ", $head, "\n";
604+
} else {
605+
print "dcommitted on a detached HEAD because you gave ",
606+
"a revision argument.\n",
607+
"The rewritten commit is: ", $new_head, "\n";
608+
}
609+
command(['checkout', $old_head], STDERR => 0);
610+
}
611+
582612
unlink $gs->{index};
583613
}
584614

t/t9100-git-svn-basic.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,25 @@ test_expect_success \
231231
"^:refs/${remotes_git_svn}$"
232232
'
233233

234+
test_expect_success 'dcommit $rev does not clobber current branch' '
235+
git svn fetch -i bar &&
236+
git checkout -b my-bar refs/remotes/bar &&
237+
echo 1 > foo &&
238+
git add foo &&
239+
git commit -m "change 1" &&
240+
echo 2 > foo &&
241+
git add foo &&
242+
git commit -m "change 2" &&
243+
old_head=$(git rev-parse HEAD) &&
244+
git svn dcommit -i bar HEAD^ &&
245+
test $old_head = $(git rev-parse HEAD) &&
246+
test refs/heads/my-bar = $(git symbolic-ref HEAD) &&
247+
git log refs/remotes/bar | grep "change 1" &&
248+
! git log refs/remotes/bar | grep "change 2" &&
249+
git checkout master &&
250+
git branch -D my-bar
251+
'
252+
234253
test_expect_success 'able to dcommit to a subdirectory' "
235254
git svn fetch -i bar &&
236255
git checkout -b my-bar refs/remotes/bar &&

0 commit comments

Comments
 (0)