941

Is there a way to revert a commit so that my local copy keeps the changes made in that commit, but they become non-committed changes in my working copy? Rolling back a commit takes you to the previous commit - I want to keep the changes made but I committed them to the wrong branch.

This has not been pushed, only committed.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • 3
    possible duplicate of [Can you explain what "git reset" does in plain english?](http://stackoverflow.com/questions/2530060/can-you-explain-what-git-reset-does-in-plain-english) – CodeFanatic Nov 08 '13 at 12:55
  • 9
    `git reset --soft` and `git reset --mixed` both do this (a bit differently), see [git-reset](https://www.kernel.org/pub/software/scm/git/docs/git-reset.html) – torek Nov 08 '13 at 12:55

9 Answers9

1601

There are a lot of ways to do so, for example:

in case you have not pushed the commit publicly yet:

git reset HEAD~1 --soft   

That's it, your commit changes will be in your working directory, whereas the LAST commit will be removed from your current branch. See git reset man


In case you did push publicly (on a branch called 'master'):

git checkout -b MyCommit //save your commit in a separate branch just in case (so you don't have to dig it from reflog in case you screw up :) )

revert commit normally and push

git checkout master
git revert a8172f36 #hash of the commit you want to destroy
# this introduces a new commit (say, it's hash is 86b48ba) which removes changes, introduced in the commit in question (but those changes are still visible in the history)
git push origin master

now if you want to have those changes as you local changes in your working copy ("so that your local copy keeps the changes made in that commit") - just revert the revert commit with --no-commit option:

git revert --no-commit 86b48ba (hash of the revert commit).

I've crafted a small example: https://github.com/Isantipov/git-revert/commits/master

James Stone
  • 118
  • 1
  • 7
Isantipov
  • 19,491
  • 2
  • 26
  • 41
  • 13
    thank you so much, in my case I had two commits I wanted to cancel, and running 'git reset HEAD~1 --soft' twice in a row got me to where I needed to be. – Geoff Gunter Jan 15 '15 at 17:48
  • 2
    to add a little clarity for if you aren't using CLI, the first `reset` command mentioned is saying "softly" reset to 1 rev prior to the head, which preserves all local changes. this was not immediately evident to me for use in SourceTree. just make sure that you are soft resetting to the previous rev, not the rev you're attempting to reset – Jon B Oct 09 '15 at 00:22
  • I had two local commits, which I wanted to remove without losing changes. I did 'git reset HEAD~2' without --soft and it did work correctly as expected. – Sanjay Bharwani Oct 15 '15 at 06:58
  • Using SmartGit for local commit you can use the GUI: from the Local menu choose "Undo last commit". Repeat the command for multiple local commit undo. – 8znr Jun 29 '17 at 15:46
  • 1
    I tried the "already pushed" approach and it doesn't work for me, with git 2.14.1: it says `"Already up to date"` when doing the merge. – Fabio A. Jan 26 '18 at 11:30
  • @FabioA. my bad, there's an error in "already pushed" approach, will update, tahnks for noticing – Isantipov Jan 26 '18 at 11:57
  • 1
    @FabioA. , I've updated the answer with a working version. Thanks for noticing this! – Isantipov Feb 04 '18 at 00:16
  • 2
    This doesn't work. I skipped reset and commit and only did the git revert and push out... now maybe changes lost not sure yet... fortunately I made a backup the easy way hopefully that one will still work ;) otherwise can copy changes from that one. – oOo Jul 12 '18 at 13:22
  • general comment: these charts might help understands what's going on with different git commands https://www.quora.com/What-is-the-best-Git-cheat-sheet – jjrr Aug 28 '18 at 14:25
  • "In case you did push publicly (on a branch called 'master')" ...and the peasants are just outside your gate waving torches, rakes and pitchforks, ... – Russ Bateman Mar 28 '19 at 20:45
  • 2
    What if the repo only has a single commit that's not been pushed? Then `git reset HEAD~1 --soft` gives the error `ambiguous argument 'HEAD~1': unknown revision or path not in the working tree` – hertzsprung Mar 30 '20 at 16:13
  • If you have multiple unpushed commits say like 2 incase of mine, you can give the command as `git reset HEAD~2 --soft` – defiant Apr 20 '21 at 18:41
  • This is no longer working, I get the same error as @hertzsprung – 576i Jun 14 '21 at 20:58
  • This is not working, – fuat Nov 29 '21 at 14:14
34

The easiest way to undo the last Git commit is to execute the git reset command with one of the below options

  • soft
  • hard
  • mixed

Let's assume you have added two commits and you want to undo the last commit

$ git log --oneline

45e6e13 (HEAD -> master) Second commit
eb14168 Initial commit

–soft option undo the last commit and preserve changes done to your files

$ git reset --soft HEAD~1


$ git status

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   file.html


$ git log --oneline

eb14168 (HEAD -> master) Initial commit

–hard option undo the last commit and discard all changes in the working directory and index

$ git reset --hard HEAD~1


$ git status

nothing to commit, working tree clean


$ git log --oneline

eb14168 (HEAD -> master) Initial commit

--mixed option undo the last commit and keep changes in the working directory but NOT in the index

$ git reset --mixed HEAD~1


$ git status

On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   file.html

no changes added to commit (use "git add" and/or "git commit -a")


$ git log --oneline

eb14168 (HEAD -> master) Initial commit
Sanka Sanjeewa
  • 1,993
  • 14
  • 16
18

If you pushed the changes, you can undo it and move the files back to stage without using another branch.

git show HEAD > patch
git revert HEAD
git apply patch

It will create a patch file that contain the last branch changes. Then it revert the changes. And finally, apply the patch files to the working tree.

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
13

New Update for fellow googlers from 2021 onwards.

Here is a modern way to undo your last commit if you are a VSCode user.

  1. Go to your Source Control tab on the left (shortcut: Ctrl + Shift + G G).
  2. press ... on the left of circlish update icon. Refer to the screenshot below: source control screenshot
  3. Navigate to Commit, then to Undo Last Commit. Here is a screenshot: enter image description here

All it does is it restores your repository just as it was before you made the commit, with your changes untouched.

Beki
  • 1,344
  • 1
  • 12
  • 22
12

For the case: "This has not been pushed, only committed." - if you use IntelliJ (or another JetBrains IDE) and you haven't pushed changes yet you can do next.

  1. Go to Version control window (Alt + 9/Command + 9) - "Log" tab.
  2. Right-click on a commit before your last one.
  3. Reset current branch to here
  4. pick Soft (!!!)
  5. push the Reset button in the bottom of the dialog window.

Done.

This will "uncommit" your changes and return your git status to the point before your last local commit. You will not lose any changes you made.

Eduard Streltsov
  • 1,754
  • 20
  • 19
  • 3
    I love learning the JetBrains way, thanks! That's equivalent to `git reset --soft "HEAD^"` on Windows, btw. :) – payne Apr 19 '20 at 05:10
  • 1
    Now when I try to commit, it says the repository is in "Detached HEAD" state. Would you please update your solution to explain how to deal with this? – M. Leonhard Jul 02 '21 at 20:30
11

2020 simple way :

git reset <commit_hash>

Commit hash of the last commit you want to keep.

Xys
  • 8,486
  • 2
  • 38
  • 56
5

With me mostly it happens when I push changes to the wrong branch and realize later. And following works in most of the time.

git revert commit-hash
git push

git checkout my-other-branch
git revert revert-commit-hash
git push
  1. revert the commit
  2. (create and) checkout other branch
  3. revert the revert
Mubashar
  • 12,300
  • 11
  • 66
  • 95
  • 1
    I tested this. Your approach also works if you have not pushed to remote. $ git revert ... then checkout some other branch, then type $ git revert (without the pushes). Thank you for sharing this simple approach!! – Natalie Cottrill Dec 01 '18 at 17:07
1

PLease make sure to backup your changes before running these commmand in a separate folder

git checkout branch_name

Checkout on your branch

git merge --abort

Abort the merge

git status

Check status of the code after aborting the merge

git reset --hard origin/branch_name

these command will reset your changes and align your code with the branch_name (branch) code.

Mohit Singh
  • 5,977
  • 2
  • 24
  • 25
0

Adding steps I followed hoping that it's helpful for a beginner like me.

Following picture shows the commits I have already pushed to the remote branch 'A' in bitbucket. enter image description here

From these 5 commits, I want to keep the last 2 as it is, but the first 3 commits I want them pushed to another branch 'B'.

These are the steps I followed:

Inside branch 'A':

  1. git revert <commit-hash> for each of the 3 commits. As an example, d4a3734 is the commit hash of the last commit in the picture. (If you want you can revert multiple commits at once - refer How to revert multiple git commits?)
  2. git push

After the push, this is how it looked like:-

enter image description here

Now, I only have the first 2 commits in my branch 'A', which is what I wanted. Next, checkout to the branch wanted. If it's a new branch, use git checkout -b <branchname>. In my case, I did git checkout B.

Inside branch 'B':

I simply cherry-picked the commits I wanted to branch 'B'. In my case I did:

git cherry-pick <commit-hash> 

for those 3 commits I reverted.

(Again, as an example, git cherry-pick d4a3734 where d4a3734 is the commit hash of the last commit in the picture)

Jolly Good
  • 452
  • 7
  • 17