Little Git Tricks: Move the Most Recent Commits to a New Branch

Does this situation sound familiar? You start with a simple change and after a few commits you notice that the change is a lot bigger than expected. It will be so big that the code better has its own feature branch. But how do we get our commits from the main branch to a new feature branch?

As long as you did not push your changes to the central repository, you can fix this problem with a few Git commands.

Make sure that all your work is committed before you continue! Otherwise, you may lose your uncommitted work.

Given we have the 4 commits A, B, C, and D:

A Git commit graph with an initial commit and the commits A, B, C, and D

We can use the following commands to create a new branch and move the main branch 3 commits back to commit A:

git branch newbranch      # Create a new branch to save your commits
git checkout main         # Checkout the branch you want to move back
git reset --hard HEAD~3   # Move main back by 3 commits
git checkout newbranch    # Continue work on the new branch 

Let us look what the different commits do and how everything works.

First, we need to create the new branch. That will protect our already committed changes and allows us to continue our work in a feature branch. If we forget that step, our commits will no longer be reachable, and it gets tricky to get them back:

git branch newbranch

This command created the branch newbranch at commit D:

The main and the newbranch point to commit D.

Make sure that you are still on the main branch:

git checkout main 

Second, we need to figure out by how many commits we want to move our main branch back. In our case it is 3 commits we need to go back from commit D to commit A. We can now tell Git to move our current branch (master) back by these 3 commits:

git reset --hard HEAD~3

The main branch now points to commit A, while newbranch still points to commit D:

The branch main points to commit A, newbranch points to commit D.

As you can see, HEAD moved back with the main branch and our repository now has the files in the state as they were in commit A.

As a final step we switch to newbranch to continue our work with commit D:

git checkout newbranch

Our local repository now has the files from commit D.

The commands from above moved the branch pointer for main from commit D back to commit A. Our newbranch contains all our changes that we want to keep but are not yet ready for our main branch.

I hope this explanation makes it simpler to understand what happens behind the Git commands.