798

I just made a perfectly good commit to the wrong branch. How do I undo the last commit in my master branch and then take those same changes and get them into my upgrade branch?

mikewilliamson
  • 24,303
  • 17
  • 59
  • 90

14 Answers14

1245

If you haven't yet pushed your changes, you can also do a soft reset:

git reset --soft HEAD^

This will revert the commit, but put the committed changes back into your index. Assuming the branches are relatively up-to-date with regard to each other, git will let you do a checkout into the other branch, whereupon you can simply commit:

git checkout branch
git commit -c ORIG_HEAD

The -c ORIG_HEAD part is useful to not type commit message again.

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
Blair Holloway
  • 15,969
  • 2
  • 29
  • 28
  • 16
    note that the soft reset leaves your changes staged and ready to commit. made me a little confused when my IDE didn't show the files return to the modified state after soft reset. – mtjhax Jan 24 '12 at 17:46
  • 16
    perfect fix, actually had a couple commits so did HEAD^^ and bam all is gravy – pablo Jan 27 '12 at 17:58
  • 9
    Thanks. This has saved me twice. If the branches are somewhat different, after the reset and before the checkout you may have to stash your changes before you can checkout another branch. Reapply the stash after checkout – Kirby Jul 16 '12 at 22:01
  • 27
    zsh users: you might find you need to escape the ^ like so: `git reset --soft HEAD\^` – Stephen Fuhry Dec 11 '12 at 15:41
  • 76
    If you get a More? in your Windows command line, use quotes to surround HEAD^ like so: git reset --soft "HEAD^" – Nate Cook Apr 29 '13 at 19:48
  • 3
    I had another issue when trying to switch branches after the reset where Git said this: "your local changes to the following files would be overwritten by checkout..." so I had to stash, switches branches and then pop. – Kelly Jul 10 '14 at 19:21
  • 1
    This version: https://github.com/blog/2019-how-to-undo-almost-anything-with-git#once-more-with-branching is definitely cooler. (and the page is a **magic** reference!) – caesarsol Oct 29 '15 at 18:46
  • 3
    Just don't forget the ^ guys. That's very important. Without that, well, gods be kind! – roopunk Jun 22 '16 at 09:10
  • 1
    To do this in two commands without re-entering the commit you can simply `git branch topic-name && git reset --hard HEAD^`. In fact you can use variants of that to *always* work on master and then branch retroactively if you need to do a hotfix or something. – gtd Jun 03 '17 at 21:57
  • In windows add an extra caret: `git reset --soft HEAD^^` – Marc Dec 01 '17 at 13:24
  • 1
    Actually you don't need to re-enter the commit message, just use `git commit -c ORIG_HEAD` – Łukasz Rajchel Dec 06 '18 at 20:49
  • 1
    SourceTree definitely needs this feature rather than "reverting commit that creates another commit" s*it – schlingel Jul 06 '20 at 07:37
  • 1
    `git reset --soft HEAD^` RUN this for the number times you've commit to the wrong branch before checking out – Toheeb Oct 30 '21 at 21:03
  • This didnt work for me. It left me some commits ahead of master, so I am in a worse situation. Sadly, this solution only works in one specific, case, if you have only made one commit. If you have made more, its not a solution. – John Little Jan 31 '22 at 22:56
213

4 years late on the topic, but this might be helpful to someone.

If you forgot to create a new branch before committing and committed all on master, no matter how many commits you did, the following approach is easier:

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

Now you have your master branch equals to origin/master and all new commits are on my_feature. Note that my_feature is a local branch, not a remote one.

Trenton
  • 11,678
  • 10
  • 56
  • 60
