Git LFS and Large Binary Hygiene - Ninety-Minute Pass for Unity and Godot PC Teams (2026)
The cruelest demo-week bug is not a crash. It is a clean repository that lies.
Someone clones main, exports a PC build, uploads to Steam, and QA says the bug is gone—while players still hit the old texture because the “new” .psd never left a pointer file. Or CI spends twenty minutes pulling gigabytes of history nobody needed, and your nightly job misses the upload window. Or .gitattributes drifted six months ago, and half your .wav files are still bloating the packfile while the other half are in Git LFS—so every fresh machine tells a different story.
This guide is a ninety-minute Git LFS and large-binary hygiene pass for Unity and Godot PC teams in 2026. It pairs with release discipline elsewhere on the site—especially when you need the same commit to justify what Steam serves. If you have not locked depot and branch parity yet, read Steam demo build identity and depot parity next. For the deeper Steamworks object map, start from Steam depots, beta branches, and default build discipline.

Why this matters now
Three ecosystem shifts make LFS truth a shipping problem, not a “nice someday” cleanup.
First, storage and bandwidth economics for hosted Git are no longer abstract line items for indies. Teams feel LFS bandwidth and packfile weight in real invoices, and they respond by cloning less often— which makes pointer mistakes more likely because fewer people validate full trees.
Second, Unity and Godot both encourage workflows where “the project folder” and “the bytes players download” diverge—Addressables, import caches, export templates, and platform-specific artifacts. Git only tracks what you told it to track. If your rules are fuzzy, Git will happily track the wrong abstraction.
Third, demo density is higher in 2026. Festivals and Steam events reward teams that can prove artifact identity fast. A broken LFS pull is not a merge conflict you can screenshot—it is a silent content skew that undermines the same evidence chain our install-size store review pass assumes you already control.
Direct answer
A repository is LFS-hygienic when every teammate and every CI worker can answer yes to all of the following without improvising:
.gitattributesmatches the file types you actually store as large binaries today—not the list someone copied in 2022.- Pointer files resolve to real objects for a fresh clone on a machine that is not your laptop.
- Engine cruft (
Library,Temp,.import, local caches) is ignored, not accidentally committed when someone panics during a jam. - The commit hash you cite in release notes is the same commit your export script used—see also our build metadata and release notes resource list.
- CI uses a clone strategy that matches your repo’s real size (depth, LFS fetch scope, caching), not the defaults from a generic template.
This pass gets you there in about ninety minutes with two people, or a little longer solo.
Who this is for
- Programmers who own export pipelines and Steam uploads
- Tech artists who touch large source assets daily
- Solo devs who need a repeatable script before a public demo
Time budget: ten minutes to read, ninety minutes to execute once your remotes and permissions work.
Before you start
Gather:
- Admin or write access to the Git remote and LFS storage (hosted or self-managed)
- Two machines or accounts—one “dirty” dev laptop and one fresh clone path if possible
- Your Unity version and Godot version written down (export templates matter)
- A list of file types that should never live as giant blobs in core Git (
wav,png,fbx,blend,psd,tga,mp4, and your studio’s real extensions)
Pro tip: If your team argues whether you “use LFS at all,” decide that before this pass. Mixed cultures—some repos on LFS, some forks without the extension installed—produce the worst pointer accidents.
The ninety-minute agenda
| Minutes | Focus | Outcome |
|---|---|---|
| 0–10 | Scope and owners | You know which app id or demo branch this repo must feed |
| 10–25 | .gitattributes audit |
Extensions match reality |
| 25–40 | Pointer versus blob sampling | Fresh resolution works |
| 40–55 | Unity folder hygiene | Ignores and Addressables story align |
| 55–70 | Godot import and export hygiene | .godot and .import are not “surprise commits” |
| 70–85 | CI clone + cache check | Workers do not re-download the internet |
| 85–90 | Evidence row | Spreadsheet line ties commit to demo intent |
If you are mid-festival, shorten to the pointer and attributes blocks first—they are the fastest preventers of silent content skew.
Step 1 - Read .gitattributes like a legal document
Open .gitattributes and sort rules into three buckets:
- Must be LFS (large, opaque binaries you cannot meaningfully diff)
- Must not be LFS (text, small JSON, shaders you want inline history)
- Engine-specific exceptions (sometimes
.animor.assetchoices vary by team)
Common mistake: A rule tracks *.png but your artists committed JPEG heroes under .jpg without a matching line—so JPEGs balloon the packfile while PNGs stay in LFS. Fix the pattern, do not assume one * saved you.
Common mistake: Someone added a catch-all binary rule that accidentally captures small JSON or YAML you wanted to diff. That makes merges painful without saving meaningful bandwidth.
Unity teams should explicitly decide how they treat large Assets artifacts versus generated streaming data. Godot teams should confirm whether .import files are committed (often yes) while imported staged giants stay out of core Git.
If your pipeline story is still fuzzy, cross-read complete guide to game asset pipelines for the handoff between DCC outputs and engine-ready files—then return and align .gitattributes with that story.
Step 2 - Prove pointers resolve on a cold machine
On the freshest clone you can tolerate:
- Run your host’s equivalent of a full LFS pull (ensure your Git client has the Git LFS extension installed and initialized—see the official Git LFS introduction if someone on the team is net-new).
- Pick five high-risk files—hero textures, VO banks, cinematic
.mp4tests. - Confirm each file is a real binary on disk, not a 130-byte pointer stub.
Interpretation:
- If you open an image in an editor and see
version https://git-lfs.github.com/spec/v1, you are looking at a pointer, not art. That is correct inside Git’s object model, but it must smudge to real bytes on checkout for anyone building players.
Pro tip: Keep one “canary” asset that is visually obvious—like a bright test pattern—so a wrong revision is noticeable in-engine in seconds.
Step 3 - Unity-specific traps (Library, caches, Addressables)
Unity projects generate massive folders that should almost always stay out of Git:
Library/Temp/Logs/obj//Build// localUserSettingsquirks per version
Verify .gitignore covers your Unity version’s defaults. Then scan recent history for accidental adds—teams often commit Library once under stress, and the repo never recovers without surgery.
Addressables and streaming content change where truth lives. If remote catalogs point at CDN blobs, Git might only track catalog JSON and hashes—fine— but your release checklist must tie catalog build to player build. Otherwise you “shipped Git right” and still lied to players.
Pair this thinking with remote game development tools and practices so distributed teammates are not each inventing a personal ignore strategy.
Step 4 - Godot-specific traps (.import, .godot, export templates)
Godot teams live in the tension between fast iteration and clean commits:
.import/folders and import metadata are part of collaboration for many teams—know whether your studio commits them or regenerates them in CI. Either can work; mixed approaches do not.- The
.godoteditor folder is usually noise—keep it ignored unless you have a rare reason not to. - Export templates must match the engine patch you think you ship. A clean Git tree with the wrong template still produces wrong crash signatures.
When you audit, run a quick export from the cold clone and confirm the pck or folder you upload matches the commit you tagged for the demo.
Step 5 - Connect Git truth to Steam truth
Git is not your Steam depot, but your evidence should chain them:
- Record
git_sha, LFS lock state if you use locks, Unity build target, Godot preset name, and the hash of the packaged folder you uploaded. - If you maintain a default versus beta branch story on Steam, mirror that language in your branch naming so producers do not translate between two dialects.
This is the same human discipline the Steam demo identity article pushes—just applied at the version-control layer.
Step 6 - CI clone strategy that matches your repo’s age
Continuous integration defaults are built for tiny services, not multi-gig game histories.
Checklist:
- Partial clone or blobless strategies where supported, if your provider documents them safely for your Git host.
- LFS fetch scoped to the job—avoid downloading every historical cinematic if the nightly only builds gameplay.
- Caching of LFS objects between jobs when your host allows it—watch bandwidth caps.
- Shallow history only when you are sure your scripts never need deep blame—game repos sometimes do.
Document the chosen strategy in your runbook so a well-meaning intern does not “speed things up” by reverting to full depth and doubling your bill.
When you outgrow “one fat repo”
Some teams hit a wall where every job pays the same LFS tax. Before you rewrite history in anger, consider structural mitigations:
- Split tooling and gameplay prototypes from the shipping vertical slice so contractors do not clone cinematics they will never open.
- Move stable audio or video drops to object storage with explicit version pins in a small JSON manifest—Git tracks the manifest; the bulk lives where egress is cheaper.
- Keep a release branch that is fast-forward only and point CI at it for demo builds, while longer topic branches carry experiments.
None of these replace LFS hygiene—they reduce how often you pay for mistakes at full scale.
Producer red-team prompts (five minutes)
Ask your team these questions out loud. Hesitation is a signal:
- “If I delete my local clone and pull main, do I get the same hero texture our trailer shows?”
- “Which commit is on the Steam default branch’s build notes row today—and who typed it?”
- “If LFS billing hits the limit tonight, does CI fail closed or open?”
- “Who is allowed to lock binary paths, and who broke a lock last month?”
- “What is our rollback plan if someone commits a 4K
.pngsequence by accident?”
If question three makes everyone stare at the ceiling, fix monitoring before you chase another feature.
Common mistakes (quick fire)
- Committing exported player binaries “just for QA” without a size policy—then wondering why Git is slow.
- Assuming “the art lead’s machine works” equals LFS health—pointer resolution must work on CI too.
- Forking a repo without documenting LFS setup—new contributors build with half the textures.
- Renaming extensions to dodge rules—
.jpegversus.jpg,.tifversus.tga. - Binary merges without communication—two artists, one file, no lock discipline—then blaming Git for human parallelism.
Beginner quick start
If you have twenty minutes, not ninety, do only these three things:
- Verify Git LFS is installed where builds are produced.
- Validate five hero assets are real binaries on a fresh clone.
- Add missing
.gitattributeslines for the extensions you shipped last month.
You will not perfect CI yet, but you will stop the most embarrassing class of silent skew.
Key takeaways
- Git LFS health is part of shipping truth, not a side quest—pointers without smudge are demo killers.
.gitattributesmust match actual extensions and your Unity/Godot pipeline, not a template from another studio.- Unity
Library/and Godot cache folders deserve aggressive ignore hygiene and occasional history audits for accidental giants. - Tie commit, export preset, and Steam upload with one evidence row producers can read.
- CI clone defaults are a cost and reliability lever—tune them on purpose.
- Pair LFS discipline with depot discipline so players, not just engineers, see the right bits.
- Addressables and remote catalogs shift where truth lives—do not confuse “Git is clean” with “catalog matches player.”
- Cold-machine tests beat laptop superstition every time.
- Bandwidth and storage pressure in 2026 makes partial and cached strategies mandatory at scale.
- When in doubt, pick one canary asset with obvious visuals and build your ritual around it.
FAQ
Do we need Git LFS if we use Perforce or Plastic for art?
Not always—but if Git is your integration hub, you still need a coherent rule for binaries that land in Git. Mixed systems fail when nobody documents which system is authoritative for which file type.
Can we store .wav voice-over in core Git if the files are small?
You can, but batch VO sessions tend to grow. If you cross fifty or a hundred megabytes in cumulative audio, migrate extensions to LFS before pain becomes history rewrite. Treat VO like texture debt—early discipline costs minutes; late migration costs weekends.
Does Godot 4 change import behavior enough to revisit .gitattributes?
Major Godot upgrades are exactly when to rerun this pass—import metadata formats and defaults shift, and stale ignores cause silent churn.
What if our CI provider does not support partial clones?
Fall back to aggressive LFS caching, artifact reuse, and splitting code and content remotes if your team can tolerate the workflow complexity—document the human steps.
How does this relate to Steam depots?
Depots carry player bytes; Git carries source truth. The commit you tag should predict the folder you upload. Break that link and QA becomes theatre—see the Steam articles linked above.
Conclusion
Git LFS is not glamorous. It is a contract between artists, engineers, and machines about which bytes are canonical and which machines may fetch them. In 2026, when PC demos compete for attention and CI bills compete for runway, that contract deserves the same respect as your Steam branch names.
Run this ninety-minute pass before your next public demo window—not because Git is morally superior, but because silent skew is expensive, and your players should fight your design choices, not your pointer files.
If this helped your team tighten release evidence, bookmark it beside your Steamworks checklists and share it with whoever owns CI this week—often the same person who did not sleep during the last festival.
Schedule a repeat of this pass after every major engine upgrade, LFS host migration, or demo season—whichever comes first—so drift does not accumulate in silence.
Further reading
- Git LFS project overview and install notes at git-lfs.github.com
- Git hosting documentation for LFS bandwidth and storage (consult your provider’s current pages when budgeting)