Undoing Mistakes

Updated

October 30, 2026

Undoing Mistakes

After this page you can discard an unstaged edit, unstage a file, and rewrite the last commit before anyone else has it.

Three common “undo”s

You did You want Command
Edited a tracked file, not staged Throw the edit away git restore <file>
git add too soon Keep the edit, leave it out of the next commit git restore --staged <file>
Last commit message (or last commit contents) is wrong, not pushed Replace that commit git commit --amend

These are safe on a laptop branch nobody has fetched. After git push, amending rewrites a hash other people may have. Chapter 9 and chapter 11 cover that case. Chapter 17 (reflog) is the safety net when you went too far.

 restore <file>              restore --staged           commit --amend
 working ← index             index ← HEAD               A ← B ← C
                                                        A ← B ← C'   (C gone from main)

Discard unstaged work

cd ~/desk/desk-api
echo "oops" >> README.md
git restore README.md

The working-tree file matches the index again. The “oops” line is gone. Git cannot get it back from Git; your editor’s undo might.

Restore one file from HEAD even if it was staged:

git restore --source=HEAD --worktree --staged README.md

That is “make this file look like the last commit, in both index and working tree.”

Unstage, keep the edit

echo "keep me" >> README.md
git add README.md
git restore --staged README.md
git status

The line is still in the file. It is not in the index. The next git commit will not include it until you git add again.

Older docs say git reset HEAD README.md for the same unstage. This book uses git restore --staged.

Amend the last commit

You just committed and noticed a typo in the message:

git commit --amend -m "Add ping helper"

You forgot a file:

git add src/ping.py
git commit --amend --no-edit

--no-edit keeps the old message. --amend replaces the last commit with a new one (new hash) whose parent is the same as before. git log no longer shows the old hash as main. The old commit is still in the reflog for about 30 days (chapter 17).

Amend only when:

  • it is the latest commit on this branch, and
  • you have not pushed it, or you are sure no one else built on it.

Revert is a new commit

git revert <hash> adds a commit that undoes a previous one. Use it on history other people already have. Chapter 10 is revert and cherry-pick. For a local last-commit mistake, amend. For an old published mistake, revert.

rm and mv

git rm src/old.py              # stop tracking and delete the file
git rm --cached secrets.env    # stop tracking, keep the file on disk
git mv src/ping.py src/health.py
git status
git commit -m "Rename ping to health"

git mv is mv plus git add of the rename. Git detects renames in diffs even if you mv and add by hand; git mv is the tidy form.

If you are lost

git status
git log --oneline -5

Status tells you which of the three trees disagree. Log tells you where main points. The hands-on page next builds a tiny desk-api from scratch so you can practice the whole loop, including one amend.