5

First off please note, I’m fully aware that Git has historically been terrible at dealing with large binary files and very large repos; there are at least a dozen questions on SO that deal with large dataset performance, but as far as I’ve found, they’re all years old and the answers all more or less predate a number of important contributions by Microsoft and others to drastically improve Git’s scalability, such as partial clone and enhancements to sparse checkout.

Context

I want to be able to put a whole game project in a single repo if I possibly can, because the programming and assets have a degree of coupling, there are various tooling scripts and metadata that accompany assets, and having to keep track of a number of separate repos for one logical project seems like a pain. The programming specific to the game is relatively simple script; the game development system and engine which are common to multiple games will be in separate Git repos.

(Full disclosure: I am totally new to revision control. I somehow managed to come up with a whole game engine and development system, mostly single-handedly, using only routine backup plus the occasional copy-paste of source folders.. lol.)

Characteristics of the contemplated project monorepos:

  • Total data size of revision controlled files (i.e., only those that aren’t reproducible from other files) in the project tree is expected to be 100 ‑ 250 GB for a smallish project, probably into terabytes for a larger project. The one I’m trying this project monorepo thing out on first will be a smallish project. This doesn’t count revisions, but see below. I may be able to exclude some types of authoritative files to get that size down quite a bit, but doing so would trade off convenience and safety, and I’d really prefer most authoritative data is in the repo.
  • Very roughly, the number of revision controlled files would likely be 10,000 to 40,000.
  • Some binary files go through numerous revisions while others are write-once. The really big ones—i.e., into 100s of MB or more—tend to be write-once, because they tend to be raw recordings which are edited in a non-linear fashion with edit decisions saved into relatively tiny project files. I’ll probably keep such video recordings out of the repo entirely, but in the case of audio it’s harder, because DAW software likes to number recording files on its own, so pesky naming conflicts could arise if those files aren’t checked in.
  • Some editable binary files, typically in 5 ‑ 50 MB range, can actually delta compress very well. I’ve seen it claimed on SO that real-life binary files don’t delta compress because they’re compressed. This is an overly simplistic view of actual DCC file formats, where typically compression is done separately on individual sub-objects within the file. I did a test on a set of 10 backup files taken from an actual art project done in Photoshop, saved to LZW compressed layered TIFFs, where I was painting in stages using many layers. By simulating delta compression using LZMA with a large dictionary, I was able to drop 129 MB down to 29 MB, whereas the same LZMA run separately on each version only got it down to 122 MB.

Other Software Considered

The present question is about native Git, but for completeness:

I’m actually also considering Subversion for the game repos. The main drawbacks of SVN are poorer handling of merging and potentially more stress on the central server. Another disadvantage for me would be having to learn two VCSes instead of one. The really big drawback of Git, if it still applies, would be poor scaling on large binary datasets. Other perks of SVN are path-based access control, versioned free-form metadata, and monotonic revision numbers. Plus, I hear Git scares the crap out of artists, so I may need to whip up friendly workflow front-ends.

I’ve also investigated git‑lfs, git‑annex, git‑media, git‑fat, git‑fit, and git‑bin, but I have big concerns with all these:

  • Each has implementation and/or maintenance issues. For instance, the only open-source server implementation for git‑lfs is not production-ready, so I can’t deploy a local server without buying into some proprietary solution.
  • I’m going to venture a guess that none of them implement any kind of delta compression, but some binary files in practice can actually delta compress rather well. (I could just use LFS on the really big, write-once stuff, but I still don’t love the idea.)
  • They all bake administrative decisions about storage into the immutable history of the data itself. This is conceptually ugly and also makes things brittle.

If it came down to having to use an LFS type extension, I’d almost rather go with Subversion.

Analysis

In trying to figure out whether Git could handle such a game monorepo ok, I analyze as follows: The number of files is not that huge considering some of the larger Git source repos that work just fine. The main thing is file size, which means I have to look for those situations where Git does operations that are O(size) or worse.

For clones and checkouts, it’s of course unavoidable, but nowadays Git can do both of those sparsely, so the client is only pulling what they actually need. So where else could large files choke Git?

