What Happens When You Type a URL and Press Enter
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →Committed to the wrong branch? Deleted work? Pushed something you shouldn't have? A calm, copy-paste guide to undoing the Git mistakes everyone makes, without making them worse.
Git has a reputation for being scary, mostly because the first time something goes wrong, people panic and type commands they found in a hurry. Here's a secret that takes the fear away: Git almost never deletes anything for real. If you committed it at some point, it's very likely still recoverable.
Below are the most common Git mistakes and the exact commands to undo them. Before running anything, check git status. It tells you more than people give it credit for.
You edited a file and want it back the way it was at the last commit:
git restore path/to/file.js
Careful: uncommitted changes discarded this way are truly gone. This is one of the few commands in this list with no safety net.
git restore --staged path/to/file.js
The changes stay in your working directory; they're just no longer staged.
If you haven't pushed yet:
git add forgotten-file.js
git commit --amend -m "Better message"
Amending rewrites the last commit. That's fine locally, but don't amend commits others have already pulled.
git reset --soft HEAD~1
The commit disappears, and its changes go back to being staged, ready to recommit. Use --mixed (the default) if you want them unstaged instead.
The one to be careful with:
git reset --hard HEAD~1
This removes the commit and discards the changes from your working directory. (Still recoverable via reflog, below, but don't make it a habit.)
Once a commit is on a shared branch, don't rewrite history. Make a new commit that undoes it:
git revert <commit-sha>
git push
revert is the polite undo: history stays intact and teammates don't get broken branches. Here's the rule of thumb: reset for local mistakes, revert for shared ones.
If you haven't pushed yet:
git switch -c my-feature # new branch that keeps the commits
git switch main
git reset --hard origin/main # put main back where the remote is
Your commits now live on my-feature, and main is clean.
git cherry-pick <commit-sha>
It copies that commit onto your current branch. Handy for hotfixes.
Meet your new best friend:
git reflog
The reflog records where HEAD has been, including commits that no branch points to anymore. Find the entry from before the mistake, then:
git branch rescue <sha-from-reflog>
Now your work lives on the rescue branch. Entries stick around for a good while by default (weeks to months), so this works long after the "oh no" moment.
While it's still in progress:
git merge --abort
git rebase --abort
Both put you back exactly where you started. Already finished? Use the reflog to find the pre-merge state.
git stash push -m "half-done navbar"
git switch other-branch
# ...later
git switch -
git stash pop
Name your stashes. Future you will not remember what stash@{3} was.
Sometimes you do (after cleaning up a feature branch, for instance). Use the safer version:
git push --force-with-lease
It refuses to overwrite the remote if someone else pushed in the meantime. Plain --force would wipe their work without asking.
Removing it in a new commit is not enough. It's still in history, and bots scan public repos constantly. Rotate the key first, then clean up. Full steps here: leaked an API key? do this next.
git status and git diff --staged before committing. Thirty seconds that saves hours.git pull --rebase on personal branches for a tidy history.| Situation | Command |
|---|---|
| Discard file changes | git restore <file> |
| Unstage a file | git restore --staged <file> |
| Fix last commit (unpushed) | git commit --amend |
| Undo last commit, keep changes | git reset --soft HEAD~1 |
| Undo a pushed commit | git revert <sha> |
| Find "lost" commits | git reflog |
| Abort a merge/rebase | git merge --abort / git rebase --abort |
| Force push safely | git push --force-with-lease |
reset moves your branch pointer backwards, effectively rewriting history. revert adds a new commit that undoes an old one. Reset suits local, unpushed work; revert is for anything already shared.
Usually, yes. Run git reflog, find the last commit of that branch, and recreate it with git branch <name> <sha>.
It discards uncommitted changes permanently. Committed work can still be recovered through the reflog, but anything you never committed is gone.
DNS lookups, TCP and TLS handshakes, HTTP requests, servers, and the browser's rendering pipeline. The whole journey of a web page, explained so it finally clicks.
Read →There are dozens of HTTP status codes, but about fifteen cover nearly everything. What each one means, when to return it, and the mix-ups (401 vs 403, 301 vs 302) that confuse everyone.
Read →A, AAAA, CNAME, MX, TXT and NS records in plain English, why DNS changes seem slow, and the troubleshooting commands that tell you what is really going on.
Read →