views:

145

answers:

2

I made a bunch of commits to the master and realized after the fact that they should have been in a branch.

I've looked at various things about rebasing and merging and resetting the master. But no attempts at manipulation have yielded a history that looks like what I'm trying to do.

My attempts lead me to believe it requires some combination of rebase --onto and reset --hard to move the master back in time. But my understanding of Git's branching leaves something to be desired. Part of doing this is to learn how I can use it.

Should be noted none of the changes that I'm trying to move have been pushed out.

Current

  * remote/trunk
--o--a--b--c--d--e--f     <- master
  |
  o                       <- remote branch foo

Desired Outcome

  * remote/trunk
--o                       <- master
  |
  o--a--b--c--d--e--f     <- remote branch foo
+1  A: 

A variation on Martin's answer that won't necessarily be applicable to your situation, but I wanna post it anyway :)

Suppose you forgot to create the branch at commit o, so you have:

x--y--z--o--a--b--c--d--e--f  master
         |
         +
   [forgot to make a branch here]

And then you realized that what you really wanted was:

x--y--z--o   master
         |
         +--a--b--c--d--e--f  topic

What you can do in this case is create a branch at o using it's hash:

git branch topic # topic will be at commit `f`
git checkout o -b newmaster # replace `o` with the actual hash
git branch -M newmaster master # force rename newmaster to master

You'll be at the master branch (commit o), so as a last step you can git checkout topic

The hash of course can be just the first 5 characters ..

EDIT

It shouldn't matter much that you're using git-svn, what really matters is that you haven't published your master branch at any point after o

A branch in git is really nothing but a pointer to a commit. That's why branching is so cheap: you just create a pointer, and you have a branch.

I don't know about tracking remote branches though, you might need to set that up after renaming/moving your branches.

hasen j
Does it matter much in either situation that I'm using git-svn? I am under the impression are certain (branch/merge related) behaviors in Git that really shouldn't be done to a Subversion backed repository.
Danny
+1  A: 

I am not sure renaming the branches is the right solution, since it would get you from:

  * remote/trunk
--M--a--b--c--d--e--f     <- master
  |
  F                       <- remote branch foo

to:

--F                       <- master
  |
  M--a--b--c--d--e--f     <- remote branch foo
  * remote/trunk

(provided you rename remote/foo, which is not advisable: you should track it first, and then rename it, but even though the end result differ from what you need)

which is not the "Desired Outcome" you want (foo needs to start from F, not M):

  * remote/trunk
--M                       <- master
  |
  F--a--b--c--d--e--f     <- remote branch foo

You can only achieve that through a rebase --onto

git checkout --track -b origin/foo  # create a local branch named after the remote one
git branch tmp                      # mark current foo HEAD to 'F'
git branch -f foo master            # put foo where it should b: at 'f'
git branch -f master tmp^           # reset master to M, parent of tmp
git checkout tmp                    # go to where we must replay the commits
git rebase --onto tmp master foo    # replay a to f on top of tmp
git svn dcommit                     # push the local foo in order to update remote/foo

giving you:

  * remote/trunk
--M                             <- master
  |
  F--a'--b'--c'--d'--e'--f'     <- local foo and remote branch foo
VonC