There is a ‑diff attribute which can tell Git not to generate diff text. We should set this on all binary files, since diffs will generally be meaningless, at least the way Git would report them.

There’s also a ‑delta attribute which stops Git from delta compressing. This is trickier, because as mentioned, some medium-sized binary files actually can be delta compressed quite well sometimes. But delta compression requires time and memory.

It seems Git packs using a sliding window, by default of 10 heuristically similar objects at a time. 10 files of 50 MB each is 500 MB of RAM, which is not totally unreasonable, but could be a slow operation. Just how slow? I imagine it would be advisable to totally disable automatic garbage collection, instead running git gc ‑‑auto manually when convenient, since it could otherwise happen on any given command, which could be quite disruptive.

Microsoft’s Scalar apparently does some repacking in the background, but that’s only documented somewhat vaguely and in the context of fetch and checkout, so I’m not totally clear on what the implications are on the central repo. (I also hit a bit of research fatigue here.)

Since delta and diff are separate attributes, I assume it’s possible to have some subset of files for which Git won’t attempt to difference for history purposes but will try to delta compress. But Git is infamous for being counter-intuitive, so I have to ask. With some files, this may be an appropriate strategy.

Another not-so-clear matter involves the fact that Git tracks content and not files. So, if, for instance, you move a function body from one source file to another, Git can tell you that and also can merge properly across that. But this comes at a cost, which must be at least O(size) in the involved files. To make matters worse, Git stores the snapshots “dumb” and then does this tracking at the time of the query or operation. I think that was a good design decision overall, but it does mean that the O(size) cost may, if I’m not mistaken, get incurred over and over again as you run routine commands.

I wasn’t able to determine whether this “content tracking” is elided on files having the ‑diff attribute. That attribute officially speaking controls whether diffs are printed, not necessarily whether intra-object content flow is being tracked. This seems to be a very important distinction with very large files.

To be clear, I don’t mean Git shouldn’t track those files at all. I mean instead that the first byte it sees that doesn’t match is enough to just say, “hey, they’re different” and be done with it, rather than trying to figure out exactly what moved or changed where within the files. This would lead to degraded behaviour if a file was moved and changed in the same commit, but that’s tolerable and no worse than SVN. Of course, it’d still take the SHA hash, which is ok as long as the file has been touched.

Question(s)

My core question is, can native Git today reasonably handle what I’m contemplating throwing at it?

I would almost say Microsoft has already answered this question by hosting the Windows OS and MS Office repos in Git, but those are not exactly the same scenario. They’re dealing with a mammoth number of relatively small files, whereas I’m dealing with a moderate number of sometimes very large files. They’re also using enhancements that have been partially but not completely contributed back to the upstream Git project.

That core question leads to some ancillary questions, hinted above, which I’d have almost posted separately, but figured to instead include in context so they don’t become “X/Y” problems.

While this is intended as a question about Git, not a “shopping” question, if some other VCS would be much better in this application, I’m open to that also.


Addendum & Update

First, to address @DocBrown and @amon:

Number of users: Right now only a few, but given migration probably being painful, I wouldn’t want to deploy something that couldn’t grow to, say, 50 total users before having to revisit.

Git intrinsically suboptimal for large data: This is a big concern and as such I’m leaning towards SVN, which seems more inherently scalable in this regard; see below.

And there is indeed something to be said for not trying to push Git to its limits as a first-time user. With that said...

Usefulness of sparse checkout: Typically, for a given task, a user could get by with a checkout in the 200 MB to 4 GB range. That’s still a little big for Git, although I also have to note that Microsoft’s Derrick Stolee has mentioned users with 30 ‑ 50 GB of background-fetched packfiles on the client side. It's not ideal to have to explicitly limit the checkout, but that's hard to avoid regardless of VCS.

Needing VFS for Git: Microsoft’s solution did originally hinge on a virtual filesystem, however this has changed more recently. For the MS Office repo with MacOS users, they developed a more native Git solution, implementing improvements to partial clone and sparse checkout, much of which they’ve fed upstream. See Git at Scale for Everyone.

