By admin , 29 April 2026

What you will achieve

You will install Git LFS, configure it for a project that includes images, video, and design files, migrate any existing binaries already in history, and verify everything works for collaborators.

Step 1: install Git LFS

# macOS
brew install git-lfs

# Debian/Ubuntu
sudo apt install git-lfs

# Verify
git lfs version

Activate per user (run once):

git lfs install

Step 2: enter the repo

cd path/to/repo
git lfs install --local      # ensure hooks for this repo

Step 3: track file types

git lfs track "*.psd"
git lfs track "*.ai"
git lfs track "*.sketch"
git lfs track "*.mp4"
git lfs track "*.mov"
git lfs track "*.wav"
git lfs track "assets/raw/**"

Each command appends a pattern to .gitattributes:

*.psd filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
assets/raw/** filter=lfs diff=lfs merge=lfs -text

Step 4: commit .gitattributes

git add .gitattributes
git commit -m "Configure LFS tracking for media files"

This is essential - other clones must see .gitattributes to know LFS applies.

Step 5: add new media files

cp ~/Downloads/logo.psd assets/
git add assets/logo.psd
git commit -m "Add logo PSD"
git push

Verify it went via LFS:

git lfs ls-files
# 1234abcd * assets/logo.psd

Step 6: migrate existing binaries

If the repo already has binaries committed normally, rewrite history:

git lfs migrate import --include="*.psd,*.mp4,*.mov,*.wav" --everything

This converts every matching binary in every commit into an LFS pointer. The repo's .git directory shrinks dramatically.

SHAs change. Force-push and have collaborators reclone:

git push --force --all
git push --force --tags

Step 7: lock binary files (optional)

Mark binaries as lockable to prevent concurrent edits:

# .gitattributes
*.psd filter=lfs diff=lfs merge=lfs -text lockable
*.ai filter=lfs diff=lfs merge=lfs -text lockable

Working with locks:

git lfs lock assets/logo.psd
# edit...
git push                       # release lock on push
# or
git lfs unlock assets/logo.psd
git lfs locks                   # see who has what locked

Step 8: verify on a fresh clone

cd /tmp
git clone <url> test-clone
cd test-clone
ls -la assets/logo.psd      # should be the actual file, not a pointer

Inspect a pointer file:

git cat-file -p HEAD:assets/logo.psd
# version https://git-lfs.github.com/spec/v1
# oid sha256:8a1b...
# size 12345678

Step 9: handle quotas

GitHub's free LFS tier is 1 GB storage and 1 GB bandwidth per month. Past that, you pay or self-host.

Self-hosted options:

  • Gitea or Forgejo - LFS built in.
  • GitLab - LFS native.
  • Bare LFS server (rudolfs, lfs-test-server) behind your own object store.

Step 10: pruning

git lfs prune                  # remove old local LFS files no longer referenced
git lfs prune --dry-run         # preview

Useful for laptops with limited disk; the remote keeps everything.

Performance tips

  • Skip LFS smudge on initial clone for speed: GIT_LFS_SKIP_SMUDGE=1 git clone <url>; later git lfs pull.
  • Use git lfs fetch --recent in CI to limit downloaded LFS data.
  • Configure CI caches to retain .git/lfs/.

Troubleshooting

  • Binary committed before .gitattributes was set up: still a regular blob; use git lfs migrate.
  • Pointer file showing in working tree: LFS not installed locally, or smudge skipped. Run git lfs install and git lfs pull.
  • Push rejected for "exceeds maximum size": LFS server quota reached.

The result

The repo's .git stays small; binaries live on the LFS server and are fetched on demand. Designers and engineers collaborate without bloating clone times. The setup pays back the first time someone joins the team and clones in seconds instead of an hour.