Undo Without Fear
four tools, one map: what each one touches, and the line none of them can cross
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 cleanThe 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 priceWhen 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 priceOnce 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.
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.txtAnd 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.