It is worth noting that many recent scalability improvements to Git are not turned on by default. These settings are still obscure enough that MS has created a tool to configure Git.

The downside to this newer system is that you have to explicitly ask for the tree subset you need checked out, whereas VFS enabled a more transparent experience where it looks like you have the entire repo checked out, with the files you actually use being fetched behind the scenes.

One big concern is that, although you can reduce the amount of data on the client, you still need an authoritative repo somewhere that’s got the whole hundreds-of-gigabytes tree. If you use Azure DevOps Server for that repo, I’m guessing it’d handle ok, but that’s fairly expensive and proprietary. Using native Git for the authoritative repo could get extremely painful depending on exactly when and where it does processes that are O(size) or worse.

Keeping source code separate: I already intend to partly do so, as the engine, script class libraries, and tools will all be separate, code-only Git repos. This is the reusable “heavy lifting” code. But each game also has script code that is specific to it, though fairly lightweight. I really don’t want to keep that and the assets under separate version control, as they have significant coupling. I’d actually rather not use Git for that code, if it means having to version it separately from the assets.

Not using a VCS on binary assets: At least some of the binary assets do belong under version control. From a programmer's perspective the assets “just show up” and as such seem like static content. However, I do asset production as well, and from that perspective, many of those files are far from static. I've got directories littered with dozens of haphazardly version-numbered asset files that wouldn't be there with proper version control.

Present Thoughts

I’m mainly focused on Git vs. Subversion. (I’ve also superficially looked at Mercurial and Perforce.) It looks like it’s mainly a trade-off between Subversion’s apparently terrible merging and Git’s not-so-great scaling to large data.

This question’s premise had been to benefit from Git’s better branching model by relying on recent improvements to avoid its scaling issues, but I’m at this point again leaning more towards Subversion, on the thinking that Git scalability is too risky. Taking a step back I appreciate that scalability is actually much more important to the game repos than ease of merging—getting more merge conflicts would be an inconvenience, but the VCS grinding to a halt would be catastrophic!

Our games tend to be story-based, with most of the boiler-plate mechanics handled in the class libraries and development system, which are not part of the game. The code that actually belongs in the game repo is lightweight and only needs to be touched by a very small number of programmers. Furthermore, a fair bit of it is split up into source files specific to game regions easily written by a single programmer.

This all seems to suggest that code merge conflicts in practice could be fairly minor even if the VCS isn’t that great at merging. OTOH, experimental branching would actually be more useful for the game than for the development system, so SVN isn’t ideal, either.

It feels a bit strange contemplating taking up a tool that much of the software industry has abandoned and whose users Linus Torvalds has called ugly and stupid. Almost like investing in dinosaurs at the end of the Cretaceous. But yet I have to wonder if it might actually be a better tool for this job.

I’m going to read the manual for SVN so I can ask questions about it more intelligently before deciding. But if anyone can say confidently that Scalar actually will be fine in this use case, that‘d be very good to hear!

11
  • How many people do you expect to work on that project using Git? – Doc Brown Nov 2 '20 at 21:52
  • 2
    Just try it, and if it doesn't work, change it. – user253751 Nov 3 '20 at 15:52
  • @DocBrown Good question; added to "Addendum & Update". Even 50 would be fairly unlikely on this particular project. – Kevin Nov 9 '20 at 3:02
  • 1
    @Kevin If you don't like it, moving to git-lfs and rewriting history shouldn't be that difficult (budget a day, and another day for people to rebase their local work and send you hate mail). It's not like moving from Git to SVN where you have to figure out what to do with the history. – user253751 Nov 9 '20 at 9:02
  • 2
    @OttoV. Thanks for the suggestion! I had several reservations about Perforce, but on closer inspection in spite of that it does have some for me killer features. I've shared my findings in an answer. I'm now leaning in that direction. – Kevin Nov 15 '20 at 13:11
5
+150

