Mastering LF/CRLF Issues and Binary File Management with .gitattributes

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Why Does Your Project Need .gitattributes?

Phantom “modified” errors when working across Windows and Mac are a nightmare for many dev teams. You just git pull new code, and before typing a single line, Git reports dozens of changed files. Opening git diff reveals the entire file content replaced by itself, with the only difference being the hidden line ending characters.

The culprit is the difference between LF (\n) on Unix/macOS and CRLF (\r\n) on Windows. Previously, many people used git config --global core.autocrlf true. However, this method relies on individual discipline. If just one member forgets the configuration or uses a GUI tool that overrides it, the entire commit log becomes chaotic.

I once spent over 3 hours debugging a shell script (.sh) running on Docker. It turned out a teammate on Windows had accidentally changed it to CRLF. Consequently, the bash script on Linux threw a ^M: bad interpreter error and couldn’t execute. To avoid these silly mistakes, .gitattributes is a mandatory solution for every professional project.

This file enforces Git rules at the repository level. Regardless of which operating system your colleagues use, Git will always handle files according to the team’s common standard.

Implementing .gitattributes in 30 Seconds

Simply create a file named .gitattributes in your project’s root directory. Think of it like a .gitignore file but for file formats. Once created, commit it to the repo so every member receives this configuration.

# Quickly create the file from terminal
touch .gitattributes

The file structure follows the rule: [file pattern] [attribute]. Git prioritizes rules from top to bottom. Subsequent declarations will override previous rules if there’s an overlap.

The “Golden” Ruleset for Real-World Projects

Here is the configuration I usually apply to ensure the project runs smoothly across all environments.

1. Automatic End-of-Line (EOL) Handling

First, set a general rule for all text files. The line below helps Git automatically identify text files. It will auto-convert them to LF when saving to the Git database. Upon checkout to a local machine, Git will automatically adjust based on the user’s operating system.

# Default rule for all text files
* text=auto

For specific files that need to run on Linux servers or Windows executables, you should specify them explicitly:

# Enforce LF for scripts running on Unix/Linux/Docker
*.sh text eol=lf
*.py text eol=lf
*.js text eol=lf

# Enforce CRLF for Windows batch files
*.bat text eol=crlf
*.cmd text eol=crlf

2. Protecting Binary Files

Git sometimes attempts to “fix” line endings for images or PDF files. This can completely corrupt the file. I’ve encountered cases where a .png file increased in size by several KB and couldn’t be opened because Git automatically inserted line ending characters.

Use the binary attribute to tell Git: “Don’t touch the internal content”.

# Mark image files as binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary

# Document, font, and executable files
*.pdf binary
*.woff binary
*.ttf binary
*.exe binary
*.dll binary

3. Quick Tip for CSV and Excel Files

If you work with CSV data, enforcing the CRLF format will help users opening files in Excel on Windows avoid column jumping or font issues.

# Ensure CSV is always Windows Excel-friendly
*.csv text eol=crlf

How to Apply the Configuration to Existing Projects

After creating .gitattributes, previously committed files will retain their old format. You need to perform a “renormalization” to apply the new rules across the entire repo:

# 1. Clear the Git index (don't worry, this doesn't delete actual files)
git rm --cached -r .

# 2. Re-add all files so Git applies the new rules
git add .

# 3. Commit and push to the server
git commit -m "Normalize line endings according to .gitattributes"

To check which attributes a file is receiving, use the git check-attr command. This is the fastest way to debug when a “stubborn” file isn’t following the rules.

# Check script.sh file
git check-attr -a script.sh

# Expected output:
# script.sh: text: set
# script.sh: eol: lf

An important note: test thoroughly on a separate branch. Ask a colleague using a different operating system to pull and test before merging into main. If no files are reported as “modified” without reason, you’ve succeeded.

Mastering .gitattributes keeps your team’s commit history cleaner. You’ll no longer waste time on pull requests containing thousands of lines of changes just because of line endings. Set it up today to protect your project.

Share: