GitLarge File Storage (Git LFS)

Git Large File Storage (LFS)

Git is designed for text — source code, configuration files, documentation. It stores every version of every file in history, which works brilliantly for text because diffs are tiny. Binary files like images, videos, compiled assets, and design files do not diff well — every version is stored in full. A 50 MB Photoshop file with 100 revisions consumes 5 GB of repository history just for that one file. Git LFS (Large File Storage) solves this by replacing large binary files in your Git history with tiny pointer files, while storing the actual binary data on a separate LFS server.

How LFS Works
  • You track a file pattern: git lfs track "*.psd"

  • When you commit a matching file, Git LFS intercepts it and stores the binary data on the LFS server

  • What gets committed to Git history is a small pointer file (~130 bytes) — not the binary data

  • When you checkout or pull, LFS automatically downloads the actual file from the LFS server

  • Your working directory always has the real file — the pointer is only visible in the object store

Installing Git LFS

Install and initialize LFS

Bash
# Install via package manager
brew install git-lfs          # macOS
sudo apt install git-lfs      # Ubuntu/Debian
winget install git-lfs        # Windows

# Initialize LFS (installs hooks into ~/.gitconfig)
git lfs install

Example output from git lfs install

Text
Updated Git hooks.
Git LFS initialized.
Tracking File Patterns

The git lfs track command adds patterns to a .gitattributes file. Always commit .gitattributes to the repository so that all collaborators use LFS for the same files.

Track large file patterns

Bash
# Track design files
git lfs track "*.psd"
git lfs track "*.ai"
git lfs track "*.sketch"

# Track video files
git lfs track "*.mp4"
git lfs track "*.mov"

# Track compiled binaries
git lfs track "*.exe"
git lfs track "dist/**"

# Commit .gitattributes (IMPORTANT!)
git add .gitattributes
git commit -m "chore: configure Git LFS tracking"

.gitattributes after tracking

Text
*.psd filter=lfs diff=lfs merge=lfs -text
*.ai filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.exe filter=lfs diff=lfs merge=lfs -text
What a Pointer File Looks Like

When an LFS-tracked file is committed, this is what actually goes into Git history. The oid is a SHA-256 hash of the actual file content, and size is the file size in bytes. The LFS server uses the OID to store and retrieve the actual binary data.

LFS pointer file content (what goes in Git history)

Text
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 2097152
Inspecting LFS Files

Inspect LFS-tracked files

Bash
# List all files currently tracked by LFS
git lfs ls-files

# Show LFS status (modified, staged, etc.)
git lfs status

# Show which patterns are being tracked
git lfs track

git lfs ls-files output

Text
4d7a214614 * assets/hero-image.psd
8c3e1f2a90 * videos/demo-reel.mp4
b1a9d7f3c5 * design/mockups.ai
Fetching and Pulling LFS Objects

LFS fetch and pull commands

Bash
# Download LFS objects for the current branch (but don't checkout)
git lfs fetch

# Download LFS objects for all branches and tags
git lfs fetch --all

# Download AND checkout (most common — equivalent to git pull)
git lfs pull

# If you cloned without LFS, retrieve LFS objects after the fact
git lfs pull
Pushing LFS Objects

Push LFS objects to remote

Bash
# Normal push — LFS objects are pushed automatically along with commits
git push origin main

# Force push all LFS objects (useful if objects are missing on server)
git lfs push --all origin
Warning
`git lfs push --all` uploads every LFS object in your local store, which can be very time-consuming and bandwidth-intensive for large repositories. Only use it when you need to repair a server that is missing LFS objects, for example after migrating to a new LFS endpoint.
Regular Git vs Git LFS

Dimension

Regular Git

Git LFS

Binary file storage

Full copy of every version in history

Pointer in history, binary on LFS server

Clone size

Entire history including all binary versions

Only current version of LFS files by default

Diff/merge for binaries

No meaningful diff; merges fail

Same limitation — binary files still need manual merge

Server requirements

Any Git host

Requires LFS-capable server (GitHub, GitLab, Bitbucket support it)

Working directory

Same as regular Git

Real files downloaded transparently on checkout

Cost

No extra cost

GitHub: 1GB free storage + 1GB bandwidth/month; paid plans available

Offline work

Full history always available locally

LFS objects may not be available offline without pre-fetching

Migrating Existing Binary Files to LFS

If your repository already has a history of large binary files committed the regular way, git lfs migrate can rewrite that history to use LFS. This rewrites commits — everyone must re-clone after migration.

Migrate existing binary files to LFS

Bash
# Migrate all .mp4 files across entire history
git lfs migrate import --include="*.mp4" --everything

# Migrate multiple patterns
git lfs migrate import --include="*.psd,*.ai,*.mp4,*.mov" --everything

# After migration, force push to update remote
git push --force --all
git push --force --tags
Warning
`git lfs migrate import --everything` rewrites all commits that touch the specified files. Every commit hash changes. All collaborators must delete their local clones and re-clone. Coordinate this carefully and communicate the change to your team before running it.
GitHub LFS Storage and Bandwidth
  • Free: 1 GB storage + 1 GB bandwidth per month

  • Data packs: $5/month for 50 GB storage + 50 GB bandwidth

  • Bandwidth: counts each time an LFS object is downloaded (clone, pull, etc.)

  • Storage: counts the total size of all LFS objects stored

  • If you exceed limits, pushes and clones of LFS objects will fail until you upgrade

Tip
For teams with many large assets, consider a dedicated LFS server or a service like Artifactory, AWS S3 + a compatible LFS proxy, or Azure DevOps (which includes LFS at no additional cost). Self-hosting LFS gives you control over storage costs and bandwidth.