Git refuses to switch branches or pull because uncommitted edits are in the way. Here's how to move them safely, and when it's fine to throw them out.
You go to switch branches, or pull the latest, and Git slams the door:
error: Your local changes to the following files would be overwritten by checkout:
src/config.js
Please commit your changes or stash them before you switch branches.
Aborting
The merge variant reads the same way, just swap "checkout" for "merge". Either way, Git is refusing to do the thing you asked. That refusal is the feature, not the bug.
The file Git names has two versions in play: the one saved in your working directory that you edited but never committed, and the one on the branch or commit you're trying to move to. If Git went ahead, it would have to write the incoming version on top of yours, and your uncommitted edits would be gone. No commit holds them, so there's no way back. Git won't guess whether you care about those edits, so it stops and hands the decision to you.
That's the whole picture. You have work Git can't see a home for, and you're asking it to overwrite the spot that work lives in. Every fix below is just a way of telling Git where that work should go: into a commit, into a stash, or into the trash.
If the edits are real work you want to keep on the current branch, the cleanest move is to commit them:
git add src/config.js
git commit -m "Update config defaults"
Now the changes have a home. The checkout or merge that was blocked will go through, because Git no longer has anything unsaved to protect. Commit when the work belongs here and it's in a decent state. Don't commit half-finished garbage just to unblock yourself, though. That's what stash is for.
Stash is the answer nine times out of ten. It pulls your uncommitted edits off to the side, leaving your working directory clean, and holds onto them so you can drop them back later.
git stash
Working tree is clean now. Do your checkout or merge, then bring the work back:
git checkout other-branch
git stash pop
pop reapplies the stashed changes and deletes the stash entry. If the reapply is clean, you're back where you started, on the new branch, with your edits on top.
If the branch you moved to has since touched the same lines, pop can hit a conflict. It looks like any merge conflict:
CONFLICT (content): Merge conflict in src/config.js
When that happens, the stash is not dropped. Resolve the conflict markers by hand, git add the file, and here's the part people miss: the stash entry is still sitting in your list because pop only removes it on a clean apply. Check with git stash list and clear it once you're happy:
git stash drop
pop reapplies and deletes. apply reapplies and keeps the stash around. I reach for apply when I'm not fully sure the reapply will land where I want, because it leaves me a copy to retry from:
git stash apply
# check things look right, then
git stash drop
The rest of the stash toolkit, which you'll want when you've got more than one:
git stash list # every stash, newest first as stash@{0}
git stash show -p stash@{0} # full diff of a specific stash
git stash apply stash@{1} # reapply an older one
git stash drop stash@{1} # delete one you're done with
Give stashes names when you make them, or future-you won't remember what stash@{2} was:
git stash push -m "wip: retry logic for the webhook"
Sometimes only one file is in the way and the rest of your edits should stay put. Stash by path:
git stash push src/config.js -m "just the config"
That file goes into the stash, everything else stays in your working directory untouched. Handy when a single stray file is blocking a checkout you need right now.
git pull is a fetch plus a merge, so it throws the same error when incoming changes would clobber your uncommitted edits. The stash dance handles it:
git stash
git pull
git stash pop
Stash out of the way, pull the remote work in, pop your edits back on top. If pop conflicts, resolve it exactly like above.
Sometimes the edits are junk. A debug console.log, a config you fiddled with, a file you touched by accident. If you're certain you don't want them, throw them out:
git restore src/config.js # modern Git
git checkout -- src/config.js # older Git, same effect
Both replace the file with the committed version. To wipe every tracked change at once:
git restore .
Read this twice: discarding is not undoable. There's no stash, no commit, no reflog entry to crawl back to. The bytes are gone. I discard only when the change is trivial and I can recreate it in under a minute if I'm wrong. Anything with real thought behind it gets a stash instead, because a stash costs nothing and buys you a way back.
For a wider tour of git failures and their fixes, see our Git troubleshooting guide.
Stash by default. It's the reversible option, it's fast, and it turns a scary error into a two-command detour. Commit when the work is real and belongs on this branch. Discard only when you can look at the file and honestly say you'd lose nothing, and even then remember there's no undo. When you're unsure which bucket a change falls in, that uncertainty is the answer: stash it and decide later.
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
The metrics stack you self-host is free software plus a real ops bill. Datadog hands you everything and mails you the invoice. Here's how we pick.
Static keys leak and live forever. Short-lived credentials from STS and Vault expire on their own — here's the token-exchange machinery and the TTL math that make it work.
Explore more articles in this category
The IaC landscape fractured after the Terraform license change. This is the map to what each tool is actually best at, and how to choose without regret.
Terragrunt keeps large Terraform setups DRY and orchestrated, but small teams often pay its learning curve for little return.
A practical comparison of Kubernetes-native continuous reconciliation against the classic CLI-driven, state-file IaC model for platform teams.
Evergreen posts worth revisiting.