Git just does not scale to huge projects. Repos should not generally grow beyond 5GB including the entire history if you want a good user experience (or if you want to use commercial hosting services). Thus, binary assets such as images or even videos should typically be managed separately from the Git repository. Git LFS is just a way to automate management of assets through another storage mechanism, but in principle you could also manage assets “by hand”, e.g. by writing a script to fetch them from a network share that can snapshot versions with ZFS¹.

1: ZFS and Btrfs are advanced file systems that support features such as block-level deduplication and atomic snapshots. This is roughly similar to Git except that they can deal with arbitrarily large amounts of data and that there is no branching, though copies are super cheap due to block-level copy-on-write.

What Microsoft did was deciding that it cost less to pour thousands of engineer-hours into hacking around Git's restrictions instead of getting developers to use a proprietary version control system. This doesn't mean that Git now has good support for huge repositories by default. Instead, Microsoft's solution hinges on Git VFS, a virtual file system that allows Git to work more efficiently. You too could use this VFS, but I doubt it will help much with huge files. Microsoft's use case is more concerned with monorepos where each individual only needs a small subset of files so that a full checkout is not physically necessary.

Since you're somewhat new to version control, it probably doesn't make too much sense to try to bend Git to your will. You should use Git and Git is the most popular version control system, but that doesn't mean it is the best possible version control system that can theoretically exist – many aspects of it are objectively crappy, and large repo support is one of them. To a large degree, these problems are inherent in the design and cannot be directly fixed.

I would suggest that starting to use Git only for source code files will already be a significant step up for your version control setup. In contrast, assets and large files should be managed with more traditional methods, such as LFS if the assets are fairly static. Instead of version control, you might prefer more traditional/linear backup. Even rotating through a few external hard drives is a great approach already, though a NAS or storage server can also be cost-effective compared to more convenient online or cloud backup services when considering the cost of a restore.

8
  • Thanks for answering! MS' solution no longer strictly needs VFS; see my "Addendum & Update." Funny you should mention ZFS.. been running Solaris with RAID-Z for some time on the fileserver because I wouldn't trust anything less with important data. Never thought to use its snapshots for anything other than admin tasks, though. Interesting idea! – Kevin Nov 9 '20 at 2:49
  • But should I take this suggestion to mean that Subversion is so horrible that ZFS would do a better job of version control? (Well, Linus Torvalds would definitely say so!) Or do you just mean that this kind of data will also choke SVN? – Kevin Nov 9 '20 at 2:49
  • @Kevin SVN scales very differently because it is a centralized system: only the server stores the entire history. When doing commits or checkouts, bandwidth will be a limiting factor. But I'd urge you to ignore SVN since it is prone to data corruption, and it's locking model makes concurrent development difficult. Torvalds doesn't actually recommend ZFS, but his opinion doesn't matter. I didn't know about Scalar, maybe that would make Git performance bearable for you – amon Nov 11 '20 at 11:42
  • As noted in my answer I'm now leaning towards Perforce, but for completeness, do you mean that SVN is vulnerable to hardware bit rot or do you mean that it has data-corrupting bugs? I'm not worried about the former, as whichever VCS I use will be stored on ZFS with block-level SHA-1; also, as of SVN 1.9 everything is under "checksum", though I don't know what kind. But data-corrupting bugs would be scary! I've read that corruption is usually seen with the older Berkeley DB backend as opposed to FSFS... – Kevin Nov 15 '20 at 13:03
  • ... As for SVN's locking model, from what I understand locking is only used on files you've configured to require it. Locking actually makes some degree of sense for binary assets, as doing a three-way merge of a binary asset at best requires manual effort and at worst is impossible. – Kevin Nov 15 '20 at 13:04
3

This is not a direct answer; I still welcome answers giving relevant experience with or insight into “Git at Scale,” and I’ll accept that type of answer. But for the benefit of future readers with similar goals I should still share my findings in looking for a practical solution for the underlying problems predicating this question.

As noted in the question, I don’t have to use Git for the game project monorepos; another VCS could be a viable solution.

Perforce Helix Core

I initially didn’t think much of Perforce.

