How to undo the last / previous / most recent commit in Git

Published on in Git

Last updated on

Run git reset HEAD~ or alias it to git undo. Bonus: how to use the commit message from the undoed commit.

Table of contents

TL;DR

Undo the last/previous/most recent commit while preserving the changes:

# Keep the undoed changes
git reset HEAD~

# or

# Keep the undoed changes in the staging area
git reset HEAD~ --soft

Afterwards, to use the commit message from the undoed commit:

git commit -c ORIG_HEAD

If using my git aliases:

git undo
# or
git undo --soft

# Use the commit message from the undoed commit
git redo

Explanation

Undoing

  • HEAD is your current "position" in Git's history; it points to the commit that you have currently checked out.
  • HEAD~ points to HEAD's parent commit, i.e. to the previous commit of your current position.
  • git reset HEAD~ resets the head to HEAD~, i.e. to the previous commit.

From git reset's documentation:

git reset [<mode>] [<commit>]

This form resets the current branch head to <commit> and possibly updates the index (resetting it to the tree of <commit>) and the working tree depending on <mode>. If <mode> is omitted, defaults to --mixed. The <mode> must be one of the following:

--soft
Does not touch the index file or the working tree at all (but resets the head to <commit>, just like all modes do). This leaves all your changed files "Changes to be committed", as git status would put it.
--mixed
Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) and reports what has not been updated. This is the default action.

"The index" refers to the staging area (the "Changes to be committed" area).

--mixed is the default mode, so git reset HEAD~ resets the index, meaning that the undoed changes are not kept in the staging area (but the changes are preserved).

git reset HEAD~ --soft on the other hand doesn't touch the index file, meaning that the undoed changes are kept in the staging area.

Should you use the --soft flag? Depends on whether you want the undoed changes to be in the staging area.

Redoing

From git commit's documentation:

-C <commit>
--reuse-message=<commit>
Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit.
-c <commit>
--reedit-message=<commit>
Like -C, but with -c the editor is invoked, so that the user can further edit the commit message.

From gitrevisions's documentation:

ORIG_HEAD is created by commands that move your HEAD in a drastic way, to record the position of the HEAD before their operation, so that you can easily change the tip of the branch back to the state before you ran them.

In other words, ORIG_HEAD points to the previous HEAD – in this case to the undoed commit.

Thus, git commit -c ORIG_HEAD uses the commit message from the undoed commit and opens the editor so you can edit the message before committing.

Further resources