# Line Endings: CRLF vs LF
Use LF everywhere. Modern Windows editors (VS Code, Notepad, JetBrains) handle LF fine, and CRLF breaks shell scripts, Dockerfiles, and Makefiles (`bad interpreter: /bin/sh^M`).
The only files that genuinely need CRLF are Windows batch files (`*.bat`, `*.cmd`).
## `.gitattributes` config
Put this at your repo root. It normalizes everything to LF and only opts in CRLF where needed:
```gitattributes
* text=auto eol=lf
*.sh text eol=lf
Makefile text eol=lf
Dockerfile text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
```
This is better than `core.autocrlf` because `.gitattributes` lives in the repo — everyone gets the same behavior without remembering to configure their local Git. ([gitattributes docs](https://git-scm.com/docs/gitattributes), [GitHub guide](https://docs.github.com/articles/dealing-with-line-endings))
## Windows/WSL users
If you use Docker or WSL on Windows, also set:
```bash
git config --global core.autocrlf false
git config --global core.eol lf
```
This tells Git to trust `.gitattributes` and keep LF in the working tree too, avoiding `^M` surprises in containers.
## Pre-commit hook
The [pre-commit](https://pre-commit.com/) framework includes [`mixed-line-ending`](https://github.com/pre-commit/pre-commit-hooks) in its official hooks repo:
```yaml
- repo: https://github.com/pre-commit/pre-commit-hooks
hooks:
- id: mixed-line-ending
args: ['--fix=lf']
```
`--fix=lf` auto-converts to LF. Use `--fix=no` to just fail on mixed endings without modifying files.
For [[Pre-commit#Frameworks|Lefthook]], use a shell one-liner:
```yaml
check-crlf:
glob: "*.{sh,yml,yaml,md,Dockerfile,Makefile}"
run: "grep -rIlP '\\r