This was partly because, much as I’m not against commercial software in general, I’m really cautious about locking up every last bit of a project’s precious data, even source code into one particular proprietary system and its backend format. This seemed particularly hard to justify given at least three mature and capable open source VCSes to choose from: Git, Mercurial, and Subversion, one of which has become an industry standard, and another of which was somewhat of an industry standard for quite some time.

I was also put off by some horror stories, which I mention more below.

But on @OttoV’s suggestion, I had a closer look at Perforce, and what I found was, it seems to have features and benefits really well aligned to my requirements. Of course, there are also some notable thorns.

Positives

  • It’s very widely used in the game industry, even still, and by big studios. This would tend to suggest that its feature set, scalability, and usability are all at least reasonable for this kind of work.
  • Being able to handle the amount of data I want it to is not even a question. It’s actually advertised to handle way more data than I need, but more importantly, being commonly used by big game studios, it couldn’t possibly not handle big data reasonably.
  • Opinions do vary, but there seems to be some consensus that its merging is reasonably good, and it’s typically considered better at merging than Subversion. As well as having the “traditional” branching style of using cheap copies, as in Subversion, it also permits what it calls “streams”, which seem to be somewhat similar to Git branches. (I think this is a newer feature.)
  • Subversion causes two copies of every file checked out to be stored on the client: the work tree version, and the “pristine copy” in the .svn directory. This may become rather slow with large files, and at worst could also tax the client’s storage space. Git effectively suffers the same problem, though from a slightly different angle: there’s a local repository (even if only a partial and shallow clone) in addition to the work copy. I’m not totally sure on this one but I’m under the impression Perforce only stores the work tree itself on the client side, so there’s less to copy locally.
  • (I don’t need this immediately but it’s good to know.) If you have long-distance workers, you can set up proxies closer to them. Unlike a Git mirror, if the proxy doesn’t have the requested file, it will go back to the main repo for it. If you just have international remote workers and not actually a remote office, I’m guessing you could run this on an AWS EC2 instance in their region, but you’d probably need some number of workers in a region for it to be worth it.
  • If you want to go with Git, they have some related products. One allows their server to host a Git repo. Another automates Git operations across multiple Git repositories that belong to the same project.
  • Maya, 3ds Max, Photoshop, and Nuendo (a Digital Audio Workstation program) all have Perforce integration. Personally, while I use all these programs, I can’t see myself use VCS integration and would be more inclined to still go at the command line, but this could nevertheless be a really good thing to have on hand for less technical people.
  • Perforce has really cool tools for visualizing file versions. They’ve even got a tool that can visually compare image versions. (Probably can’t deal with layers, but still.) Of course, you can potentially find tools like this from third parties for any VCS, but with Perforce you have it right there.
  • Path-based access control, so you don’t need to put your entire collection of project IP “on blast.” (Subversion has this too, but not Git & friends.)
  • Optionally, you can make files require a lock. Sometimes it is possible to meaningfully merge separate changes to the same binary file (think Photoshop layers), but often it’s not, and even when you can, even just identifying the 3-way differences usually takes manual work, and merging them always does. Better to just avoid such changes. Arguably out-of-band team co-ordination is a better approach than locks, but at least the option is there if you want to try locks. (SVN also supports locking as an option, but Git & friends inherently can’t.)
  • Revision numbers are monotonic decimal numbers instead of arbitrary hex hashes. (Same with SVN.)
  • Shelving support is more developed, whereas it’s somewhat experimental in Subversion if I’m not mistaken.
  • Perforce is overall much more configurable than either Git or SVN. For instance, there are per-file options to preserve timestamps and to discard files after a certain number of revisions.
  • It appears that Perforce keeps versioned files openly in a directory tree on the underlying filesystem on the server, instead of clumping them into packfiles (Git) or revision files and packs (SVN). Initially this seems inferior, in no small part because it doesn’t easily do delta compression of binary files, and also might require whole disk clusters for every version of a small file. However, there are some notable advantages:
    • If the underlying filesystem is efficient, access may be somewhat faster. This will be particularly true when compared with delta compression on large binary files.
    • I have a custom backup system that can use several different storage types and strategies depending on the importance and size of a given file. These decisions are made at the path & file level, which is a problem with either Git or SVN because files as stored on the server at best become unrecognizable and at worst wind up clumped into a single file along with a bunch of other files. As such, I’d have to place an entire repo under a single backup strategy, and in order to use mixed strategies, I’d have to arbitrarily segregate files into separate repos and therefore separate file trees, which is quite undesirable. Perforce it seems would let me continue to do fine-grained backup the way I do now.
    • If a packfile is damaged by a disk error, this could potentially affect many files and versions, whereas with discrete files, only the one file is damaged. This is especially true where packfiles are delta compressed.
    • If Perforce becomes obsolete, some disaster happens, or whatever, it’s easy to get files back using simple tools that aren’t specific to Perforce.
  • Trees and commits it seems aren’t referenced by hashes (unless it’s acting as a Git repo). An advantage to this, when dealing with big data, is that you can remove files after the fact without having to rewrite history globally. The downside is that it’s theoretically less safe/secure, but I’d be keeping the depot on a local server filesystem with its own strong hashing anyway, so the practical risk is negligible for me.
  • This is the killer feature for me: p4 archive, which is designed to reversibly move chosen files to off‑line storage without taking them out of the history. I love this not because I want to actually put stuff into off‑line storage, but instead because I know my data better than any VCS can; I know how it can be packed up most efficiently, so by taking files physically out of Perforce’s management, I can easily create systems to potentially save a lot of disk space for stuff that isn’t being used at the moment.
    • I had been unhappy that Perforce doesn’t properly do delta compression of binary files, which Git does and I think SVN more or less does. However, with p4 archive I can get the same space savings for older versions just by using 7-Zip’s LZMA with a very large dictionary in solid archive mode, which effectively does really good delta compression. Of course, this doesn’t benefit file versions that are on-line, but on the other hand, you ideally want those ones to have fast access, anyway, and delta compressed large binary files can’t be accessed as quickly. Overall it seems to make more sense to pack them once you know you’re not using them, although admittedly it’s a bit more work and/or scripting.
    • gzip, which all the VCSes I’ve looked at use internally, is not the best. Some data can be packed a lot better by LZMA or in some cases even moreso by domain-specific compressors. p4 archive lets me run whatever compression I want once the files are off‑line.
  • Big benefit: Because Perforce can handle huge amounts of data which it’s also practical to back up selectively and remove after the fact, I can put big stuff under version control that can be regenerated but isn’t convenient to regenerate. (Game & media development has tons of such stuff... I was almost going to post a question about it until I realized it’s a non-issue with Perforce.) It would be hard to justify putting stuff like that into Git or even SVN, which would force me to look for other ways to place such files into checkouts.
  • I’ve read Perforce provides excellent customer support.

