Freebie

Undoing changes

Git gives you several ways to undo work at different stages of the workflow. The right tool depends on whether the change is in your working tree, in the staging area, or already committed. The sections below cover the most common recovery operations.

Amending the last commit

git commit –amend

--amend replaces the most recent commit with a new one. Git creates a fresh commit object (with a new SHA-1 hash) that incorporates any staged changes alongside the previous content. It is best reserved for local commits that have not been pushed to a shared branch, because rewriting a published commit forces anyone who has based work on it to reconcile their history.

The following example corrects a commit message after the fact:

# original commit
$ git log --oneline
07c2519 (HEAD -> master) amend setup

# amend with a new message
$ git commit --amend -m 'updated amend commit'
[master 9a22606] updated amend commit
 2 files changed, 132 insertions(+), 2 deletions(-)

# the old commit is replaced
$ git log --oneline
9a22606 (HEAD -> master) updated amend commit

To add a forgotten file to the previous commit without changing the message, stage the file first and then amend:

# you forgot to include forgot.file in the last commit
$ git add forgot.file
$ git commit --amend --no-edit

--no-edit reuses the existing commit message so the editor does not open.

Unstaging a file

git restore –staged

git restore --staged <file> removes a file from the staging area but leaves your working tree changes intact. Git prints this command as a hint in git status output whenever a file is staged:

$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   README.md
        new file:   unstage.md

# unstage README.md but keep the edits on disk
$ git restore --staged README.md

Discarding working tree changes

git restore

git restore <file> discards uncommitted changes in the working tree and reverts the file to its state in the last snapshot. This operation is irreversible: any unsaved edits are permanently lost.

# discard all changes to README.md since the last commit
$ git restore README.md

To discard all working tree changes at once, pass .:

git restore .

Choosing the right undo tool

The table below maps each situation to the correct command:

SituationCommand
Wrong commit message or forgot to stage a filegit commit --amend
File staged but should not be in the next commitgit restore --staged <file>
Working tree edits you want to throw awaygit restore <file>
Changes you want to save but not commit yetgit stash (see Basics)