Git Reset & Undo
Working-tree inspection, diffing, restoring, and amending — knowing which of Git’s three zones a change lives in determines which command undoes it safely.
Prerequisites —
- Must be inside a valid Git repository (
git initor cloned).git restorerequires Git 2.23.0+ (2019) — use legacy equivalents on older versions.- For
--amend: must be on a local-only branch — do not amend commits already pushed to a shared remote.
Working tree state — conceptual overview: Git tracks files across three zones:
- Working Tree — your local filesystem; where you edit files.
- Staging Area (Index) — files queued for the next commit via
git add.- Repository — committed history; each snapshot has a unique SHA hash.
Understanding which zone a file lives in determines which command to use.
Output state reference —
Status Message Meaning Changes not staged for commitModified in working tree, not yet staged Changes to be committedStaged; ready for next commit nothing to commit, working tree cleanWorking tree matches last commit exactly Untracked filesNew file Git has never seen
Diff output prefix reference —
Prefix Meaning ---Old version of the file +++New version of the file -Line removed in new version +Line added in new version (none) Unchanged context line
@@ -1 +1 @@indicates line numbers affected in the old (-) and new (+) file.
Inspecting Working Tree State
# Check current state of working tree and staging area
git status
Command breakdown —
git status:
- No flags required — produces full human-readable output by default.
-s/--short— terse, machine-friendly output format.- Read-only; generates no network traffic and no Git history artefacts.
Diffing Working Tree vs. Last Commit
# Diff all modified files against staging area / last commit
git diff
# Explicitly diff working tree against latest commit on current branch
git diff HEAD
# Diff a specific file against a specific commit hash
git diff 4620193 example.html
Command breakdown —
git diff:
- (no args) — compares working tree against the staging area; equivalent to last commit if nothing is staged.
HEAD— explicitly targets the latest commit on the current branch.<commit> <file>— targets a specific file at a specific commit SHA.- Read-only; no history artefacts created.
Warning — Pager mode: If output fills the terminal, Git enters pager mode (usually
less). Scroll with arrow keys; pressqto exit. Pager behaviour is controlled by the$PAGERenvironment variable.
No output shown — The file may already be staged; staged changes are invisible to
git diff(no args). Usegit diff --stagedto compare staged changes against the last commit.
Discarding Local (Unstaged) Changes
Danger — Destructive operation:
git restoreon the working tree permanently discards uncommitted edits. Changes are not recoverable unless a stash or reflog entry exists. Always rungit difffirst to review what will be lost.
# Restore all files in the current directory to last committed state
git restore .
# Restore a single named file only
git restore hello.html
# Restore a subdirectory
git restore src/
Command breakdown —
git restore(working tree):
.— restores all files in the current directory recursively.<file>— restores a single named file only.<path/>— restores an entire subdirectory.--worktree— explicit flag for this mode; same as omitting it (default behaviour).- No network activity; modifies only local files.
# Confirm clean state after restoring
git status
# Expected: nothing to commit, working tree clean
Result —
git restoreproduces no output on success. Confirm withgit status— should shownothing to commit, working tree clean.
Common errors —
error: pathspec 'X' did not match any file(s)→ check filename spelling and current working directory.- Accidentally discarding intended work → always run
git diffbeforegit restore.
Tip — Legacy equivalent:
git checkout -- <file>performs the same action but is superseded. Prefergit restoreon modern installs (Git 2.23.0+).
Unstaging Staged Changes
# Unstage all staged files — edits are preserved in working tree
git restore --staged .
# Unstage a single file — edits preserved
git restore --staged hello.html
# Unstage AND discard working tree changes in one step (destructive)
git restore --staged --worktree .
Command breakdown —
git restore --staged:
--staged— operates on the staging area (index) rather than the working tree; non-destructive.--staged --worktree— unstages and discards working tree changes in a single command; destructive.- After
--stagedalone: file appears underChanges not staged for commit— edits still present.- After
--staged --worktree:git statusshowsnothing to commit, working tree clean.
Warning — Easy to confuse:
git restore .≠git restore --staged .— the first only affects the working tree; it does not unstage. After--stagedalone, edits are not gone — rungit restore .separately if you also want to discard them.
Tip — Legacy equivalent:
git reset HEAD <file>performs the same unstaging action. Available on Git versions older than 2.23.0.
Fixing the Last Commit — --amend
Danger — History-rewriting warning:
--amendreplaces the last commit — a new SHA is generated; the old one disappears locally.- Do not amend commits already pushed to a shared remote — this requires
git push --force, which is visible to all collaborators.- The old commit object remains accessible via
git refloguntil garbage-collected.- On shared branches, prefer adding a new fix commit rather than amending.
# Fix only the commit message inline
git commit --amend -m "Added HTML tags to hello.html"
# Add a forgotten file and update the message in one step
git add hello.html
git commit --amend -m "Added H1, HTML, and BODY tags to hello.html"
# Amend message interactively via default text editor (vim/nano)
git commit --amend
Command breakdown —
git commit --amend:
--amend— replaces the most recent commit with a new one (new SHA generated).-m "<msg>"— sets the new commit message inline; omit to open the configured text editor.- Pre-stage additional files with
git addbefore running--amendto include them in the amended commit.- Git prints the updated commit summary including the new amended SHA on success.
Common editor traps —
- Stuck in vim (opened by omitting
-m) → pressEsc, type:wq, pressEnterto save and exit.- Stuck in nano →
Ctrl+Oto save →Enterto confirm filename →Ctrl+Xto exit.- Amended a pushed commit → coordinate with the team before force-pushing; prefer a new fix commit on shared branches.
Tip — Best-practice workflow:
- Stage any missed files:
git add <file>- Review what will change:
git diff --staged- Amend with corrected message:
git commit --amend -m "<message>"- Verify result:
git log --oneline -1