.gitattributes, Line Endings & LFS

.gitattributes - per-path rules

.gitattributes is a file, committed alongside your code (unlike .gitignore, which just excludes paths, this one changes how Git treats the paths it does track), that sets rules for specific files or patterns.

# .gitattributes
* text=auto            # normalize line endings
*.sh text eol=lf       # shell scripts MUST stay LF (or they break on Linux)
*.png binary           # never try to diff/merge binaries
*.psd filter=lfs diff=lfs merge=lfs -text
Danger: The classic cross-platform bug this solves: Windows text editors traditionally end lines with CRLF (carriage return + line feed), while Linux and macOS use just LF. A Windows developer commits a shell script with CRLF endings; it runs fine on their machine, then fails on the Linux server with a cryptic bad interpreter error, because the shell's #!/bin/bash line literally has an invisible extra character on the end. *.sh text eol=lf in .gitattributes forces Git to normalize those line endings for every contributor, regardless of their OS or editor settings.

Git LFS (Large File Storage)

Git is fundamentally bad at large binary files - because every commit stores a full snapshot, even a small change to a huge file (a video, a design file, a dataset) bloats the repository's history forever, since the old versions never go away. Git LFS solves this by storing the actual big file content outside the normal Git history, and keeping only a small, lightweight text pointer inside Git in its place.

$ git lfs install
$ git lfs track "*.psd"     # writes a .gitattributes rule
$ git add .gitattributes design.psd && git commit -m "Add design"
Tip: A simple rule of thumb: source code → plain Git; large binaries that change occasionally (design files, models, datasets) → Git LFS; huge static assets that rarely if ever change (marketing videos, archived releases) → dedicated object storage/CDN, not Git at all, even with LFS.