Restore and reset
git restore discards working-tree edits or unstages files; git reset moves HEAD and can reset the index and working tree. Its three modes — soft, mixed, hard — differ in how far the reset reaches, and --hard is the one that permanently destroys uncommitted work.
You staged the wrong file, or you spent an hour on an experiment that went nowhere and you just want the file back the way it was. Git has two tools for “take this back”: git restore for everyday file-level undo, and git reset for moving the branch pointer and the index. They overlap enough to confuse people, and one mode of reset can silently delete your uncommitted work for good.
By the end of this lesson you will be able to pick the right command to discard edits, unstage a file, or move HEAD back a commit — and you will know exactly which of those operations is destructive.
After this lesson you can use git restore to discard or unstage changes, explain how git reset moves HEAD across the working tree, index, and HEAD, and state precisely what --soft, --mixed, and --hard each touch — and which one loses uncommitted work.
Git has three places a change can live: the working tree, the index, and HEAD. The working tree is the files you edit on disk. The index (also called the staging area) is what you have marked with git add, ready for the next commit. HEAD is the last commit on your current branch. Every undo command in this lesson is really just a question of which of those three you want to rewind, and how far back. Hold that mental model and the flags stop being arbitrary.
git restore is the modern, file-scoped undo. Two everyday jobs:
# Throw away uncommitted edits in the working tree, restore file from HEAD
git restore src/app.js
# Unstage a file (remove it from the index) but KEEP your edits on disk
git restore --staged src/app.jsThe first form is destructive to working-tree edits — the on-disk file goes back to its committed content and your unsaved changes are gone. The second form only touches the index; your edits stay, they are just no longer staged. restore was split out of the overloaded git checkout precisely so these two intents stop being ambiguous.
git reset moves the current branch pointer (HEAD) to another commit. Where restore works on files, reset works on history position. The most common form rewinds one commit:
git reset HEAD~1 # move HEAD back one commitWhat happens to the index and working tree afterward depends entirely on the mode flag. By default (no flag) it is --mixed. The commit you “removed” is not gone — HEAD just no longer points at it — but the changes it contained reappear as uncommitted work, exactly as far as the mode allows.
The three modes differ only in how far the reset reaches. Same target commit, three depths:
git reset --soft HEAD~1 # move HEAD only; index + working tree untouched
git reset --mixed HEAD~1 # move HEAD + reset index; working tree untouched (default)
git reset --hard HEAD~1 # move HEAD + reset index + reset working tree (DESTRUCTIVE)
| Mode | Moves HEAD | Resets index | Resets working tree | Uncommitted work |
|---|---|---|---|---|
--soft | yes | no | no | kept, still staged |
--mixed (default) | yes | yes | no | kept, now unstaged |
--hard | yes | yes | yes | discarded permanently |
Read it as a staircase: --soft rewinds the least, --hard the most. --soft HEAD~1 is the classic “uncommit but keep everything staged” move — perfect for redoing a commit message or splitting a commit.
▸Common mistake
git reset --hard is the single most common way developers destroy work they wanted. It overwrites the working tree, so any uncommitted edit — staged or not — is gone, and restore/reset cannot bring it back because it was never committed. Before running it, ask: “Is everything I care about either committed or stashed?” If not, run git stash first. (Committed work it removes is still recoverable via git reflog — a later lesson — but uncommitted work is not.)
Uncommit a too-big commit, keep the work.
You committed everything in one go but realise it should have been two commits. You want to undo the commit without losing a single edit.
git reset --soft HEAD~1
git status--soft moves HEAD back one commit but leaves the index and working tree exactly as they were — so git status shows all your files still staged, ready to be re-committed in smaller pieces. Now you can unstage one group with git restore --staged tests/ and commit the rest:
git restore --staged tests/
git commit -m "Add parser"
git add tests/
git commit -m "Add parser tests"If you had typed git reset --hard HEAD~1 instead, the same first step would have thrown away every edit on disk — the exact opposite of what you wanted. One flag is the difference between reshaping a commit and losing an afternoon.
▸Why this works
Why does --mixed reset the index but not the working tree? Because the most common reason to undo a commit is to re-stage its changes differently — review the diff, split it, drop part of it. Leaving the working tree alone keeps your actual edits safe while clearing the staging area so you start the re-staging from a clean slate. It is the safe default precisely because it never touches the bytes on disk.
You run `git reset --soft HEAD~1` with several files staged. What is the state afterward?
Think in three layers: working tree, index, HEAD. git restore <file> discards working-tree edits; git restore --staged <file> unstages while keeping your edits. git reset moves HEAD, and its mode decides the reach: --soft moves HEAD only (work stays staged), --mixed also clears the index (work stays on disk, unstaged), and --hard also overwrites the working tree, permanently destroying uncommitted work. The safe instinct is to stash before any --hard. Next you will meet git revert — an undo that adds a new commit instead of rewinding, so it is safe even on shared branches.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.