Negatives

  • It sounds fairly expensive if you need to go past the free license limit. With that said, if you’ve got contractors who only work on the project for a limited duration, you can delete them afterwards so the license can be reassigned, so depending on the project it might be possible to stay within the free limit. But once that won’t do, well, Perforce’s web site is evasive about the pricing, which means it can’t be good. But I’ll have to ask them.
  • Merging probably not as good as Git’s. See below.
  • From what I understand, you have to explicitly mark files for editing before you’re allowed to edit them. This sounds painful!
  • Because you’ve only got the work tree on the client and nothing else, it generates a lot of traffic to the server, even compared with Subversion, which at least keeps the “pristine copy” for diffing. (On the other hand, keeping stuff locally incurs copies which Perforce doesn’t do, so the most optimal approach will depend on usage patterns.)
  • Doing any work if the server is not accessible may be challenging. Even shelving stuff depends on the server.
  • There are some horror stories out there. See below.

Knowing the Backend Format

One of the things that made me uneasy about Perforce was not knowing its backend data format. With Git or SVN, at worst, if I want to know that, I just need to read its source code, but the formats are documented, anyway.

On closer examination, it turns out Perforce actually stores the versioned files themselves in a way that is more transparent than Git or SVN. Text files are just RCS files, and binary files are either stored directly, or as .gz files. I haven’t confirmed, but it looks like you can openly see their logical paths and names as stored in the backing filesystem.

