What this error means
You see:
fatal: The following paths have staged content different from both the file and the HEAD
It occurs when the index (staged version) of a path does not match either:
- the working tree file, and
- the version in HEAD (last committed version).
This usually shows up while running checkout or restore to pull a version from HEAD or another commit, which would overwrite your staged changes.
Quickstart fixes
Decide which version you want to keep, then use one of these targeted fixes:
Keep working tree, drop staged changes for path:
- git restore --staged <path>
- or: git reset HEAD -- <path>
Keep staged version, overwrite working tree with staged:
- git checkout -f -- <path>
Overwrite both staged and working tree with HEAD (discard everything for path):
- git restore -s HEAD --staged --worktree -- <path>
- or: git reset --hard HEAD -- <path>
After applying your choice, re-run the original command.
Minimal working example (reproduce and fix)
# 1) Setup
mkdir demo && cd demo
git init
echo "v1" > app.txt
git add app.txt
git commit -m "init"
# 2) Create staged and working tree differences
# Stage one change…
echo "staged" > app.txt
git add app.txt
# …then modify working tree again without staging
echo "worktree" >> app.txt
# 3) Try to pull HEAD’s version into app.txt (will fail)
# This wants to replace both index and working tree with HEAD
git checkout HEAD -- app.txt
# fatal: The following paths have staged content different from both the file and the HEAD: app.txt
# 4A) Fix option: Keep working tree; drop staged
git restore --staged app.txt
# Now you can restore from HEAD if you still want
git checkout HEAD -- app.txt # or: git restore -s HEAD --worktree -- app.txt
# 4B) Fix option: Keep staged; overwrite working tree
# Reset state again to reproduce the conflict
# (recreate staged + different worktree)
echo "staged" > app.txt && git add app.txt
echo "worktree" >> app.txt
# Force write index to working tree
git checkout -f -- app.txt
# 4C) Fix option: Discard both staged and worktree; use HEAD
git restore -s HEAD --staged --worktree -- app.txt
Step-by-step resolution
- Inspect what differs
- See staged vs HEAD:
- git diff --staged -- <path>
- See working tree vs staged:
- git diff -- <path>
- See HEAD vs working tree (ignoring staged):
- git diff HEAD -- <path>
- Decide which version to keep per path
- Working tree is correct → unstage it
- Staged is correct → force it into working tree
- HEAD is correct → restore both index and working tree from HEAD
- Apply the corresponding command
- Keep working tree:
- git restore --staged <path>
- Keep staged:
- git checkout -f -- <path>
- Keep HEAD:
- git restore -s HEAD --staged --worktree -- <path>
- Verify and continue
- git status
- Re-run your original checkout/restore/rebase/merge command
Why it happens
Commands like git checkout <tree-ish> -- <path> and git restore -s <tree-ish> --staged --worktree <path> attempt to write both the index and the working tree from a given commit. If the index already holds unique changes (different from both HEAD and your working tree), Git refuses to avoid destroying those staged changes inadvertently.
Pitfalls and safety notes
Force flags are destructive
- git checkout -f -- <path> and git reset --hard HEAD -- <path> discard data for that path. Inspect diffs first.
Use pathspecs to limit scope
- Always specify the exact path(s) to avoid impacting unrelated files.
Mixed new Git and legacy commands
- git restore is the modern alternative; git checkout works everywhere. Prefer restore where available for clarity:
- Unstage: git restore --staged <path>
- Restore file only: git restore -s HEAD --worktree -- <path>
- git restore is the modern alternative; git checkout works everywhere. Prefer restore where available for clarity:
CRLF or mode-only changes
- If diffs look odd, check line endings and filemode:
- git config core.autocrlf input|true|false
- git config core.filemode false
- If diffs look odd, check line endings and filemode:
In-progress merges or rebases
- If you are mid-merge/rebase, resolve conflicts or use stash/commit carefully before retrying.
Performance notes (large repos)
- Limit diffs to impacted paths:
- git diff --staged -- <path>
- git status -- <path>
- Avoid scanning the whole repo unnecessarily; target specific files to reduce index/worktree comparison costs.
- If status feels slow, refresh the index timestamps:
- git update-index --refresh
FAQ
Q: Which version am I about to lose with -f? A: For git checkout -f -- <path>, you overwrite the working tree file with the staged content, losing un-staged edits for that path.
Q: How do I keep both staged and my current edits? A: Commit the staged changes first (git commit -m "..."), then stash your working tree edits (git stash push -u) or commit them afterward.
Q: Can I avoid this by operating on only the working tree? A: Yes. Use git restore -s <commit> --worktree -- <path> to change only the file, leaving the index untouched.
Q: Why does git checkout HEAD -- <path> fail here? A: It would modify both the index and working tree from HEAD, discarding staged content. Git blocks that unless you force or unstage first.
Q: Is there a way to preview exactly what is staged? A: Yes. Use git diff --staged and git show :<path> to view the index’s version.