Undo anything: restore, reset, revert and reflog
Almost every Git mistake can be undone, if you pick the right tool. The right tool depends on two questions: where is the mistake (your files, the staging area, or a commit), and has anyone else seen it? This lesson maps each undo command to exactly what it moves, then breaks things on purpose and recovers each time.
By the end you can
- Discard or unstage changes with
git restoreandgit restore --staged - Say exactly what
reset --soft,--mixedand--hardmove between the three areas, and model it in code - Undo a pushed commit safely with
git revert - Recover a "lost" commit or deleted branch with
git reflog - Tell which undo is safe after pushing and which is not
The everyday picture
Think of the stock register in a store's backroom. A note you wrote in pencil a minute ago, before anyone checked it, you simply erase. That is undoing changes in your own files. An entry the area manager has already signed off is different. You do not tear out the page. You write a new line: "Correction to entry 47: 12 cartons, not 21." The register now shows the mistake and the fix, and everyone who copied page 47 can follow it. That is git revert.
And sometimes a page really is torn out by mistake. It is not gone yet: it is in the bin under the desk until the cleaners come. You can fish it out. Git's reflog is that bin, and the cleaners come rarely: by default, not for at least 30 to 90 days.
First question: where is the mistake?
Recall the three areas from Snapshots and the three areas: the working folder, the staging area (index) and the repository (commits, plus branch pointers such as main). Each undo command works on a specific area, so start by locating the mistake:
- Only in your files, not staged:
git restore filecopies the file back from the staging area, which holds the last committed or staged version. Your edit is gone for good, because Git never saved it. VS Code's Discard Changes does the same. - Staged by mistake:
git restore --staged filecopies the committed version back into the staging area. Your edit stays in the working folder. Nothing is lost. - Committed, not pushed: amend the last commit (Rewriting history safely) or move the branch back with
git reset. - Committed and pushed: add a new commit that reverses it, with
git revert. - Lost: a branch deleted, a reset gone wrong, a rebase you regret. Find the commit ID in
git reflog, then point a branch at it.
Two more file commands help. git restore --source=HEAD~3 src/config.js brings back the version of one file from three commits ago, without moving any branch. git clean deletes untracked files (ones Git has never seen). Always run git clean -n first, which only lists what would go; git clean -f -d then deletes files and folders. Ignored files such as .env are left alone unless you add -x.
Quick check
A teammate asks for src/config.js exactly as it was three commits ago, but everything else must stay as it is now. Which command fits?
Restore with a source copies one file's old version into your working folder and moves no branch. reset --hard would throw away three commits for every file, and revert would undo the change that commit made, which is a different thing from getting an old version back.