As for the metadata, the database schema is given here, and while this doesn’t get into nitty-gritty of the bytewise layout, it does give some insight into the overall structure of the table files. You probably don’t need the table files anyway, since it’s supposed to be adequate to back up the “checkpoint” and journal files that are periodically generated. These could have a straightforward format. Before I actually trust real data in it, I’ll make sure the format seems comprehensible.

Merging

FWIW, back in 2007, at a Google talk, Linus Torvalds harshly derided CVS, SVN, and Perforce all, in part for making merges very difficult. I’ve seen various other remarks that seem to corroborate this, but they tend to be dated. It looks like Perforce originally had a branching model similar to SVN’s, but has since added a second model that looks more similar to Git’s typical workflow, less the decentralization. Even SVN has had major improvements to merging since 2007.

I wouldn’t expect Perforce to now be using Git’s “content not files” model of tracking, since it appears to be a fundamentally different model with different scaling properties. As such, Git is still probably better at merging and especially “blaming”, but the difference may not be nearly so huge at this point. The content-based model comes at the cost of being less scalable, so unless the system uses a fundamentally different model for textual vs. binary files, there’s going to be a trade‑off.

As mentioned in my Addendum to the question, the code in the game project monorepo may for many projects not be as prone to merge conflicts, anyway, so the trade-off may be worth it. (For some game projects this may be more equivocal.)

Horror Stories

One thing that does worry me are the horror stories. It’s to be expected that some people are going to say, “X/Y/Z is a terrible program, don’t use it” about any program in existence. But when horror stories give specifics of incidents, they become a bit more credible and worrisome. One account in particular from a game developer on Quora stuck in my mind:

...

Once we even had Perforce shut down and fail mid project for no reason we could identify. Our IT person needed to hack the server: He tracked the problem down to the tag file. We were shocked to discover that:

  • The tags were stored in a flat text file.
  • A single tag of a branch wasn't one line in the file, but one line per file in the branch.
  • We were tagging releases.
  • A bug in the server meant that when the tag file got larger than 4Gb, the server would just crash.

This is so incompetent on so many levels that I personally can't trust the engineering of anything developed by Perforce. It's like they had an intern design the feature and never even performed a code review. Instead they just advised you not to use the tagging feature that much. "Fix it in documentation."

The above are core design flaws, and don't count the times where we've just lost data spontaneously and needed to roll back to a backup. Be sure to have frequent backups and a full time IT admin if you're using Perforce. As far as I'm concerned, as a product, it's an utter waste of money and time.

Of course, there are also lots of remarks about Perforce being the best tool out there for game development and how well it works (if you can afford the licenses and storage). In fact, in the context of games, I’ve seen a fair bit more positive remarks than negative ones.

Current Impression

Overall, Perforce may be a surer bet than relying on Microsoft’s enhancements to Git, in part because Perforce has some pretty useful features and properties that Git doesn’t, even with the enhancements. And because it’s already proven on this particular type of large workload.

The existence of the odd horror story is right now maybe the biggest barrier to my just going with Perforce for game project monorepos, with potential license costs also being somewhat concerning. Because otherwise, it seems to have the best combination of scalability and features of anything I’ve looked at.

This first game project I’m trying to get under VCS is by far not the biggest or the most critical, or one where I anticipate lots of merge problems, or one where Perforce’s free license limit is extremely likely to be a problem. And I wouldn’t use Perforce for the engine or development system anyway, as Git is perfectly suited to those; as such, the VCS chosen for this game has no bearing on other games. From that perspective, I may as well just say Perforce is most probably fine, so just go with it for now, and the experience can inform more critical projects.

There is some theoretical risk, based on the horror stories, that the repo goes “poof” at some point. I don’t think that’s likely, but as a precaution, I can just aggressively back up the work tree as well as the repo, particularly before switching branches, and keep the incrementals around for a good while. That’ll waste backup space but at least mean that in the very worst case, I know I can at least recover most work even if the history is lost.

