Skip to main content
On this page

Version Control

Git with Git LFS for Unreal Engine

Git version control with separate storage for large files and optional file locking.

It's ideal for code-heavy teams that already work in Git. Once artists commit large assets every day, storage, transfer, and locking become the main cost.

What it is

Git LFS stores large-file contents separately from the Git repository. Git commits contain small pointer files that identify the matching LFS objects.

Five distinct 500 MB revisions of an asset can consume about 2.5 GB of LFS storage. The pointer in Git stays small, but the server retains each version of the file.

Every workstation and build agent needs the LFS client, and file locking needs support from the host. Unreal's built-in Git provider is beta and has no check-out or lock state, so artists who need to see locks in the Content Browser install the community UEGitPlugin instead.

With Unreal Engine

Git LFS can track .uasset and .umap files alongside source art and audio. The lockable attribute normally makes matching files read-only until you own the lock. Unreal's built-in Git provider is still beta and can't lock files. Editor-level locking comes from the community UEGitPlugin.

Where it fits

Strengths

  • Developers keep local history, branches, and commits while offline.
  • Git hosting can keep pull requests, automation, issues, and releases beside the repository.
  • Git LFS keeps each distinct large-file revision out of the normal Git object database.

Tradeoffs

  • Every distinct binary content revision adds another LFS object.
  • Adding a rule to .gitattributes does not move existing history into LFS.
  • Locking depends on client setup and host support, and the built-in editor provider has no locking.

Choose it when

  • The team already depends on Git hosting, pull requests, and Git-based automation.
  • Developers need local commits and branches while disconnected.
  • Binary history and transfer can stay within a measured storage budget.

Look elsewhere when

  • The project contains a large binary asset library that changes constantly.
  • Artists need locking that is visible and enforced without command-line setup.
  • The team is unwilling to coordinate history migrations and workstation configuration.

How it works

Pointer files
A pointer records the LFS specification version, a SHA-256 object identifier, and the original file size. Git versions that small text file. The LFS client uses it to fetch the matching object from remote storage.1
.gitattributes
Tracking rules live in .gitattributes. A rule can send *.uasset through LFS and mark it lockable. Commit this file so the artist workstation and the build agent agree on how the same package is stored.12
History migration
New tracking rules don't rewrite earlier commits. The git lfs migrate command can convert existing history, which changes commit IDs. Replacing published history needs a coordinated force push and updated clones.2
Storage and transfer
Each distinct file revision creates an LFS object; identical contents reuse one object. A small Blueprint edit can replace the whole package. Include build-agent downloads and fresh clones when estimating transfer usage.456
Locks and push verification
Marking a pattern lockable normally makes matching files read-only unless the current user owns the lock. Teams can disable that local behavior. On push, Git LFS checks locks with the server and halts a push that touches a file locked by another user. If the server errors, it only warns unless lfs.<url>.locksverify is set to true. Unreal's built-in Git provider can't lock files; the community UEGitPlugin shows and takes LFS locks from the editor.3810

In production

  1. 01

    Define tracking before the first asset commit

    Commit .gitattributes before importing Content, source art, audio, or video. Keep .ini, .uproject, .uplugin, and source files in normal Git unless there is a specific reason not to. The git lfs track command is not retroactive.

  2. 02

    Install and verify every client

    Run git lfs install on each workstation and build agent. Test a clean clone by opening the Unreal project. If an asset contains pointer text, check LFS installation, download settings, credentials, and remote object availability.1

  3. 03

    Lock packages that cannot merge

    Use git lfs lock before editing a lockable package and unlock it after the changed commit reaches the remote. Confirm that lockable files become read-only without an owned lock, then set locksverify to true so a push fails when the lock server can't be reached.3

  4. 04

    Control what each job downloads

    Use fetch include and exclude paths when a job needs only part of the asset tree. Keep a separate backup plan for the Git repository and LFS objects. One without the other does not restore a usable project.

  5. 05

    Restore a clean clone before adoption

    Fetch the protected refs and every LFS object reachable from them into the backup path, then restore them into a machine with no warm cache. Open or build the Unreal project and record storage and transfer totals from that clean run.4

Best practices

Commit attributes before assets
Put the complete .gitattributes policy in the repository before the first Unreal package, source-art file, or large media commit. Mark binary packages as LFS, non-text, and lockable where the team depends on exclusive editing.
Verify pointers in continuous integration
Run git lfs fsck --pointers across the proposed commit range to detect files that belong in LFS but are stored as Git blobs. Test a clean checkout that downloads the objects and opens or builds the project.9
Enable lock verification against the real host
Test the host's locking API and set locksverify to true so pushes fail closed when lock verification errors. Document force-unlock ownership and release locks after the accepted commit reaches the remote.
Budget by revision and download
Estimate storage from every changed binary revision and transfer from fresh clones, build agents, forks, and source archives. The current size of Content is only the starting point.
Mirror Git and LFS together
A migration or backup needs repository refs plus every LFS object reachable from them. Use git lfs fetch --all for the refs being protected, verify the destination objects, and restore into a clean clone before trusting the copy. It does not recover objects reachable only from deleted or orphaned refs.4

Gotchas

git lfs track doesn't convert existing files
The git lfs track command updates .gitattributes. It does not rewrite existing commits, and existing working-tree files may still need git add --renormalize . before they are stored as LFS pointers.2
History migration changes commit IDs
Running git lfs migrate import --everything rewrites reachable history. Open pull requests, tags, forks, build references, and every collaborator need a coordinated cutover and force push.2
Lock behavior has two separate controls
Lockable files are read-only by default unless the user owns the lock, but that behavior can be disabled. Push protection depends on the pre-push hook, host support, and a workflow that acquires the lock before editing. Without locksverify set to true, a server error only produces a warning.3
Source archives may contain only pointers
GitHub ZIP and tar archives omit LFS objects by default. Enabling LFS objects in archives consumes bandwidth, and archives cannot include objects hosted on an external LFS server.7
Pruning ignores the reflog
The git lfs prune command ignores the reflog and can remove objects referenced only by orphaned commits. Review a dry run and verify remote copies before pruning. Don't prune a shared LFS storage directory.45
.gitattributes case matching differs by platform
Pattern matching follows core.ignoreCase, which is usually true on macOS and Windows and false on Linux. A rule for *.png can match .PNG on an artist's machine and miss it on a Linux build agent. Use bracket patterns such as *.[pP][nN][gG].211

Adoption checklist

  • Commit .gitattributes and the Unreal ignore rules before importing content.
  • Confirm the chosen host supports the Git LFS locking API and push verification.
  • Estimate storage from full binary revisions, not the current working tree size.
  • Include build-agent downloads and source archives in transfer estimates.
  • Add pointer and object checks to continuous integration.
  • Write and test a history migration plan before rewriting an existing repository.

Sources

Official sources checked .

  1. 1Git LFS manualgithub.com
  2. 2Git LFS FAQ and migrationgithub.com
  3. 3Git LFS lock verificationgithub.com
  4. 4Git LFS backup fetchgithub.com
  5. 5Git LFS pruninggithub.com
  6. 6Git LFS billingdocs.github.com
  7. 7Git LFS objects in archivesdocs.github.com
  8. 8Unreal Engine team scaling resourcesdev.epicgames.com
  9. 9Git LFS pointer validationgithub.com
  10. 10UEGitPlugin (Project Borealis)github.com
  11. 11Git core.ignoreCasegit-scm.com

Unreal Directive is free and ad-free.

If it saved you time, you can help keep it that way.

Donate