Command Palette

Search for a command to run...

Hectal
PHASE 7Advanced ~14 min· topic 1 of 5

Topic 7.1

Line Endings, .gitattributes & Large Files (Git LFS)

In one line

Windows and Unix-based systems use different invisible line-ending characters, .gitattributes lets you control exactly how Git handles that (and other file-type quirks) per-file-type, and Git LFS solves the genuine problem of large binary files bloating a repository's history forever.

0/5 · 0%

Think of it like this

Two people writing on the same page, one always pressing Enter with a slightly different, invisible keystroke than the other — visually identical on screen, but the underlying character sequence differs, and version control sees that difference as a change even when nothing meaningful actually changed.

Key ideas

  1. 01

    Windows traditionally uses CRLF (carriage return + line feed) to end each line; Unix-based systems (Linux, macOS) use just LF (line feed) — a genuinely common cross-platform annoyance where a file that looks completely unchanged shows as ENTIRELY modified in git diff, purely because line endings were silently converted by an editor or Git itself.

  2. 02

    git config --global core.autocrlf true (on Windows) or input (on Mac/Linux) tells Git to normalize line endings automatically — converting to LF when committing and, on Windows specifically, back to CRLF when checking files out, so the repository itself stores a consistent format regardless of which OS anyone commits from.

  3. 03

    A .gitattributes file, committed to the repository itself (unlike personal core.autocrlf config), makes line-ending handling CONSISTENT for every contributor regardless of their own local Git configuration — * text=auto is the standard baseline line, letting Git auto-detect text files and normalize them, with more specific rules addable per file type (e.g. forcing .sh files to always use LF, since a CRLF shell script can genuinely fail to run on Linux).

  4. 04

    .gitattributes also controls other genuinely useful per-file-type behavior beyond line endings — marking specific files as binary (never attempt a text diff or line-ending conversion on them, correct for anything like compiled assets or images), or configuring a custom diff driver for a file type Git can't meaningfully diff as plain text otherwise.

  5. 05

    GIT LFS (Large File Storage) solves a different, genuine problem: committing large binary files (video, high-res images, datasets) directly bloats the repository's history PERMANENTLY, since Git normally keeps every version of every file forever — LFS instead stores a small pointer file in the actual Git history, with the real large file content kept in separate LFS storage, fetched on demand only when needed.

Code & diagrams

.gitattributesmarkdown

A realistic baseline for a cross-platform project.

# Auto-detect text files and normalize their line endings
* text=auto

# Force these specific types to always use LF, regardless of OS,
# since a CRLF shell script can fail to run on Linux
*.sh text eol=lf

# Never attempt to diff or line-ending-convert genuine binary files
*.png binary
*.jpg binary
*.pdf binary
git-lfs.shmarkdown

Setting up LFS for a specific large file type — requires the git-lfs tool installed once.

# One-time setup per machine
git lfs install

# Tell LFS to manage a specific file pattern
git lfs track "*.psd"
git lfs track "datasets/*.csv"

# This creates/updates .gitattributes automatically — commit it
git add .gitattributes
git commit -m "Track large files with Git LFS"

# From now on, files matching those patterns are stored via LFS automatically
git add design-mockup.psd
git commit -m "Add design mockup"
# The actual .psd content lives in LFS storage;
# Git's own history just stores a small pointer file

# Confirm what's currently tracked by LFS
git lfs ls-files

Explain it without notes

01

Why can a file that looks completely unchanged show up as fully modified in git diff, when working across Windows and Unix-based systems?

02

What specific problem does Git LFS solve that a plain .gitignore entry for large files does not?

Practice

01

Create a .gitattributes with * text=auto plus a forced-LF rule for one file type, and commit it to a test repository.

02

If you have git-lfs available, track a file type with it, commit a matching file, and confirm with git lfs ls-files that it's being managed by LFS rather than stored directly in normal Git history.

Trade-offs

  • ↔

    Git LFS solves the large-file bloat problem genuinely well, but it adds a real dependency (the git-lfs tool must be installed by everyone who clones the repo) and a genuine ongoing cost (LFS storage is often billed separately by hosting platforms, based on storage and bandwidth) — for a project with only occasional, small binary assets, plain Git without LFS is simpler and sufficient; LFS earns its complexity specifically once large files are numerous or change frequently.

Done when you can

  • I understand why CRLF vs LF line endings can make an unchanged file appear fully modified.

  • I can write a basic .gitattributes file to normalize line endings consistently for a whole team.

  • I know what problem Git LFS solves and when a project genuinely needs it.