Version Control with Unity 3D Projects in 2020Sebastian Pohl - 10. März 2020
Since I last wrote that we were using Unity 3D as the go-to engine for almost all of our projects a few years have passed and a lot has changed. What did not change is the fact that we are still using Unity a lot.
The engine has evolved into a swiss army knife and we use it for a lot more than only for games.
This means we will, at any point in time, have multiple projects parallel with at least a few people working on them simultaneously. As you can imagine, manually keeping everything up to date would be a pain. And that is the point where you start using version control.
The idea is, to have a location, the repository, where the project is stored and which keeps track of every change that is made to the files. This way, people can work on the data and then tell the repository what they have changed. The software then can check if anything the user did conflicts with changes from someone else. At least, that is the most broken down explanation of what version control does. It can do a lot more, but that is beyond the scope of this article.
But in general, this does sound like a good idea, doesn’t it?
Choosing the right option
The first problem you will encounter is the selection of the „right“ version control system for your projects and your style of working.
Unity itself comes with integration for two of the available solutions:
Unfortunately, both of them did not work out for us. I wrote an article about using perforce with Unity a while ago but it turned out that the whole process of how it works does not go well with some of the involved developers and artists. Plastic SCM, on the other hand, is a paid solution with free plans for Open Source, Non-profit or private use. We tried to avoid adding additional costs to our projects.
The other options we had in mind were the usual suspects:
We used SVN for a long time but we had a lot of problems here and there, also, we really like the decentralized approach Git takes.
But let’s see what steps are necessary to make our Unity project compatible with our version control system. Anyone using Unity for more than a few years may remember how much of a hassle it could be to get these two to work together without breaking too often.
A quick glance at the project setting dialogue reveals that there has been some changes. Some time ago it became the default settings to make a project work together with most version control systems. The most important settings are the „Mode“ dropdown under „Version Control„. If you do not want to work with Plastic SCM or Perforce, set this to „Visible Meta Files„. This makes the meta files Unity is creating for each file in the project visible to the version control system. The other noteworthy setting is the „Mode“ of the „Asset serialization„. It should be set to „Force Text„.
When a user wants to store a change, this is called a commit, the software checks what has changed in comparison to the previous version of the file and only stores the parts that have changed. For a text file, this is relatively easy and results in minimal data that has to be saved for each change. If we do not use text files it becomes a lot more challenging. The data will be encoded in some form or way which makes it harder to find the differences and results in a lot more data that has to be saved to document the change. Therefore we like our assets to be serialized (Converting something to a serial representation of itself which can be stored and later loaded and deserialized to restore it) as text files.
The .gitignore file
So… if everything is set up correctly by default. Where is the problem?
Problems will occur if someone inserts a file into the version control system that should not be there. With Unity, there are some settings that are only for the local interpretation of the project and should not be or do not need to be under version control. In the worst-case those files could break the project for someone else.
But how do we tell Git to ignore those? Turns out, there is something specifically made for this purpose: The „.gitignore“ File.
In this file, we can list all the elements we do not ever want to be sent to the repository. Fortunately, there are a lot of smart people out there who compiled such a file that can easily be used for most Unity projects. You can get it here:
To enable it, just save it with the name „.gitignore“ to the base folder of your project and send it to the repository. Git automatically interprets the contents. To see what it does, let us take a look at the first few lines:
# This .gitignore file should be placed at the root of your Unity project directory # # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore # /[Ll]ibrary/ /[Tt]emp/ /[Oo]bj/ /[Bb]uild/ /[Bb]uilds/ /[Ll]ogs/ /[Uu]ser[Ss]ettings/ [...]
Basically, this just lists a lot of directories that should not be store in the repository because that would either be unnecessary or even harmful to the projects of other developers.
The Line „/[Ll]ibrary/“ tells Git to ignore both „/Library/“ and „/library/“ folders in the base directory of the project. The square brackets just mean that it can start with either of the included characters.
Of course, there are a lot more subtleties to know about gitignore files so feel free to read up a few articles on the internet on how to work with them. Especially if you need information for non-Unity projects.
For the sake of brevity, we assume that you have set up a repository somewhere either locally or with an online service. Use these references to get you started:
If you prefer using a graphical interface you can take a look at these projects:
Now we do know how we can set up our project to work with Git and we know how to tell it what not to include. But how do we tell it what we want to have in the repository?
We can split this into two cases:
- Files already in the repository.
- Files that are not in the repository, yet.
If we changed something inside a file that was already in the repository, this means Git is tracking the changes, we just „commit“ the changes. This means storing whatever modification we made to the local copy of the repository. Of course, you should always add a meaningful „commit message“ to tell your coworkers what you did.
If we created a new file, we simply add it to the repository and then commit it. Again, with a nice message attached to it.
The last step is, if we are working on a repository with other people, to „push“ all the commits we made to the main repository.
That is the basic gist of working with Git in a Unity project. Yes, there are a lot more subtleties you can learn about using Git but this would simply be too much for this article.
Gitflow and Git LFS
There are two things left to talk about. Git discipline and binary files.
Git discipline will be necessary as soon as you work with another person on the same project. There have to be certain rules on how commits and pushes will be handled and how things should be written in the messages to not break stuff or make people really, really angry.
The base for this are the „branches“. These are separate paths of development that are independent from each other. If for example, a developer wants to add a new feature to a piece of software, he would open a new branch. When he is done with his feature, he would then merge it back to the main branch, usually called „master“ and everyone would be happy.
Especially with larger teams, there will be a need to regulate the creation and merging of branches. An easy guide to follow is „gitflow“ which you can find described here:
Read through the linked article and then extend or prune the workflow described to suit the needs of your project, you and your coworkers. You could also create your own strategy from scratch.
As we mentioned before, version control is not always happy with binary files. That’s why we chose to serialize our assets to text files. But from time to time, we can not avoid having binary files. Especially in game projects where you will have a lot of image or sound files which usually are, you guessed it, binary files.
Simply committing them to your repository would almost certainly create a full copy with each change, no matter how minuscule it was, of the content of the files. Now imagine this happening with several hundreds of textures, each having between one and a hundred Megabytes of data…
Luckily, someone thought of this and invented „Git LFS“. This stands for „Git Large File Storage“ and separates the binary files from your „normal“ repository. With this, you will not get the full data-heavy history of the file if you check it out but only the current version.
You can read up on it here: https://www.atlassian.com/git/tutorials/git-lfs
Git LFS is not enabled by default in the repositories and unfortunately, it is dependent on multiple factors, so we can not give you a one-size-fits-all solution on how to enable it.
This concludes the article and I hope to have given you a good overview which enables you to start your own adventure with Git and Unity. If you have any questions, feel free to write a comment. I am giving my best to answer all the question I get!