fotanus
  • 19,618
  • 13
  • 77
  • 111
  • Thanks for the answer. Now I'm using egit and I'm wondering if I can accomplish the same thing by doing the following: 1) Rename current 'master' to 'my_feature'. 2) Recreate local 'master' from 'origin/master'. I'm not sure what egit is doing under the hood for these operations but this seems to be a viable solution – mjj1409 Oct 30 '14 at 16:03
  • 1
    why the merge? you could create the branch directly on `master`, then reset `master` to `origin/master`. – caesarsol Oct 29 '15 at 18:41
  • @caesarsol this is a good tip, however then I'm not sure how to see the number of commits? The way I describe is an algorithm to do it, no matter the current state. – fotanus Oct 29 '15 at 20:22
  • 1
    That's the most interesting part: you don't need a number of commit, because `origin/master` is already on the commit you want to reset at! The credit for the tip is however this page: https://github.com/blog/2019-how-to-undo-almost-anything-with-git#once-more-with-branching – caesarsol Nov 02 '15 at 18:23
  • 6
    This should be the accepted answer. Simple, obvious, straightforward, works regardless of number of commits and only using basic Git functionality. I did these steps with TortoiseGit. Thanks! :) – Ian Grainger Feb 11 '16 at 14:13
  • 1
    I thought this was the best answer, but it has a limitation. It only helps if you recently pulled from remote. And it assumes you have a remote to start with. If you only have local branches "master" and your new feature fix, the only right answer is a reset hard on master counting back a certain number of commits. – pauljohn32 Mar 05 '18 at 22:44
  • @fotanus You are my hero of the day. Thanks so much. It's such an obvious solution, but I needed your answer to understand it. Thanks. @pauljohn32 I think you can very well `git reset --hard {commit-sha-of-the-latest-valid-commit-to-master}` if you don't have a remote master. – Thomas Praxl Mar 10 '18 at 10:43
  • 2
    The reset in this example didn't restore my changes, had to find them in reflog and then merge them in my new branch.  Why? Dunno. – Gringo Suave Sep 11 '18 at 17:10
  • I think checkout branch should be done before git reset, otherwise the commit is lost. – Vikas Pandey Aug 31 '20 at 21:40
  • 2
    @GringoSuave you probably, like I did, used `git checkout -b my_feature` and your HEAD now is at my_feature branch. I corrected this by going back to master and actually did `git branch my_feature` which from the man page will create a new branch but not switch to it but rather stay in the working tree. When not specifying a start point for this command `git branch my_feature []` it creates creates my_feature branch to the current HEAD (which was the one you committed to) - this is the default. – mikemols Dec 01 '20 at 13:26
118

If you have a clean (un-modified) working copy

