| Every edit re-stores the whole file |
A delta filter tuned for line diffs finds no structural similarity between two
zstd-compressed texture mips. Flip one texel and you get a brand-new multi-gigabyte
object, stored in full, next to the old one. |
| History only grows |
There's no garbage collector deciding old asset revisions are unreachable and
safe to drop - they sit in the object store forever, whether any live branch
references them or not. |
| Dedup is whole-blob, exact-match only |
LFS addresses content by the SHA-256 of the entire file. "Nearly
identical" isn't "identical" to a hash function - move one texel and the whole
object is a new, unrelated hash with zero storage reuse against the old one. |
| No partial or lazy fetch |
The smudge filter pulls an LFS object in full before checkout proceeds. There is
no byte-range concept - reading one KB of a 10 GB file still downloads all
10 GB. |
| Pointer-stub roulette |
A pointer file is ~130 bytes of YAML-flavored text pretending to be your asset.
Skip the smudge step - a fresh clone, a misconfigured CI runner - and you commit
that pointer text as if it were the real texture. Nothing stops you. |
| A meter running you don't control |
Hosted LFS storage and bandwidth are billed as their own SKU, separate from the
repository. A team can be nowhere near its Git quota and still get throttled just
for checking out assets. |
| Locking is a courtesy, not a lock |
git lfs lock writes a row to a server-side table that git
push never reads. Enforcement happens in Slack, when someone notices, after
the fact. |
| History rewrite is a scorched-earth op |
git lfs migrate import rewrites every commit that ever touched a
tracked path - new tree hashes, new commit SHAs, top to bottom. Every existing
clone, fork, and open PR is now stale and has to be re-cut. |