What these warnings mean
Git is telling you it will convert line endings between LF (Unix) and CRLF (Windows) based on your settings or attributes:
- warning: LF will be replaced by CRLF
- warning: CRLF will be replaced by LF
These appear when adding or checking out files if your line-ending configuration conflicts with the file’s current endings.
Goal: store consistent endings in the repository (usually LF) and define how files are checked out on each platform. Do it with .gitattributes and, if needed, core.autocrlf.
Quickstart: recommended cross-platform fix (deterministic)
Standardize to LF in the repo, allow CRLF only where required (e.g., .bat files). Avoid relying on core.autocrlf.
- Add a .gitattributes at repo root:
* text=auto eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
- Ensure Git will not override via autocrlf:
# Per-repo (preferred)
git config core.autocrlf false
# Or globally
# git config --global core.autocrlf false
- Renormalize tracked files so Git rewrites working tree endings per .gitattributes:
git add --renormalize .
git commit -m "Normalize line endings via .gitattributes"
- Verify:
git ls-files --eol | head
# Expect: i/lf w/lf for most text; i/lf w/crlf where forced
Result: Warnings disappear. The repo stores LF; Windows users get CRLF only for file types you explicitly mark.
Minimal working example
Reproduce a warning and fix it.
# 1) New repo
git init lf-crlf-demo
cd lf-crlf-demo
# 2) Create a text file with LF
echo "hello" > hello.txt
git add hello.txt # on Windows with core.autocrlf=true you may see: LF will be replaced by CRLF
# 3) Add deterministic attributes
cat > .gitattributes <<'EOF'
* text=auto eol=lf
*.bat text eol=crlf
EOF
git add .gitattributes
# 4) Turn off autocrlf in this repo and renormalize
git config core.autocrlf false
git add --renormalize .
git commit -m "Add .gitattributes and normalize"
# 5) Check endings
git ls-files --eol
Alternative strategies
Pick one model and stick to it across your team.
Model A (attributes-first, recommended)
- Repo: LF via .gitattributes (text=auto eol=lf)
- Windows-specific CRLF: only for file types that require CRLF
- Config: core.autocrlf=false everywhere
Model B (autocrlf convenience)
- .gitattributes: minimal normalization
* text=auto *.sh text eol=lf *.bat text eol=crlf - Windows users: git config --global core.autocrlf true
- macOS/Linux users: git config --global core.autocrlf input
- Renormalize after adding attributes: git add --renormalize .
- .gitattributes: minimal normalization
Tip: Use one model per repo to avoid churn.
Step-by-step normalization of an existing repo
- Communicate freeze: ask teammates to pause commits briefly.
- Add/adjust .gitattributes (pick a model above).
- Disable conflicting autocrlf in the repo:
git config core.autocrlf false - Clean and re-checkout (optional but thorough):
or simply: git add --renormalize .git rm -r --cached . git reset --hard - Commit normalization:
git commit -m "Normalize line endings" - Have all contributors pull and, if needed, rebase to avoid large diffs.
Verifying and inspecting line endings
- Show index/working-tree EOL: git ls-files --eol
- Show diffs ignoring EOL: git diff --ignore-cr-at-eol
- Detect CR bytes in files (Unix): grep -Il $'\r' -n .
- On Windows PowerShell, spot CRLF: Get-Content file | ForEach-Object { $_ }
Pitfalls to avoid
- Mixing strategies: core.autocrlf=true on some machines while forcing eol=lf in attributes causes flip-flopping and warnings.
- Forgetting .gitattributes in submodules: each submodule needs its own policy.
- Marking binary as text: text=auto may mis-detect rare binaries. Explicitly mark binaries:
*.png -text *.jpg -text *.pdf -text - Renormalizing on a huge branch: expect large diffs. Coordinate and merge quickly.
- Global overrides: a user’s global core.autocrlf may override expectations. Prefer per-repo config.
Performance notes
- Renormalization cost: git add --renormalize . scans and reindexes all tracked files. On large repos this is I/O heavy; run once, commit, and avoid churn.
- Checkout speed: Minimizing conversions (by standardizing to LF and limiting CRLF to needed types) reduces per-file filters during checkout on all platforms.
- CI efficiency: Set a consistent policy in the repo so CI runners don’t spend time converting endings or producing noisy diffs.
- Binary files: Mark as -text to skip content checks and avoid unnecessary filter passes.
Small FAQ
Q: Can I just hide the warning? A: You can disable it by aligning config with attributes (e.g., core.autocrlf=false and use .gitattributes). Hiding without fixing leads to churn.
Q: What does core.autocrlf=input do? A: It converts CRLF to LF on commit (input), but does not change LF to CRLF on checkout. Good for macOS/Linux.
Q: Do I need core.eol? A: Rarely. Prefer .gitattributes eol=lf/crlf for per-path control. core.eol is a fallback when attributes are absent.
Q: How do I force CRLF for a specific file? A: Add a rule in .gitattributes, e.g., README.txt text eol=crlf, then renormalize and recommit.
Q: How do I recover if a commit flipped thousands of files? A: Add proper .gitattributes, renormalize, commit once, and ensure all contributors update and continue from that commit.
By defining line endings in .gitattributes and aligning core.autocrlf, you eliminate LF/CRLF warnings and keep diffs clean across platforms.