Git Course 0%

Wrong branch: committed or pushed to the wrong place

Advanced ≈ 10 min

What you will learn

  • The standard fix for "I committed to main
  • How to move uncommitted work to the right branch
  • How to copy a commit to another branch with cherry-pick

After this lesson you can

  • I can move work to the branch it belongs on, before or after pushing

Why this matters

Committing to main is the most common Git mistake there is, and it happens to everyone who works on more than one thing at once. It is completely recoverable, in two commands, provided you have not pushed.

Case 1: committed to main, not pushed

This is the standard fix, and it is worth memorising as a pair.

Fixing a commit made on the wrong branch Before: main has three commits and a fourth, the Windows steps commit, was made on main by mistake, with the remote origin/main still at the third commit. The fix is two steps. Step one, git branch docs/12-windows-install-steps, which gives the commit a branch name without moving anything else. Step two, git reset --hard origin/main, which moves main back to match the remote. After: main matches origin/main again and the Windows steps commit lives on its own branch, ready to be pushed and turned into a merge request. A caption notes this works only because the commit had not been pushed. Before: the commit is on main by mistake A B C D origin/main main (HEAD) D is the Windows steps commit, made on main and not pushed. 1. Name the commit git branch docs/12-windows-install-steps 2. Move main back git reset --hard origin/main After: main matches the remote, the work has its own branch A B C D main = origin/main docs/12-windows-install-steps push it and open a merge request This works because D was never pushed. If it had been, the fix is git revert on main and a cherry-pick onto the branch.
Name the commit with a branch, then move main back to match the remote.

You notice the problem in git status:

Terminal
$ git status -sb
## main...origin/main [ahead 1]
Terminal
$ git log --oneline -2
95a0014 docs: add Windows steps to installation guide (#12)
d3b92ec chore: add CI configuration and contributing guide

Ahead by one, and that one should have been on a branch. Two commands:

Terminal
$ git branch docs/12-windows-install-steps
$ git reset --hard origin/main
HEAD is now at d3b92ec chore: add CI configuration and contributing guide

The first gives the commit a name without switching to it, so nothing moves. The second moves main back to match the remote. Confirm:

Terminal
$ git log --oneline -1
d3b92ec chore: add CI configuration and contributing guide
Terminal
$ git log --oneline -1 docs/12-windows-install-steps
95a0014 docs: add Windows steps to installation guide (#12)

main is clean and the work is on its branch, ready to be pushed and turned into a merge request. Then git switch docs/12-windows-install-steps and carry on.

For several commits, the shape is identical: git branch <name> then git reset --hard origin/main moves all of them, because the branch you just created points at the newest one and takes the whole chain with it.

Case 2: uncommitted work on the wrong branch

Nothing has been committed, so nothing needs undoing. Move the work:

Terminal
$ git stash
$ git switch -c docs/faq-tidy
$ git stash pop
 M docs/faq.md

Your edits are now on the new branch. If the target branch already exists, drop the -c.

There is an even shorter version when the branches share the same starting point: git switch -c <name> on its own carries uncommitted changes with it, because switching does not touch modified files unless it has to. The stash version always works, so it is the one to remember.

Case 3: the commit is on the wrong branch and belongs on another

git cherry-pick copies a commit onto the branch you are on:

Terminal
$ git switch release/1.2
$ git cherry-pick 95a0014
[release/1.2 83d3709] docs: add Windows steps to installation guide (#12)
 1 file changed, 4 insertions(+)

Note the new hash: cherry-pick creates a copy, it does not move anything. The original commit is still on its original branch, which is why the second half of the job is removing it there, with a reset if it is unpushed or a revert if it is not.

This is also how backports work: a fix lands on main and is cherry-picked onto a release branch (lesson 13.5).

Case 4: already pushed to the wrong branch

Once it is on the server, rewriting is off the table unless the branch is yours alone (lesson 12.8). The safe sequence has three steps:

  1. Cherry-pick the commit onto the branch it should be on, and push that branch.
  2. Revert it on the branch it should not be on: git revert <hash>, then push.
  3. Say so in the merge request or the team channel, because for a few minutes the history contained something unexpected and someone may have pulled it.

If the wrong branch was main and it is protected, step 2 is a merge request like any other, which is exactly what protection is for.

Case 5: pushed to a protected branch and were refused

Nothing is broken. The push was rejected, so the commit is still only in your clone:

Output
remote: GitLab: You are not allowed to push code to protected branches on this project.

Apply case 1: name the commit with a branch, reset main, push the branch. The rejection did the work of catching the mistake.

How to do it

The two-command fix, and the stash version:

Terminal
$ git branch <new-branch>        # name the commit where it is
$ git reset --hard origin/main   # move main back
Terminal
$ git stash                      # uncommitted work
$ git switch -c <new-branch>
$ git stash pop

Common mistakes

  • git switch -c <name> first, then wondering how to remove the commit from main. Creating the branch first, while still on main, is what makes the fix two commands.
  • git reset --hard with uncommitted work. Stash first.
  • Resetting a branch that was already pushed, which then needs a force push.
  • Cherry-picking and forgetting to remove the original, leaving the same change on two branches with different hashes.
  • Panicking about a rejected push. A rejection means nothing happened, which is the good outcome.

Try it yourself

Goal: commit to main on purpose and fix it.

  1. On your practice repository with main tracking origin/main, make a change and commit it to main.
  2. Run git status -sb and see [ahead 1].
  3. Run git branch fix/wrong-branch-demo, then git reset --hard origin/main.
  4. Confirm with git log --oneline -1 on both main and the new branch.
  5. git switch fix/wrong-branch-demo, push it, and open a merge request as usual.
  6. Repeat with uncommitted work, using the stash version.

Expected result: main matches the remote, the commit is on its own branch, and you have done the fix once before you need it in earnest.

Show solution

The order in step 3 is the entire trick, and it is worth saying why: git branch <name> creates a name at the current commit without switching to it, so main and the new branch briefly point at the same commit. The reset then moves only main, leaving the new branch where it was.

Check yourself

1. You committed to main and have not pushed. What is the two-command fix?
2. What does git cherry-pick <hash> do?
3. Your push to a protected main was rejected. What does that mean?

Key terms

Branch main Stash Protected branch