This morning I woke up with an extremely sore throat. I could hardly talk at all and swallowing was quite painful. It looks like the cold bug that was going around finally got to me. I called in sick, stocked up on lots of fluids and cough drops, and cuddled by the side of my computer waiting for my body to fight off the cold. Since I wasn’t in the mood for a game or anything particularly creative, I decided to give Subversion a whirl.
Checking out Subversion had been on my list of things to do ever since it showed up on my radar, about a year ago. I also needed to decide on a version control system to use at home, so this was a perfect chance to finally try out Subversion. I could go the familiar route with Perforce, but, even though Perforce is a great product, the more I use it the more I run up against its limitations. Besides, I needed more than two clients for my home network, and I’m not about to spend $750 per user.
Originally I had been planning on writing a grandiose article comparing all the major source control systems, highlighting their strengths, and making some recommendations on how they applied to game development. Fortunately, I quickly realized what a hugely ambitious project that was, and besides, other people had already done most of the legwork (and here) for me. Not being one to waste my time with duplicated effort, I decided to scale back the scope of the project to just having a look at Subversion and comparing it to my experience with Perforce. Besides, my throat is killing me and I’m low in energy, so I’m taking it easy.
I went ahead and downloaded the latest version (1.0.5). I’m using different flavors of Linux in my home network: Debian Woody for the server, and Mandrake 9.2 on the rest of the computers (3 others). Subversion runs on a variety of platforms: Linux, FreeBSD, Solaris, MacOS X, and even Windows. Not only that, but it has binaries for every Linux flavor out there, including my outdated Debian Woody. It certainly gets the compatibility checkmark.
I first tried to install Subversion by getting the tarball and compiling the source. It turns out that was a bit more complicated than I expected due to the dependencies on other libraries. Compiling the GUI RapidSVN was even more problematic, requiring a particular directory structure with the original Subversion source code. Still, I eventually got both of them up and running. For the second computer, I just installed it with RPMs and I was done in a minute. Lesson learned.
I had the option to make the server run over Apache or as a standalone daemon. Since I didn’t have Apache installed and I didn’t want to mess with that, I went ahead with the standalone daemon and it worked like a charm “out of the box.” I just ran it with svnserve -d -n /var/lib/subversion/main and we were off.
One really big plus for Subversion is its documentation. Normally, you wouldn’t think that open-source software would have great documentation, especially for software that claims not to be even beta yet. But in this case, Subversion exceeds all expectations, with a very clearly-written, full online book. It’s actually even better than Perforce’s documentation, and that’s saying a lot.
So I went ahead and ran through the book’s examples, familiarized myself with the workflow in Subversion (copy-modify-merge, similar to CVS, but quite different to Perforce or–gasp–Visual SourceSafe), and played around with branches and merging for a few hours.
The Good Stuff
A lot of the good stuff is apparent from a feature checklist: atomic operations, concept of changesets (changelists in Perforce parlance), good support of binary files, good command-line support, etc, etc. Then we get into things that don’t always make it to the marketing checklist level, but are crucial in everyday work, as I learned the hard way over the years.
File renaming and moving are supported very well in Subversion. They’re considered just another operation and are submitted along with any other changes. That’s a really important feature for me because I like to do a lot of refactoring, and, as part of that, I end up renaming and moving files around a fair amount.
Creating new branches and working with them is a snap in Subversion. If you’ve gone through the convoluted process of setting up a branch in Perforce, you’ll know what I mean. In Subversion all you do is svn copy src dest and you’re done. You have a branch of your files and it was a blazingly fast operation. Unfortunately branches are going to be the downfall of Subversion as it stands, but let’s not get ahead of ourselves. We’ll deal with the negatives in a moment.
Revisions are much more intuitive than in Perforce. Here we just have one global revision number, not one per file as well as a global one. For me, that makes a lot more sense. It also makes it very easy to roll back changes or recover deleted files.
I wasn’t sure whether to include the GUI under the good stuff or the bad stuff. It’s good because there is one available. Actually, there are many available, and choice is always good. But it’s not so good because they’re clearly a work in progress and are not really at the level of the Perforce GUI. Still, they’re functional. Also, they had the nice effect of encouraging me to use the command line and now I like it so much better that I doubt I’ll go back to the GUI.
The Bad Stuff
So far, everything looks really good. So, what’s not to like? Subversion, like CVS, likes to use what I affectionately call “file droppings” to mark its territory. Instead of storing metadata somewhere else, Subversion adds .svn directories to every directory that you use as a workspace. Under Linux they aren’t a big deal since you can’t see them most of the time, but I just don’t like the concept very much. I really like to keep my data separate from any computer-generated data.
I’m still a bit uncomfortable with the whole copy-modify-merge workflow. Somehow, I always feel that I’m going to forget to commit files or forget to add them to source control because I don’t have to think about checking them out in the first place. It’s completely a matter of getting used to it though, and I suspect I will like it better in the long run.
As I mentioned earlier, the RapidSVN GUI (which is the only one I tried) still has a long way to go. Right now it can only be described as having barebones functionality. Trying to do something as simple as diff’ing two versions in the file history dialog is not supported, and it wouldn’t display the history of a file after it was renamed. Oh well. Good thing the command-line is so good.
As of this version (1.0.5), one of the features Subversion is lacking is the ability to lock a file and prevent other people from modifying it. This is extremely important in the case of binary files (think of art assets, project schedules, or even Microsoft Word documents). The last thing you want to do is spend a while editing a binary file, commit it, and then find out that someone else made a change to it already. Good luck with that merge. Fortunately, that’s one of the features high in the roadmap, and it’s supposed to be coming around version 1.2.
The real ugly side of Subversion appears when you start using branches. One of the first things that caught my eye was that Subversion has no automatic conflict resolution of any kind. If you try to merge two files that have both been modified in different parts, Subversion will not attempt to merge them automatically for you. Instead, it generates three files and leaves it up to you to do the dirty work. That’s quite a blow to productivity! When working with Perforce and making heavy use of branches, I rely on Perforce to resolve most of the conflicts in my files and I only have to deal with the ones that resulted in a real conflict. Fortunately, they’re aware of that shortcoming and are planning on addressing it… sometime. Until then, I wouldn’t really be able to recommend Subversion for production use. But wait, it gets worse… much worse.
Here’s the real killer blow for me: Subversion doesn’t keep track of what merges have been applied to a file. That’s up to you to keep track of somehow. That means that for every file (or set of files), you have to know up to what revision they’ve been integrated, and only pull in the changes from that revision on. Since it’s hard to believe that a version control system could be lacking that functionality (I suppose I’ve been spoiled by Perforce), here’s an excerpt from the book itself:
Ideally, your version control system should prevent the double-application of changes to a branch. It should automatically remember which changes a branch has already received, and be able to list them for you. It should use this information to help automate merges as much as possible.
Unfortunately, Subversion is not such a system. Like CVS, Subversion 1.0 does not yet record any information about merge operations. When you commit local modifications, the repository has no idea whether those changes came from running svn merge, or from just hand-editing the files.
That really kills Subversion dead in its tracks for anybody making heavy use of branches (which is very tempting considering how easy it is to do in Subversion). Whenever they fix that, Subversion will be a real candidate though.
I also decided to try one of my current litmus tests for good handling of branching and merging: start with a file A in the main trunk, create a branch from it, modify the file both in the branch and in the main trunk in a way that no conflicts occur, then rename it to A_1 in the branch and attempt to merge back into main. Maybe I’m dreaming, but I’d like a good version control program to realize that file A has been modified and renamed, and apply both those changes to file A in main. Subversion falls short yet again by ignoring all changes done to file A in main and simply bringing over the changes from A_1. I didn’t even get a warning of any kind. Not exactly refactoring friendly. But then again, Perforce fails this test as well, but at least it prints a warning to let you deal with the merge before giving up.
Does it mean that Subversion is useless at it stands? No, not at all. Actually, I’ve decided it’s the source control system I’m going to use in my home network. I never use branches at home, so Subversion’s limitations are not going to affect me. So let’s continue waiting and let’s keep an eye out for future Subversion improvements. The day automated conflict solving and improved merge are implemented, Perforce and other source control systems should start trembling in fear.
Edit: Jonathan Blow brought up a very good point about another advantage of Subversion over Perforce or SourceSafe:
He writes: “Also, one awesome thing about subversion that didn’t come up in your article is that it only needs the network for update and commit operations. The rest of your workflow is not affected at all–so if you want to add, delete, or whatever to files, you just do it, even if your network connection sucks, the cable is unplugged or you’re on your laptop and don’t have wifi right now. That has been great and it’d be very difficult for me to go back to anything else.”
Personally, most of the time, when I’m using Perforce at work, I don’t really care whether my network connection is on or not. But I’ve really wished for that feature every time I would do some work from home. It’s possible to work disconnected from Perforce, but not exactly trivial. I suppose that’s something inherent about the lock-modify-unlock workflow approach and it can’t be helped.
Another good point that several people brought up is that branching in Perforce is not more complicated from Subversion. Sam Stafford, from Perforce, writes: “I just read through your Subversion writeup on Games from Within, and was curious about one particular point (I haven’t used Subversion at all yet): How does “svn copy src dest” differ from “p4 integ src dest”?“.
I’m partly to blame for that one. Usually, when I branch with Perforce, I use branchspecs, not filespecs, which require creating a new branchspec, adding the new tree in the client view, doing the initial integration, and checking-in the files. Not exactly trivial, especially not from the GUI. In the future I’ll try filespec branching for less complicated branches.