Help / Systems & Tools / Git LFS — large files (models, textures, builds)
Systems & Tools
Git LFS — large files (models, textures, builds)
When a file is too big for plain git, and how to put it in Git LFS on git.nuilab.org — from the command line and from a GUI client.
Git was built for source code — text files that change a few lines at a time. It handles those beautifully. It handles large binary files badly, and the reason matters:
Every time you change a binary file, git stores a complete new copy of it — forever, in the repository history. Change a 20 MB texture ten times and you’ve added ~200 MB that every person who clones the repo downloads, permanently. You can’t get it back by deleting the file later; it’s already in the history.
Git LFS (Large File Storage) fixes this. The big file is stored outside the repository, and git keeps only a tiny text pointer in its place. Clone is fast, history stays small, and the actual file still appears in your working folder exactly as you’d expect.
Git LFS is enabled on git.nuilab.org (opens in new tab) .
The rule: when does a file go to LFS?
The threshold is 10 MB. Anything at or above that goes in LFS — no exceptions.
But size isn’t the whole story. Use this:
| File | Where it goes |
|---|---|
Source, text, config, .md, .json, .cs, .py — any size | Plain git |
Any binary you expect to edit or re-export — models, textures, .psd, audio, video | LFS, even if it’s small today |
| Anything ≥ 10 MB | LFS |
| Anything ≥ 100 MB | LFS — never plain git |
The middle row is the one people miss. A 3 MB .fbx looks harmless, but if it gets
re-exported twenty times over a semester it costs the repo 60 MB of dead weight. Text files
don’t have this problem — git compresses and diffs them properly — so for source code, size
genuinely doesn’t matter.
“But GitHub allows 100 MB”
It does — GitHub warns at 50 MB and blocks the push at 100 MB. Those are enforced limits: a wall you hit. 10 MB is a recommendation, which is a different thing, and it’s deliberately far below any wall.
Two reasons it’s lower:
- git.nuilab.org has no such wall. We run Forgejo, not GitHub. Nothing will stop you pushing a 400 MB file — so the limit that protects the repo is your judgement, not the server’s.
- The damage isn’t one big file, it’s repetition. No single 12 MB commit gets rejected anywhere. But re-export that asset thirty times and the repository permanently carries 360 MB, which every teammate downloads on every fresh clone. By the time it’s a problem, fixing it means rewriting history for everyone.
So: 100 MB is where git stops you elsewhere. 10 MB is where you should have stopped yourself.
When in doubt, put it in LFS. Moving a file into LFS later means rewriting history for everybody; putting it there from the start costs nothing.
What should never be in the repo at all
Build outputs and caches — Unity’s Library/, Temp/, Build/, obj/, .apk/.exe
builds, node_modules. These regenerate. Put them in .gitignore, not LFS.
One-time setup
Install the git-lfs extension once per machine:
# macOS
brew install git-lfs
# Windows — included with Git for Windows, or:
winget install GitHub.GitLFS
# Ubuntu / Debian
sudo apt install git-lfs
# Fedora
sudo dnf install git-lfs
Then, once per machine:
git lfs install
That’s it — you don’t repeat this per repository.
Command line
Inside the repository, tell LFS which file types to take over:
git lfs track "*.fbx"
git lfs track "*.png"
git lfs track "*.psd"
This writes a .gitattributes file. Commit it — this is the step people forget, and
without it nobody else’s clone knows to use LFS:
git add .gitattributes
git commit -m "Track 3D assets with LFS"
From then on it’s ordinary git. Add, commit, push as usual — LFS intercepts the tracked files automatically:
git add model.fbx
git commit -m "Add hand model"
git push
You’ll see LFS report its own upload during the push:
Uploading LFS objects: 100% (1/1), 13 MB | 4.6 MB/s, done.
Useful commands
git lfs track # what patterns are tracked
git lfs ls-files # which files in this repo are in LFS
git lfs status # LFS view of your pending changes
git lfs pull # fetch LFS content if a clone came down as pointers
git lfs migrate info # audit: what's big in this repo's history
A starter .gitattributes for an XR / Unity project
*.fbx filter=lfs diff=lfs merge=lfs -text
*.obj filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.unitypackage filter=lfs diff=lfs merge=lfs -text
*.asset filter=lfs diff=lfs merge=lfs -text
Drop that in the repository root as .gitattributes and commit it.
From a GUI
The important thing to understand: Git LFS is an extension to git itself, not a feature of
any particular app. Every desktop client runs the real git underneath. So:
Install
git-lfs(above), rungit lfs installonce, and your GUI client picks it up automatically. There is usually nothing to turn on in the app.
Client-specific notes:
- GitHub Desktop — works with git.nuilab.org even though it isn’t GitHub: File → Clone
repository → URL, and paste the
ssh://git@git.nuilab.org:2222/…URL from the Code button. LFS is handled automatically oncegit-lfsis installed. - Sourcetree — has LFS built in. Right-click a repository → Git LFS to see tracked files and to add tracking patterns from the UI.
- GitKraken — LFS support is on by default; tracked files show an LFS badge.
- Fork — same story; LFS just works with
git-lfsinstalled. - VS Code — the built-in Source Control panel shells out to
git, so LFS is transparent. - Unity — use any of the above alongside the editor. Make sure Unity’s
Edit → Project Settings → Editor → Version Control is set to Visible Meta Files, and
commit the
.metafiles (they’re small text — plain git, not LFS).
Editing the .gitattributes file by hand works in every client and is the most reliable
route, whatever app you use.
Seeing LFS files in the web UI
On git.nuilab.org (opens in new tab) , open the repository and click a tracked file — it’s labelled “Stored with Git LFS” with its real size instead of showing you the pointer. The full inventory is under the repository’s Settings → LFS tab.
Already committed something huge?
Don’t panic, but don’t just delete it — the file stays in history and everyone still downloads it. Two cases:
- Not pushed yet — undo the commit (
git reset HEAD~1), add the LFS tracking, re-commit. - Already pushed — it needs a history rewrite (
git lfs migrate import --include="*.fbx"), which changes commit hashes and forces everyone else to re-clone. Coordinate it: message Francisco before running it, don’t do it unilaterally on a shared repository.
Trouble
- A file downloaded as a few lines of text starting
version https://git-lfs.github.com/…— that’s the pointer. You cloned withoutgit-lfsinstalled. Install it, thengit lfs pull. - Your teammates get pointers but you don’t — you almost certainly didn’t commit
.gitattributes. Check it’s in the repository, not just on your disk. - Push rejected for size — the file wasn’t tracked before you committed it. Tracking only applies to commits made after the pattern was added.
- Browser drag-and-drop upload refuses a big file — the web UI has its own upload cap
(Forgejo’s 50 MB default). That limit doesn’t apply to
git push; use the command line or a GUI client.
See also
- Git — code hosting (Forgejo) — signing in, SSH keys, cloning, pushing.
Source: content/systems/git-lfs.md · maintained in the lab docs repository.