Game Development Version Control Best Practices: A Beginner’s Guide

Updated on
11 min read

Version control is an indispensable tool for game development teams, facilitating collaboration, enabling experimentation, and providing a comprehensive project history. This guide is tailored for novice developers and game studios, focusing on effective strategies for managing source code and large binary assets unique to gaming projects. Expect insights on choosing tools, setting up repositories, handling large assets, optimizing workflows, and more. By following these best practices, your team can streamline development processes and minimize common pain points.


1. Choose the Right Version Control System and Tools

Game teams typically choose between distributed systems (Git) and centralized, asset-optimized systems (Perforce / Plastic SCM). Below is a quick comparison to help you decide.

FeatureGit (+ Git LFS)Perforce / Plastic SCM
Best forSmall-to-medium teams, code-heavy reposLarge studios, mono-repos, heavy binary assets
Binary handlingGit LFS (separate store)Native support, fast depot access, file locking
File lockingOptional via Git LFSBuilt-in exclusive locking
CostFree / hosted tiers on GitHub/GitLabCommercial for enterprise; free tiers for small teams
Ecosystem & toolsBroad (GitHub, GitLab, Bitbucket). Lots of GUI/IDE supportStrong studio integrations and scalability

When to use Git:

  • Your team is small or distributed and you want the open ecosystem of Git.
  • Your project is code-forward with some large assets that can be tracked with Git LFS.
  • You prefer hosted options like GitHub or GitLab with built-in CI and issue tracking.

When to consider Perforce or Plastic SCM:

  • You manage many large binaries and need exclusive file locking to prevent conflicting edits.
  • You want very fast performance for mono-repos with many files and large depots.
  • Your studio can invest in Perforce/Plastic licenses and self-hosting or enterprise hosting.

Hosting options include:

  • Git Hosting: GitHub, GitLab, Bitbucket. See detailed Git concepts in Pro Git.
  • Perforce/Plastic: Commonly self-hosted or enterprise-hosted. See Perforce Helix Core docs.

GUI and helper tools:

  • SourceTree, GitKraken, and Git extensions in VSCode/Visual Studio.
  • Perforce has P4V (GUI) and integrations with major engines.

For a hybrid setup, consider using Git for code and Perforce/Plastic for art, or Git combined with Git LFS for binary support.


2. Handle Large Binary Assets Correctly

Storing large files directly in Git can create significant challenges:

  • Git stores the full history of every file in the repo; binary file changes cause size bloat and slow cloning.
  • Binary files aren’t mergeable, leading to manual conflict resolution.

Git LFS (Large File Storage) addresses some of these issues by storing large files as pointers in the Git history, while keeping the actual content separately. Learn more in the Git LFS docs.

Basic setup:

# Install Git LFS
git lfs install

# Track specific file types
git lfs track "*.psd"
git lfs track "*.fbx"

# Commit the .gitattributes file
git add .gitattributes
git commit -m "Enable Git LFS tracking for art assets"

Advantages of Git LFS:

  • Reduces repository clone sizes.
  • Is compatible with many hosting providers (GitHub/GitLab support LFS).
  • Supports file locking in many implementations.

Perforce and Plastic workflows offer optimized performance for large binary assets with exclusive file locking, reducing conflicts. For teams editing large, non-mergeable files (e.g., large PSDs or scene files), Perforce or Plastic are viable options. Check the Perforce Helix Core docs.

Consider alternative storage strategies:

  • Use asset servers or cloud storage (S3, Azure Blob) alongside Git for very large assets.
  • Maintain separate repositories for frequently-changing assets to enhance cloning speeds for developers needing only code.
  • Implement Git submodules or subtrees if necessary, while being aware of the added coordination complexity.

Locking and Ownership:

  • Use exclusive locking for files that cannot be merged safely.
  • For assets allowing merging, standardize workflows and integrate assets frequently.

3. Project Setup: .gitignore, .gitattributes, and Repository Layout

Begin your project with engine-specific templates to exclude build artifacts or user-specific files.

Example .gitignore for Unity:

# Unity
[Ll]ibrary/
[Tt]emp/
[Oo]bj/
[Bb]uild/
UserSettings/
*.csproj
*.sln
*.userprefs

# OS
.DS_Store
Thumbs.db

# Visual Studio
.vs/

