Mercurial TFS2010
Lately I've written about that we we decided to change our version control system in favour of Mercurial, and today I will provide some facts about our migration, harmless central repository's installation especially for .NET programmers and about other things, which may come in useful for everyone willing to do the same :)

Configuring Mercurial on Windows Server 2008 R2

Expected configuration will use Mercurial 1.9.1, Python 2.6, IIS 7.5, Windows Server 2008 R2. There is a very good step-by-step tutorial explaining all necessary steps to conduct available on: Installing Mercurial 1.8.4 on IIS 7.5 as a Repository website. I must admit, that this tutorial is very comprehensive and also compatible with the newest version of Mercurial, so it's just enough to start actually work with this VCS. Unfortunately, in our environment that wasn't enough, because we've encountered a very strange and mysterious problem, which had emerged, of course, just a few minutes after go live in production environment. Serious problems on production need to be fixed really quickly.

Before that - quick explanation. In the test environment me and my co-worker were performing some test cases to check if everything works just fine. Unfortunately, we have been using our notebooks at the moment and we were attached to our local network by WiFi (well, it's rather standard nowadays, isn't it?). When I moved repositories to our production server, first person which wanted to check out things on Mercurial was my another co-worker, who used standard and big PC and was connected to our network by the RJ-45 cable. That was the only reason we have found explaining why some people were constantly breaking up our server by just pulling or pushing changesets. That was actually pretty amazing that you can so easily crash a whole system by doing such a simple request like hg incoming. Well, that's just one line and it's thousands times more effective than performing DoS attack! You just need an IIS server and Mercurial. Moreover - while crashing, operating system haven't ever written even a single line of message in EventLog, which could help us in finding actual problem. Some quick attempts to deal with this problem definitively failed (like increasing limit of concurrent active connections to IIS Server to 10,000). There was a chance that server's configuration was flawed, but there wasn't much time for reinstalling and configuring this machine (we are still live on production server and because of this problem some people could not share progress of their work with others)

Very good and very quick solution for this problem was use an alternative web server for Windows OS - Abyss Web Server, which in my humble opinion is much more easier and faster in configuration, and works very efficiently after set up. Moreover - Abyss Web Server can be easily installed side-by-side with IIS and there are no conflicts with existing projects and services.

Now few words about configuring Abyss Web Server especially for use with Mercurial

Abyss Web Server's Configuration

  1. Application's installation. After complete, we'll see a web page with the administration panel. On the first run you will provide access data for administrator, etc.Configuring CGI on Abyss Web Server
  2. Upon complete let's open: http://localhost:9999 in a browser and click Configure on the default host
  3. Click Scripting Parameters. We will set here settings for CGI and Python for our hgweb
  4. In Interpreters section click Add and fill similarly to the picture on the right
  5. Next back to the host's main page and select Aliases
  6. Add a new alias (it's a virtual directory in IIS). In my case VirtualPath is just /hg, and a PhysicalPath points to physical directory on hard disk. I've pointed the same directory which was used by IIS with no changes within and work just fine :)
  7. Optionally you can configure URL Rewrite to remove the hgweb.cgi part from repository's URL, but in my case it wasn't really necessary, so I skipped that step :)
  8. Enjoy your new working Mercurial's repository on Windows Server! ;]

In the meantime, it became clear that possibilities of Abyss Web Server are quite amazing, especially when we consider size of the Installer's package (~1,8 MB). I haven't tested yet ASP.NET hosting capabilities on this web server (which supports even the newest ASP.NET - 4.0), but it's definitely worth checking out :)

Migrating repositories

After setting up the central repository we should fill it with the commit data from the previous version control system (in our case - TFS) to provide maximal functionality of the new repository. For migration I've used a very small console application - tfs2hg. This program for repository containing 4,000 changesets takes something around 2 - 3 hours to copy all data from TFS, so you need to be patient. I will also suggest running this application on a non-developer workstation to avoid a lot of complications with TFS bindings / mappings / or whatever else (TFS' project can be mapped to only one location on hard disk without special hacks).

There is also a curiosity connected with migrating process:

Migrating tool works in a very simple way. It gets all commits from TFS repository one by one starting from the very first, until it reaches the last one and after each step it commits changes to Mercurial repository with custom meta data. It's a very simple, yet long-running process and rather flawless. Unfortunately, after 4 hours of running program, repository and working directory in the hg were slightly different, especially there was something about 800 files missing. Rather random files. It was really hard to point out where this problem comes from; moreover there wasn't any log entries indicating some issues in migrating process. Well, just a curiosity while moving 4000 changesets ;]

Differenced between TFS and Mercurial

While beginning work in Mercurial and .NET environment you should start with providing a file with filters for ignoring files while committing changes. In this case just create or edit file .hgignore in the main directory of your repository and after editing save and commit to the repository. TFS didn't force you to create such things because it was a dedicated software for development of .NET applications and it was preconfigured in that direction. Mercurial is much more versatile project and because of that you need to point out what types of files you want to store in your repository (actually what types of files you don't want in the repository). There is already a good sample of .hgignore file for .NET projects for example on the stackoverflow's discussion. I've also attached a slightly improved version of this file, which better fits our environment (you may find it especially useful if you develop .NET 4.0 projects) and is available here.

