Quick Tip: Getting Started with Mercurial
From Aventine Solutions
Mercurial is a good choice for a distributed revision control system, so I'm not going into the actual reasons to choose it. I did notice, however, that the instructions for setting it up with a centralized server using HTTP were very patchy and required a couple of days of hacking to get satisfaction; hence the reason for this article.
One of the advantages of a distributed repository approach is that they can be used in a number of collaborative scenarios and some of those may not even require a centralized server. If you're already OK with the later, then you don't need this article at all.
If you do want to have a more formalized central server to push/pull changes to/from and you want that protocol to be HTTP or HTTPS, then read on.
Another goal of mine was to feel satisfied I could get Mercurial working reasonably well in Eclipse the way I use Subversion doing most of my day to day stuff with the Eclipse GUI, and maybe only occasionally doing some housekeeping from the command line. The distributed repository approach means committing many changes to a local repository from Eclipse and occasionally pushing the sets of changes to the server, the push being also done from Eclipse. The cloning of repositories to other development workstations can be done using HTTP or HTTPS from that central server. That will be nice to collaborate across the cloud when firewalls and nasty proxies may get in the way.
Here, then, is the initial platform for this scenario:
- Developer's workstation #1: MacOSX Leopard using the Eclipse Ganymede IDE.
- Developer's workstation #2: Windows XP also using Eclipse Ganymede and Cygwin for the command line.
- Mercurial Repository Server: Fedora 6 with Apache
Developer #1 and #2 will be able to push/pull changes through the central repository even when there are firewalls and a proxy (the latter may require authentication) between them.
 Installing Mercurial
I use Cygwin on Windows XP, so installation is straightforward using the Cygwin package installer. Mercurial is written in Python, so Cygwin will determine the dependencies there if you don't already have it installed:
Checking our work ...
% hg --version Mercurial Distributed SCM (version 1.0.2) Copyright (C) 2005-2008 Matt Mackall <firstname.lastname@example.org> and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
For when we make changes to our repositories in the future, we indicate our user name by creating a file .hgrc under our Cygwin home (not Windows home) directory which contains your user details as follows:
[ui] username = Matthew Eichler <email@example.com>
If you are going to use #Mercurial from Eclipse, the Cygwin version of Mercurial will not work because Eclipse will try to send Windows style paths to the Mercurial command. Instead, install the self-contained Windows distribution from Lee Cantey. (I have both installed so that I can use Mercurial from both the Cygwin command line and from Eclipse).
On Macintosh, I also use a convenient package installer, Fink:
- In the Fink commnder, first do a Source Scanpackages then Source Utilities Index to get the most up-to-date listing.
- Then, search for the Mercurial package and install either from source or binaries. The Python dependencies will also be installed if you don't already have them.
Like we did on Windows ...
% hg --version Mercurial Distributed SCM (version 1.0.1) Copyright (C) 2005-2008 Matt Mackall <firstname.lastname@example.org> and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Also, just like Windows, we create an .hgrc in our home directory with our user details:
[ui] username = Matthew Eichler <email@example.com>
Once again, a package manager to the rescue, this time yum.
% su - % yum install mercurial
Now checking what we have:
% hg --version Mercurial Distributed SCM (version 0.9.3) Copyright (C) 2005-2008 Matt Mackall <firstname.lastname@example.org> and others This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
From yumex, selection of the package looks like:
 Proxy Setup
Since we're going to use HTTP to access remote repositories, you will have to follow these instructions if you use any of the clients behind a proxy server.
 Getting hgwebdir Going
Now there's a little work getting the HTTP/HTTPS interface to Mercurial repositories working, but I felt the added flexibility was worth it. The following assumes that the Fedora host is the server and already has Apache web server running on it, or that you know how to translate the setup for your particular distribution of Linux. Also, the user running Apache on my setup is apache and the group is also apache ... again, adjust this for your own particular setup.
 Create a Test Respository
First, determine on the server where the home for the collection of Mercurial repositories will be. I choose /export/home/hg but something like /var/hg is also popular:
% su - % mkdir /export/home/hg % chown apache:apache /export/home/hg
We're going to create a test repository there for proving that our setup is working:
% su - % cd /export/home/hg % mkdir hgtest; cd hgtest % hg init # we're going to add some changes, so it's not a completely empty repo % echo 'Hello World!' >> README.txt % hg add README.txt % hg commit -m 'this is the first change to my test repository' % hg log changeset: 5:11c41a5926be tag: tip parent: 3:e768ae005b9e user: email@example.com date: Mon Nov 24 11:41:19 2008 +0100 summary: this is the first change to my test repository # now, fix all the permissions on this repository % chown -R apache:apache .
There are some important things to note at this point. First of all, to initialize a new repository on the server, we had to have login access. Some might say this is a disadvantage to Mercurial. Second, apache will be the user accessing this repository through the web server and must own all the files. Finally, Mercurial created a subdirectory .hg which maintains metadata about the repository and we'll be adding to this later.
% su - % cd /export/home/hg % wget http://www.aminus.net/browser/modpython_gateway.py\?format=raw ./modpython_gateway.py
We are now going to expose our repository using CGI. There seems to be several ways to do this, but the one way that worked for me was the mod_python approach. Locate the hgwebdir.cgi and copy it into the Mercurial home (in my case, /export/home/hg), giving it the py extension instead of cgi.
Now we hack this Python script. Check that the imports match this:
from mercurial.hgweb.hgweb_mod import hgweb from mercurial.hgweb.hgwebdir_mod import hgwebdir from mercurial.hgweb.request import wsgiapplication
Uncomment this section so you'll get a full stack trace should something go wrong with the CGI interface:
import cgitb cgitb.enable()
Now, we're going to add two new Python functions to this script, at the end:
def make_web_app(): return hgwebdir("/export/home/hg/hgweb.config") def gateway(environ, start_response): app = wsgiapplication(make_web_app) return app(environ, start_response)
You may download my version of the full script from here.
Notice that the make_web_app() is configured with a file hgweb.config. We're now going to create this file in our Mercurial home /export/home/hg, and it simply contains a pointer to our collection of Mercurial repositories. As long as we create new repositories under /export/home/hg, they will automatically get picked up in the web interface:
[collections] /export/home/hg = /export/home/hg
Now, we're going to tweak some parameters for our test repository. Every time you add a new repository to your collection, you will have to do the same thing. Create a file hgrc in the .hg directory I mentioned earlier under /export/home/hg/hgtest:
[web] contact = Aventine Solutions description = testing Mercurial Web style = gitweb allow_push = * push_ssl = false
In this case, we are allowing changes to be pushed from anyone that is authenticated by Apache and we are saying that not only HTTPS is required for pushing, but it is allowed from HTTP as well.
 More Permissions
