What this error means
Git stops a merge (or pull) if it would write a path that currently exists as an untracked file in your working tree. Git refuses to proceed to avoid data loss.
Typical triggers:
- You created local files that aren’t tracked.
- The branch you’re merging adds files with the same paths.
- You ran git pull and the remote branch adds those files.
You must either keep your local files (commit or stash them) or discard/move them before merging.
Quickstart (safe default)
- Save your local untracked files temporarily:
- git stash push -u -m "temp: stash untracked"
- Merge (or pull):
- git pull # or: git fetch && git merge <branch>
- Restore your files and resolve any conflicts:
- git stash pop
- If conflicts arise, resolve them, then git add and git commit.
This flow preserves your work while allowing the merge to complete.
Minimal working example
Reproduce the error, then fix it.
# Create a repo with two branches: one introduces a tracked file.
mkdir demo && cd demo
git init -q
echo base > README.md
git add README.md
git commit -q -m "init"
# Branch that will introduce a tracked file with path 'app.cfg'
git switch -q -c incoming
printf "tracked\n" > app.cfg
git add app.cfg
git commit -q -m "Add app.cfg on incoming"
# Go back to main and create a 'work' branch without that file tracked
git switch -q -c main
git switch -q -c work
# Create a conflicting local UNTRACKED file with the same path
printf "local-only\n" > app.cfg
# Attempting to merge will fail with the error
git merge incoming || true
# fatal: The following untracked working tree files would be overwritten by merge:
# app.cfg
# Fix: stash untracked, merge, then restore
git stash push -u -m "temp untracked" # saves app.cfg
git merge incoming # succeeds now
git stash pop # brings back your local app.cfg
# Resolve any conflicts if Git reports them, then:
# git add <paths> && git commit -m "resolve"
Choose an approach based on intent
| Your intent | Actions |
|---|---|
| Keep your local files and integrate upstream | git add <paths>; git commit -m "keep local"; then merge. You’ll resolve conflicts if contents differ. |
| Temporarily set files aside (recommended) | git stash push -u; merge; git stash pop. |
| Discard local untracked files and take upstream | Preview: git clean -n <paths>; then delete: git clean -f <paths> (add -d for dirs). Then merge. |
| Move local files elsewhere manually | mkdir backup; mv <paths> backup/; merge; compare and reintroduce as needed. |
Notes:
- Don’t rely on .gitignore to solve this: ignoring doesn’t move or delete existing files.
- Use pathspecs to limit scope (e.g., git clean -f -- path/).
Identify the offending files quickly
- List untracked files:
- git status -u
- git ls-files --others --exclude-standard
- See which files the incoming branch will add (that may collide):
git fetch origin # Replace origin/main with the branch you plan to merge git diff --name-only --diff-filter=A HEAD..origin/main - Intersect both lists to pinpoint collisions (POSIX grep-based example):
git diff --name-only --diff-filter=A HEAD..origin/main > incoming_added.txt git ls-files --others --exclude-standard > local_untracked.txt grep -Fxf incoming_added.txt local_untracked.txt || true
Any paths printed by grep are the untracked files that block your merge.
Step-by-step recipes
- Keep your local files (commit them)
- Review what you’re keeping: git status -u
- Commit just the blocking files:
- git add path/one path/two
- git commit -m "keep local versions of blocking files"
- Merge: git pull or git merge origin/main
- Resolve conflicts if any, then git commit.
- Discard local untracked files (take upstream)
- Preview deletions: git clean -n path/one path/two
- Include directories if needed: git clean -nd path/dir/
- Execute: git clean -f path/one path/two (add -d for dirs)
- Merge: git pull
- Stash, merge, unstash (most flexible)
- Save everything untracked too: git stash push -u -m "temp"
- Merge: git pull
- Restore: git stash pop
- Resolve conflicts, then commit.
- Move files out of the way (manual backup)
- mkdir -p backup
- mv path/one path/two backup/
- Merge, compare, and reintroduce selectively.
Pitfalls
- git clean is destructive. Always preview with -n before -f/-fd, and target specific paths.
- Adding patterns to .gitignore does not remove existing files. You must stash, move, or delete them yourself.
- Case-insensitive filesystems (Windows, default macOS) can cause surprises if the merge adds a file that only differs by case (e.g., Config vs config). Rename or clean appropriately.
- Large binary files in stashes consume disk space. Drop stale stashes: git stash drop or git stash clear.
- git pull implies a merge; the same safety check applies to rebase (git pull --rebase) if it would write to paths occupied by untracked files.
Performance notes
- Limit scope. Operate only on blocking paths: git clean -f -- path/; git stash -u -- path/
- Use fast listings. git ls-files --others --exclude-standard is faster than parsing git status output.
- Skip untracked scan when you don’t need it: git status -uno
- Enable untracked cache to speed status on large repos:
- git config --global core.untrackedCache true
- Avoid sweeping cleans (git clean -xfd) in large monorepos; prefer targeted paths to reduce I/O.
Tiny FAQ
- Can I force the merge to overwrite untracked files? No. Git intentionally blocks this to prevent data loss. Move, stash, commit, or clean first.
- Will .gitignore fix the error? No. It only affects future untracked files; existing files remain until you handle them.
- Does rebase avoid the problem? No. Rebase will also stop if applying a commit would overwrite an untracked file.
- How do I keep both versions? Rename or move your local file (or commit it), complete the merge, then compare and reconcile.
- How do I prevent this in CI? Use clean workspaces: fresh clones or a pre-step like git reset --hard && git clean -xfd (be cautious; it deletes untracked files).