Getting Unity 3D working with Git on Windows

Git is a brilliant, yet peculiar beast. It has the most flexibility of any of the VCS's I've used, and it's extremely powerful and quick once you get used to how it works. Suffice to say that I've fallen in love with it over the past year, for both personal and commercial projects, and online services like github and bitbucket just enhance the overall appeal of it. I therefore want to use it as my VCS of choice when developing games... but those who have tried to get Unity and git working together will probably either be dead by their own hand, or crouched in a corner, rocking back and forth in the foetal position.

Unity3D is an entirely different, and possibly more peculiar beast. It's a great tool, and the editor is feature rich, but it's source control compatibility is weak to say the least. I don't know if this is through necessity, or the marketing people at Unity have pressed the developers to make it as complicated as possible in order to sell their Asset Server control system. The complexity is mostly due to the fact that the Unity editor serializes most assets into binary by default, and git - by it's very nature - is built to compare textual files. In addition, Unity3D creates a shed load of files that should not be version controlled (such as its asset cache), and the Visual Studio / MonoDevelop solution and project files change constantly.

I spent the good part of a couple of weeks getting Git and Unity3D playing nice together, but, because I'm not currently collaborating with other developers I'm still not 100% convinced that Unity3D and git are suited to each other yet. Regardless, it's very handy for me at the moment, so here's how I've implemented my git repo for Subnet, my upcoming First Person stealth and parkour game.

This tutorial is for Unity Pro 4.1.5f, which - at the time of writing - is a little bit out of date, but I believe Unity have recently made a number of pro only features available in the indie version as well (such as asset serialization), so you should be able to follow this for any of the later versions. Unity have provided a tutorial on how to integrate with VCS's, but (as with pretty much all of the Unity documentation) it's not great.

Setting Up Unity

Open up your Unity project and go to Edit -> Project Settings -> Editor:


This will open the Editor Settings in the Inspector. Here you should set "Version Control -> Mode" to "Meta Files" and "Asset Serialization -> Mode" to "Force Text".


The "Meta Files" option will run through your entire Assets folder and generate a text based .meta file for each file and folder contained within. This file holds some internal Unity data, such as identifiers, version numbers and import settings. You will not need to manually interact with these files, unless you start moving assets around outside of the Unity Editor.

The "Force Text" setting will force relevant assets to serialize as YAML. This allows git to compare changes to editor settings, such as the assets location and scale. It's not brilliant (sometimes even changing a single setting in a prefab might regenerate the entire file), but it's about as good as you're going to get.

That's it for Unity Editor settings. The only other thing to mention is that you should always move files around within Unity Editor, rather than on your file system, unless you know exactly what you're doing, otherwise you might break physical references to your assets that can be difficult to resolve, especially if you have a lot of references set up to the moved asset within Unity.

Setting Up Git

My git repository has my Unity project inside it, as well as a number of standard Visual Studio solutions and projects that I use for creating some shared and unit tested code. I tend to set up the following directory structure:

  • /build/
    • For unity builds. This directory contains a .gitignore file with a single line in it - "!.gitignore", as I do not wish to push any of my unity builds to git.
  • /source/
    • For all source code. I create sub-directories inside this folder for each individual solution - so, one for my Unity project, and another directory for my separate VS solution.

I also set up a .gitignore file in the root of my repository containing the following patterns:

*.suo
*.sqlsuo
*.user
*_ReSharper.*
*.suo
*.log
obj/
bin/
Library/
Temp/
*.pidb
*.userprefs
*.orig
Assembly-CSharp*.csproj
Assembly-UnityScript*.unityproj
.DS_Store

*.subnet
source/POC/SubnetPOC/SubnetPOC-csharp.sln
source/POC/SubnetPOC/SubnetPOC.sln

The last three entries are project specific; "*.subnet" is the extension I have applied to my serialized Save Game files, and the other two lines are direct links to the generated Unity solution files. You don't have to be explicit here; if you don't have any .sln files in your repo that are external to the Unity directory (which I do), then you should just add "*.sln" to the list at the top.

A lot of the ignore patterns are pretty standard when using git with .Net repositories, but .Net developers paying attention might wonder why I'm also excluding .sln, .csproj and .unityproj files from the repo. This is because they are recreated every single time you modify the Project structure within the Unity Editor. Different versions of Unity also create slightly different versions of these files, meaning that if you're collaborating with someone who has a different version of Unity than you, these files will be constantly updated as you both commit to the repo, even if you don't change anything in the project structure. Because Unity Editor manages the creation of these files, you don't need to worry about them - anyone cloning the repo will generate their own version of the project and solution files as soon as they open up Unity.

This raises another "gotcha". You cannot add projects to the Unity Visual Studio / MonoDevelop solution, as they will be automatically removed next time you change a file inside Unity. This is why I have a separate solution containing any shared code - so Unity doesn't screw up my references and project links constantly!

