Undo Without Fear

four tools, one map: what each one touches, and the line none of them can cross

the whole chapter in one grid
the whole chapter in one grid

Most git fear is undo fear, and it dissolves into one question: what does this tool touch? restore copies file content over your working directory or staging area. reset <commit> moves HEAD and your branch. revert adds a cancelling commit (your branch advances onto it). clean deletes untracked files. None of them edits an existing commit - git undoes by copying, moving pointers, or adding.

$ git status --short
 M menu.txt
$ git restore menu.txt
$ git status
nothing to commit, working tree clean
real output - executed, not staged

The everyday undo is a copy: Maria scribbles a mistake into menu.txt, and git restore menu.txt lays the staging area's clean copy back over it. No commit changes, no branch moves - and that is also its edge: the scribble's bytes never entered git, so this undo is permanent.

$ git reset --soft HEAD~1   # demo repo 1:
$ git status --short
M  ledger.txt
$ git reset --mixed HEAD~1   # demo repo 2:
Unstaged changes after reset:
M	ledger.txt
$ git reset --hard HEAD~2   # the bakery repo:
HEAD is now at 7a879c4 raise the focaccia price
the dial, executed - three separate demonstrations

When whole commits were the mistake, git reset walks HEAD and the branch back, and the mode dial decides the rest: --soft keeps the undone work staged, --mixed drops it to the working directory, --hard rewrites tracked files there too. The commits left behind lose their name and go unreachable - still in the object store for now, findable through the reflog until entries expire and pruning runs.

$ git revert 7a879c4
Auto-merging menu.txt
[main c939e70] Revert "raise the focaccia price"
...
$ git log --oneline -3
c939e70 Revert "raise the focaccia price"
0358cc3 add rye bread
7a879c4 raise the focaccia price
history only grows - the bad commit stays visible

Once a commit is published, walking the branch back would rewrite history teammates already hold. git revert undoes by ADDING: a new commit applying the inverse of the bad one's change. The mistake stays visible, the cure sits on top, and an ordinary push ships it (conflicts and branch policy permitting - it is a merge of changes underneath).

One pitfall deserves its own poster: a revert is a commit, so it travels with merges (a merge makes your branch's commits part of the target's history) - cancel something on a branch and the cancellation arrives wherever that branch merges.

the ledger - every HEAD move, on the record
the ledger - every HEAD move, on the record

Behind all of it sits the safety net: git reflog, the local reference log of HEAD's recorded moves ("the ledger", in this course's furniture). A bad reset is undone by finding the entry and walking back - git reset --hard HEAD@{1} brought the whole bakery history back in one move. Local only, committed work only, entries expire - it is a net, not an archive.

$ git clean -f
Removing scratch.txt
$ ls   # gone for good:
menu.txt
the far side of the boundary

And the honest line under the whole promise: git can only resurrect bytes that entered its object store. Committed content comes back; staged-only content survives as nameless blobs until pruning. Unstaged edits you overwrite and untracked files git clean -f sweeps were never inside - no tool brings them back. The habit that keeps you safe costs one command: commit (or stash - covered later, in Sharp tools - remembering plain stash skips untracked files) before any risky move.

The decision rule, whole chapter in one breath: one file wrong - restore. Local commits wrong - reset. Published commit wrong - revert. Committed work missing - reflog first (never-committed work has no net). Next door: the rescue playbook, drill by drill.

tline