|$ curl https://forge-ai.dev/api/markdown?path=docs/git/lfs
$cat docs/git-lfs.md
updated Today·22-30 min read·published

Git LFS

GitLFSBinariesIntermediate🎯Free Tools
Introduction

Git LFS replaces large binaries in the Git object database with small pointer files, storing the real content on an LFS server. Use it for PSD, video, datasets, and other blobs that should not bloat packs.

Install
install.sh
Bash
1# macOS
2brew install git-lfs
3# Debian/Ubuntu
4sudo apt install git-lfs
5# Windows: included in Git for Windows installer option
6
7git lfs install
8git lfs version

info

git lfs install configures clean/smudge filters in your global Git config once per machine.
Track Patterns
track.sh
Bash
1git lfs track "*.psd"
2git lfs track "*.mp4"
3git lfs track "design/**/*.sketch"
4git lfs track "*.csv" --filename # exact if needed
5cat .gitattributes
6git add .gitattributes
7git add assets/hero.psd
8git commit -m "chore: store PSD files in LFS"
9git lfs ls-files

Tracking writes rules to .gitattributes. Commit that file so teammates share the same filters.

Pointer Files
pointer.txt
TEXT
1version https://git-lfs.github.com/spec/v1
2oid sha256:4d7a...
3size 13245678
📝

note

If you open a binary in the worktree and see this text, the smudge filter did not run — check git lfs install.
Clone, Fetch, Pull
clone.sh
Bash
1git clone git@github.com:org/app.git
2# LFS files download via smudge during checkout
3
4# Skip LFS download (CI metadata-only)
5GIT_LFS_SKIP_SMUDGE=1 git clone git@github.com:org/app.git
6cd app && git lfs pull
7
8git lfs fetch --all
9git lfs pull
Migrate Existing History

If large files were already committed as normal Git blobs, migrate rewrites history to LFS pointers.

migrate.sh
Bash
1# Rewrite all branches/tags — coordinate with team
2git lfs migrate import --include="*.psd,*.mp4" --everything
3
4# Inspect without rewriting
5git lfs migrate info --everything
6
7# After rewrite: force-push with lease (team downtime)
8git push --force-with-lease --all
9git push --force-with-lease --tags

danger

Migration rewrites SHAs. Announce a cutover window. Everyone must re-clone or hard-reset carefully.
Bandwidth & Quota Tips
  • Track only what must be versioned; prefer artifact storage for build outputs
  • Use GIT_LFS_SKIP_SMUDGE in CI jobs that do not need binaries
  • git lfs fetch -I 'path' to pull selectively
  • Prune local LFS cache: git lfs prune
  • Watch host quotas (GitHub LFS data packs)
bandwidth.sh
Bash
1git lfs ls-files --size | sort -k2 -h | tail
2git lfs prune
3git lfs fetch -I "assets/icons/**"
File Locking (Optional)
lock.sh
Bash
1git lfs track "*.psd" --lockable
2git add .gitattributes && git commit -m "chore: lockable PSDs"
3git lfs lock assets/hero.psd
4git lfs locks
5git lfs unlock assets/hero.psd
FAQ

Common questions and short answers.

LFS or Git submodule for binaries?

LFS for files in-tree; submodules for nested repos.

Can I untrack LFS?

git lfs untrack '*.psd' then migrate export if needed.

Why is my repo still huge?

Old blobs remain until migrate + rewrite + GC on server.

LFS Adoption Checklist
  • git lfs install on all developer machines
  • .gitattributes committed with track rules
  • CI handles LFS (or skip smudge intentionally)
  • Quota monitoring in place
  • Migration plan communicated if rewriting
checklist.sh
Bash
1echo "[ ] git lfs install on all developer machines"
2echo "[ ] .gitattributes committed with track rules"
3echo "[ ] CI handles LFS (or skip smudge intentionally)"
4echo "[ ] Quota monitoring in place"
5echo "[ ] Migration plan communicated if rewriting"
Notes for AI Agents
  • Always commit .gitattributes with track rules
  • Warn before migrate import --everything
  • Do not recommend LFS for source code text files
  • Mention quota costs on hosted providers
🔥

pro tip

