First, a little intro about VCS': why Mercurial for Game Development? In the past I have worked with another Distributed VCS you might have heard about - Git. Git has its drawbacks and complications, and having worked with EGit (extension for Eclipse that provides Git functionality) I found it to be very problematic. Having learned a bit of Git's peculiar syntax, I was curious to see how Mercurial (Hg) compares to it. I can echo the general attitude that you can learn Hg syntax within a day or two, while with Git I was constantly surprised as soon as I had to 'wander off the beaten path'. I also really liked how Mercurial did things in general, so Git vs Mercurial choice was very clear for me. Imagine you have a job to complete and 2 engineers to do it: one engineer that can complete a job within 30 hours, but he knows much more and is more popular (his name starts with G); and you have another engineer which can complete the same job within 5 hrs without much fuss (and his name starts with M). Which one would you hire?
On the other hand there are Centralized VCSs like Perforce or SVN. These are, in theory, much better for Artists, because they can lock individual files for editing, thus preventing other team members to "step on each other's toes" by editing the same files and doing redundant work. DVCSs presume the work will be merged as text files (code) and don't even have the option to lock the file - it's not in their nature. As a generalization, DVCSs are better for code collaboration and CVCSs are better for binary and asset collaboration. I would have chosen CVCS if it was not for one thing: they don't really work with Unity. They work by setting a specific file flag (on a file system level) that is 'Read-only' to denote the lock status. Unfortunately Unity does not honor the flag: it allows editing of the file either way. This makes a CVCS pretty much useless, and yes: there are scripts out there that help with the problem (locked file becomes grayed out in the hierarchy) but those are not real solutions - nothing about those is low-level industry-strength guarantee that taking of the locked file won't happen. As of writing this (Unity 5.1 is active) this has not been resolved to the satisfactory level. On a more general note, some Game Development teams resolve the conflicting general need to both have distributed versioning of code and file locking for binary files by making a Frankenstein - using both in a complicated setup. This will be further addressed in a future article.
The other question that may arise is: why CodeCompare for Merging actions? Take a look at the competition:
WinMerge: I used it in the past, it's fairly nice but the interface is not "immediate" - which means you have to use the toolbar instead of arrows to the side of the code. This, of course is only for comparison (not merging), as WinMerge does not support standard 3-column configuration for merging which makes it a misnomer and unsupported by SourceTree as you'll find on their forum. Pity.
Kdiff3: Quite popular but I never could get into the 3 + (1 below) interface (and it is not 'immediate'); more importantly the interface styling could be liked only by the authors.
Meld: Popular in FOSS circles, not so much under windows. It's good: you can copy up/down from right to left and vice versa (what I mean by immediate), but I haven't found a way to do it in single click under Windows like under Linux. Additionally, I've found the lines selection style to be tiresome. On the plus side, it has a nice section for ignoring similarities. Alright tool overall.
TortoiseMerge: Part of TortoiseSVN; you could download it standalone in the past from SourceForge, but it seems now you have to install full TortoiseSVN which I did not want. It's style is like kdiff3, though I've read it's better if you're into it.
SourceGear DiffMerge: Similar to all the contenders above, I've found the interface a bit archaic too.
P4Merge: Is free now, made by Perforce. I did try it, but couldn't get into its way of doing things fully. I also didn't like that it wastes space on the legend - when you figure it out once you've got it. Should be a very solid tool if you like its ways.
If you're finding this article helpful, consider our asset Dialogical on the Unity Asset store for your game dialogues.
Okay, enough of that. My favorite is CodeCompare. It's both a standalone tool and VS extension (which makes it especially handy). It has all the options I personally like: by holding Shift or Ctrl and clicking the arrow you can quickly insert the difference above/below; you can quickly resolve the merge by taking 'All mine
' / 'All theirs
'; it has both file and folder comparisons; it's fairly smart and has some additional features such as bookmarks. There is a commercial and free version, and the free version cannot show the 3-file view at once (you have to use the 2-side view and scroll). That's okay, I usually merge the changes into the file that has less changes just like in Meld. Then, when you save and exit it's smart enough to figure out that the file that was saved was the result of the merge (as opposed the 4th file marked as result). I also really like how it clearly marks and colors 'Mine', 'Theirs' etc. in the file title, making jumping between multiple 2-sided views a breeze, which you want to have anyway if you don't like vertical scrolling all the time in 3-way view.
So, what's the problem? Well, it takes a bit of a setup with SourceTree. If you go to CodeCompare documentation, you will find how to integrate it with Mercurial itself, by pasting this in the mercurial.ini
file that is located in the user profile directory (docs found here).
[merge-tools]
codecompare_merge.regkey=SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\CodeCompare_is1
codecompare_merge.regname=InstallLocation
codecompare_merge.regappend=CodeMerge.exe
codecompare_merge.args=/SC=Hg /TF=$other /MF=$local /RF=$output /BF=$base /TT="Other: $other" /MT="Local: $local" /RT="Output: $output" /BT="Base: $base"
codecompare_merge.binary=False
codecompare_merge.gui=True
codecompare_merge.checkconflicts=True
codecompare_merge.premerge=Keep
[extensions]
extdiff=
[extdiff]
cmd.codecompare=C:\Program Files\Devart\Code Compare\CodeCompare.exe
opts.codecompare=/SC=Hg /title1="$plabel1" /title2="$clabel" $parent $child
[merge-patterns]
*.*=codecompare_merge
[ui]
merge=codecompare_merge
Then, you would set up in SourceTree System Default as in the picture:
Unfortunately, this does not work. For some strange reason, SourceTree is ignoring the mercurial.ini
file when it comes to these settings (I tried it on 2 PCs, win 7 and win 8.1). This may be worth a try in future versions. So you dig up a bit further and find there's indeed a specific configuration for CodeCompare for Merge - from the Dropdown chose Custom and input this below:
Merge Tool: C:\Program Files\Devart\Code Compare\Codemerge.exe
Merge attributes: -MF=\"$LOCAL\" -TF=\"$REMOTE\" -BF=\"$BASE\" -RF=\"$MERGED\"
This works, but what about Diff? I have tried to conclude the parameters by comparing parameters of CodeCompare.exe (used for comparison) and CodeMerge.exe (used for Merge like above), both of which you get when you install CodeCompare tool. Turns out I was thinking too hard, you just have to do this:
Diff: C:\Program Files\Devart\Code Compare\CodeCompare.exe
Diff attribnutes: -MF=\"$LOCAL\" -TF=\"$REMOTE\"
And of course choose Custom from the Dropdown above. Seems like it's working now.
Well, it isn't.
We need to specify UnityYAMLMerge.exe (a tool that comes with Unity installation just for merging) as per here http://docs.unity3d.com/Manual/SmartMerge.html. The problem is we need to specify that tool only for .unity
and .asset
files, and for the rest use the tool from above. For this we need to use config files as the input dialog does not have the option. So, since we know mercurial.ini
is not the right one for the job, which one is it?
I found that I can modify C:\Users\<Username>\AppData\Local\Atlassian\SourceTree\hgrc_sourcetree
and get the desired behavior. Here is the config file for both setting up CodeCompare and UnityYAMLMerge.exe.
[extensions]
rebase=
transplant=
hgext.extdiff=
hgext.fetch=
hgext.hgattic=C:\Program Files (x86)\Atlassian\SourceTree\extras\hgext\hgattic\attic.py
hgext.mq=
hgext.hgflow=C:\Program Files (x86)\Atlassian\SourceTree\extras\hgext\hgflow\hgflow.py
sourcetree_auth=C:\Program Files (x86)\Atlassian\SourceTree\extras\hgext\sourcetree_hg_auth.py
[diff]
git=True
[ui]
commitsubrepos=no
ssh="C:\Program Files (x86)\Atlassian\SourceTree\tools\putty\plink.exe"
diff=extdiff
[web]
cacerts=C:\Users\XXXXXXXXXXXXXXXX\AppData\Local\Atlassian\SourceTree\hg_local\cacert.pem
[extdiff]
cmd.sourcetreediff= C:\Program Files\Devart\Code Compare\CodeCompare.exe
opts.sourcetreediff=
cmd.extdiff=C:\Program Files\Devart\Code Compare\CodeCompare.exe
opts.extdiff=
[merge-tools]
sourcetreemerge.executable=C:\Program Files\Devart\Code Compare\Codemerge.exe
sourcetreemerge.args=-MF=$local -TF=$other -BF=$base -RF=$output
sourcetreemerge.binary=True
sourcetreemerge.gui=False
sourcetreemerge.checkconflicts=True
sourcetreemerge.premerge=True
unityyamlmerge.executable = C:\Program Files\Unity\Editor\Data\Tools\UnityYAMLMerge.exe
unityyamlmerge.args = merge -p $base $other $local $output
unityyamlmerge.checkprompt = True
unityyamlmerge.premerge = False
unityyamlmerge.binary = False
[merge-patterns]
*.*=sourcetreemerge
**.unity = unityyamlmerge
**.prefab = unityyamlmerge
This should work fine. I've left parameters for diff empty, it seems alright as is.
So, are we done? Nope.
See, when you do run a merge with UnityYAMLMerge, if it cannot resolve the merge it will run an external tool as fallback, which it will try to find based on default installations of some popular merge tools, and it does not include CodeCompare by default. As a side note, I have yet to see a successful mere done by UnityYAMLMerge, so let's configure it to at least fall on its back properly.
Find your equivalent of C:\Program Files\Unity\Editor\Data\Tools\mergespecfile.txt
; make a backup copy just in case. In our case we don't need all the other tools, so your whole file can look like this:
#
# UnityYAMLMerge fallback file
#
# Modify the next two lines if scene or prefab files should fallback
# on other that the default fallbacks listed below.
#
# %l is replaced with the path of you local version
# %r is replaced with the path of the incoming remote version
# %b is replaced with the common base version
# %d is replaced with a path where the result should be written to
# On Windows %programs% is replaced with "C:\Program Files" and "C:\Program Files (x86)" there by resulting in two entries to try out
# On OSX %programs% is replaced with "/Applications" and "$HOME/Applications" thereby resulting in two entries to try out
* use "C:\Program Files\Devart\Code Compare\CodeMerge.exe" -MF="%l" -TF="%r" -BF="%b" -RF="%d"
Now you're really done. If you used this config feel free to say thanks in the website comments.
If you're finding this article helpful, consider our asset Dialogical on the Unity Asset store for your game dialogues.