Apr 12, 2023

How to Undo the Last Commit in Git

How to Undo the Last Commit in Git

Undoing commits in Git allows you to correct mistakes, make changes, or revert code, while keeping a project's history organized and easy to understand.

The most common reasons for undoing the last commit in Git are usually:

  • Files that were included in the commit by mistake.
  • Typos that were introduced in the commit message.
  • New code that causes unforeseen bugs or accidental code changes.

In this article, you'll learn how to undo the last commit in Git using the git-revert and the git-reset commands.

Undoing the last commit with git-revert

The git-revert command allows you to create a new commit that reverts the changes made in another commit, which means that the commit you want to undo will still exist in the history, but will be followed by a new commit that reverts the changes introduced by the previous one.

For example, let's consider the following commit history:

$ git log --oneline
e97698a (HEAD -> master) third commit
cd2bbfe second commit
9e01fd9 first commit

To undo (i.e. revert) the last commit, you can use the following command, where HEAD refers to the last commit in the history:

$ git revert HEAD

Git will then open up a text editor asking you to enter a commit message for the new commit:

 1 Revert "third commit"
 2
 3 This reverts commit e97698ac66bec08055e23e3cc3d1885a4b63908.
 4
 5 # Please enter the commit message for your changes. Lines starting
 6 # with '#' will be ignored, and an empty message aborts the commit.
 7 #
 8 # On branch master
 9 # Your branch is up to date with 'origin/master'.
10 #
11 # Changes to be committed:
12 # modified:   index.js
13 #

Alternatively, if you don't want to edit the commit message and keep the default one suggested by Git, you can use the --no-edit flag, which will prevent the text editor from opening.

$ git revert --no-edit HEAD

Finally, once the git-revert command has been executed, you can see that the original commit (i.e. e97698a) still exists in the history, but its changes have been effectively canceled out by the new commit (i.e. fr853b1).

$ git log --oneline
fr853b1 (HEAD -> master) Revert "third commit"
e97698a third commit
cd2bbfe second commit
9e01fd9 first commit

Note that in order to execute this command, your working tree needs to be in a clean state, as otherwise, Git will throw the following error:

error: Your local changes to the following files would be overwritten by merge:
Please commit your changes or stash them before you merge.
Aborting

Removing the last commit with git-reset

The git-reset command is different from the git-revert command as it allows you to rewind the commit history to a specific commit, which means that any changes made after that commit will no longer be part of the branch.

To undo the last commit, you can use the following command:

$ git reset HEAD~1

Where HEAD~1 refers to the commit prior to the last commit in the history; which roughly translates to "rewind the history one commit before the current HEAD".

For example, let's consider the following commit history:

$ git log --oneline
e97698a third commit  (HEAD)
cd2bbfe second commit (HEAD~1)
9e01fd9 first commit  (HEAD~2)

When executing this command:

$ git reset HEAD~1
Unstaged changes after reset:
M   index.js

Git will remove the last commit from the history and the staging area, but will preserve the changes made in the working tree.

$ git log --oneline
cd2bbfe second commit (HEAD)
9e01fd9 first commit  (HEAD~1)

$ git status
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:   index.js

Preserving the working tree and the staging area (soft reset)

To undo the last commit without altering the changes made in the working tree nor the staging area (i.e. index file), you can use the --soft flag as follows:

$ git reset --soft HEAD~1

For example, here is what the commit history and the staging area would look like after executing this command:

$ git log --oneline
cd2bbfe second commit (HEAD)
9e01fd9 first commit  (HEAD~1)

$ git status
Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
      modified:   index.js

Discarding all changes (hard reset)

To undo the last commit and discard all changes made both in the working tree and the staging area, you can use the --hard flag as follows:

$ git reset --hard HEAD~1

For example, here is what the commit history and the staging area would look like after executing this command:

$ git log --oneline
cd2bbfe second commit (HEAD)
9e01fd9 first commit  (HEAD~1)

$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean

Note that when executing the git reset --hard command, Git will completely remove any changes made after the commit you're resetting to, which means that any changes that haven't been committed or backed up elsewhere will be lost.

Also note that, it is usually best to avoid using this option when working on a branch shared with other developers as it might create innumerable conflicts when trying to pull the latest changes.