Mercurial is a distributed source control management system, which allows a greater flexibility in your workflow than the venerable SVN. With the recent improvements to GameMaker: Studio's Source Control Management, it is now possible to use Mercurial from within the IDE.
This guide will walk you through how to set it up, and will follow the same lines as the Adding Git Support to GameMaker:Studio guide.
Getting Started
So, first thing's first, we need to setup the Mercurial file paths in GameMaker: Studio. This can be achieved via File -> Preferences then clicking the Source Control tab.
- Click down the use built-in SVN box, and click Custom.
- You'll then need to point it to where hg.exe resides ( for example: C:\Program Files\Mercurial\hg.exe )
- As Mercurial will only accept File commits, rather than File and Folder commits, check the No Folder Commits option.
- We also need to check the Enable Advanced SCM Options.
- Now, click Create SCM Config.
This creates a default SVN config, the majority of which we will be replacing.
SCM Commands - Mercurial
Now you need to edit the SCM Config file, so click the button labelled Edit SCM Config to open the SCM Configuration window. Here, we are going to change and modify settings and options to make sure it all works with Mercurial, starting with the SCM Commands list. It should be set up as follows:
add: add
blame: blame
changelog: log
checkout: clone
clean: <empty> (There is no clean-like command in Mercurial)
commit: commit
(Like Git, we could emulate SVN's usage patterns here, by having 'push' as post-commit, which would automatically push our changes to the remote path, rather than waiting for an explicit 'push').
delete: rm
info: <empty> (There is no info-like command in Mercurial as there is for SVN)
import: init
lock: <empty> (There is no lock command in Mercurial)
rename: mv
resolve: resolve
post-resolve: resolve
(Mercurial requires you to mark resolved files as finally resolved - it won't do it for you)
resolved: resolve
revert: revert
showlog: log
status: status
unlock: <empty> (There is no unlock command in Mercurial)
update: pull
SCM Command Options - Mercurial
Once you have configured the Commands, you need to set up the Options where we should have the following:
add: $FILE
blame: $FILE
changelog: --rev $REVISION --template "commit:{rev} | {author} | {date|isodate} | \n{desc}\nChanged paths:\n{file_adds % 'A\t{file}\n'}{file_dels % 'R\t{file}\n'}{file_mods % 'M\t{file}\n'}"
(This scary looking mess is to reformat the log output into something GameMaker:Studio will be able to pick up. Mercurial supports 'templates' to change how things are displayed, which in this case follows the format of 'commit:' then the revision name, followed by the commit author, the date it was committed in an ISO standard, a new line then the changelog description, followed by another new line. The phrase 'Changed paths:' is used so GameMaker:Studio knows where the files are listed, which we again format so that added files are prefixed with an A and a tab, deletions are prefixed with a R and a tab, and modifications are prefixed with a M and a tab. Each of which has a newline afterwards. It's not complicated, just messy)
checkout: $SERVERURL $PATH
clean: <empty> (There is no clean option in Mercurial)
commit: $FILE -m $MESSAGE -u $USERNAME -s $PASSWORD
(Mercurial doesn't necessarily need a username and password unless it's different from the default. If you've not specified a username and password when setting up the repository, it will just use whatever the default is)
delete: $FILE -f
info: <empty> (There is no info option in Mercurial)
import: .
lock: <empty> (There is no lock option in Mercurial)
rename: $FILE $RENAMED
resolve: $FILE
resolve-mine: $FILE -t internal:local
resolve-theirs: $FILE -t internal:other
post-resolve: $FILE -m
resolved: $FILE -m
revert: $FILE
showlog: --template "commit:{rev} | {author} | {date|isodate} | {desc}\n"
(Again, like changelog above, we set a template that roughly matches what we had. We don't need as much information at this point, as this is only for calculating the line in the top SCM History box)
status: $FILE
unlock: <empty> (There is no unlock option in Mercurial)
update: $SERVERURL
External SCM Tools - Mercurial
In the External SCM Tools section, we need to specify the merge tool to use, in this case we use Mercurial itself, which will attempt to choose for us:
Mergetool: hg
You then need to add the following into the External SCM Tools Options:
Option: merge $MERGED
Status Log - Mercurial
The Source Control Config window also has a Status Log tab, which you should now select. Here you can just have the following two headers:
status: Status
filepath: Filepath
and you can remove the rest of them.
The Status Log Format will then need to read as follows:
status: ,M,A,R,U,I,C,?,! (NOTE THE INITIAL SPACE!)
filepath: $PROJECTPATH
And these are the required Status Log Values:
Unmodified: (NOTE THAT THIS IS A SPACE!)
Modified: M
Added: A
Deleted: R
Replaced: R
Conflicted: U
Updated: M
External: <empty>
Ignored: I
Unversioned: ?
Missing: !
Wrong-Type: <empty>
Copied: <empty>
Unmodified is a <space>, whereas External, Wrong-Type and Copied are blank.
SCM Functions- mercurial
Finally, we need to configure the Functions tab (if this is not visible, then you need to select the "Advanced SCM Options" check-box in the Preferences). This is mostly personal preference as to what you want, however it may be beneficial to add the following Additional Functions:
blame: Blame
push: Push
pull: Pull
phase: Change to Public
phase: Change to Private
With the accompanying Additional Function Options:
blame: $FILE
push: $SERVERURL --new-branch
pull:
phase: -fp tip
phase: -sp tip
Specifying --new-branch means that any new branches created, will be mirrored on the remote as well, otherwise, you'll just get an error back from Mercurial that it cannot create a new branch when attempting to push. The two phase commands change whether the changes you are doing are to be secret or public.
- If they are secret, then they will not be pushed to the remote server.
- If they are public, they will be pushed.
By specifying "tip" it will change all commits to be either public or secret. If you want more control over this, there is an advanced option you can use instead by changing the following in the Additional Functions Options:
phase: -fp $STRINGDIALOG
phase: -sp $STRINGDIALOG
The $STRINGDIALOG option will bring up a text input box for you to type, in this case, a revision number to mark as private or public. A list of revisions can be found from the Show Log option in the Source Control menu, activated from right clicking the resource tree. Be aware that the $STRINGDIALOG option is not error checked. If you put something wrong in there, GameMaker:Studio cannot catch it - it is passed straight to the Source Control system. As such, it is advanced functionality and should be used sparingly.
You could also add functionality to change branches here, or any other Mercurial command. This could be useful for switching between testing and working sets, for instance. Therefore, assuming a 'testing' branch exists you would have the following Additional Functions:
update: Switch to Working
update: Switch to Testing
and their Additional Function Options, in order:
update: default
update: testing
Using Mercurial support in GameMaker:Studio
Unlike SVN, Mercurial is a "distributed" source control system. This means that the entire source tree is copied to each user, meaning that they are free to make their own branches and merges locally before pushing back to a remote tree that others will pull from. While this does give an additional step of pushing the changes to the remote server, it offers extra flexibility in how you work. You can also revert back changes that you may have decided against before pushing them to the remote for everyone else to get.
We'll now look at a few use cases for Mercurial with GameMaker:Studio, as well as some of the more interesting uses of the new config system.
Local Mercurial Repositories
The first interesting use we have, is that of creating a local repository right where our projects are created. This gives us the ability to track and revert changes without requiring a remote server, or any special setup, to store them. In order to do this, we have two methods we could use:
- When creating a New Project, we tick the Use Source Control box, and specify '.' in the server url. That's it, just a period in the server url box, then click Ok. Mercurial can use a username and password if they are different from the default set you may have already setup. So you can put them in here if you like, and ensure your config has been setup correctly. GameMaker:Studio will then tell Mercurial to initialise in the projects directory and use that. This does make the Push and Pull/Update commands useless, as we have no "remote" repository in this case, but we can still commit changes and track them as if we did.
- Of course, you may already have a Project you want to use Mercurial with. In this case, you would access Global Game Settings and click on the Source Control tab. Then, here all you need to do is specify '.' in the URL box (that is a single period). Again, Username and Password can be set, but you'll need to ensure your config supports it. Click on the Use Source Control checkbox, then Import Project to Repository. As before, Push and Pull/Update commands will be useless as there is no "remote" repository.
Remote Mercurial Repositories
Most users will likely be wanting to use their own repositories - perhaps on BitBucket, for instance. In this case, it works exactly the same way as it would for a local repository, explained above. Again, Mercurial can use the username and password boxes, but you must ensure your config is setup to accept them. The default options are set via your Mercurial management tools, as well as importing SSH keys as needed. Check your tools documentation on how to achieve this.
There are two methods to adding a remote Mercurial repository to your project through GameMaker:Studio:
When creating a New Project, we tick the Source Control box and directly specify the server's URL. Then click Checkout, which will then clone the repository and set it up for Push and Pull/Update to work properly.
Alternatively, adding a remote to an existing project is done in a similar manner. Open Global Game Settings, and click on the Source Control tab. Fill out the URL box, tick Use Source Control, and then Import Project to Repository.
Branching and Merging
GameMaker:Studio does not directly handle branching and merging, however basic support can be added via the additional commands config.
- Open up the SCM Config Tools via File -> Preferences, then clicking the Source Control Tab and Edit SCM Config.
- Click the Functions tab.
- Add a new function with the command "update" and the option being your branch name, in this case "test1". Have the title read "Switch to Test1"
- Add another new function with the command "update" and the option being "default" - which is generally the default branch name. Have the title read "Switch to Default"
These will allow us to switch branches via the right click menu in GameMaker:Studio. However, if these branches do not exist yet, it will throw an error.
There are two methods of creating branches; through the external Mercurial tools, or via an advanced option within GameMaker:Studio. As there are many varients of Mercurial tools, we'll go for an advanced option within GameMaker:Studio.
Create another Additional Command with the following description and option:
branch: Create Branch (command)
branch: $STRINGDIALOG (option)
The $STRINGDIALOG will give us a text input window to type whatever we want in. That alone should warrant caution in it's use, as what you type is not checked before being passed to Mercurial. If you make a typo or anything, it won't be caught. It is therefore important that $STRINGDIALOG is used sparingly. However, in this case, it is useful for being able to create branches from within GameMaker:Studio.
To Merge, we need to deal with a few differences as well. Following with our Test1 and Default branches, we'll add another two Additional Functions.
merge: Merge from Testing
commit: Commit Merge
And their options:
merge: testing
commit: -m "Merge Commit"
The merge command takes the option of what branch to merge from. In this case, testing. Again, you could use $STRINGDIALOG here to specify any, but it would not be checked, and any typos would cause errors. The commit command is specific to merges, as it takes no files to commit. It commits everything that was changed. This is unlike our usual commit command, so it needs to be specified separately here. We're also specifying a commit message '-m "Merge Commit"' to track what's going on. If we left this out, we could specify our own commit message, as Notepad would appear to type one in.