.gitattributes for LFS tracking:

*.psd filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text

Logical Repository Layout:

  • /Assets or /Content — engine assets (textures, models, audio)
  • /Source or /Scripts — game code and engine modules
  • /Tools — build tools and scripts
  • /Docs — design documentation and onboarding materials
  • /Builds or /Artifacts — CI-produced builds (not checked in; stored in artifact storage)

Mono-repo vs. Multiple Repositories:

  • Mono-repo: Simplifies refactoring and merge requests; larger clones.
  • Multiple Repositories: Faster for team members needing fewer files; however, adds complexity concerning inter-repo changes.

Choose based on your team size, asset volume, and build infrastructure.


4. Branching, Commits, and Pull Requests — Practical Workflows

Consider the following branching models:

  • Feature Branch Workflow: Create a branch per feature or task, push it, then open a pull request to merge.
  • Trunk-Based Development: Short-lived feature toggles with frequent merges into the main branch; ideal for quick CI and delivery.
  • Gitflow: Encompasses release and hotfix branches; beneficial when managing releases strictly.

Refer to Atlassian’s Git tutorials for more insights.

Practical Commands for a Feature Branch Workflow:

# Create and switch to a new branch
git checkout -b feature/add-inventory-system

# Stage and commit changes
git add .
git commit -m "UI: Add inventory panel and initial data model\n\n- Add InventoryPanel prefab
- Implement InventoryModel and Unit tests"

# Push the branch and open PR
git push -u origin feature/add-inventory-system

Commit Frequency and Message Guidelines:

  • Commit frequently; prefer many small, focused commits over a single large commit.
  • Use a short summary line (50-72 characters) along with an optional body explaining the “why”.

Example Commit Message Template:

Short summary (what changed)

Detailed explanation and reasoning (why changed, impact).
Reference: #ISSUEID (if applicable)

Pull Requests and Code Review Best Practices:

  • Keep PRs small and focused; they’re easier for reviewers.
  • Include screenshots or recorded play sessions to showcase visual changes.
  • Provide artist notes and test builds for art changes.
  • Require at least one reviewer for main branches using branch protection rules.

Handling Art vs. Code Changes:

  • Artists should work on separate branches and coordinate merge timings to support programmers.
  • Implement file locking or designate asset ownership on files that are not mergeable.

5. Merging, Conflicts, and Scene/Asset Strategies

Merges frequently fail with binary assets and engine scenes, but several strategies can help alleviate these issues:

Why Merges Fail:

  • Many game engine files are binary or serialized in a format that isn’t human-readable, making automated merges infeasible.

Unity-specific Advice:

  • Enable Visible Meta Files and Force Text serialization in Unity. This transforms scenes and prefabs into YAML format, enhancing readability and mergeability. You can read more in the Unity Manual.

Best Practices to Reduce Merge Pain:

  • Split large scenes into smaller, additive scenes to allow parallel work.
  • Use prefabs and modular design to minimize dependencies.
  • Commit smaller, frequent changes to avoid larger conflicts.
  • Coordinate with artists to prevent simultaneous edits on the same files.

Resolving Merge Conflicts:

  • Utilize diff/merge tools like Beyond Compare, kdiff3, or your IDE’s merge tool (execute git mergetool).
  • For text-serialized files (YAML), carefully inspect the differences at a hunk level.
  • If uncertain, revert to the last known good commit and reapply changes in smaller increments.

Example Using Git mergetool:

git fetch origin
git checkout feature/branch
git merge origin/main
# If conflicts arise
git mergetool
git commit

6. Automation: CI/CD, Build Servers, and Hook Scripts

Why Automate Builds and Tests?

  • Automation detects integration problems early and offers consistent builds for quality assurance and stakeholders.
  • Even basic automation can save considerable manual effort and minimize regression issues.

Common CI Setups:

  • Cloud CI: Services like GitHub Actions and GitLab CI are excellent for code and small builds.
  • Self-hosted Build Servers: Necessary for extensive engine builds or when large artifacts are generated. See our guide on building a home lab for hardware requirements.
  • Containerized Runners: Provide reproducible environments. Learn more about using Docker for CI.

Pre-commit Hooks and Server-side Checks:

  • Implement pre-commit hooks to enforce formatting and avoid accidentally committing large files.
  • Use server-side checks in CI to validate prefabs, run linting tests, and prevent PRs from breaking validations.

