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.
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.
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.
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.
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.