Should you use Crab or Git LFS?
Both keep large bytes out of normal Git blobs. The important difference is what gets transferred and who owns the data path.
Both tools keep an 8 GB model out of ordinary Git blobs. The difference starts after Git stores the pointer: Git LFS transfers a complete file object through an LFS endpoint; Crab splits the file into reusable chunks and transfers them to your bucket.
Where the large bytes travel
Scroll horizontally to explore the full diagram →
Compare one repository
Use a concrete project instead of a feature checklist:
vision-search/
├── README.md
├── src/train.py
└── models/encoder.safetensors # 8 GBThe source files stay in normal Git. Only the model follows the large-file path.
Git LFS
git lfs install
git lfs track '*.safetensors'
git add .gitattributes models/encoder.safetensors
git commit -m "Train encoder v1"
git pushgit lfs track writes the shared rule to .gitattributes. The commit contains an LFS pointer; the pre-push hook sends the 8 GB object to the configured LFS endpoint.
Crab
In a configured Crab repository:
crab track '*.safetensors'
crab ship . -m "Train encoder v1"crab track also writes a shared .gitattributes rule. crab ship stages the files, creates the commit, and pushes new chunks through Crab's native pipeline.
| After the first push | Git LFS | Crab |
|---|---|---|
| Git stores | LFS pointer | Crab pointer |
| Large data stores | One 8 GB LFS object | Chunks packed into xorbs |
| Data path owner | Forge or LFS service operator | Your object-storage account |
The second version is the useful test
Now train version 2. It is still 8 GB, but 7.5 GB of encoded bytes are unchanged and 0.5 GB are new.
# Git LFS
git add models/encoder.safetensors
git commit -m "Train encoder v2"
git push
# Crab
crab ship models/encoder.safetensors -m "Train encoder v2"The Git LFS pointer specification gives the complete file one SHA-256 object ID and size. A changed file gets a new ID. The LFS Batch API requests that object by ID and size, and the standard basic transfer uploads its raw bytes.
Crab hashes chunks inside the file. Chunks already proven in the remote do not need another upload.
One local edit preserves distant chunks
Scroll horizontally to explore the full diagram →
| Illustrative result | Git LFS | Crab |
|---|---|---|
| Version 1 data | 8 GB | 8 GB |
| New data for version 2 | 8 GB | about 0.5 GB |
| Data after two versions | 16 GB | about 8.5 GB |
These numbers show the storage unit, not a promised ratio. Recompression, encryption, or a format rewrite can change bytes across the whole file and leave little for Crab to reuse. Test the real files your team produces.
Checkout: decide when the 8 GB becomes local
Git LFS normally replaces pointers during checkout. You can skip that download and fetch a narrower path later:
git lfs install --skip-smudge
git lfs fetch --include='models/encoder.safetensors'
git lfs checkout models/encoder.safetensorsCrab can keep managed files as pointers, hydrate a known working set, or expose files through a mount:
crab config set checkout.lazy true
crab hydrate models/encoder.safetensorsChoose when bytes become local
Scroll horizontally to explore the full diagram →
The practical question is local disk, not clone speed alone. If a developer needs one checkpoint from a 500 GB repository, measure how clearly each workflow selects and removes that working set.
Who handles a failed transfer?
| Question | Hosted Git LFS | Crab |
|---|---|---|
| Who serves large data? | Forge's LFS service | Object-storage provider |
| What does the client authenticate to? | LFS endpoint | Repository bucket or prefix |
| Where do you inspect access? | Forge or LFS service logs | Bucket access logs and policy |
| Who owns quotas and retention? | Forge plan and service policy | Your storage account and lifecycle rules |
Self-hosting Git LFS changes the first column: you gain control and also own another service. Crab removes a Crab data server, but every developer machine and CI runner still needs Crab plus valid object-storage credentials.
Choose the boundary your team can operate at 2 a.m. A lower upload number does not rescue an unusable credential flow.
Migration is a separate choice
Do not rewrite history just because a two-version pilot favors Crab.
Crab's LFS compatibility path keeps existing LFS pointers and commit IDs while routing transfers through Crab:
crab lfs install
crab lfs fetch
crab lfs checkout
crab lfs fsckA native conversion is different:
crab lfs migrate export \
--include '*.safetensors' \
--to-crab \
--everything \
--object-map ../lfs-to-crab.csvThat command replaces selected LFS pointers with Crab pointers. Rewritten commits and their descendants get new Git IDs, so test it in an isolated clone and coordinate the cutover.
Compatibility and migration are separate decisions
Scroll horizontally to explore the full diagram →
Run a two-version pilot
- 1Push the same source tree and 8 GB model from an empty cache.
- 2Clone from another machine and materialize only encoder.safetensors.
- 3Create version 2 with the same training or export process used in production.
- 4Push again; record uploaded bytes, requests, elapsed time, and local disk use.
- 5Reconstruct both versions from a fresh client and compare their cryptographic hashes.
Also record setup time, credential delivery, quota visibility, and recovery from an interrupted push. Those results often decide the system before raw transfer speed does.
Choose in 30 seconds
Choose Git LFS when your forge's LFS service is the easiest boundary to operate, existing tools require LFS pointers, and large files change infrequently.
Choose Crab when versions share substantial encoded bytes, the team wants data in its own bucket, or contributors should hydrate and mount only what they need.
Choose a pilot when files are compressed, encrypted, or regenerated. Their extensions cannot tell you how many bytes will survive between versions.
If Crab fits, continue with How do you set up a Crab repository?. If you already use LFS, read How do you move a Git LFS repository to Crab? before changing history.
KNOWLEDGE PROOF
Check the decision, not your memory.
An 8 GB model changes by 500 MB of reusable byte regions. What difference should you measure?