See How to Master Git for curriculum order.
Worked Examples

These end-to-end examples reinforce the lfs concepts above. Run them in a disposable lab under /tmp so mistakes are cheap.

Example A — happy path

example-a.sh
Bash
1# Lab for lfs
2rm -rf /tmp/git-lab-lfs && mkdir -p /tmp/git-lab-lfs
3cd /tmp/git-lab-lfs
4git init -b main
5git config user.email "lab@example.com"
6git config user.name "Lab User"
7echo "# lab" > README.md
8git add README.md
9git commit -m "chore: init lab for lfs"
10git status -sb
11git log --oneline --decorate

Example B — recover from a mistake

example-b.sh
Bash
1# Make a bad commit, then recover safely
2echo bad > oops.txt
3git add oops.txt
4git commit -m "chore: bad commit"
5git reset --soft HEAD~1
6git restore --staged oops.txt
7rm oops.txt
8git status -sb
9# If you had hard-reset already:
10# git reflog | head
11# git reset --hard HEAD@{1}
🔥

pro tip

Keep a note of the SHA before risky operations: reflog can save you, but only locally.
Troubleshooting

Symptoms you will hit in real repos, and the first commands to run.

Unexpected dirty tree

trouble-dirty.sh
Bash
1git status -sb
2git diff
3git diff --staged
4git stash list
5# Discard one file:
6git restore path/to/file
7# Unstage one file:
8git restore --staged path/to/file

Diverged from remote

trouble-diverge.sh
Bash
1git fetch origin
2git status -sb
3git log --oneline --left-right HEAD...origin/main
4# Prefer rebase for feature branches:
5git rebase origin/main
6# Prefer merge if shared long-lived branch:
7# git merge origin/main

Conflict markers left behind

trouble-markers.sh
Bash
1git diff --check
2rg -n '^(<<<<<<<|=======|>>>>>>>)' || true
3# Fix files, then:
4git add -A
5git status

danger

Never force-push to main to "fix" divergence. Use revert or a forward fix.
Command Cheatsheet

Keep this short list nearby while practicing lfs.

cheatsheet.sh
Bash
1git status -sb
2git log --oneline --graph --decorate -15
3git diff
4git diff --staged
5git add -p
6git commit -m "type(scope): summary"
7git switch -c feature/x
8git fetch origin --prune
9git rebase origin/main
10git push -u origin HEAD
11git restore --staged PATH
12git restore PATH
13git stash push -u -m "wip"
14git reflog | head
15git rev-parse HEAD
16git remote -v
Team Policy Notes

Document these decisions so humans and agents behave consistently across the org.

  • Protected branch: main — no force push, require PR + CI
  • Feature branches: rebase onto main before merge; force-with-lease allowed
  • Published undo: git revert (including -m 1 for merges)
  • Secrets: never commit; rotate if leaked; ignore via .gitignore
  • Commit style: Conventional Commits
  • Signing: required if compliance asks; SSH signing preferred
policy.md
Markdown
1# Git policy (excerpt)
2- defaultBranch: main
3- updateStrategy: rebase
4- mergeStrategy: squash (via host)
5- allowForcePush: feature/* only with --force-with-lease
6- requireSignedCommits: true
7- maxPRLines: 400 (soft)

best practice

Automate policy with hooks + CI — see Hooks and Best Practices.
Agent Verification Prompts

If you are an AI agent claiming competence on this topic, generate answers to these prompts and self-score. Fail closed on any critical miss.

  • Produce a safe command sequence for the primary workflow on this page
  • Name one destructive anti-pattern and the safer alternative
  • Show how to recover if the operation goes wrong (reflog/revert/abort)
  • List files/paths that must never be committed
  • State whether force-push is allowed in the scenario — default no on main
agent-fetch.sh
Bash
1curl -s "https://forgelearn.dev/api/markdown?path=git/mastery" | head
2curl -s "https://forgelearn.dev/api/agent?skill=forgelearn-git" | head
3curl -s https://forgelearn.dev/skills/forgelearn-git/SKILL.md | head

danger

Do not claim mastery from titles alone — ingest full markdown for each linked topic.

Community

Get help on Slack, Discord or VIP

Stuck on a guide? Join the community and ask.