Overview
Category: DevOps Collection: Git Topic: How to fix 'fatal: refusing to merge because you have unstaged changes'
Git blocks a merge when your working tree has unstaged edits that would be overwritten by the merge. This protects your work from being lost. You must either save, temporarily shelve, or discard those edits before merging.
Quickstart
- Stash and merge:
- git stash push -u -m "WIP before merge"
- git merge <branch>
- git stash pop
- Or commit and merge:
- git add -A && git commit -m "WIP"
- git merge <branch>
- Or discard local changes, then merge:
- git restore .
- git clean -fd # if you also want to remove untracked files
- git merge <branch>
Minimal working example (reproduce and fix)
# Create a demo repo
mkdir demo-merge && cd demo-merge
git init
echo "v1" > app.txt
git add app.txt
git commit -m "init"
git switch -c feature
echo "feature change" > app.txt
git commit -am "feature: change app.txt"
git switch -
# Make an unstaged change that conflicts with the feature branch
printf "local wip\n" > app.txt
# Attempt to merge -> error
git merge feature
# fatal: refusing to merge because you have unstaged changes.
# Fix 1: stash, then merge, then restore your changes
git stash push -u -m "WIP before merge"
git merge feature
# Resolve conflicts if any, then bring back your work
git stash pop
Why Git refuses to merge
- Your working tree has modifications not in the index (unstaged).
- The merge would update the same paths, risking data loss.
- Git requires a clean working tree or that your edits be safely recorded first.
Resolution strategies
| Strategy | When to use | Commands |
|---|---|---|
| Stash (temporary) | You want to keep uncommitted work but merge now | git stash push -u -m "WIP"; git merge <branch>; git stash pop |
| Commit (permanent) | Your changes are ready to keep in history | git add -A; git commit -m "WIP"; git merge <branch> |
| Discard | You do not need the local edits | git restore .; git clean -fd (optional); git merge <branch> |
| Isolate in worktree | You want to merge in a clean checkout without disturbing WIP | git worktree add ../wt-merge; cd ../wt-merge; git merge <branch> |
Notes:
- Use -u/--include-untracked with stash if new files are involved.
- git clean -fd is destructive; double-check with git clean -fdn first.
Step-by-step: pick the right fix
- Inspect what will be affected
- git status -s
- git diff --name-only
- If specific files are the issue, decide per file: stash, commit, or discard.
- Choose a strategy
- Keep work but not yet ready to commit: stash.
- Ready to keep: commit.
- Not needed: discard.
- Execute the fix
- Stash everything, including untracked files:
- git stash push -u -m "WIP before merge"
- Commit current work:
- git add -A && git commit -m "WIP before merge"
- Discard unstaged changes to tracked files:
- git restore .
- Remove untracked files/directories if they block the merge:
- git clean -fd # irreversible
- Merge
- git merge <branch>
- If conflicts appear, resolve, then git add <files> and git commit.
- Restore or tidy up
- If you used stash: git stash pop
- If you made a temporary WIP commit and want to avoid an extra commit:
- After the merge, optionally squash it away: git reset --soft HEAD^ and recommit with a clean message.
Variations and pro tips
- Partial stash to keep staged work: stage what you want to keep in the index, then stash only unstaged edits:
- git add -p
- git stash push --keep-index -m "stash unstaged only"
- Stash specific paths:
- git stash push -m "partial" -- path/to/file path/to/dir
- Keep a clean CI workspace:
- Use git reset --hard && git clean -ffd before merge-based tasks.
- Work in a separate worktree to avoid disturbing WIP:
- git worktree add ../merge-wt
- cd ../merge-wt && git merge <branch>
Common pitfalls
- Forgetting untracked files:
- git stash does not include untracked files unless you use -u.
- Destructive commands:
- git restore . discards unstaged edits; git clean -fd deletes untracked files. There is no undo.
- Stash conflicts on pop:
- git stash pop can still conflict after the merge. Resolve and continue; your work is not lost.
- Line ending and mode changes:
- Files may look modified due to CRLF/LF or chmod changes. Configure core.autocrlf and filemode appropriately.
- Submodules:
- Modified submodules can block merges. Update or commit submodule pointers, then retry.
Performance notes
- Stashing large trees creates a snapshot; it can be slower than a quick WIP commit. Prefer committing in very large repos.
- Use targeted operations:
- Stash only the necessary paths to reduce snapshot size.
- Avoid repeatedly creating many stashes; list and drop old ones: git stash list, git stash drop <stash>.
- Keep .gitignore accurate so generated files do not churn the working tree.
- In CI/CD, start from a clean checkout to avoid diff scans and merge blockers.
- For monorepos, consider sparse-checkout or partial clones to reduce working set when performing merges.
Tiny FAQ
Why does Git refuse to merge when I have unstaged changes?
- To prevent overwriting your uncommitted work with incoming changes.
Can I merge without losing my edits?
- Yes. Stash or commit your edits first, then merge, and reapply the stash if needed.
Does stash include untracked files?
- Only with -u/--include-untracked. Otherwise untracked files remain.
I ran git pull and saw this error. What now?
- Treat pull as a merge: stash/commit/discard your local edits, then pull. Some Git versions support git pull --autostash; check your git help pull.
After fixing this error, I got merge conflicts. Is that expected?
- Yes. Resolve conflicts, add the files, and commit to complete the merge.