Skip to content

Chapter 1 of 8

Undoing Commits and Local Changes

Git offers a spectrum of "undo" commands whose power increases from safe to destructive. The lightest touch is git reset --soft HEAD~1, which moves the HEAD pointer back one commit but leaves every change staged for an immediate recommit. The default git reset --mixed HEAD~1 (or just git reset HEAD~1) does the same move but unstages the changes, leaving them in the working tree for inspection. The most destructive is git reset --hard HEAD~1, which discards both staged and working-tree changes entirely, so it should only be used when you are certain the work has no further value. If you want to revise the most recent commit rather than erase it, git commit --amend -m 'new message' rewrites the message, and git add forgotten-file followed by git commit --amend --no-edit folds in files you forgot to include without prompting for a new message.

For mistakes that never made it past the working tree, Git provides the restore family of commands (and older checkout equivalents). git restore file discards local edits to one file, while git restore . throws away every modification in the working tree. To unstage a file you accidentally added, git restore --staged file (or the legacy git reset HEAD file) moves it back to modified-but-not-staged. To temporarily inspect an older state without creating a branch, git checkout <sha> checks out a commit directly and leaves you in detached HEAD; if you decide to keep the work, git switch -c branch-name turns the detached HEAD into a real branch. These commands are safe to run repeatedly because they only touch uncommitted state.

When the wrong branch received a commit, or you simply want to move a single commit between branches, you can rescue it without losing work. From the source branch, run git log --oneline -n 3 to note the commit's SHA, switch to the destination with git switch right-branch, apply the commit via git cherry-pick <sha>, then return to the source and either git reset --hard HEAD~1 (to delete the original outright) or use rebase to drop it more surgically. The same idea works for restoring a single file from any other branch or commit using git checkout HEAD~1 -- path or git checkout branchname -- path/to/file, which writes the historical version of that path into your working tree.

For undoing a public commit that has already been pushed, git revert <sha> is the safe alternative to resetting: it creates an inverse commit that cancels the changes without rewriting shared history, leaving every collaborator's branch intact. This distinction between reset (rewinds locally, dangerous on pushed commits) and revert (adds a new commit, safe on pushed commits) is one of the most important mental models in Git.

All chapters
  1. 1Undoing Commits and Local Changes
  2. 2Cleaning the Working Tree and Fixing .gitignore
  3. 3Rewriting History with Rebase
  4. 4Merging and Conflict Resolution
  5. 5Stashing Work in Progress
  6. 6Branches, Remotes, Tags, and Force-Push Safety
  7. 7Investigating and Searching History
  8. 8Advanced Recovery, Configuration, and Housekeeping

Drill it

Reading is not remembering. These come from the Git Recovering From Common Mistakes deck:

Q

Undo the last commit but keep changes staged.

git reset --soft HEAD~1

Q

Undo the last commit AND discard changes.

git reset --hard HEAD~1 &nbsp;⚠ destructive.

Q

Undo the last commit but keep changes unstaged in the working tree.

git reset --mixed HEAD~1 (the default).

Q

Amend the last commit message.

git commit --amend -m 'new message'