Mercurial on Yosemite

Mercurial is a great source control system… it is light and easy to use, and versatile enough for a professional environment. When I started my current company I worked extensively on Ubuntu with a local Mercurial server, and so when I switched to OS X (Lion at the time) I brought my same setup with me. Unfortunately, after upgrading to Yosemite, I found some tweaks were necessary. Here is how I got Mercurial setup with SSL on Yosemite for command line use.

1) Install Mercurial from MacPorts

$ sudo port install mercurial

2) Create a repository… I use /var/depot for the config and /var/depot/repos for the actual source.

$ cd /var
$ sudo mkdir depot
$ sudo mkdir depot/repos
$ sudo chown -R _www:_www depot/repos

3) To setup the Mercurial web server we first create some needed files to run the web interface, then we will need to modify apache. To start create hgweb.cgi. Note that I’ve modified the Python path on the first line… the default is /usr/bin/env, which is the wrong version of Python for HG.

# An example hgweb CGI script, edit as necessary
# See also
# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "/var/depot/hgweb.config"
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb import hgweb, wsgicgi
application = hgweb(config)

4) Create hgweb.config

/var/depot/repos = /var/depot/repos

5) Create the hgwebdir.cgi file, and again update the python path:

# An example CGI script to export multiple hgweb repos, edit as necessary
# enable importing on demand to reduce startup time
from mercurial import demandimport; demandimport.enable()
from mercurial.hgweb.hgwebdir_mod import hgwebdir
import mercurial.hgweb.wsgicgi as wsgicgi
application = hgwebdir('hgweb.config')

6) Create the users file to allow people to submit to your repo. I created the username mike. Repeat for all users you need:

$ htpasswd -m hgusers mike

7) To setup Apache and SSL you need to do a few things. I am assuming you already have Apache started. To make the needed changes, open /etc/apache2/httpd.conf. Make sure the following modules are included (some additional config is necessary if you want your webroot to run out of the user dirs… I put mine in /var/www/ so I skip those steps):

LoadModule authz_core_module libexec/apache2/
LoadModule authz_host_module libexec/apache2/
LoadModule cgi_module libexec/apache2/
LoadModule userdir_module libexec/apache2/

8) In the <directory> directive for your web root, make sure after “Options” you have “ExecCGI”. Mine looks like this:

Options FollowSymLinks Multiviews ExecCGI

9) Also in that same directive, add a handler for CGI:

AddHandler cgi-script .cgi

10) Finally, make sure near the bottom the following line is uncommented:

Include /private/etc/apache2/extra/httpd-ssl.conf

11) Save that file. One more step to setup Mercurial, then we can configure the SSL certificate and a few other things. Create and open this file: /etc/apache2/other/httpd-hg.conf

ScriptAlias /hg "/var/depot/hgweb.cgi"
<Location /hg>
Options ExecCGI
Order allow,deny
Allow from all
AuthType Basic
AuthName "Your Authentication Prompt Message Goes Here"
AuthUserFile /var/depot/hgusers
Require valid-user

12) Now to configure the SSL certificate return to the /etc/apache2/ directory and do the following. This will create a private key, a signing request, and finally a usable (non password locked) public key:

$ openssl genrsa -des3 -out server.key 1024
$ openssl req -new -key server.key -out server.csr
$ cp server.key server.key.orig
$ openssl rsa -in server.key.orig -out server.key
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

13) Now setup Apache to use the certificate you just setup. Edit /etc/apache2/extra/httpd-ssl.conf, and make sure the following are uncommented and pointing to the files we just setup:

SSLEngine on
SSLProtocol all -SSLv2
SSLCertificateFile '/private/etc/apache2/server.crt'
SSLCertificateKeyFile '/private/etc/apache2/server.key'

14) Ok that is the bulk of the server setup. Now we can configure a repository and try setup our user (mike). Let’s first create a quick repository to use.

$ cd /var/depot/repos
$ sudo mkdir example; cd example
$ sudo hg init

15) This is a quirk that seems to be necessary for Yosemite only. Go into the freshly created .hg directory inside this repo, and create an hgrc file.

$ cd /var/depot/repos/example/.hg
$ sudo nano hgrc

Enter the following:

allow_push = *

Now make sure this whole directory is owned by _www;
$ cd ../../
$ sudo chown -R _www:_www example

16) Nearly there. Restart apache, and make sure a few things are working.

$ apachectl restart

17) If you have a problem, try apachectl configtest. Now visit https://localhost/hg. It will alert you of a certificate error, again because the cert is self signed, but you can select to trust it. Then it should ask you to login using the name and password we created in step 6. You should be able to get in and see the example repository.

18) The last piece of configuration we need is for the user that will be cloning/pulling/pushing from the command line. Go to your home directory and create an .hgrc file with the following content:

default.prefix = https://localhost/hg/
default.username = mike
default.password = <>
default.schemes = https
username = mike <>
cacerts = /etc/apache2/server.crt
allow_push = *
push_ssl = true
description = localhost/hg

19) This won’t work quite yet because our SSL cert is self signed, which will fail most security checks. We can fix this — go to your webroot (/var/www in my case) and follow these steps.

$ hg clone https://localhost/hg/example
$ cd example
$ touch test
$ hg addrem; hg ci -m testing; hg push

This is going to fail with a message something like this:

(configure hostfingerprint XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX or use --insecure to connect insecurely)

20) Copy all the numbers for the fingerprint above, and paste that into your ~/.hgrc file in the [hostfingerprints] section we left blank above:


21) You are done! Mercurial works, the web utility works, and SSL works.