Home DevOps Git LFS — A 2GB .git Folder Broke CI for Everyone
Intermediate 3 min · July 07, 2026
Git LFS: Large File Storage for Git Repositories

Git LFS — A 2GB .git Folder Broke CI for Everyone

Binary assets bloated the .git folder to 2GB.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Production
production tested
July 07, 2026
last updated
214
articles · all by Naren
Before you start⏱ 20 min
  • Solid grasp of devops fundamentals
  • Comfortable reading and writing code examples independently
  • Basic understanding of production deployment concepts
 ● Production Incident
Quick Answer

Install with brew install git-lfs or apt install git-lfs. Run git lfs track '*.psd' to track PSD files. Commit the .gitattributes file. Git LFS transparently replaces tracked files with pointers.

✦ Definition~90s read
What is Git LFS?

Git LFS (Large File Storage) replaces large files in your repository with text pointers, storing the actual file content on a remote server. This keeps your .git folder small and clone/push/pull operations fast.

Git stores every version of every file in the .git folder.
Plain-English First

Git stores every version of every file in the .git folder. A 10MB image modified 100 times = 1GB in .git. Git LFS is like a valet parking service for big files: you hand the keys (a text pointer) to Git, and the valet (LFS server) parks the actual car (binary file) elsewhere. When you need the car, the valet brings it back. Your garage (.git) stays small because you're only storing parking tickets (42-byte pointers), not the cars themselves.

Git is designed for text files. Every version of every file lives in .git forever. A 100MB design file modified 50 times generates 5GB of .git storage — and everyone who clones the repo downloads all 5GB. Git LFS solves this by replacing large files with text pointers and storing the actual blobs on a remote server. The trade-off: LFS files aren't in the object store, so git bisect, git log -p, and git archive may not include LFS content. This guide covers setup, the incident that broke CI with a 2GB .git folder, and how to migrate existing history to LFS.

Installing and Configuring Git LFS

Install git-lfs: brew install git-lfs (macOS) or apt install git-lfs (Linux). Run git lfs install once to configure Git. Then track file patterns: git lfs track '*.psd' creates/updates .gitattributes.

git lfs track supports glob patterns: .zip, assets//.png, .psd, .sketch. Each pattern adds a line to .gitattributes. Commit .gitattributes to share the tracking rules with your team.

Push and pull work transparently: git push uploads LFS files alongside commits. git pull downloads LFS files. git lfs pull fetches only LFS content (run after a shallow clone).

LFS files stored on GitHub LFS count toward your GitHub storage quota (1GB free, paid plans for more). Self-hosted LFS servers are available for enterprises.

01_lfs_setup.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Install and configure git-lfs
git lfs install

# Track large file patterns
git lfs track '*.psd'
git lfs track '*.zip'
git lfs track 'assets/**/*.png'

# Commit the .gitattributes file
git add .gitattributes
git commit -m 'chore: configure Git LFS for binary assets'

# Add a large file (it's automatically handled)
cp ~/design.psd .
git add design.psd
git commit -m 'feat: add design mockup'

# Check what files LFS is tracking
git lfs ls-files

# See LFS status
git lfs status
Output
Updated Git hooks.
Git LFS initialized.
Tracking '*.psd'
Tracking '*.zip'
* design.psd (SHA: a1b2c3d...)
Git LFS objects to be pushed to origin/main:
design.psd (2.3 MB)
LFS Files Are NOT in the Object Store
Git LFS files are stored on the LFS server, not in the Git object database. git bisect, git log -p, and git archive don't include LFS content by default. Use GIT_LFS_SKIP_SMUDGE=1 to clone without downloading LFS files, then selectively fetch what you need.
Production Insight
In CI/CD, use shallow clones + GIT_LFS_SKIP_SMUDGE=1 to avoid downloading LFS files unless the build needs them. For builds that need assets, use git lfs pull --include='.png' --exclude='.psd' to fetch only what's required. GitHub Actions users: actions/checkout@v4 with lfs: true handles this automatically.
Key Takeaway
Git LFS replaces large files with text pointers. Install before adding binaries. Track patterns via .gitattributes. CI should use shallow clones + selective LFS smudge. Migrate existing history with git lfs migrate import.
● Production incidentPOST-MORTEMseverity: high

CI Clone Time Went From 2 Seconds to 15 Minutes — Blame 2GB .git

Symptom
A design team started committing 50-200MB Sketch and Figma export files. Within 3 months, .git was 2GB. CI clones took 15 minutes. Developers started skipping pulls. Merge conflicts piled up. Deployments slowed to a crawl.
Assumption
The team assumed Git could handle binary files as efficiently as text. They didn't realize Git stores every version of every binary, and large files never get smaller.
Root cause
1. Design files (15-25MB each) were committed alongside code. 2. Each designer iteration created a new version stored in .git. 3. After 3 months, 15 designers × 20 iterations × 10MB average = ~3GB of binary blobs in .git. 4. CI ran git clone --depth 1 but even depth 1 required downloading the pack files containing LFS-like blobs. 5. CI clone time went from 2 seconds to 15+ minutes. 6. Developers avoided pulling main because of the download time, leading to stale branches and merge hell.
Fix
1. Installed git-lfs on all machines: brew install git-lfs. 2. Created .gitattributes with .psd filter=lfs diff=lfs merge=lfs -text. 3. Ran git lfs migrate import --include='.psd,.sketch,.fig' --everything to rewrite history. 4. Force-pushed the cleaned history (coordinated team-wide reset). 5. Updated CI pipeline to install git-lfs and run git lfs pull only for essential assets. 6. Set LFS file size limit to 50MB per file.
Key lesson
  • Git stores every version of every binary file.
  • LFS replaces binaries with text pointers.
  • Install LFS BEFORE binary files enter the repo.
  • Migrate existing history with git lfs migrate import.
  • CI should use shallow clones + selective LFS pull.
Production debug guideUse this when production is on fire3 entries
Symptom · 01
Repo is growing too large due to binary files
Fix
Install git-lfs, track large file patterns with git lfs track
Symptom · 02
Need to migrate existing large files in history
Fix
Use `git lfs migrate import --include='*.psd' --everything'
Symptom · 03
CI clones are too slow due to .git size
Fix
Add git lfs fetch --all only when needed, otherwise shallow clone + LFS smudge

Key takeaways

1
Git stores every version of every file
binaries bloat .git exponentially
2
LFS replaces large files with 42-byte text pointers
3
Track patterns in .gitattributes and commit the file
4
CI should skip LFS smudge and fetch only needed assets
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Verified
production tested
July 07, 2026
last updated
214
articles · all by Naren
🔥

That's Git. Mark it forged?

3 min read · try the examples if you haven't

Previous
Signed Commits with GPG: Verify Your Identity in Git
33 / 47 · Git
Next
GitHub Issues and Projects: Track Work Beyond Code