Skip to content

Commit b3d2da2

Browse files
brabojclaude
andauthored
docs: add Git LFS recipe to playbook (#194)
Covers pointer file mechanism, setup, tracking, common operations, migration, hosting quotas, and gotchas. Added to playbook under Project Structure. Closes #165 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9771bfb commit b3d2da2

2 files changed

Lines changed: 161 additions & 0 deletions

File tree

chapters/07-playbook.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ For definitions, see [Glossary](09-glossary.md).
5050
| [Submodules](playbook/submodules.md) | Add, clone, update, and remove submodules |
5151
| [Remove a Submodule](playbook/remove-submodule.md) | Step-by-step cleanup — deinit, git rm, cached data |
5252
| [Subtrees](playbook/subtrees.md) | Add, pull, push, and remove subtrees |
53+
| [Git LFS](playbook/lfs.md) | Track large files with pointer references and external storage |
5354

5455
## Advanced
5556

chapters/recipes/lfs.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
title: "Git LFS"
3+
description: "Git recipes for tracking large files with Git Large File Storage — setup, tracking, common operations, hosting limits, and gotchas."
4+
section: "playbook/lfs"
5+
order: 95
6+
---
7+
8+
## Git Large File Storage
9+
10+
Git stores every version of every file as a blob. For large binary
11+
files — images, videos, datasets, compiled assets — this causes the
12+
repository to grow quickly. Cloning becomes slow, and every developer
13+
downloads the full history of every large file whether they need it
14+
or not.
15+
16+
**Git LFS** (Large File Storage) solves this by replacing large files
17+
with small **pointer files** in the repository. The actual file content
18+
is stored on a separate LFS server. Git downloads large files only
19+
when you check out a commit that needs them.
20+
21+
### How it works
22+
23+
```text
24+
Without LFS:
25+
.git/objects/ contains every version of every large file
26+
repo size grows with each commit that touches a large file
27+
28+
With LFS:
29+
.git/objects/ contains small pointer files (~130 bytes each)
30+
large file content lives on the LFS server
31+
Git downloads only the versions you check out
32+
```
33+
34+
A pointer file looks like this:
35+
36+
```text
37+
version https://git-lfs.github.com/spec/v1
38+
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
39+
size 12345678
40+
```
41+
42+
Git LFS intercepts `push`, `pull`, and `checkout` to upload and
43+
download the real content transparently.
44+
45+
### Setup
46+
47+
Install Git LFS (once per machine):
48+
49+
```text
50+
$ git lfs install
51+
Updated git hooks.
52+
Git LFS initialized.
53+
```
54+
55+
This adds LFS hooks to your global Git configuration. The hooks
56+
intercept Git operations to handle large files automatically.
57+
58+
### Track files by pattern
59+
60+
Tell LFS which files to manage using glob patterns:
61+
62+
```text
63+
$ git lfs track "*.psd"
64+
$ git lfs track "*.zip"
65+
$ git lfs track "assets/videos/**"
66+
```
67+
68+
Each `track` command adds a line to `.gitattributes`:
69+
70+
```text
71+
$ cat .gitattributes
72+
*.psd filter=lfs diff=lfs merge=lfs -text
73+
*.zip filter=lfs diff=lfs merge=lfs -text
74+
assets/videos/** filter=lfs diff=lfs merge=lfs -text
75+
```
76+
77+
Commit `.gitattributes` so other developers get the same LFS rules:
78+
79+
```text
80+
$ git add .gitattributes
81+
$ git commit -m "Track large files with LFS"
82+
```
83+
84+
### Common operations
85+
86+
#### Push
87+
88+
LFS uploads tracked files to the LFS server automatically during
89+
`git push`:
90+
91+
```text
92+
$ git push origin main
93+
Uploading LFS objects: 100% (3/3), 45 MB | 2.1 MB/s, done.
94+
```
95+
96+
#### Pull and fetch
97+
98+
`git pull` downloads LFS files for the current checkout. To download
99+
LFS content without merging:
100+
101+
```text
102+
$ git lfs fetch # download LFS objects for current ref
103+
$ git lfs fetch --all # download LFS objects for all refs
104+
$ git lfs pull # fetch + checkout (update working tree)
105+
```
106+
107+
#### Check tracked files
108+
109+
```text
110+
$ git lfs ls-files # list all LFS-tracked files in the repo
111+
$ git lfs status # show pending LFS uploads
112+
```
113+
114+
### Migrate existing files to LFS
115+
116+
If large files are already in the repository history, use `migrate`
117+
to rewrite history and move them to LFS:
118+
119+
```text
120+
# Migrate all .zip files in the entire history
121+
$ git lfs migrate import --include="*.zip" --everything
122+
123+
# Migrate only in the current branch
124+
$ git lfs migrate import --include="*.zip"
125+
```
126+
127+
This rewrites commits, so coordinate with your team and force-push
128+
afterward.
129+
130+
### Hosting support
131+
132+
| Host | Free LFS storage | Free bandwidth/month |
133+
|------|-------------------|---------------------|
134+
| GitHub | 1 GB | 1 GB |
135+
| GitLab | 5 GB (project) | Unlimited (self-managed) |
136+
| Bitbucket | 1 GB | 5 GB |
137+
138+
All three hosts offer paid plans for additional storage and bandwidth.
139+
Self-hosted GitLab and Bitbucket have configurable limits.
140+
141+
### Gotchas
142+
143+
- **LFS requires server support.** The remote must have an LFS
144+
endpoint. All major hosts support it, but a plain bare repository
145+
on a file server does not.
146+
- **Cloning without LFS installed gives you pointer files.** If a
147+
developer clones without Git LFS installed, they get the small
148+
pointer text instead of the actual files. Run `git lfs pull` after
149+
installing LFS to fix this.
150+
- **CI pipelines need LFS.** If your CI runner does not have Git LFS,
151+
builds that depend on tracked files will fail. Most CI platforms
152+
support LFS — check that `git lfs install` runs before checkout.
153+
- **Forks do not share LFS storage.** On GitHub, each fork has its
154+
own LFS quota. Large LFS repositories can be expensive to fork.
155+
- **Bandwidth counts on download.** Every `git clone`, `git fetch`,
156+
or `git lfs pull` that downloads LFS objects counts against the
157+
bandwidth quota.
158+
- **You cannot un-track a file retroactively.** Removing a pattern
159+
from `.gitattributes` only affects future commits. Existing LFS
160+
pointers in history stay as pointers.

0 commit comments

Comments
 (0)