Also notice that the Library, obj and Temp directories are excluded from the repo. Again, Unity generates these directories whenever you open the editor or build the solution - they are local cache directories that each collaborator will have a local copy of. They're full of binary files, and can get absolutely HUGE. The more assets you have, the larger these directories will become.

Lastly, but possibly most importantly, is the .gitattributes file. This controls the line endings that git applies to each file type when you check files in and out. If I remember correctly, Unity applies LF line endings to most files by default, which can confuse things (and present you with a lot of laborious popups in the various editors you might use) on a Windows machine. I found a template somewhere online (which I can't find again - please let me know if this if your file so I can credit you), but it still took me a while to get everything working to an acceptable level. I'm still not 100% convinced that this list is comprehensive, but it's a damn good start:

# Apply native OS line-endings on checkout of these files...
*.boo              text
*.c                text
*.cginc            text
*.config           text
*.contentproj      text
*.cpp              text
*.dae              text
*.DAE              text
*.dtd              text
*.fx               text
*.glsl             text
*.h                text
*.inc              text
*.ini              text
*.js               text
*.JSFL             text
*.jsfl             text
*.json             text
*.log              text
*.md               text
*.mel              text
*.php              text
*.shader           text
*.txt              text
*.TXT              text
*.xaml             text
*.xml              text
*.xsd              text
.gitattributes     text
.gitignore         text
COPYING            text
INSTALL*           text
KEYS*              text
LICENSE*           text
NEWS*              text
NOTICE*            text
README*            text
TODO*              text
WHATSNEW*          text

# Apply Unix-style LF line-endings on checkout of these files...
*.meta             text eol=lf
*.sh               text eol=lf
*.vspscc           text eol=lf
.htaccess          text eol=lf

# Previous "binary"
*.unity            text eol=lf
*.asset            text eol=lf
*.prefab           text eol=lf

# Apply Windows/DOS-style CR-LF line-endings on checkout of these files...
*.bat              text eol=crlf
*.cmd              text eol=crlf
*.csproj           text eol=crlf
*.sln              text eol=crlf
*.user             text eol=crlf
*.vcproj           text eol=crlf
*.cs               text eol=crlf
*.css              text eol=crlf
*.htm              text eol=crlf
*.html             text eol=crlf

# No end-of-line conversions are applied (i.e., "-text -diff") to these files...
*.7z               binary
*.ai               binary
*.anim             binary
*.apk              binary
*.bin              binary
*.bmp              binary
*.BMP              binary
*.com              binary
*.COM              binary
*.controller       binary
*.cubemap          binary
*.dex              binary
*.dll              binary
*.DLL              binary
*.dylib            binary
*.eps              binary
*.exe              binary
*.EXE              binary
*.exr              binary
*.fbx              binary
*.FBX              binary
*.fla              binary
*.flare            binary
*.flv              binary
*.gif              binary
*.guiskin          binary
*.gz               binary
*.ht               binary
*.ico              binary
*.jpeg             binary
*.jpg              binary
*.keystore         binary
*.mask             binary
*.mat              binary
*.mb               binary
*.mp3              binary
*.mp4              binary
*.mpg              binary
*.ogg              binary
*.PCX              binary
*.pcx              binary
*.pdb              binary
*.pdf              binary
*.physicMaterial   binary
*.physicmaterial   binary
*.png              binary
*.ps               binary
*.psd              binary
*.qt               binary
*.so               binary
*.swf              binary
*.tga              binary
*.tif              binary
*.tiff             binary
*.ttf              binary
*.TTF              binary
*.unitypackage     binary
*.unityPackage     binary
*.wav              binary
*.wmv              binary
*.zip              binary
*.ZIP              binary

You can read more about .gitattributes here.

Unity Script Default Line Endings

As I alluded to a bit earlier, Unity uses LF line endings by default. This is particularly annoying on Windows, especially considering that every time you create a script, you have to modify the line endings manually. Luckily, Unity uses text based template files to create the default scripts, and you can modify the line endings in a program like Notepad++ yourself. The templates are located in the following folder by default:

C:\Program Files (x86)\Unity\Editor\Data\Resources\ScriptTemplates\

In Notepad++ it's as simple as opening all the files at once, and replacing "\n" with "\r\n" In All Open Documents.

There's not much point of me providing these files for you, as it's possible they could be different in each version of Unity, and you might have already modified them yourself.

That's It

As I said, I'm not 100% convinced this approach will work for everyone, and I'm still very nervous about two people modifying a single Unity scene or prefab file at the same time (I had numerous issues last time I collaborated), but it's about as close as anyone's going to get, I think.

Popular posts from this blog

GDPR: Application Password Security in 2018

How I Learned to Lose Weight and Love Exercise (again)

AutoMapper: UseValue vs ResolveUsing vs MapFrom