You've installed Git and started using it. Everything's going fine — until you run into a warning you've never seen before. Turns out it has a name: the Git line ending problem.

Most developers never configure the autocrlf setting after installing Git. That's completely fine — there's no reason to, especially if you're working solo. Even in a team, it may never come up if everyone's on the same operating system.

The Invisible Character War

While writing this, I kept coming back to this analogy: we write our code, but the operating system quietly appends invisible characters to mark the end of each line.

  • Windows uses both a Carriage Return and a Line Feed — CRLF — at the end of every line. That's the familiar \r\n.
  • Linux/Unix systems use only a Line Feed — LF. Just \n.

A Brief History

This distinction goes all the way back to typewriters.

  • CR (Carriage Return): Physically moved the print head back to the start of the line.
  • LF (Line Feed): Advanced the paper up by one line.

Windows kept simulating both steps separately. The Unix world decided that if a line is over, you're obviously going back to the start anyway — so LF alone is enough.

Why Does Git Show the Whole File as Changed?

Git tracks files byte by byte. When Windows saves a file, it appends \r\n to every line. On macOS and Linux, it's just \n. The text looks identical — you can't see the difference — but at the byte level, every single line is different.

So Git looks at that file and says: "this has changed." Even though you didn't touch a thing. Open the diff and you're staring at 200 red and green lines. A classic first-day surprise. Git usually surfaces this as a warning: LF will be replaced by CRLF or warning: CRLF will be replaced by LF message — sometimes called the "Git line ending warning."

What Does the Warning Look Like?

Git will show one of the following:

warning: LF will be replaced by CRLF
warning: CRLF will be replaced by LF

This means line endings differ between what's on disk and what Git expects to store.

A Real-World Scenario

  • 1. Alice saves a file on Windows. Line endings: \r\n.
  • 2. Bob opens the same file on macOS, changes one character, and saves. Line endings: now \n.
  • 3. Git sees the entire file as modified — every line is a different byte sequence, even though the actual code barely changed. New team members tend to find this one particularly confusing.

How to Fix It

There are two approaches. The quick one: core.autocrlf. The proper one: .gitattributes.

A) Fix with core.autocrlf

On Windows, run git config --global core.autocrlf true. Here's what that does:

  • On commit: converts \r\n → \n before storing
  • On checkout: converts \n → \r\n so Windows gets what it expects
Windows always sees \r\n locally, but the repository always stores \n.

On macOS or Linux, use git config --global core.autocrlf input:

  • On commit: converts \r\n → \n
  • On checkout: leaves the file untouched

The name input means: convert on the way in, don't touch on the way out. There's also a third option — false — which disables conversion entirely. Use it carefully in mixed teams.

The catch: this is a per-machine setting. Every developer has to configure it themselves. New team member joins and forgets? The problem comes back. For a proper fix, you need something that lives in the repository itself.

B) Fix with .gitattributes (the Right Way)

Create a .gitattributes file in your project root, add * text=auto, and commit it. That one line tells Git: normalize all text file line endings. Store \n in the repository, but convert to whatever the local OS expects on checkout.

Need more granular control? You can add file-specific rules:

  • *.bat text eol=crlf — batch files must have \r\n since they run on Windows
  • *.sh text eol=lf — shell scripts must have \n since they run on Linux/macOS

Everything else falls through to the * text=auto rule.

Check Your Current Setting

git config --global core.autocrlf

To summarize the difference: core.autocrlf is a local machine setting — it only applies to the developer who configured it. Anyone new to the project has to set it up themselves. .gitattributes is a repository-level setting — clone the repo and it applies automatically, for everyone.