Overview
Windows forbids certain file names and path forms. When a repo contains them, Git on Windows can fail with:
- fatal: invalid path '...'
Common triggers:
- Reserved names: CON, PRN, AUX, NUL, COM1–COM9, LPT1–LPT9 (any extension)
- Invalid characters: < > : " / \ | ? *
- Trailing space or dot in any path segment
- Case-only collisions on case-insensitive filesystems (Windows, macOS default)
- Path length issues (often a different error, but related)
This guide shows how to detect, rename, and, if needed, rewrite history to fix these issues while keeping your team unblocked.
Quickstart (most common fix)
- Detect problematic paths:
- On any OS: use the detector script below.
- Rename the files/directories to Windows-safe names:
- Easiest: perform the rename on Linux/macOS or inside WSL, then push.
- Or use your Git hosting web UI to rename and commit.
- Push the fix and have Windows users fetch/checkout:
- If the invalid names were only in the latest commit, a normal pull works.
- If you rewrote history, coordinate a force-push and fresh clones.
- Prevent regressions:
- On Windows: git config --global core.protectNTFS true
- Add a pre-receive or pre-commit hook to block new invalid paths.
Minimal working example: detect and fix by renaming
The following demonstrates finding a bad file and renaming it to a safe path on a POSIX environment (Linux/macOS/WSL) and pushing the fix.
# Clone the repo that fails on Windows
git clone https://example.com/org/repo.git
cd repo
# 1) Detect invalid paths (see full detector below for more checks)
git ls-files | grep -Ei '(^|/)(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|/|$)'
# Suppose it prints: src/AUX/config.json
# 2) Rename to a safe name
git mv src/AUX src/aux_device
# 3) Commit and push
git commit -m "Rename AUX to aux_device for Windows compatibility"
git push
# Windows users can now pull and checkout successfully
Detect invalid paths (script)
Use this fast detector to list paths that are invalid on Windows.
#!/usr/bin/env bash
set -euo pipefail
regex_reserved='(^|/)(?i:con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|/|$)'
regex_badchars='[<>:"\\|?*]'
problem=0
while IFS= read -r -d '' p; do
base=$(basename "$p")
segs_ok=1
# Check reserved names
if [[ "$p" =~ $regex_reserved ]]; then echo "RESERVED: $p"; segs_ok=0; fi
# Check invalid characters
if [[ "$p" =~ $regex_badchars ]]; then echo "BADCHARS: $p"; segs_ok=0; fi
# Trailing space or dot in any segment
IFS='/' read -ra parts <<< "$p"
for s in "${parts[@]}"; do
if [[ "$s" =~ [[:space:].]$ ]]; then echo "TRAILING-DOT/SPACE: $p"; segs_ok=0; break; fi
done
# Case-collision heuristic (same path differing only by case)
lower=$(printf %s "$p" | tr '[:upper:]' '[:lower:]')
echo "$lower" >> .git/.casecheck.tmp
(( problem |= 1-segs_ok ))
done < <(git ls-files -z)
# Case-collision report
if sort .git/.casecheck.tmp | uniq -d | grep -q .; then
echo "CASE-COLLISION: multiple entries differ only by case"; sort .git/.casecheck.tmp | uniq -d
problem=1
fi
rm -f .git/.casecheck.tmp
exit $problem
If it exits nonzero or prints lines, you have paths to fix.
Remedies
1) Rename on a POSIX filesystem (recommended)
- Use Linux/macOS or WSL (inside the Linux filesystem, not /mnt/c).
- Perform git mv to safe names, commit, and push.
- Safe naming tips:
- Avoid reserved names entirely, even with extensions.
- Replace invalid characters with hyphens or underscores.
- Remove trailing dots/spaces; normalize spaces.
Example renames:
git mv "docs/CON.txt" docs/con_device.txt
git mv "src/prn" src/print_port
git mv "models/v1./schema.json" models/v1/schema.json
2) Rename via hosting web UI
- If you only have Windows, use GitHub/GitLab/Bitbucket’s web editor to rename and commit.
- Then pull on Windows.
3) Temporarily exclude bad paths with sparse-checkout
If you must proceed on Windows before fixing upstream:
git clone --no-checkout https://example.com/org/repo.git
cd repo
git sparse-checkout init --cone
# Exclude known-bad directories or files
echo 'bad/dir/' >> .git/info/sparse-checkout
echo '!bad/dir/' >> .git/info/sparse-checkout
# Or: git sparse-checkout set path/you/need
git checkout
Note: This avoids checking out problematic paths but does not fix the repo.
4) Case-only renames on Windows
Windows is case-insensitive. Do a two-step rename:
git mv File.txt file.tmp && git commit -m "temp rename"
git mv file.tmp file.txt && git commit -m "final case rename"
Or perform the single rename on a POSIX system.
5) Path length issues
If the error is actually about long paths, enable long paths support:
# Windows Git
git config --global core.longpaths true
You may also need OS-level long path support enabled. Shorten long directory names when possible.
Rewrite history (if bad names exist in past commits)
If tags/old commits contain invalid paths, Windows users may fail when checking them out. Use git filter-repo to rewrite:
# Install git-filter-repo first, then:
# Rename across history
git filter-repo --path-rename 'legacy/AUX':'legacy/aux_device'
# Or delete an impossible path from history
git filter-repo --path 'bad/CON.txt' --invert-paths
# Force-push and coordinate with the team
git push --force --tags origin main
Caution: History rewrites require everyone to rebase or reclone. Communicate changes and freeze merges during the rewrite.
Prevent regressions
- On Windows, keep protection on:
git config --global core.protectNTFS true
- Add a pre-commit or pre-receive hook using the detector to block invalid paths.
- Document naming rules in CONTRIBUTING.md.
Pitfalls
- Trailing whitespace/dots may be invisible in code reviews; use the detector.
- Submodules: fix names in submodules and update the superproject SHA.
- Archives: old tags may still contain invalid names after a partial fix; consider a history rewrite.
- WSL: operate inside the Linux filesystem (e.g., /home), not /mnt/c, to avoid Windows filename rules.
Performance notes (Windows)
- Enable fast index operations:
git config --global core.fscache true
git config --global core.preloadindex true
- Large history rewrites are I/O bound; run on SSDs and exclude repo paths from real-time antivirus during the operation.
- Use sparse-checkout or partial clone to limit data while you fix names.
FAQ
Q: Why does my repo work on Linux but fail on Windows? A: Windows forbids certain names/characters and path forms. Git stores paths verbatim; checkout fails when the filesystem rejects them.
Q: Can I keep files named CON if I never develop on Windows? A: Yes, but contributors on Windows will be blocked. Safer to rename for cross-platform compatibility.
Q: Does adding an extension (e.g., CON.txt) make it valid? A: No. Reserved names are invalid even with extensions.
Q: Will core.longpaths fix invalid names? A: No. It only helps with long paths. You must rename invalid files.
Q: Do I have to rewrite history? A: Only if you need Windows users to check out old commits/tags that contain invalid paths. Otherwise, fixing the latest state may be enough.