It's also a good merit to know what differs "standard" version control systems like Subversion and TFS from distributed ones.

Centralized System Distributed System
Centralized system Distributed system

Pictures' source: Joomla's Documentation

You can see here a main difference in distributed version control system - every developer in project group has a very own version of whole repository, which is used whenever a commit, revert, diff and others are made. There is another set of operations for cooperating with other repositories - push and pull for example. It's the most important point for developers bounded to the TFS, where a green icon is indicating that file is committed and available for others. In Mercurial - that indicates that file has been committed to local repository - nothing more, nothing less :)

Another difference you can spot is how you actually work with the repository and - for example - how merges are done. You - as a TFS developer - may assume that if there are no locking files, then naturally you will have to deal with a lot of conflicts, but in Mercurial's (and Git's) case - merging changesets is done automatically by Mercurial. To better explain how is it done, let's review terms like branch, conflict and merge in Mercurial. Every standard commit to Hg repository extends the previous branch (or creates new if you choose so). At this moment you will never encounter conflicts, because your repository hasn't changed since your previous commit. There is no possibility to pull changes from other repository while there are uncommitted changes (well, actually you can do that, but you will have to discard all your changes). But if someone has committed and pushed changes to central repository in the meantime and you will try to push your changes from the last commit, you will get warning that your push may create accidentally a new separate branch on the central repository. Often you need just pull changes and then push merged version of the current branch.

Merges - so troublesome in SVN and TFS - in Mercurial are mostly automatic (to be honest I've done more manual merges in TFS than in Mercurial after 0.5 year of using both). You should remember that synchronizing (in both directions) and other between-repository operations only our local repository may changed - nothing more. And to actually see changes pulled from central repository you need to get latest version from your own repository (it's an Update operation). Now we are approaching to the hardest part, because Update isn't actually the best name for that kind operation. Better would be: Discard all your uncommitted changes and update working directory to the newest revision. TortoiseHG won't do it without warning, but if you're random-button-clicker on all message boxes you get then you'll have a problem. To generally avoid problem with that kind of situation I'd recommend using fetch instead of update. Fetch is doing pretty much the same thing as update in standard version control system. Fetch pulls changes from central repository and automatically merges them with local repository and updates working directory to the newest version.

It may look very complex and daunting for programmers which used to "just committing and just updating theirs solution", but now I will show how to configure Mercurial client to simplify and increase its usability. After some changes it would look at least similar to working with TFS or SVN.

Client configuration

There are few things you have to set up after starting using Mercurial. For example:

  • Enter your user name (Commit –> Username). Generally, there are other authentication methods, but in our case - using closed intranet network - we haven't used any advanced access limit for repositories. So because of that any user which want to push changes to central repository is required to fill that field in TortoiseHg settings. That has some flaws - for example one can change it's name as often as he wish and two people can have the same name. In small development team - it isn't big deal. In more professional environments there should be configured advanced authorization method (for example based on SSH).
  • Turn on extension fetch (Extensions –> Fetch), which I've mentioned earlier.

Things you may want to configure if you're migrating from TFS environment:

  • Default action after pull operation (Workbench –> After Pull Operation). This default action should be fetch. With that setting whenever we pull changes from central repository, automatically we will have merged and updated working directory to the newest version.
  • Automatic push after commit (Commit –> Push After Commit). When we choose ‘default-push’ and assert that we have saved repository connection with the same name then every time we will commit changes to out local repository, Mercurial will try to push changes to central repository.
  • Configuration of repository server's list. In our case (it's also rather general case) we will use only one central repository entry for one repository. To configure it let's change tab to Repository Settings, after that click Edit file and add at the end of file:
default-push = <repository address>

That was most important configuration settings to increase our user experience while using Mercurial. Now few words about using TortoiseHg client.

Using a client application

Generally I recommend using TortoiseHg Workbench to work with our repository. I have attached picture with Workbench screen with a brief explanation about visible functionality. In the red box there are 4 buttons for synchronizing our repository with others. From the left: Check incoming changes, Pull changes, Check outgoing changes, Push changes. in the blue box there are bookmarks which change design of the Workbench to target functionality. On the attached screen you can see bookmark for Committing changes.

There's a worth mention graph presenting revisions and branches, which is very important to actually understand repository's history. Every time when pushing changes fails (it may be quite common when using push after commit) you should take a look at this graph. Usually in that situation you just need to fetch changes from central repository and/or decide if an active branch is the one you wish to extend..

As a result we have rather long article about Mercurial on Windows Server 2008 :) Some may be discouraged to migrating from TFS to Mercurial by the length of this article - but don't. Migration isn't very hard - is much easier than installing and configuring TFS Server and everyone could make it. Besides it is a very good opportunity to change technology to more developer-friendly and much more innovative.


Abyss Underground

Abyss - URL Rewriting Tutorial

Abyss Web Server Download

Migrator TFS –> Mercurial

HgInit - a very good introduction to the Mercurial