Nightly Builds and Artifact Storage:

  • Generate nightly builds and store them in an artifact repository or cloud storage (like S3 or Azure Blob).
  • Maintain a rotation policy for artifacts to manage storage costs effectively.

Basic Example of GitHub Actions:

name: Build
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Run unit tests
      run: ./run-tests.sh

7. Access Control, Backups, and Disaster Recovery

User Permissions and Branch Protections:

  • Secure main branches with required reviews, status checks, and disallow force pushes.
  • Use detailed permissions for release branches and asset depots.

Backups for Large Binary Stores:

  • Ensure LFS servers, Perforce depots, and artifact storage have solid backup plans.
  • Regularly back up metadata (Git repository) and binary stores (LFS or depot contents).

Disaster Recovery:

  • Develop offsite backup, snapshots, and geo-replication strategies for critical projects.
  • Maintain written restoration procedures and routinely test them to ensure readiness.

8. Common Pitfalls and Troubleshooting Checklist

Slow Clones / Large Repo Size:

  • Identify large files using git rev-list --objects --all | sort -k 2 or by employing tools like BFG Repo-Cleaner.
  • Use BFG or git filter-repo to clean up the repo history if unintentionally committed large files.

Accidentally Committed Binaries:

  • Use BFG or git filter-repo to retroactively remove unwanted files from your history.

Merge Conflicts in Scenes/Prefabs:

  • If using Unity, enable Force Text and split scenes. Prefer manual careful merges or revert and apply changes incrementally if necessary.

LFS Authentication or Storage Quota Issues:

  • Inspect tracked files using git lfs ls-files.
  • If your LFS host has storage quotas, consider cleaning up old assets or upgrading your plan.

Emergency Response:

  • Designate a point person or process for repository emergencies (like accidental git push --force to protected branches, broken CI, or LFS outages).

9. Practical Starter Checklist and Templates

Starter Checklist for a New Project:

  1. Initialize the repository and choose hosting (GitHub/GitLab/Perforce).
  2. Add engine-specific .gitignore.
  3. Enable Git LFS and include .gitattributes for large file extensions.
  4. Formulate a basic branching policy and add branch protections.
  5. Configure basic CI for tests and nightly builds.
  6. Implement backups for repo and LFS/depot storage.

Example .gitattributes Snippet:

*.psd filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text

Sample Branching Policy:

  • main (protected): always pass CI; require 1-2 reviews.
  • develop (optional): integration branch for features.
  • feature/*: short-lived branches for tasks, merged via PR.

Sample Commit Message Template:

Short summary (<=72 chars)

Longer description explaining the "why" and implications.
Refs: #ISSUE

10. Conclusion and Next Steps

Recap:

  • Version control is crucial for collaboration, rollback, and release management in game projects.
  • Begin with Git + Git LFS for most indie and small teams; evaluate Perforce/Plastic for scaling needs, performance, and asset locking.
  • Employ engine-specific settings (e.g., Unity’s visible meta files and Force Text serialization) to ease merging.
  • Automate builds and checks from the start, safeguard essential branches, and regularly back up both metadata and binary stores.

Next Learning Steps:

Where to Get Help:

  • Consult the Pro Git book for foundational Git knowledge.
  • Access the Git LFS docs for handling large files.
  • Leverage community forums, engine-specific documentation, and your studio’s internal knowledge base.

Ready to start? Download the starter .gitignore and .gitattributes snippets! Subscribe for a follow-up tutorial on “Setting up Git LFS and CI for Unity projects.” (Primary CTA: Download starter snippets — Secondary CTA: Subscribe for follow-up tutorial.)


Further Reading and References

Internal Resources You Might Find Useful:

Useful Tools Mentioned:

  • BFG Repo-Cleaner (for history cleanup)
  • kdiff3, Beyond Compare (for merge tools)
  • GitKraken, SourceTree (for GUI clients)

Would you like a downloadable package containing the example .gitignore, .gitattributes, and a README outlining branching policy and commit template ready for your new repository?

TBO Editorial

About the Author

TBO Editorial writes about the latest updates about products and services related to Technology, Business, Finance & Lifestyle. Do get in touch if you want to share any useful article with our community.