GitLine Endings (CRLF vs LF)

Line Endings (CRLF vs LF)

Text files end each line with a special character. Unfortunately, different operating systems use different characters. If you ever clone a repository and Git warns about “LF will be replaced by CRLF”, this is the topic that explains why — and how to make the warnings go away forever.

The basic fact

System

Line ending

Bytes

Unix, Linux, macOS

LF

\n (0x0A)

Windows, DOS

CRLF

\r\n (0x0D 0x0A)

Classic Mac (pre-OSX)

CR

\r (0x0D) — extinct

A text file written on Windows ends each line with two bytes (\\r\\n). The same file written on Linux ends each line with one byte (\\n). The visible content is identical, but the bytes are not, and Git tracks bytes.

Why Git cares

If a Mac user and a Windows user collaborate on the same file without managing line endings, every commit shows the entire file as changed, because every line’s ending byte flipped. Diffs become useless. Merges become painful. Histories balloon.

Git solves this with two settings: core.autocrlf (a per-user default) and .gitattributes (a per-repo override).

core.autocrlf

core.autocrlf controls automatic conversion between Windows and Unix line endings. There are three values:

Value

On checkout

On commit

Use on

true

LF → CRLF

CRLF → LF

Windows

input

no conversion

CRLF → LF

macOS / Linux

false

no conversion

no conversion

when using .gitattributes

Set it once per machine

Bash
# Windows
git config --global core.autocrlf true

# macOS / Linux
git config --global core.autocrlf input

# If you control line endings with .gitattributes instead:
git config --global core.autocrlf false
What 'input' really does
With `core.autocrlf=input`, Git stores LF in the repository (the right thing). When you check files out, Git leaves them as LF — because your OS uses LF anyway. When you commit, Git silently rewrites any stray CRLF to LF. You almost never notice.
.gitattributes — the modern, portable way

core.autocrlf is a personal setting — every contributor must configure it themselves, and they might not. The robust solution is to put a .gitattributes file in your repo so the rules ship with the project.

.gitattributes

Text
# Default: normalize to LF in the repo, native on checkout
* text=auto

# Force LF for these (good for scripts and config that must be LF)
*.sh        text eol=lf
*.bash      text eol=lf
Makefile    text eol=lf

# Force CRLF for Windows-only files
*.bat       text eol=crlf
*.cmd       text eol=crlf

# Treat these as binary (never convert)
*.png       binary
*.jpg       binary
*.pdf       binary
*.zip       binary
*.woff2     binary

Commit .gitattributes to the repo. Now every contributor — regardless of their core.autocrlf setting — gets the same consistent behaviour.

Fixing an already-messed-up repo

If your repository already has inconsistent line endings, do a one-time normalisation:

One-time renormalize

Bash
# 1. Add or update .gitattributes (see above)
# 2. Tell Git to renormalize
git add --renormalize .
# 3. Commit the result
git commit -m "Normalize all line endings"
Inspecting line endings

Useful inspections

Bash
# Show how Git interprets each path
git ls-files --eol

# Look at the raw bytes of a file
cat -A myfile.txt   # macOS/Linux — CR appears as ^M
od -c myfile.txt | head -1

# Find files with CRLF on Linux
grep -rl $'\r' . --exclude-dir=node_modules
The “warning: LF will be replaced by CRLF” message

This warning fires on Windows when core.autocrlf=true and you commit a file that contains LF. Git is telling you: I am about to convert this LF to CRLF when I check it out next time. The repository stores LF either way; only the working-tree copy changes.

It is harmless. You can suppress it if you want:

Bash
git config --global core.safecrlf false
Shell scripts on Windows
Warning
If you save a Bash script with CRLF line endings and try to run it on Linux or macOS, it will fail with errors like `bad interpreter: /bin/bash^M`. Always commit shell scripts with LF — pin this in `.gitattributes` (`*.sh text eol=lf`).
Recommended setup
  • Add a .gitattributes to every repo with at least * text=auto.

  • On macOS/Linux: core.autocrlf=input globally.

  • On Windows: core.autocrlf=true globally — but .gitattributes takes precedence anyway.

  • For mixed-OS teams, use .gitattributes and treat core.autocrlf as a fallback for contributors who did not configure their machines.

  • Force LF for any file that runs on Linux (*.sh, Makefile, Dockerfiles).

  • Force CRLF for Windows-only files (*.bat, *.cmd, *.ps1 if you want them readable in Windows tools).

  • Mark known binary types (*.png, *.pdf, *.zip) as binary.

Tip
If you ever see a pull request whose diff says *every line of every file changed*, line endings are almost certainly the cause. Reject the PR, fix `.gitattributes`, run `git add --renormalize .`, and try again.