git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD
@ 2009-05-29 15:09 Thomas Rast
  2009-06-04  2:45 ` Eric Wong
  0 siblings, 1 reply; 2+ messages in thread
From: Thomas Rast @ 2009-05-29 15:09 UTC (permalink / raw)
  To: git; +Cc: Eric Wong

'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>
---

Apologies for the noise.  I immediately wanted to use it on a live
repository, but noticed that I forgot to change the mentions of $head,
So in the relative case it would look at the wrong history to commit.
The interdiff is

  diff --git a/git-svn.perl b/git-svn.perl
  index 0f94c37..6a5b40e 100755
  --- a/git-svn.perl
  +++ b/git-svn.perl
  @@ -469,7 +469,7 @@
          }
   
          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.";
  @@ -555,7 +555,7 @@
                          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) !=


plus a change of the test to verify that indeed the right commits were
committed.


 Documentation/git-svn.txt |    5 +++--
 git-svn.perl              |   36 +++++++++++++++++++++++++++++++++---
 t/t9100-git-svn-basic.sh  |   19 +++++++++++++++++++
 3 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index ca3fc3d..5aa9beb 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -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.
 +
diff --git a/git-svn.perl b/git-svn.perl
index a70c7d7..6a5b40e 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -447,15 +447,29 @@
 	print "Done committing ",scalar @revs," revisions to SVN\n";
 	unlink $gs->{index};
 }
-
+#"
 sub cmd_dcommit {
 	my $head = shift;
 	git_cmd_try { command_oneline(qw/diff-index --quiet HEAD/) }
 		'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 @@
 			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 @@
 			}
 		}
 	}
+
+	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};
 }
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 64aa7e2..570e035 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -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 &&
-- 
1.6.3.1.286.gcb89e

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD
  2009-05-29 15:09 [PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD Thomas Rast
@ 2009-06-04  2:45 ` Eric Wong
  0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2009-06-04  2:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Thomas Rast

Thomas Rast <trast@student.ethz.ch> wrote:
> '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>

Thanks.  Took me a while to remember why dcommit was was the way it
originally was and I couldn't remember for the life of me.

Acked and pushed out to git://git.bogomips.org/git-svn

-- 
Eric Wong

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-06-04  2:54 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-29 15:09 [PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD Thomas Rast
2009-06-04  2:45 ` Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).