Move commits from one branch to another

Have you ever made a few commits on a branch, only to later realise that you should have been working on a topic branch (i.e. a branch specific to the task you're working on)? So long as you haven't yet shared any of these commits with anybody else, you can easily move them on to a new branch, and then remove them from your current branch.

Making the topic branch

When I decide that I'd be better off working in a topic branch, the first thing I do is commit any outstanding work. It doesn't matter if the tests aren't currently passing; we'll just undo the commit after we've switched branches.

So let's do a "WIP" (Work In Progress) commit and make the branch:

$ git add .
$ git commit -m "WIP"
$ git checkout -b some-feature

You can also make a new branch with the git branch command, but I prefer checkout -b as it also switches you to the new branch immediately (whereas git branch will just make the new branch, leaving you on your current branch).

Your "WIP" commit will now be stored safely at the head of the branch that you were on and also on the new some-feature branch.

Tip: If you're not familiar with branching, you can check that your most recent work is on the new branch before you continue:

$ git log -p some-feature

Removing commits from master

All you need to do now is to switch back to the master branch and remove any work that you'd rather develop on the topic branch. If the work to remove is just your last commit you can use git reset to roll the branch back:

$ git checkout master
$ git reset --hard HEAD^

The --hard option tells git to set the head of the current branch to the commit that you specify, while modifying the files on disk to match the contents of the repository.

The HEAD^ syntax refers to the previous commit to the head of the current branch (i.e. the last commit on the branch), so this will roll us back one commit. You can add extra ^ characters, so HEAD^^^ will throw away three commits.

If you want to go back more than a couple of commits you can use the tilde syntax to save some typing:

  • HEAD~1 is equivalent to HEAD^
  • HEAD~2 is equivalent to HEAD^^
  • HEAD~8 is equivalent to HEAD^^^^^^^^

Note: Be careful with the --hard option to git reset. It isn't something to be afraid of, but you do need to make sure that you've committed all your local changes to another branch before you run it.

Back to work...

Now we can switch back to the topic branch and carry on from where we left off.

$ git checkout some-feature

If you had some work in progress that you saved with a "WIP" commit message you can back that commit out now, without losing the changes (they'll still be on your filesystem). We'll use git reset again, but without the --hard option:

$ git reset HEAD^

All that'll do is to remove the last commit from your repository, without actually changing your files.

And there you are; all the commits that you deleted from master are now on your topic branch.

An insurance policy

Should you make a mistake while you're fiddling around with branches and git reset --hard you could find yourself in a position where you've thrown a bunch of commits away by mistake. It's unlikely but -- let's face it -- could happen. Don't worry, Git has got your back, and you can recover lost commits without too much trouble.

Published on in Git