The completely fleshed out version of my my blog post setting up mercurial on textdrive with ssh.

Mercury, the Winged Messenger
Mercury, the Winged Messenger
© Toshiyuki IMAI

I've been thinking about setting up a simpler, change-set based source code repository for my little personal projects for a while now. For the past six months or so I've been using SVN on my TextDrive account but ... looking for something different.

I ran across Mercurial (hg) at least twice now recently, so that speaks to me "check it out". Getting it set up on my local box was straightforward, and of course the next step is getting it set up on your server. I host at TextDrive. And Bill de hÓra recently posted some instructions on how to do just that. Kind of.

The problem with Bill's instructions are that you're setting it up to run using Basic Auth but using http instead of https. Bill points out himself, that "This isn't secure". Using https with TextDrive is possible, but at times confusing. Luckily, there is a fairly straight-forward way to get to a secure solution.

The basic idea is to use the ssh instead of http for when accessing your hg repositories programmatically. Instructions on using ssh with hg are available in the hg(1) man page.

In a nutshell, follow Bill's instructions, with a few slight changes, and it just works, assuming you have ssh set up in the first place.

If this doesn't work, ping me; I perhaps forgot a step.

I also created a ~.hgrc file on my client box, with the following contents. The ssh setting causes ssh to use compression when transfering the data/files.

    username = your name <yourname@yourmail>
    ssh = ssh -C

The only thing I don't like about the resulting set up is having to update the hgweb.config file on the server whenever you create a new repository. Though I suppose it's nice that you can selectively make repositories easily publicly accessible or not this way. I don't think I'd rely on this trick to hide something.

Here are Bill's instructions, with changes made. Stuff I've deleted is in red and striked out, stuff I've added is in green, stuff I've changed is in blue.

Install mercurial in your home folder:

    #mkdir ~/local; mkdir ~/local/mercurial
    # cd ~local
    # wget 
    # tar xvzf mercurial-0.9.3.tar.gz 
    # cd  ~/local/mercurial-0.9.3
    # python install --home=~/local/mercurial
    # nano ~/.profile
    PYTHONPATH=${HOME}/local/mercurial/lib/python; export PYTHONPATH
    PATH=${HOME}/local/mercurial/bin:$PATH; export PATH
    #export PYTHONPATH=${HOME}/local/mercurial/lib/python
    #export PATH=${HOME}/local/mercurial/bin:$PATH

To get hg running with ssh, you'll also need to make sure your shell initialization for ssh sessions runs these commands as well. I just copied the PYTHONPATH and PATH settings to my .bashrc file as well. Not very DRY; ah well. I've not spent a whole lot of time setting up my shell account up there.

Create a base configuration file:

    # touch ~/.hgrc
    # nano ~/.hgrc
    username = your name <yourname@yourmail>

Check your setup:

    # hg debuginstall
    Checking encoding (US-ASCII)...
    Checking extensions...
    Checking templates...
    Checking patch...
    Checking merge helper...
    Checking commit editor...
    Checking username...
    No problems detected

Make a public repository area, and serve it:

# mkdir ~/web/public/hg
# mkdir ~/web/public/hg/repos
# ln -s ~/web/public/hg/ ~/hg

The symlink was added because using ssh means having to specify the complete path to your repository relative to your home directory. Which would mean that web/public would show up in your ssh urls. Ick. Even still, you'll see that the repos path segment shows up in the ssh urls, but not in the http ones. Deal.

~/web/public/hg/repos is where you will create your public mercurial repositories. Note that symlinking into here doesn't work, they have to be housed. To serve it out

    # cp  ~/local/mercurial-0.9.3/hgwebdir.cgi  ~/web/public/hg
    # chmod 755 ~/web/public/hg/hgwebdir.cgi
    # nano ~/web/public/hg/hgwebdir.cgi
    import sys
    sys.path.insert(0, "/users/home/$youraccountname/local/mercurial/lib/python")

Now tell the cgi where the repos are (for example suppose we had created a repo called 'weblog'):

    # nano ~/web/public/hg/hgweb.config 
    weblog = repos/weblog

Create a user account for pushing changes:

    # mkdir etc
    # htpasswd -c ~/etc/hgpasswd $mercurialname

Configure apache access to the repositories:

    # nano ~/web/public/hg/.htaccess 

    Options +ExecCGI
    RewriteEngine On
    RewriteBase /hg
    RewriteRule ^$ hgwebdir.cgi  [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.*) hgwebdir.cgi/$1  [QSA,L]
    AuthUserFile /users/home/$youraccountname/etc/hgpasswd
    AuthGroupFile /dev/null
    AuthName "My Repository"
    AuthType Basic
    <Limit POST PUT>
    Require valid-user

the above will allow anyone to browse

and see all the repositories under:

The Auth* directives mean commits are restricted to authenticated users, but anyone can browse (if you want to restrict browsing add GET to the methods in <Limit>. The rewrite rules are explained in the mercurial wiki.

For each repository under repos you'll need to add the following to its .hg/hgrc file:

    push_ssl = false
    allow_push = $mercurialname

where "$mercurialname " matches what you added to hgpasswd earlier. This isn't secure - mercurial by default does not allow push over http, with good reason, you have to disable via push_ssl. If you can get a https setup running in TextDrive, you should do so (and tell me what you did ;).

To pull a repository down via HTTP use "hg clone":

    # hg clone ssh://$yourdomain/hg/repos/weblog weblog

To commit (you'll be challenged for auth details):

    # cd weblog
    do work
    # hg ci -m "my changes"
    # hg push ssh://$yourdomain/hg/repos/weblog
    pushing to ssh://$yourdomain/hg/repos/weblog
    searching for changes
    http authorization required
    realm: My Repository
    user: $mercurialname
    adding changesets
    adding manifests
    adding file changes
    added 1 changesets with 1 changes to 1 files