Undoing things without losing work
Most Git accidents are recoverable, and the safe commands are the ones that add rather than rewrite.
Three different undos
`git restore <file>` throws away uncommitted changes to that file. It is the one genuinely destructive command here: the changes were never committed, so Git has no copy, and nothing can bring them back.
`git reset` moves a branch pointer to a different commit. With `--soft` your changes stay staged; with `--mixed`, the default, they stay in your working directory; with `--hard` they are discarded along with the commits. Only `--hard` loses work, and even then the commits themselves usually survive.
`git revert` makes a new commit that undoes an earlier one. It changes nothing that already exists, which is why it is the right tool on a shared branch: everyone else keeps the history they already have.
The reflog is the safety net
Git records every position HEAD has held — every commit, checkout, merge and reset — in the reflog, for about ninety days by default. `git reflog` prints it.
This is why "I reset --hard and lost my commits" is usually recoverable: the commits are still there, nothing is pointing at them, and the reflog knows where they were. `git reset --hard HEAD@{1}` or `git checkout -b rescue <id>` brings them back. Knowing the reflog exists is the difference between a bad ten minutes and a lost afternoon.
What .gitignore does and does not do
.gitignore stops Git suggesting untracked files. It has no effect on a file already tracked: adding node_modules to .gitignore after committing it changes nothing, and you need `git rm -r --cached node_modules` to stop tracking it.
It is also not a security measure. Ignoring .env keeps it out of future commits; if a secret has already been committed it is in the history, and it stays there for anyone who clones the repository even after you delete the file. The only correct response to a committed secret is to rotate it — treat it as public from the moment it was pushed.
Worked examples
Undo the last commit but keep the changes
/git reset --soft HEAD~1/Against:
The commit is gone, the work is staged and ready to recommitUse --soft when the commit was premature and --hard only when the work itself should go.
Find a commit you thought you had lost
/git reflog/Against:
After a reset that went too farEvery position HEAD has held is listed with its id. Check one out into a new branch and nothing is lost.
Check yourself
Practice questions written for this lesson — not past exam papers.
Practise every question in this subject
You added node_modules to .gitignore but Git still tracks it. Why?
A password was committed and pushed last week, then deleted in a later commit. What should you do?