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.

Updated Jul 27, 2026 · Francisco

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:

FileWhere it goes
Source, text, config, .md, .json, .cs, .py — any sizePlain git
Any binary you expect to edit or re-export — models, textures, .psd, audio, videoLFS, even if it’s small today
Anything ≥ 10 MBLFS
Anything ≥ 100 MBLFS — 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:

  1. 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.
  2. 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), run git lfs install once, 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 once git-lfs is 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-lfs installed.
  • 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 .meta files (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 without git-lfs installed. Install it, then git 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

Source: content/systems/git-lfs.md · maintained in the lab docs repository.