# 2. Git LFS for Unity Assets
**Target:** Unity 6000.5+. Part of [[Version Control]]. Assumes [[1. Serialization Meta and Gitignore]].
## Why LFS exists for Unity
Git stores every version of every file in history. A 50 MB texture revised twenty times is painful; a 200 MB audio bank without LFS can **block** pushes to GitHub. Git Large File Storage replaces large file contents with small **pointer** files in Git and stores blobs on an LFS server (GitHub hosts this for GitHub remotes).
- Project site: https://git-lfs.com/
- GitHub: [About Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-git-large-file-storage)
- Configure tracking: [Configuring Git Large File Storage](https://docs.github.com/en/repositories/working-with-files/managing-large-files/configuring-git-large-file-storage)
- Hard GitHub limits without LFS: [About large files on GitHub](https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-large-files-on-github)
### GitHub size facts (from GitHub docs; not invented)
- Warning around **50 MiB** for regular Git files; **hard block above 100 MiB** without LFS.
- Browser uploads capped lower (25 MiB) — irrelevant for normal CLI/Desktop pushes.
- Per-file LFS maximums depend on plan (GitHub docs table: Free/Pro **2 GB**, Team **4 GB**, Enterprise Cloud **5 GB** as of the fetched docs). Confirm current plan limits on GitHub’s LFS pages before assuming headroom.
- Prefer keeping whole repositories small (GitHub recommends ideally **< 1 GB**, strongly **< 5 GB**).
> [!warning] Not verified live
> `git lfs install`, `track`, `lock`, and bandwidth quotas were **not** exercised on Enceladus for this note. Run the commands on your machine and check GitHub **Settings → Billing / Packages & Actions / Git LFS** (UI labels vary) for remaining quota.
## Step 1 — Install and enable LFS once per user
1. Install Git LFS from https://git-lfs.com/ (Windows installer, or package manager). Latest published on that site at fetch time was **v3.8.1** — check the site for the current build; do not hard-pin blindly in team docs without re-checking.
2. In any terminal:
```bash
git lfs install
```
That registers LFS filters for your user account (once per machine/user).
## Step 2 — Decide what to track
**Strong LFS candidates (binary, large, revised often):**
| Pattern | Typical content |
|---|---|
| `*.psd`, `*.psb`, `*.tga`, `*.tif`, `*.tiff` | Source art |
| `*.png`, `*.jpg`, `*.jpeg`, `*.exr`, `*.hdr` | Large textures / HDR (optional if small UI icons — see below) |
| `*.fbx`, `*.obj`, `*.blend` | Meshes / DCC sources |
| `*.wav`, `*.aiff`, `*.mp3`, `*.ogg`, `*.flac` | Audio |
| `*.mp4`, `*.mov`, `*.webm` | Video / cutscenes |
| `*.dll`, `*.so`, `*.dylib`, `*.a`, `*.bundle` | Native plugins (when you must version them) |
| `*.zip`, `*.7z`, `*.rar`, `*.unitypackage` | Archives (prefer not shipping `.unitypackage` in-repo) |
**Usually keep in normal Git (text / tiny):**
- `.cs`, `.shader`, `.hlsl`, `.compute`, `.json`, `.txt`, `.md`
- `.unity`, `.prefab`, `.asset`, `.mat`, `.controller`, `.anim` (YAML after Force Text) — LFS here **defeats** readable diffs and UnityYAMLMerge
- `.meta` files — **never** LFS; they are tiny text GUID carriers
**Judgment call:** thousands of tiny UI PNGs may be fine in Git; a handful of 8K EXRs belong in LFS. Track by **extension + folder** when mixed.
## Step 3 — Track patterns (writes `.gitattributes`)
From the **project root**:
```bash
git lfs track "*.psd"
git lfs track "*.fbx"
git lfs track "*.wav"
git lfs track "*.mp4"
git lfs track "*.dll"
```
Or lockable binaries (see Step 5):
```bash
git lfs track --lockable "*.psd"
git lfs track --lockable "*.fbx"
```
**Always commit `.gitattributes`** so every clone shares the same rules ([GitHub configuring LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files/configuring-git-large-file-storage)):
```bash
git add .gitattributes
git commit -m "Track large Unity binaries with Git LFS"
```
### Example `.gitattributes` (illustrative)
```gitattributes
# Git LFS — adjust to your art/audio pipeline
*.psd filter=lfs diff=lfs merge=lfs -text lockable
*.psb filter=lfs diff=lfs merge=lfs -text lockable
*.fbx filter=lfs diff=lfs merge=lfs -text lockable
*.blend filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.tif filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
# Optional: large textures only under a folder
Assets/Art/Textures/HD/**/*.png filter=lfs diff=lfs merge=lfs -text
Assets/Art/Textures/HD/**/*.jpg filter=lfs diff=lfs merge=lfs -text
# Native plugins (example)
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dylib filter=lfs diff=lfs merge=lfs -text
```
Pointer files look like ([About Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-git-large-file-storage)):
```text
version https://git-lfs.github.com/spec/v1
oid sha256:4cac19622fc3ada9c0fdeadb33f88f367b541f38b89102a3f1261ac81fd5bcb5
size 84977953
```
If a teammate clones **without** LFS installed, they only get pointers — broken textures/audio until they install LFS and fetch ([Collaboration with Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files/collaboration-with-git-large-file-storage)).
## Step 4 — Add, commit, push as usual
```bash
git add Assets/Art/Hero.psd
git commit -m "Add hero PSD (LFS)"
git push origin main
```
You should see LFS transfer progress on push. GitHub Desktop also supports LFS clones/pushes (see GitHub Desktop docs linked from the LFS pages).
## Step 5 — Lock vs unlock (caveats)
Git LFS can mark patterns **`lockable`**. Intent: exclusive edit of non-mergeable binaries.
```bash
# claim
git lfs lock Assets/Art/Hero.psd
# list
git lfs locks
# release when done
git lfs unlock Assets/Art/Hero.psd
```
Reference: [git-lfs-lock(1)](https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-lock.adoc).
### Caveats you must plan for
1. **Server must support locking.** GitHub supports LFS locking for repos that use it; still verify with a test lock on your remote. Locking is **not** a substitute for communication.
2. **Lockable files are often made read-only** in the working tree until locked — artists using DCC tools that refuse read-only files will hit friction. Document the lock → edit → unlock loop.
3. **Locks are social + server-side, not magic.** Someone can still force-unlock (`git lfs unlock --force` where permitted) or edit offline and fight on push. Treat locks like checkouts.
4. **Scenes/Prefabs:** Prefer Prefab isolation and branch discipline ([[4. Conflicts Prefabs and Branching]]) over LFS locks on `.unity` / `.prefab`. Those should stay text + UnityYAMLMerge, not LFS.
5. **Migrating history:** `git lfs track` alone does **not** rewrite old commits. Existing large blobs already in Git need `git lfs migrate` (see git-lfs docs / `git lfs migrate --help`). Migration rewrites history — coordinate with the team.
6. **Bandwidth & storage quotas** are billed/limited on GitHub. Every clone that downloads LFS objects consumes bandwidth. Large binary thrash (re-exporting the same FBX daily) burns quota even with LFS — see [[6. Pitfalls]].
7. **PRs on github.com** often show the **pointer**, not a binary diff ([Collaboration with Git LFS](https://docs.github.com/en/repositories/working-with-files/managing-large-files/collaboration-with-git-large-file-storage)). Review art locally.
## Step 6 — Verify tracking
```bash
git lfs track # patterns
git lfs ls-files # files currently pointer-managed
git check-attr filter -- Assets/Art/Hero.psd
```
Expect `filter: lfs` for tracked paths.
## When UVCS Smart Locks fit better
If your pain is **exclusive checkout of non-mergeable assets** across a mixed artist/engineer team, Unity Version Control’s **Smart Locks** are purpose-built ([Smart Locks](https://docs.unity.com/en-us/unity-version-control/smart-locks)). Compare in [[5. Clients and UVCS Comparison]].
## Next
[[3. UnityYAMLMerge Smart Merge]] — semantic merges for scenes and Prefabs.