All articles

CRLF vs LF: why line ending characters still matter

Push a repository through GitHub Actions with both windows-latest and ubuntu-latest runners in the build matrix, and line endings stop being a theoretical concern — Windows runners check out files with core.autocrlf defaulting to true, so the exact same commit can produce CRLF on one runner and LF on the other.

Where the split came from

Unix and macOS use a single character — LF (line feed, \n). Windows inherited a pair of characters from old teletype machines — CRLF (carriage return + line feed, \r\n): one character returns the carriage to the start of the line, the other moves down a line — a literal emulation of a typewriter.

Why it still matters

  • Git. If a CRLF file ends up in a repository where other files use LF, git can show "the entire file changed" even though only one line was edited — because technically every line ending changed.
  • Shebang scripts. A Unix shell script saved with CRLF endings can fail to run, because the interpreter sees a stray \r character on the first line.
  • String comparison in code. A line read from a CRLF file can fail to match an expected LF string in a comparison, even if the visible text looks the same.

How this gets handled

Git's core.autocrlf setting automatically converts line endings on checkout/commit, but relying on every contributor's local config is fragile. A .gitattributes file checked into the repo is the more reliable fix — it pins the line-ending style per file type (for example, forcing LF on *.sh regardless of what OS or editor touched it) so the behavior doesn't depend on anyone's personal git settings.

Why manual conversion is needed

  • Fixing a file that ended up in a repository with the wrong line-ending style.
  • Preparing a Unix script that was edited in a Windows editor before deploying it to a Linux server.
  • Diagnosing why a text comparison of two seemingly identical files shows a difference.

Mixed line endings in one file

A file edited across multiple editors or operating systems can contain both CRLF and LF at once — part of the lines with one style, part with the other. This is the trickiest case: converting "to LF" appears to change nothing for lines that already had LF, but the conversion needs to be applied to the whole file, not just the visibly "suspicious" lines, or the problem stays hidden.

Try the tool