Merging Unity scenes, prefabs and assets with git

When it comes to working as a team on the same project we are all thankful for source control. But even if you’re cool with git there are some things to be aware of when starting new source controlled Unity projects that should help to reduce the chance of nasty merge conflicts.

Solo Scenes

Something to generally avoid in Unity is working on the same scene. Thats why the question of how to merge a scene when a team of developers are working on it is a fairly hot topic. One basic strategy is for each person to clone the main scene and work on their own version, then nominate a scene master to combine the various elements into in the main scene to avoid conflicts. But because this is quite a restricted way of working Unity 5 introduced Smart Merge and the UnityYAMLMerge tool that can merge scenes and prefabs semantically.

Asset Serialization using “Force Text”

By default Unity will save scenes and prefabs as binary files. But there is an option to force Unity to save scenes as YAML text based files instead. This setting can be found under the Edit > Project Settings > Editor menu and then under Asset Serialization Mode choose Force Text.

unity-edit-projectsettings-editor-assetserializationmode-forcetext

But as this is not the default setting make sure when applying this mode that everyone else on the team is happy to switch.
If you select “Force Text” to save files in YAML format you should add a .gitattributes file that tells git to treat *.unity, *.prefab and *.asset files as binary to ensure git doesn’t try to merge scenes automatically. Paste the following into the .gitconfig file inside your Unity project:

*.unity binary
*.prefab binary
*.asset binary

Another result of saving in text file mode is that you can see the changes in source control commits.

Setting up UnityYAMLMerge with Git

You can access the UnityYAMLMerge tool from command line and also hook it up with version control software. Paste the following into the .gitconfig file inside your Unity project:

UnityYAMLMerge (Windows):

[merge]
tool = unityyamlmerge

[mergetool "unityyamlmerge"]
trustExitCode = false
cmd = 'C:\Program Files\Unity\Editor\Data\Tools\UnityYAMLMerge.exe' merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

UnityYAMLMerge (Mac):

[merge]
tool = unityyamlmerge

[mergetool "unityyamlmerge"]
trustExitCode = false
cmd = '/Applications/Unity/Unity.app/Contents/Tools/UnityYAMLMerge' merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

GitMerge for Unity

Worth a mention is the free GitMerge tool for Unity for merging scene and prefabs inside Unity Editor but unfortunately this editor plugin is currently broken in Unity 5. Once you start merging and are in a git merge state you can resolve the conflicts inside the Unity app using GitMerge Window for Unity which is opened via menu Window > GitMerge.

Merging Unity C# script conflicts with P4Merge app

For merging conflicts I prefer to use the free P4Merge visual merge tool which is available for Mac and Windows. Here’s how to hook up the P4Merge app as the global git merge tool when issuing the git mergetool command:

P4Merge (Windows):

git config --global merge.tool p4merge
git config --global mergetool.p4merge.path 'C:/Program Files/Perforce/p4merge.exe'

P4Merge (Mac):

# Setup p4merge as a visual mergetool
git config --global merge.tool p4mergetool
git config --global mergetool.p4mergetool.cmd "/Applications/p4merge.app/Contents/MacOS/p4merge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"

git config --global mergetool.p4mergetool.keepTemporaries false
git config --global mergetool.p4mergetool.trustExitCode false
git config --global mergetool.p4mergetool.keepBackup false
git config --global mergetool.p4mergetool.prompt false

# Setup p4merge as a visual diff tool
git config --global diff.tool p4mergetool
git config --global difftool.p4mergetool.cmd "/Applications/p4merge.app/Contents/Resources/launchp4merge \"$LOCAL\" \"$REMOTE\"

# show updated git config
git config --global --list

Setup a .gitignore file for Unity projects

First up there are certain Unity folders and files you don’t want to include in the repo. Only ‘Assets’ and ‘ProjectSettings’ need to be included. Other Unity generated folders like ‘Library’, ‘obj’, ‘Temp’ should be added to the .gitignore file. Or you can just copy the boilerplate Unity .gitignore file. I also suggest ignoring generated files like OS and source control temp files:

# Source control temp files
*.orig
# OS generated
.DS_Store

Unfortunately I made the over zealous mistake of adding all *.meta files to the .gitignore file. At first this seemed like a good idea until the repo gets cloned and you end up with broken script and resource links in the Unity Editor scene. The Unity source control documentation mentions that these .meta files should be added to source control. However I found that its only the meta files associated with resource files and scripts that are linked to a GameObject in the Unity Editor that are required. By using the exclusion rule in gitignore I can limit it so the only .meta files to be saved are those within the Unity special folders like: ‘Prefabs’, ‘Resources’, ‘Scenes’ as well as a ‘Scripts’ folder. So if you wish to limit the meta files just add the following rules to the .gitignore:

# Include only the .meta files in specific folders
*.meta
!Assets/[Ee]ditor/**/*.meta
!Assets/Editor Default Resources/**/*.meta
!Assets/[Gg]izmos/**/*.meta
!Assets/[Pp]refabs/**/*.meta
!Assets/[Rr]esources/**/*.meta
!Assets/[Ss]cenes/**/*.meta
!Assets/[Ss]cripts/**/*.meta
!Assets/Standard Assets/**/*.meta
!Assets/StreamingAssets/**/*.meta

For example if I import the Azure AppServices library for Unity by copying it into the Assets/AppServices directory that would mean no meta files would be pushed in commits for this folder as it’s outside the Assets/Scripts folder. But what if I use a library that will be linked with GameObjects like TSTableView for example which attaches to a Unity UI Scroll View. Either I can drop the TSTableView folder inside the Assets/Scripts directory, or if you prefer to keep third party scripts outside as I do then you also need to add the Assets/TSTableView directory to the list of exceptions in the .gitignore file:

!Assets/TSTableView/**/*.meta

If you adopt this convention just be aware that every time you add third party MonoBehaviour script libraries outside the Assets/Scripts folder then these directories will need to be added as .gitignore exceptions to save the associated .meta files.