To rollback one commit (make sure you note the commit's hash for the next step):

git reset --hard HEAD^

To pull that commit into a different branch:

git checkout other-branch
git cherry-pick COMMIT-HASH

If you have modified or untracked changes

Also note that git reset --hard will kill any untracked and modified changes you might have, so if you have those you might prefer:

git reset HEAD^
git checkout .
Michael Mrozek
  • 169,610
  • 28
  • 168
  • 175
  • `git rev-parse BRANCH_NAME` to get the sha. – wilhelmtell May 31 '10 at 05:51
  • 12
    If you forget to note the hash first, just use `git reflog show `! – Cascabel May 31 '10 at 12:21
  • 15
    For an extra secure feeling, perform the cherry-pick first on the correct branch and only then reset the wrong branch. – Age Mooij Dec 27 '11 at 22:54
  • 1
    Also in case of untracked changes, one can `git stash` before the reset and use `git stash pop` afterwards to restore them, so no need to be afraid of the `--hard` part – Clemens Klein-Robbenhaar Dec 12 '13 at 16:07
  • To summarise: Create a new branch from master. Cherry pick the commits (by hash ID) into your new branch. Voila. That is my first cherry pick after using Git for years (basic user alert!). – kevinarpe Apr 15 '21 at 01:16
24

If you already pushed your changes, you will need to force your next push after resetting the HEAD.

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

Warning: a hard reset will undo any uncommitted modifications in your working copy, while a force push will completely overwrite the state of the remote branch with the current state of the local branch.

Just in case, on Windows (using the Windows command line, not Bash) it's actually four ^^^^ instead of one, so it's

git reset --hard HEAD^^^^
Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128
  • 6
    Note that you should *not* force-push to a branch that other people are using unless absolutely necessary - otherwise they will be unable to push until they rebase. If you're the sole developer using git, however, this is fine. – Blair Holloway May 31 '10 at 06:29
  • 2
    Or unless you realize quickly enough before anyone else has pulled the erroneous commits. – Michael Mior May 12 '11 at 15:30
  • 1
    If your more than one commit off, you can specify the commit you need: `git reset --hard COMMIT_HASH` `git push --force` – David Cramblett Dec 18 '12 at 22:37
21

I recently did the same thing, where I accidentally committed a change to master, when I should have committed to other-branch. But I didn't push anything.

If you just committed to the wrong branch, and have not changed anything since, and have not pushed to the repo, then you can do the following:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

NOTE: in the above example, I was rewinding 1 commit with git reset HEAD~1. But if you wanted to rewind n commits, then you can do git reset HEAD~n.

Also, if you ended up committing to the wrong branch, and also ended up write some more code before realizing that you committed to the wrong branch, then you could use git stash to save your in-progress work:

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

NOTE: I used this website as a reference https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/

SomeGuy
  • 1,702
  • 1
  • 20
  • 19
  • Similar thing happened to me, I committed a few changes in master, but I should have done in new branch and send PR, I ended up just doing a `git checkout -b new_branch` right from there, commits were intact, just pushed, and created a PR, didn't have to commit again. –  Jun 08 '17 at 05:46
14

For multiple commits on the wrong branch

If, for you, it is just about 1 commit, then there are plenty of other easier resetting solutions available. For me, I had about 10 commits that I'd accidentally created on master branch instead of, let's call it target, and I did not want to lose the commit history.

What you could do, and what saved me was using this answer as a reference, using a 4 step process, which is:

  1. Create a new temporary branch temp from master
  2. Merge temp into the branch originally intended for commits, i.e. target
  3. Undo commits on master
  4. Delete the temporary branch temp.

Here are the above steps in details:

  1. Create a new branch from the master (where I had accidentally committed a lot of changes)

    git checkout -b temp
    

    Note: -b flag is used to create a new branch
    Just to verify if we got this right, I'd do a quick git branch to make sure we are on the temp branch and a git log to check if we got the commits right.

  2. Merge the temporary branch into the branch originally intended for the commits, i.e. target.
    First, switch to the original branch i.e. target (You might need to git fetch if you haven't)

    git checkout target
    

    Note: Not using -b flag
    Now, let's merge the temporary branch into the branch we have currently checkout out target

    git merge temp
    

    You might have to take care of some conflicts here, if there are. You can push (I would) or move on to the next steps, after successfully merging.

  3. Undo the accidental commits on master using this answer as reference, first switch to the master

    git checkout master
    

    then undo it all the way back to match the remote using the command below (or to particular commit, using appropriate command, if you want)

    git reset --hard origin/master
    

    Again, I'd do a git log before and after just to make sure that the intended changes took effect.

  4. Erasing the evidence, that is deleting the temporary branch. For this, first you need to checkout the branch that the temp was merged into, i.e. target (If you stay on master and execute the command below, you might get a error: The branch 'temp' is not fully merged), so let's

    git checkout target
    

    and then delete the proof of this mishap

    git branch -d temp
    
Cadoiz
  • 1,446
  • 21
  • 31
Mitali Cyrus
  • 446
  • 4
  • 12
13

So if your scenario is that you've committed to master but meant to commit to another-branch (which may or not may not already exist) but you haven't pushed yet, this is pretty easy to fix.

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

Now all your commits to master will be on another-branch.

Sourced with love from: http://haacked.com/archive/2015/06/29/git-migrate/

Lorcan O'Neill
  • 3,303
  • 1
  • 25
  • 24
  • seems to be the most straightforward approach! Not sure why so little love and upwotes – keligijus Aug 06 '18 at 13:41
  • 5
    This didn't seem to work for me. `another-branch` already existed. In this case, it just nuked the commits I'd made to master and didn't put them on `another-branch`. – Giselle Serate Dec 30 '18 at 01:45
9

To elaborate on this answer, in case you have multiple commits to move from, e.g. develop to new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started
arsenius
  • 12,090
  • 7
  • 58
  • 76
  • 1
    I had three commits to revert, and this question appears to have pulled my ass out of the fire. Thanks! – holdenweb Nov 21 '18 at 16:23
4

If you run into this issue and you have Visual Studio, you can do the following:

Right-click on your branch and select View History:

enter image description here

Right-click on commit you want to go back to. And Revert or Reset as needed.

enter image description here

Trevor
  • 4,620
  • 2
  • 28
  • 37
3

In the common case where you forgot to switch from master to your feature branch before commiting:

git checkout -B feature
git branch -f master origin/master

Replace origin/master with the commit you want your master branch to point to. For example, use HEAD~3 if you want it to point 3 commits behind HEAD, or a1b2c3d if you want it to point to the commit with that hash.

The idea is to recreate the feature branch on the current commit and switch to it. Then make the master branch point to the same commit as origin/master.

General case

In the general case where you want to replay the commits done on master on your feature branch, like the following diagram:

A---B---C---D  $old_master                   A---B---C---D  master
    |        \                                   |        \
    |         G---H---I  master <- HEAD  =>      |         G---H---I
    |                                            | 
    `-E---F  feature                             `-E---F---G'--H'--I' feature <- HEAD

Then cherry-pick the commits you made on master on your feature branch using the following commands. Replace $old_master by the hash of the commit master was pointing to before you made your changes.

git checkout feature
git cherry-pick $old_master..master
git branch -f master $old_master

If needed, stash your local changes using git stash --include-untracked, and then unstash them later using git stash pop.

Without rewriting history

Instead of resetting the master branch into the past, you need to git revert the changes, in addition to cherry-picking the changes on the feature branch.

git checkout feature
git cherry-pick $old_master..master
git checkout master
git revert $old_master..
git checkout feature

Make sure not to git merge your commits into feature. Those changes will be ignored if you try to merge your feature branch back into master, because we just reverted them.

Here's what the result would look like, with rG, rH and rI the revert commits of G, H and I respectively:

A---B---C---D             rG--rH--rI  master
    |        \           /
    |         G---H---I-`
    | 
    `-E---F---G'--H'--I' feature <- HEAD
tqdv
  • 114
  • 1
  • 6
2

For me, this was solved by reverting the commit I had pushed, then cherry-picking that commit to the other branch.

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

You can use git log to find the correct hash, and you can push these changes whenever you like!

arr0nax
  • 21
  • 1
1

If the branch you wanted to apply your changes to already exists (branch develop, for example), follow the instructions that were provided by fotanus below, then:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

And obviously you could use tempbranch or any other branch name instead of my_feature if you wanted.

Also, if applicable, delay the stash pop (apply) until after you've merged at your target branch.

Community
  • 1
  • 1
fbicknel
  • 1,219
  • 13
  • 21
  • I think the first command (checkout develop) is unnecessary... the rebase will just checkout "my_feature" as the first thing it does. – JoelFan Feb 23 '17 at 01:07
  • Also you can leave out the "my_feature" parameter of the "rebase" command (since you already have checked out "my_feature"). you can also leave out the "develop" parameter of the "merge" (since you already checkout out "develop") – JoelFan Feb 23 '17 at 01:10
1

Keep changes and Uncommit The simple solution is to run this command.

git reset HEAD^

This will uncommit the code, while keeping your changes

0

For this, I had made about 6 commits to the wrong branch and pushed them to the remote before noticing. I followed these steps and they helped:

  1. I did a git log to view the commits I had made with:

     git log --oneline
    
  2. From the list of previous commits and push, I chose the commit that I needed to make the head ie the first commit with the "head" title in the list as it represents the whole list of new commits you made. Save the id. ![example of my code](here I demonstrate the list of commits and the one I chose. The top one as it was the head of my last commits)

  3. Then I reset this branch back to the 6 commits before using;

     git reset --hard HEAD~6
    
  4. I checkout to the new branch I intend to put the commits I had mistakenly commited;

     git checkout -b newbranch
    
  5. Use

     git reset --hard < commit_id > 
    

to bring the entire list of commits to your new branch.

  1. Then use

     git push --force 
    

to make all these changes to your remote repo as well