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 do a commit and 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 toHEAD
's parent commit, i.e. to the previous commit of your current position.git reset HEAD~
resets the head toHEAD~
, 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", asgit 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 yourHEAD
in a drastic way, to record the position of theHEAD
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.