Undo a commit & redo
$ git commit -m "Something terribly misguided" # (0: Your Accident)
$ git reset HEAD~ # (1)
[ edit files as necessary ] # (2)
$ git add . # (3)
$ git commit -c ORIG_HEAD # (4)
- The
git reset
command is used to undo changes. It reverts your last commit without altering your working tree, meaning the state of your files on disk remains unchanged. You’ll need to stage these files again before you can recommit them.
git reset --hard <commit_id>
“Move” your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard HEAD~
# Alternatively, if there's work to keep (stash your changes before):
git stash -u
git reset --hard HEAD~
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
- Make corrections to the files in your working tree.
- Use
git add
to stage the changes you want to include in your new commit. - Commit the changes, reusing the old commit message. The
git reset
command copies the old HEAD to.git/ORIG_HEAD
. Usinggit commit -c ORIG_HEAD
opens an editor with the old commit message, allowing you to edit it. If you don’t need to edit the message, you can use the-C
option instead.
Alternatively, to edit the previous commit or just its commit message, use git commit --amend
. This will add the changes from the current index to the previous commit.
To eliminate (not undo) a commit that has been pushed to the server, rewriting history with git push origin main --force[-with-lease]
is required. It’s generally unwise to employ --force
; it’s better to use --force-with-lease
instead, as emphasized in the Git manual:
Reversing a commit might seem daunting if you’re unfamiliar with the process, but it’s surprisingly straightforward once you grasp it. Let’s explore the four methods you can use to undo a commit.
Imagine you have this scenario, where C represents your HEAD, and (F) denotes the state of your files.
(F)
A-B-C
↑
master
Option 1: git reset --hard
You aim to eliminate commit C along with discarding any uncommitted alterations. This can be achieved by:
git reset --hard HEAD~1
The result is:
(F)
A-B
↑
master
Now B becomes the HEAD. By utilizing –hard, your files revert to their state as they were at commit B.
Option 2: git reset
Perhaps commit C wasn’t catastrophic, just slightly off the mark. You want to undo the commit but retain your changes for a bit of editing before making a better commit. Starting afresh from this point, with C as your HEAD:
(F)
A-B-C
↑
master
Do this, leaving off the --hard
:
git reset HEAD~1
In this case the result is:
(F)
A-B-C
↑
master
In both scenarios, HEAD serves as a pointer to the most recent commit. When you execute git reset HEAD~1
, you instruct Git to move the HEAD pointer back one commit. However, unless you employ --hard
, your files remain unchanged. Consequently, git status
now displays the modifications you had included in commit C. Rest assured, nothing has been lost!
Option 3: git reset --soft
For the gentlest approach, you can even undo your commit while keeping your files and your index intact:
git reset --soft HEAD~1
This not only preserves your files but also keeps your index unchanged. Upon running git status
, you’ll notice that the same files remain in the index as before. In fact, immediately after this command, you could execute git commit
, effectively recreating the exact same commit you just reverted.
Option 4: you did git reset --hard
and need to get that code back
One more thing: Imagine you obliterated a commit as illustrated in the first example, only to later realize you actually needed it. Tough luck, right?
Not quite! There’s still a way to retrieve it. Type this:
git reflog
and you’ll be presented with a list of (partial) commit SHAs (hashes) that you’ve manipulated. Locate the commit you destroyed, and perform the following:
git checkout -b someNewBranchName shaYouDestroyed
You’ve successfully resurrected that commit. In Git, commits aren’t permanently destroyed; they typically persist for around 90 days. Hence, you can usually go back and rescue a commit you didn’t intend to discard.