Flukz — open-source shmup community resource open-source GPL devlog  ·  about
// indie shmup & game-dev resource

Game Dev · July 6, 2026

Version Control for Game Teams: Git Workflows for Code, Art, and Levels Together

A game repository is not a software repository with pictures added. The binary assets, the merge-hostile level files, and the mixed skill levels of contributors all push against git's default assumptions.

Git was built to version text: diffable, mergeable, small. A shmup project's source code fits that model fine, but the rest of the repository does not. Sprite sheets, audio files, and compiled shaders are binary blobs that git cannot diff meaningfully — every change to a texture, however small, stores a full new copy in history by default. A repository that mixes a few megabytes of code with a few hundred megabytes of art assets will, after a year of active development, become slow to clone and painful to work with unless the binary problem is addressed early.

Git LFS is not optional past a certain project size

Git Large File Storage replaces binary files in the repository with small text pointers, storing the actual file content in a separate store that is fetched on demand. Setting it up takes an afternoon; retrofitting it onto a repository that has already accumulated gigabytes of binary history in its normal object store takes considerably longer, since existing history needs to be rewritten to move those blobs into LFS retroactively. The practical rule for a new project: decide your LFS file-type patterns (`.png`, `.wav`, `.ogg`, `.ttf`, and any project-specific binary formats) in the first commit, before anyone has added a single asset, using a `.gitattributes` file checked into the repo root.

# .gitattributes, committed before any assets are added *.png filter=lfs diff=lfs merge=lfs -text *.wav filter=lfs diff=lfs merge=lfs -text *.ogg filter=lfs diff=lfs merge=lfs -text *.ttf filter=lfs diff=lfs merge=lfs -text

Level files: text format enables merges, binary format prevents them

This connects directly to the data format discussion in level editors in games: a text-based level format is not just easier for community tools to parse, it is also the only format that gives git any chance of merging two people's simultaneous edits to the same level. A binary level format means two designers working on the same stage in the same week will produce a merge conflict that git cannot resolve automatically, forcing one person to manually redo their changes on top of the other's. A JSON or similar text-based level format at least allows git's line-based merge to succeed when the two designers touched different sections of the file, and when it does conflict, the conflict is human-readable instead of two incompatible binary blobs.

Branching strategy for a two-to-five person team

Elaborate branching models designed for large software teams — git flow with its develop, release, and hotfix branches — add process overhead that a small game team rarely needs. A simpler pattern works better in practice: a stable main branch that always builds and is playable, short-lived feature branches for anything larger than a same-day fix, and direct commits to main for small, low-risk changes like tuning a single enemy's spawn timing. The goal is not process purity, it is making sure main never sits broken for more than an hour or two, since a broken main blocks every other team member's ability to test their own work against the current build.

Commit hygiene that pays for itself

Commit messages that describe what changed and, more importantly, why — "reduce stage 3 mid-boss bullet density, playtesters consistently died before reaching second phase" — are worth far more than they cost to write, particularly for an open-source project where contributors join without full context on past decisions. This is doubly true for a project accepting outside pull requests, where the discipline described in how to contribute to an open-source game project depends on maintainers being able to understand a contributor's intent quickly. A one-line summary plus a short "why" paragraph, applied consistently, turns the commit log into a searchable design history rather than a list of noise.

None of this requires deep git expertise from every contributor. It requires a small number of decisions made once, early, and enforced through `.gitattributes`, a documented branch policy, and a commit message convention pinned somewhere new contributors will actually see it. The Git LFS documentation covers the setup mechanics in more detail than fits here, and is worth reading in full before the first binary asset lands in the repo.