Quick answer: Use Git with LFS for small-to-mid indie teams and Perforce for large studios with massive asset libraries. Track all binary files through LFS, use file locking to prevent merge conflicts on assets, and establish clear ownership conventions for asset directories.
Game repositories are fundamentally different from typical software repositories. A web application might be a few hundred megabytes of source code. A game repository can easily reach tens or hundreds of gigabytes once you include textures, 3D models, audio files, cutscenes, and compiled assets. Standard Git was not designed for this. Without the right version control strategy, your team will face slow clones, impossible merges on binary files, and a repository that grows uncontrollably with every asset revision.
Git with LFS vs. Perforce
The two dominant version control systems for game development are Git (with Large File Storage) and Perforce (Helix Core). Each has distinct strengths depending on your team size and workflow.
Git with LFS extends Git to handle large binary files by storing them on a separate server and keeping only lightweight pointers in the repository. This keeps Git operations fast while supporting files of any size. Git LFS is free, integrates with GitHub and GitLab, and uses the same Git workflow your programmers already know. The tradeoff is that LFS has limited file locking support, clone times can still be slow for very large repositories, and artists unfamiliar with Git may struggle with the command line.
Perforce was built for large binary repositories from the start. It supports exclusive file checkout (preventing merge conflicts by design), streams-based branching that handles massive repositories efficiently, and a visual client (P4V) that artists find more approachable than Git GUIs. Perforce is the industry standard at large studios and integrates natively with Unreal Engine. The downsides are cost (free for up to 5 users, paid beyond that), self-hosting complexity, and a workflow model that differs significantly from Git.
Configuring Git LFS for Games
If you choose Git with LFS, proper configuration is critical. Create a .gitattributes file in your repository root that tracks all binary asset types:
# Textures
*.png filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
# 3D Models
*.fbx filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text
*.gltf filter=lfs diff=lfs merge=lfs -text
*.glb filter=lfs diff=lfs merge=lfs -text
# Audio
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
# Engine-specific
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
*.import filter=lfs diff=lfs merge=lfs -text
Use git lfs lock before editing binary files to prevent other team members from making conflicting changes. Set up a pre-commit hook that warns when someone modifies an unlocked binary file. This is not as seamless as Perforce’s exclusive checkout, but it provides a safety net.
Branching Strategies for Game Projects
Game development branching differs from software branching because binary assets cannot be merged. A branching strategy that works well for code — like feature branches with pull requests — becomes painful when two artists modify the same texture on different branches.
For most indie teams, a simplified trunk-based workflow works best. Keep a single main branch that always represents the current state of the game. Artists commit directly to main (with file locking). Programmers can use short-lived feature branches for code changes, merging frequently. Avoid long-lived branches that diverge significantly from main, as the merge pain increases exponentially with time.
For teams that need parallel development streams — for example, maintaining a live service build while developing the next content update — use a two-branch model with main (current release) and develop (next update). Establish clear rules about which branch receives which types of changes, and merge from main into develop regularly to prevent drift.
Managing Repository Size
Even with LFS, game repositories grow over time as assets are revised. A texture that goes through 20 iterations stores 20 versions on the LFS server. For large projects, this can add up to hundreds of gigabytes of historical data.
Strategies for managing repository size include pruning unused LFS objects periodically, using shallow clones for CI/CD pipelines that do not need full history, and archiving old branches that are no longer active. If your repository exceeds what Git LFS handles comfortably, consider splitting assets into a separate repository or switching to Perforce for the asset portion while keeping code in Git.
Document your repository structure and conventions in a README that every team member reads on day one. Consistent file naming, directory organization, and commit message formats prevent the chaos that large game repositories tend toward without discipline.
Lock your binaries, keep your branches short, and never commit a 500MB PSD to regular Git.