Now, fixing the permissions on all these files:
% su - % cd /export/home/hg % chown apache:apache hgweb.config hgwebdir.py modpython_gateway.py hgtest/.hg/hgrc % chmod 755 hgwebdir.py modpython_gateway.py
 Configuring Apache
The best approach to configure the Mercurial web interface for Apache is to give it it's own separate configuration file that will be included in the core Apache configuration when the server is restarted. In /etc/httpd/conf.d, create a file hg.conf with the following content:
<Location /hg> PythonPath "sys.path + [ '/export/home/hg' ]" PythonDebug On SetHandler mod_python PythonHandler modpython_gateway::handler PythonOption SCRIPT_NAME /hg PythonOption wsgi.application hgwebdir::gateway AuthType Basic AuthName "Aventine Solutions" AuthUserFile conf/httpd.passwd <LimitExcept GET> require user matthew </LimitExcept> </Location>
After the last PythonOption, we are configuring the type of authentication Apache will be using. Whatever authentication and access control is supported by Apache is available, but in this case we have a password file in /etc/httpd/confg/httpd.passwd where there exists a user matthew and only he may do actions besides GET. Because GET is not limited, the public may access the web interface in a read-only mode and download files from the repository's contents.
Now, restart Apache:
% su - % service httpd restart
 Checking Your hgwebdir Installation
Try accessing your new configuration with the URL http://myserver.org/hg and you should see the home page as:
If you click on our hgtest repository, you should see the details of this repository:
 Try Pushing and Pulling
This series of commands is from Cygwin Windows, but Mac users, you'll get the idea:
% cd /cygdrive/d/staging; mkdir hgtest; cd hgtest # creating an empty repository % hg init # pulling changes from the server and updating % hg pull http://myserver.org/hg/hgtest % hg update # making a change % echo 'I''m making a change from Windows' >> README.txt % hg commit -m 'I''m committing a change from Windows' >> README.txt # pushing changes back to the server % hg push http://aventinesolutions.mine.nu/hg/hgtest # username and password will be asked for here
The more logical way to start, is to clone the repository from the server, make your changes and push occasionally:
% cd /cygdrive/d/staging; rm -rfv hgtest; % hg clone http://aventinesolutions.mine.nu/hg/hgtest ./hgtest # I've got a full copy now, let's make changes % echo 'I''m making a change from Windows' >> README.txt % hg commit -m 'I''m committing a change from Windows' >> README.txt # pushing changes back to the server % hg push http://aventinesolutions.mine.nu/hg/hgtest # username and password will be asked for here
 Default Server Path
To automatically choose a server path from your workstation(s), add this to the paths section of the .hg/hgrc in the local repository:
[paths] default = http://firstname.lastname@example.org/hg/hgtest
 Dealing with a Proxy
To push/pull changes from behind a proxy, you'll need to add a section in the .hgrc file on the home directory. For Cygwin, that would be the Cygwin home and not the Windows home. The file contents will look like:
[ui] username = Matthew Eichler <email@example.com> [http_proxy] host = proxy.myorganization.net:8078 user = myproxyuser passwd = myproxypassword no = localhost
Note that if you have a percent [%] sign in your password, escape it with an extra one [%%].
 Installing the Plugin
From MacOSX or Windows, start Eclipse Ganymede and from the menu, do Help -> Software Updates -> Available Software and add the Vectrace http://www.vectrace.com/eclipse-update site. Check this site and click on Install to get the plugin:
 Windows Configuration
Similarly, on MacOSX when Fink was used to install Mercurial, you'll have to tell the plug-in where the hg command is to be found in Preferences -> Team -> Mercurial Eclipse. With a default install, Fink executables will be in the directory /sw/bin unless you changed this:
 Try it Out
Once the plugin has been successfully installed and configured, you can clone the repository from the new web server by choosing File -> Import, then selecting Clone repository using Mercurial from the first step of the wizard:
The next step, you'll enter the parameters for cloning, including the URL and the username/password for Apache:
Once the repository is cloned here, it will become visible in the project explorer and right clicking on it give you access to the Team menu and all the Mercurial functionality:
Most of the information getting the web server going came from here and you'll find there some tips on tweaking the server for your particular needs and level of security. However, I took the detour to this page in order to use the mod_python gateway method.