Direct answer
For a game project with a large volume of big binary assets (textures, meshes, audio), I would recommend Perforce (Helix Core) as the primary system, because it was purpose-built for huge, mostly-binary trees with per-file locking. Git with Git LFS (Large File Storage, a Git extension that stores big files outside the normal object database and checks out only pointers by default) works for smaller teams that are already Git-native, but it degrades as asset volume and history grow. A hybrid split, Perforce for art and audio, Git for code, is the common answer at mid-size and larger studios, because it gives each discipline the tool suited to how its files actually behave.
Structured elaboration
| Perforce (Helix Core) | Git + Git LFS | Hybrid |
|---|
| Built for | Large binary trees, centralized | Distributed text-diff history, LFS bolted on for big files | Splits by discipline |
| Locking | Native exclusive checkout on file types | Possible via git lfs lock, but not the default workflow | Perforce locking for assets, Git branching for code |
| Repo size at scale | Scales well, partial/sparse checkouts | Clone size and fetch time grow with LFS history | Each side stays lean for its own content |
| Ops cost | Requires a managed server, backups, licensing | Needs a well-provisioned LFS storage backend | Two systems to operate |
Locking vs mergeable assets. Binary assets like a .fbx mesh or a .psd texture cannot be merged the way text can: two people's edits to the same file cannot be combined line by line. Lock these (Perforce's exclusive-checkout file type modifier, or Git LFS file locking) so only one person edits a given asset at a time. Text or text-like files (shader source, material definition files, config) stay mergeable and belong wherever your code lives.
Branching strategy. Code: a lightweight trunk-based or short-lived feature-branch model works fine. Assets: avoid long-lived asset branches, since merging binary changes back is painful or impossible; instead, lock, edit, and submit atomically per task, and only branch assets for genuinely separate release lines during a content freeze.
Repository layout. Keep code and large assets in separate repositories or depots rather than one giant repo, and organize assets by project/module with clear ownership. Never let build artifacts land in version control; those belong in artifact storage instead.
Supporting artists and programmers. Artists need GUI tooling (Perforce's P4V, or engine-integrated plugins for Unreal/Unity) so checkout, locking, and preview are not a command-line exercise. Programmers keep a fast, familiar Git workflow for code. A bridge step, for example recording the number of the Perforce changelist (Perforce's equivalent of a git commit: an atomic, numbered set of changes) that a given Git commit was built against, keeps the two systems' notion of "current state" in sync for builds.
Worked example
A 50-person studio: artists produce .fbx, .png, and .wav assets in Perforce, locking a character mesh before editing it so a second artist cannot silently overwrite their work. Programmers work in Git on gameplay code in short-lived feature branches, opening pull requests as usual. A small integration script records the current Perforce changelist number into a tracked file in the Git repo at build time, so a given Git commit unambiguously maps to a specific asset revision, and a CI build can check out both consistently.
Trade-offs and pitfalls
Perforce needs real operational investment: a managed server, backup strategy, and typically per-seat licensing. Git LFS needs a properly provisioned storage backend and can still bloat local clones over a long asset history, since it stores every historical version of every large file even though only the pointer is checked out by default. Hybrid setups solve both teams' problems but add integration complexity: two systems, two mental models, and a bridge that itself needs maintenance.