I have been reflexively using Git version control for all of my programming projects since being introduced to it by Michael Hartl’s excellent Ruby on Rails Tutorial book1. The most immediate and obvious advantage of doing this is the ability to use Github, Bitbucket and others as online backups of one’s work – the especially paranoid can even tie their code to more than one of these hosts, or host their own Git server. And then, with a few pulls and pushes, one can easily sync code across all the devices one works on, avoiding the dreaded flashstick file-copying mixup.
In fairness, you can achieve the same thing with Dropbox or Google Drive. What makes version control services more than just a glorified backup interface with a complicated/command-line interface, however, is the sort of time-travel antics they allow you to perform. A typical, basic workflow might look like this:
- Initialise repository around new codebase and add and commit all files. This is the first commit.
- Make some changes. Commit for the second time with these changes.
- Try something experimental. Commit again, for the third time, even though it’s not all working perfectly.
- Realise you’ve made a huge mistake. Rollback to the second commit.
- Now you’re back to step two and can continue in a different direction from your disastrous mistake.
And all through this, you never once had to comment out huge swaths of code that you weren’t sure about deleting or worry that you’d have to manually undo2 a lot of work in case an approach or idea didn’t work out quite as well in practice as in theory.
All of this was great for working on my solo programming projects, and although they tended to be small enough that I didn’t often have to use any sort of rollback, it was nice to know the option was there if I needed it. But what’s been even better than that is using Git on a team project. I’d go so far as to call it indispensable in team situations. Not a revolutionary statement, perhaps, but there are people out there who still work on projects with versions transmitted back and forth over email and flashsticks (or at best Dropbox).
What’s more – as the title hints at – I actually first learned this during a project with a non-programmer, in which our tool of choice was GameMaker Studio. The main reasons behind the choice were my great familiarity with GM (the first thing I ever programmed in) and the ease with which it allowed my non-programming collaborator to contribute, as GMS uses intuitive GUIs for the creation of game objects and level design.
I knew from the first that I would need to use source control on the project to avoid the madness of manually tracking versions and collating progress. Despite some misgivings about whether Git would actually work with GM Studio, I popped open my terminal3, did a
git init and all the rest of it, and crossed my fingers.
To start off, I let my collaborator work on the
master branch while I made a separate branch to do my stuff. Initially, we decided that each of us would work on a separate group of assets: if he was busy with a given room, I wouldn’t touch it, and if I was busy with given objects, he wouldn’t touch them.
That worked well for a while, but things happen and eventually we got to a point where we’d both modified the same objects and rooms. As a result, when it came to merge our branches, we hit a bunch of merge conflicts. Exactly what I’d been dreading.
But to my great delight, the conflict turned out to be very simple to resolve. Unlike the original Game Maker series that came to an end with version 8.1, which stored projects as single, opaque files, GameMaker Studio stores its projects in neat directory structures containing XML files. Here’s a sample from the
.project.gmx file for one of my old WIPs:
<objects name="Diver"> <object>objects\diver</object> <object>objects\diver_corpse</object> <object>objects\diver_land</object> <object>objects\standpad</object> <object>objects\divepad</object> <object>objects\getup</object> </objects>
The file just contains a list of different resources used by the game, in plain, human-readable text.
If you haven’t run into them before, a merge conflict happens when Git is unable to automatically merge the versions of a given file existing on both branches. This tends to crop up a fair bit when you have two people editing the same thing and Git’s not quite smart4 enough to figure out what the end result is supposed to look like. When this happens, Git will edit conflicting areas of the affected files to look something like this:
<<<<<<< HEAD <sprite>sprites\spr_player</sprite> ======= <sprite>sprites\spr_block</sprite> <sprite>sprites\spr_menubutton</sprite> <sprite>sprites\spr_enemy</sprite> >>>>>>> refs/remotes/origin/somebranch
Your job then is to manually edit the file to get the result you want. In this example, you might replace the above with this:
<sprite>sprites\spr_player</sprite> <sprite>sprites\spr_block</sprite> <sprite>sprites\spr_menubutton</sprite> <sprite>sprites\spr_enemy</sprite>
spr_player is already defined somewhere else above or below the merge conflict, you might use this:
<sprite>sprites\spr_block</sprite> <sprite>sprites\spr_menubutton</sprite> <sprite>sprites\spr_enemy</sprite>
But basically the idea is get rid of the
<<<<<<<<<<< markup and make sure you keep all your sprites, objects and rooms listed, so you can still edit them in GM.
As long as you’re wary of balancing the number of opening and closing
<rooms> tags (there’s one for each resource listing as a whole, and then one for each of the interior folders you define in GMS), you can successfully perform text editor surgery on such files without ill effect. Object and room files are much the same. You could hypothetically write an entire game in XML like this, if you’re masochistic enough.
And that’s all you really need to know about using GMS and Git version control. Create new branches to work on new features, commit often and with reasonable commit messages, don’t forget to push every now and then so you have an up-to-date off-site backup, and if you’re working in a team, merge your branches as often as possible so you don’t have to fix too many merge conflicts all at once.
An excellent primer not only on RoR but on MVC web development and general software development practices such as version control and testing. ↩︎
Or clairvoyant enough, rather. ↩︎