Eudis Duran
Eudis Duran

Reputation: 782

A git-svn checkout peculiarity

My git-svn work flow is as follows:

Production code goes in master, off which I do my git svn dcommits/rebase. I work on feature/topic branches, and continue to rebase -i to master and merge until I'm ready to bring those into master and subsequently push to svn trunk using dcommit.

I can usually do git checkout - to checkout the previous branch I was on.

For some reason though, when I do git svn rebase, and then try to git checkout to my previous branch, it does not work (it just stays in master). That is, lets say I do:

(master)$ git checkout -b my-feature-branch

I do some work on that branch, then commit

(my-feature-branch)$ git commit -am "Some work"

I then want to bring in the latest changes, and the quickly change back to my branch:

(my-feature-branch)$ git checkout master
(master)$ git svn rebase

This brings in the latest svn trunk changes into master. Now I just want to quickly change back to my topic branch.

(master)$ git checkout -

At this point, the branch checkout stays as master. I'm guessing some sort of operation is popping off the last branch I worked on, but I don't know about the internals to know this for sure.

So my question is, does anyone know why this is?

Upvotes: 2

Views: 144

Answers (2)

larsks
larsks

Reputation: 311635

When you run git checkout -, git consults the file .git/logs/HEAD to find the last branch that you checked out.

When you run git svn rebase, this triggers the cmd_rebase function in the git-svn command, which in turns calls:

command_noisy(rebase_cmd(), $gs->refname);

This calls rebase_cmd, which looks like this:

sub rebase_cmd {
        my @cmd = qw/rebase/;
        push @cmd, '-v' if $_verbose;
        push @cmd, qw/--merge/ if $_merge;
        push @cmd, "--strategy=$_strategy" if $_strategy;
        push @cmd, "--preserve-merges" if $_preserve_merges;
        @cmd;
}

So the git command line built by this chain looks something like:

git rebase $gs->refname

(where $gs->refname would be substitute with a branch name.) And from the git-rebase man page:

If <branch> is specified, git rebase will perform an automatic git checkout before doing anything else. Otherwise it remains on the current branch.

Since the rebase command specifies a branch name, rebase performs a checkout, which appends an entry to .git/logs/HEAD even if you are already on that branch. This is why the target of git checkout - is not what you expect after running git svn rebase.

UPDATE I may be wrong about why rebase is performing the checkout, but if you examine .git/logs/HEAD you can see clearly that rebase is performing (multiple) checkouts. For example, if I have a branch master and a branch b1 (descended from master), and then do:

git checkout master
git rebase b1

I end up with the following in the the log:

6240c11... c4bfd14... Lars Kellogg-Stedman <[email protected]> 
  1352952244 -0500  checkout: moving from b1 to master
c4bfd14... 6240c11... Lars Kellogg-Stedman <[email protected]> 
  1352952260 -0500  checkout: moving from master to 6240c1154706c675d19d771ad36aebc2658a5df8^0
6240c11... 6240c11... Lars Kellogg-Stedman <[email protected]> 
  1352952260 -0500  rebase finished: returning to refs/heads/master

Upvotes: 1

Tom Panning
Tom Panning

Reputation: 4772

This actually doesn't seem to have anything to do with git-svn, and is just a side-effect of rebasing in git. A git rebase seems to imply re-checking out the current branch. To prove this to your self, use the following commands:

$ git checkout master
$ git checkout HEAD~1
 # A bunch of stuff about being in detached HEAD mode.
$ git checkout -b foo
$ git rebase master
$ git checkout -
 Already on 'foo'

This is because git rebase detaches HEAD using git checkout -q "$onto^0". If you check .git/logs/HEAD after running the above commands, you'll see entries that state "moving from foo to 876AF98", followed by "rebase finished: returning to refs/heads/foo".

Upvotes: 1

Related Questions