And in the worst case, if Perforce turns out to be a huge mistake or we hit the free license limit and can’t justify the price, we can always revisit the question and try something else. Maybe by that time there’ll be more crowd experience with “Git at Scale.” Migration could be a pain, but in the worst case we could just commit the branch heads into a fresh repo on the new VCS and keep Perforce around just for history reference. The disruption wouldn’t be as terrible on this particular project as it would be on a bigger one.

That seems like a feasible answer, but I’m still open to new information.

Disclaimer: My current impressions come entirely from reading large portions of Pro Git, various documents from the Git project and related projects, a bit of the SVN book, blogs and videos from Microsoft and others, Perforce’s marketing materials and casual examination of its documentation, Wikipedia, various discussion forums, and reading various questions, answers, and comments on several SE network sites. I have thus far never laid a finger on any VCS tool.

Anything Else?

If you know of any significant benefits or downsides to Perforce I may have missed, particularly for this sort of use case, please leave a comment.

Or, add an answer if you know about “Git at Scale” as it applies to large binary assets.

1
  • A few years back I recieved pricing information. If I remember it correctly, it was something a bout ~800€ per user for a perpetual license or alternativly a subscription based licensing with regular updates. Perforce also offers free live demos where you can ask questions. I used this offer ones and it was helpful. By the way I'm not associated to the company in any way. I just really like to work with this version control. – Otto V. Nov 26 '20 at 13:34
1

The reason you were asked about the number of developers is that when using Git you will effectively be duplicating the entire repository onto each developer's machine. If many or most of them do not need the binaries, it is a waste of time and resources and network load. Bear in mind that removing a large file does not alter the space needed for it, as Git retains it forever, since remove is not an actual delete.

Better would be to use a binary repository for your binaries, e.g. Nexus, Archiva, or Artifactory, which you can reference from your Git sources and build scripts and have it integrated into your CI/CD tool chains. The references to the binaries would be under version control, so the binaries do not need to be. This would also allow you to manage external binary dependencies, such as libraries from other parties. Such repositories are designed to scale.

Using a distributed version control system, which exists to manage source code & text-based resources, is rarely a good idea for managing non-text objects. If you are tempted to use SVN because it is not distributed and handles binary objects, why not use a system explicitly designed to do so?

6
  • Git requiring the entire repo on each developer's machine is explicitly not part of the question, which pertains very specifically to the case of recent improvements to Git scalability where among other things you don't need to clone the entire repo. See article and video. – Kevin Nov 9 '20 at 18:23
  • I very briefly looked at Nexus, Archiva, and Artifactory, but I'm confused as to how they'd fit in. They are build artifact repositories, mainly for CI/CD, and seem to be designed around binary files which are packages that came from some other kind of source files. In stark contrast, I'm often dealing with binary files which ARE the source files - as in, human beings make edits to them directly (using interactive tools such as Photoshop or Maya)... but those edits are sometimes coupled to edits to program source code, so ideally should all be versioned together. ... – Kevin Nov 9 '20 at 18:24
  • ... My knowledge of formal DevOps is limited so it's possible I'm missing some subtlety here, but just from skimming their web sites they seem like screw drivers when I have nails. Perhaps a brief example of how an artist would use, say, Artifactory, in exactly the same way a programmer would use Git, would make this answer much clearer. – Kevin Nov 9 '20 at 18:24
  • "Git at scale" requres specific version(s) of Windows and also Azure - it is then far from the Git that we all know and love. I can't give you an example, but as I said, these repos are also useful for storing 3rd party binaries, such as libraries, so are not just concerned with your own build artifacts. Good luck. – Jool Nov 19 '20 at 12:08
  • That was true for "VFS for Git", but due to the MS Office team needing MacOS support, they went with a more native Git approach in "Scalar", with many of the improvements being fed back to the upstream Git project that everyone uses, although it takes some configuring. – Kevin Nov 20 '20 at 2:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.