Today I would like to talk about something which isn’t actually programming, but which every programmer should know – source control (also known as version or revision control). You will see this topic listed on most job listings as something you should be familiar with, but many hobbyists go far too long (sometimes waiting until getting hired into a big company) before realizing its many benefits. Source control can be extremely valuable even if you work solo on a project!
What is Source Control
Source control is a tool which records the history of your changes to files in your project. If you use a Mac you can think of it as something like “Time Machine” which allows you to see your file at various states in time. This way if you accidentally delete something, or change something on accident, or on purpose but want to go back to an earlier version, you have the means to do so.
Source control is smart and only records “changes” to files rather than the entire file itself so that storing many revisions of your work doesn’t un-necessarily bloat your disk. Of course there are limits to this (such as “binary” files like images or sound), but text based files such as those used for programming are easy to version.
Since there are apps on mac and windows that allow you to see versions of your files in history, you may be wondering what the need is for another tool like this? I’ll give two main reasons:
Some changes to a project touch many files (either by refactoring, or because a new system is large and referenced by many classes, requires art assets, etc.) The larger the project the harder it will be to remember all of the files that change from feature to feature. If you want to go back in time to a point before you started adding a feature, you would have to remember all of the files that changed (and when they were changed from the version you wanted), what files were removed (and what they were named and where they were located), what files were added, etc. Needless to say, it would be a lot of work to truly “reset” a project to exactly the way it had been.
If you’re not sure when or why this might happen to you, imagine the following scenario. You’ve been working really hard on a project, and decide that it is ready to be published. You still have some ideas to work on but think they would be fine as updates or as a version 2 type of feature. So you publish your game. Now you continue development on the other features for your next release. As people start playing your game you realize there was a huge bug or exploit. What you want to be able to do is go back in time to the way your project was when you created the build for the store, fix just the problem that needs to be fixed, and upload this fix to the store. Then, you also want to keep those changes in place for the future version releases of your app.
In a worst case scenario, you didn’t backup your project as it was when you made the release. In this case, you have to manually start removing new features and modifying others to try to get things back to exactly the way they were. With a large effort, you might get it pretty close, but its very possible you will have created new bugs that weren’t there before thanks to bits of dangling code here and there that were missed and needed to be removed or that needed to be added back in and were forgotten about.
In another scenario you may have cleverly decided to create a zip file of the project exactly as it was when you released the store build. Thats pretty good foresight (not everyone would think to do it). You can unzip the project, make your changes and release the fix in a short time, but you still have to manually re-implement your changes in a second place (the other code you were working on).
If you had used source control, you could have tagged a “check-in” of your project as the version used for your store build. Then you can “check-out” that version at any time and allow it to determine the exact state of every file (including adding, removing, and modifying files as necessary). Now you “branch” from this point in history, fix just the bug that needed fixing, and you’re ready for your next store release. Even better, you can then tell Source Control to automatically “merge” your bug fix back into the other “branch” of code which had your newer features instead of needing to manually do it yourself.
Some projects end up distributed among multiple machines. Even when you are a solo developer you may find yourself working on a laptop while you’re out and about, and on your desktop when you go home. Some developers may copy their project to a thumb drive, or drop box, etc and then try to copy it from one computer to another, but this inevitably makes it difficult to remember which version of a file is the one which should be used. You might have two new scripts in one copy, and two different but new scripts on the other copy. Or even worse, you might have some new code in one copy of a script and some new code in a second copy of the same script and you can’t just replace one with the other. In these kinds of cases you have to traverse all the files in both locations to make a new clean version with all of your up-to-date material. This problem is quickly magnified in the cases where you do work on a project with more than one person, particularly if you aren’t on the same network and working from a shared project.
If you had used source control, synching your project across multiple devices or team mates is easy. You make your changes, “push” them to a server, and then “pull” the changes to any other copy of your project. Because only the changes to a file are stored, you can even allow multiple people to modify the same script at the same time and merge the two together (note that sometimes there will still be “conflicts” that need to be resolved but for the most part version control is very successful with merges).
There are a number of options for Source Control out there, both free and paid:
- SVN: I used this option initially and it performed especially well with projects that were heavily reliant on binary files (textures and sounds, etc) because you could “lock” files which prevents people from attempting to modify a file that you were working on.
Git: We use this option at work and are largely happy with it. In my opinion it is far easier to work with that SVN in regards to branching and merging. It also allows you to work and commit changes locally without requiring the need to immediately push your changes to a server.
Two of the biggest complaints we have are that you can’t “lock” files as you could with SVN, so you will need to communicate well with your team. Even worse is that as your projects repository passes 1GB in size, Git will really start to slow down. You may not even be able to “check-out” your project from scratch (this has happened to me) – a workaround is to obtain a copy of the project which already includes the git data (as a hidden file within the project) and then you can reconnect to the server and push and pull changes as before.
- Perforce: I hear it is the best of both worlds – it has the ability to lock files, can actually use Git within it, etc. Due to its large feature-set it can be a bit intimidating to attempt to learn. Unfortunately I haven’t been able to give it a fair chance because I find it too difficult to install and configure correctly – perhaps you will have better luck. I believe it has some free options but as your team size grows you will need to pay.
In this post we introduced the concept of Source Control and why you might want to use it. I listed a few of the options available such as SVN, Git, and Perforce with some of my opinions on each. Hopefully you are able to see the benefits of integrating version control into your pipeline! Next week we will examine Git a bit more closely and show how to use it along side Unity.