{"thread":{"id":"19576","subject":"[PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD","startedAt":"2009-05-29T15:09:42Z","lastAt":"2009-06-04T02:45:27Z","messageCount":2,"participants":["Thomas Rast","Eric Wong"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"115017","messageId":"64a802c5249465dc9e39faa480133f501e5d1b59.1243609198.git.trast@student.ethz.ch","threadId":"19576","inReplyTo":null,"subject":"[PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-05-29T15:09:42Z","receivedAt":"2009-05-29T15:09:42Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"'git svn dcommit' takes an optional revision argument, but the meaning\nof it was rather scary.  It completely ignored the current state of\nthe HEAD, only looking at the revisions between SVN and $rev.  If HEAD\nwas attached to $branch, the branch lost all commits $rev..$branch in\nthe process.\n\nConsidering that 'git svn dcommit HEAD^' has the intuitive meaning\n\"dcommit all changes on my branch except the last one\", we change the\nmeaning of the revision argument.  git-svn temporarily checks out $rev\nfor its work, meaning that\n\n* if a branch is specified, that branch (_not_ the HEAD) is rebased as\n  part of the dcommit,\n\n* if some other revision is specified, as in the example, all work\n  happens on a detached HEAD and no branch is affected.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nApologies for the noise.  I immediately wanted to use it on a live\nrepository, but noticed that I forgot to change the mentions of $head,\nSo in the relative case it would look at the wrong history to commit.\nThe interdiff is\n\n  diff --git a/git-svn.perl b/git-svn.perl\n  index 0f94c37..6a5b40e 100755\n  --- a/git-svn.perl\n  +++ b/git-svn.perl\n  @@ -469,7 +469,7 @@\n          }\n   \n          my @refs;\n  -       my ($url, $rev, $uuid, $gs) = working_head_info($head, \\@refs);\n  +       my ($url, $rev, $uuid, $gs) = working_head_info('HEAD', \\@refs);\n          unless ($gs) {\n                  die \"Unable to determine upstream SVN information from \",\n                      \"$head history.\\nPerhaps the repository is empty.\";\n  @@ -555,7 +555,7 @@\n                          if (@diff) {\n                                  @refs = ();\n                                  my ($url_, $rev_, $uuid_, $gs_) =\n  -                                             working_head_info($head, \\@refs);\n  +                                             working_head_info('HEAD', \\@refs);\n                                  my ($linear_refs_, $parents_) =\n                                                linearize_history($gs_, \\@refs);\n                                  if (scalar(@$linear_refs) !=\n\n\nplus a change of the test to verify that indeed the right commits were\ncommitted.\n\n\n Documentation/git-svn.txt |    5 +++--\n git-svn.perl              |   36 +++++++++++++++++++++++++++++++++---\n t/t9100-git-svn-basic.sh  |   19 +++++++++++++++++++\n 3 files changed, 55 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex ca3fc3d..5aa9beb 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -170,8 +170,9 @@ and have no uncommitted changes.\n \tIt is recommended that you run 'git-svn' fetch and rebase (not\n \tpull or merge) your commits against the latest changes in the\n \tSVN repository.\n-\tAn optional command-line argument may be specified as an\n-\talternative to HEAD.\n+\tAn optional revision or branch argument may be specified, and\n+\tcauses 'git-svn' to do all work on that revision/branch\n+\tinstead of HEAD.\n \tThis is advantageous over 'set-tree' (below) because it produces\n \tcleaner, more linear history.\n +\ndiff --git a/git-svn.perl b/git-svn.perl\nindex a70c7d7..6a5b40e 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -447,15 +447,29 @@\n \tprint \"Done committing \",scalar @revs,\" revisions to SVN\\n\";\n \tunlink $gs->{index};\n }\n-\n+#\"\n sub cmd_dcommit {\n \tmy $head = shift;\n \tgit_cmd_try { command_oneline(qw/diff-index --quiet HEAD/) }\n \t\t'Cannot dcommit with a dirty index.  Commit your changes first, '\n \t\t. \"or stash them with `git stash'.\\n\";\n \t$head ||= 'HEAD';\n+\n+\tmy $old_head;\n+\tif ($head ne 'HEAD') {\n+\t\t$old_head = eval {\n+\t\t\tcommand_oneline([qw/symbolic-ref -q HEAD/])\n+\t\t};\n+\t\tif ($old_head) {\n+\t\t\t$old_head =~ s{^refs/heads/}{};\n+\t\t} else {\n+\t\t\t$old_head = eval { command_oneline(qw/rev-parse HEAD/) };\n+\t\t}\n+\t\tcommand(['checkout', $head], STDERR => 0);\n+\t}\n+\n \tmy @refs;\n-\tmy ($url, $rev, $uuid, $gs) = working_head_info($head, \\@refs);\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD', \\@refs);\n \tunless ($gs) {\n \t\tdie \"Unable to determine upstream SVN information from \",\n \t\t    \"$head history.\\nPerhaps the repository is empty.\";\n@@ -541,7 +555,7 @@\n \t\t\tif (@diff) {\n \t\t\t\t@refs = ();\n \t\t\t\tmy ($url_, $rev_, $uuid_, $gs_) =\n-\t\t\t\t              working_head_info($head, \\@refs);\n+\t\t\t\t              working_head_info('HEAD', \\@refs);\n \t\t\t\tmy ($linear_refs_, $parents_) =\n \t\t\t\t              linearize_history($gs_, \\@refs);\n \t\t\t\tif (scalar(@$linear_refs) !=\n@@ -579,6 +593,22 @@\n \t\t\t}\n \t\t}\n \t}\n+\n+\tif ($old_head) {\n+\t\tmy $new_head = command_oneline(qw/rev-parse HEAD/);\n+\t\tmy $new_is_symbolic = eval {\n+\t\t\tcommand_oneline(qw/symbolic-ref -q HEAD/);\n+\t\t};\n+\t\tif ($new_is_symbolic) {\n+\t\t\tprint \"dcommitted the branch \", $head, \"\\n\";\n+\t\t} else {\n+\t\t\tprint \"dcommitted on a detached HEAD because you gave \",\n+\t\t\t      \"a revision argument.\\n\",\n+\t\t\t      \"The rewritten commit is: \", $new_head, \"\\n\";\n+\t\t}\n+\t\tcommand(['checkout', $old_head], STDERR => 0);\n+\t}\n+\n \tunlink $gs->{index};\n }\n \ndiff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh\nindex 64aa7e2..570e035 100755\n--- a/t/t9100-git-svn-basic.sh\n+++ b/t/t9100-git-svn-basic.sh\n@@ -231,6 +231,25 @@ test_expect_success \\\n                               \"^:refs/${remotes_git_svn}$\"\n         '\n \n+test_expect_success 'dcommit $rev does not clobber current branch' '\n+\tgit svn fetch -i bar &&\n+\tgit checkout -b my-bar refs/remotes/bar &&\n+\techo 1 > foo &&\n+\tgit add foo &&\n+\tgit commit -m \"change 1\" &&\n+\techo 2 > foo &&\n+\tgit add foo &&\n+\tgit commit -m \"change 2\" &&\n+\told_head=$(git rev-parse HEAD) &&\n+\tgit svn dcommit -i bar HEAD^ &&\n+\ttest $old_head = $(git rev-parse HEAD) &&\n+\ttest refs/heads/my-bar = $(git symbolic-ref HEAD) &&\n+\tgit log refs/remotes/bar | grep \"change 1\" &&\n+\t! git log refs/remotes/bar | grep \"change 2\" &&\n+\tgit checkout master &&\n+\tgit branch -D my-bar\n+\t'\n+\n test_expect_success 'able to dcommit to a subdirectory' \"\n \tgit svn fetch -i bar &&\n \tgit checkout -b my-bar refs/remotes/bar &&\n-- \n1.6.3.1.286.gcb89e\n"},{"id":"115408","messageId":"20090604024527.GA19622@dcvr.yhbt.net","threadId":"19576","inReplyTo":"64a802c5249465dc9e39faa480133f501e5d1b59.1243609198.git.trast@student.ethz.ch","subject":"Re: [PATCH v2] git-svn: let 'dcommit $rev' work on $rev instead of HEAD","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2009-06-04T02:45:27Z","receivedAt":"2009-06-04T02:45:27Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Thomas Rast <trast@student.ethz.ch> wrote:\n> 'git svn dcommit' takes an optional revision argument, but the meaning\n> of it was rather scary.  It completely ignored the current state of\n> the HEAD, only looking at the revisions between SVN and $rev.  If HEAD\n> was attached to $branch, the branch lost all commits $rev..$branch in\n> the process.\n> \n> Considering that 'git svn dcommit HEAD^' has the intuitive meaning\n> \"dcommit all changes on my branch except the last one\", we change the\n> meaning of the revision argument.  git-svn temporarily checks out $rev\n> for its work, meaning that\n> \n> * if a branch is specified, that branch (_not_ the HEAD) is rebased as\n>   part of the dcommit,\n> \n> * if some other revision is specified, as in the example, all work\n>   happens on a detached HEAD and no branch is affected.\n> \n> Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n\nThanks.  Took me a while to remember why dcommit was was the way it\noriginally was and I couldn't remember for the life of me.\n\nAcked and pushed out to git://git.bogomips.org/git-svn\n\n-- \nEric Wong\n"}]}