Mercurial

Mercurial (official site) is a distributed version control system that is used track revisions of your files. You can find the unofficial manual here: (Distributed Revision Control with Mercurial).

Mercurial, git, and subversion are apparently the most popular version control systems used by DreamHost customers.

This page will document how to install the latest version of Mercurial in your home account and get the webserver up and running. This is a work in progress.

(Optional) Install an Updated Mercurial Into Your Home Directory
Type "hg -v" at a server shell prompt.

The DreamHost people have already installed Mercurial 1.6.x on most (all?) of their servers, so server should reply with something like "Mercurial Distributed SCM" -- so skip to Configuration.

If the server replies with something like "-bash: hg: command not found", follow the following instructions to install the latest version of Mercurial in your home account:


 * Note: This script should work with no problems. If you have any issues, please make a note and we can try and get them fixed.  Last updated: March 2014.


 * 1) !/bin/bash

if | -d ~/lib/python2.6 ; then echo echo "Script does not support installing when" echo "~/lib/python* already exists. Exiting." exit 1 fi
 * 1) This script should install the latest Mercurial onto a DreamHost
 * 2) account.  It will only run if ~/lib/python* does not already exist.

echo -n "[+] Determining latest mercurial... " HG_URL="`curl -s "http://mercurial.selenic.com/sources.js" | \   grep "source release" | \    sed "s/.*\\\"\\(http:\\/\\/[^\\\"]\\+\\)\\\".*/\1/g"`" HG_FILENAME="${HG_URL##*/}" if  -z ${HG_FILENAME} ; then    echo "Failed, please use failsafes in script. Exiting."   exit 1 fi

HG_BASE=${HG_FILENAME%.tar.gz} LATEST_HG=${HG_BASE#mercurial-} echo ${LATEST_HG}
 * 1) Use these "failsafes" if the above lines do not work
 * 2) LATEST_HG="2.9.1"
 * 3) HG_FILENAME="mercurial-${LATEST_HG}.tar.gz"
 * 4) HG_URL="http://mercurial.selenic.com/release/${HG_FILENAME}"

echo "[+] Preparing home directory... " export PYTHONPATH=~/lib/python2.6/site-packages export PATH=~/bin:${PATH} export HGRCPATH=~/.hgrc pushd ~ &>/dev/null                   || exit 1 mkdir -p ~/bin                        || exit 1 mkdir -p ~/lib/python                 || exit 1 mkdir -p ~/lib/python2.6/site-packages || exit 1
 * 1) Prepare your home directory and environment

cat >> ~/.bashrc << _EOF export PYTHONPATH=~/lib/python export PATH=~/bin:\${PATH} export HGRCPATH=~/.hgrc _EOF

if -f ${HOME}/.bash_profile ; then PROFILE_FILE="${HOME}/.bash_profile" elif -f ${HOME}/.bash_login ; then PROFILE_FILE="${HOME}/.bash_login" elif -f ${HOME}/.profile ; then PROFILE_FILE="${HOME}/.profile" else PROFILE_FILE="${HOME}/.bash_profile" fi cat >> "${PROFILE_FILE}" << _EOF export PYTHONPATH=~/lib/python export PATH=~/bin:\${PATH} export HGRCPATH=~/.hgrc _EOF

echo "[+] Installing required Python utils..." easy_install --prefix="~" docutils &>/dev/null if $? -ne 0 ; then echo "Failed, exiting." exit 1 fi
 * 1) Install Python docutils

echo "[+] Downloading mercurial... " wget -q ${HG_URL} if ! -f mercurial-${LATEST_HG}.tar.gz ; then echo "Failed to get mercurial sources, exiting" exit 1 fi
 * 1) Retrieve and extract the latest mercurial

echo "[+] Extracting mercurial..." tar zxf ./mercurial-${LATEST_HG}.tar.gz || exit 1
 * 1) Extract

pushd mercurial-${LATEST_HG} &>/dev/null || exit 1
 * 1) Go into extracted mercurial directory

echo "[+] Building   mercurial..." make local &>/dev/null if $? -ne 0 ; then echo "Failed to build, exiting" exit 1 fi
 * 1) Build local copy of mercurial

echo "[+] Installing mercurial..." make install-home &>/dev/null if $? -ne 0 ; then echo "Failed to install, exiting" exit 1 fi
 * 1) Install local copy of mercurial

popd &>/dev/null || exit 1
 * 1) Change back into home directory

mv ~/lib/python2.6/site-packages ~/lib/python/ || exit 1 rmdir lib/python2.6 || exit 1 echo "[+] Successfully installed!" popd &>/dev/null || exit 1 exit 0
 * 1) Relocate local PYTHONPATH

Configure Your DreamHost Account to Serve Mercurial Repositories

 * Note: These instructions are based on the instructions listed here
 * Make sure you change $MY_DOMAIN_DIR below!
 * 1) !/bin/bash

HG_DIR=~/hg PYTHON_LIB=~/lib/python MY_DOMAIN_DIR=~/somedomain.com
 * 1) This script should initialize a Mercurial repository in DreamHost account.

readlink --help 2>/dev/null | grep -q -- "--canonicalize " if $? -ne 0 ; then echo echo "Script requires \`readlink\` and " echo "\"--canonicalize-missing\" support. Exiting." exit 1 fi
 * 1) Ensure existence of readlink

. ~/.bashrc
 * 1) Re-source .bashrc in case the companion script was *just* run

pushd ~ &>/dev/null || exit 1 HGWEB_CGI=`echo mercurial-*/hgweb.cgi` if -f ${HGWEB_CGI} ; then HG_BASE=${HGWEB_CGI%/hgweb.cgi} LATEST_HG=${HG_BASE#mercurial-} else echo -n "[+] Retrieving latest mercurial... " HG_URL="`curl -s "http://mercurial.selenic.com/sources.js" | \       grep "source release" | \        sed "s/.*\\\"\\(http:\\/\\/[^\\\"]\\+\\)\\\".*/\1/g"`"    HG_FILENAME="${HG_URL##*/}"    if  -z ${HG_FILENAME} ; then        echo "Failed, please use failsafes in script. Exiting."       exit 1    fi
 * 1) Enter home directory

# Use these "failsafes" if the above lines do not work #LATEST_HG="2.9.1" #HG_FILENAME="mercurial-${LATEST_HG}.tar.gz" #HG_URL="http://mercurial.selenic.com/release/${HG_FILENAME}" HG_BASE=${HG_FILENAME%.tar.gz} LATEST_HG=${HG_BASE#mercurial-} echo ${LATEST_HG}

# Download wget -q ${HG_URL} if ! -f mercurial-${LATEST_HG}.tar.gz ; then echo "Failed to get mercurial sources, exiting" exit 1 fi

# Extract echo "[+] Extracting mercurial..." tar zxf ./mercurial-${LATEST_HG}.tar.gz || exit 1 fi

echo "[+] Preparing local repository..." HG_DIR="`readlink --canonicalize-missing \"/${HG_DIR}\"`" mkdir -p "${HG_DIR}/repos" || exit 1

HGWEB_CONF="${HG_DIR}/hgweb.conf" cat > "${HGWEB_CONF}" << _EOF [collections] repos/ = repos/ [web] style = paper _EOF
 * 1) style = gitweb

cp "${HG_BASE}/hgweb.cgi" "${HG_DIR}/" || exit 1 sed -i "s/^config = .*/config = \\\"${HGWEB_CONF//\//\/}\\\"/" \ "${HG_DIR}/hgweb.cgi" NEW_PY_SYS_STR="import sys; sys.path.insert(0, \\\"${PYTHON_LIB//\//\/}\\\")/" sed -i "s/^#import sys.*/${NEW_PY_SYS_STR}" "${HG_DIR}/hgweb.cgi"

cat > "${HG_DIR}/.htaccess" << _EOF Options +ExecCGI RewriteEngine On RewriteBase /hg RewriteRule ^$ hgweb.cgi [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (.*) hgweb.cgi/$1 [QSA,L] _EOF
 * 1) Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
 * 2) Used at http://ggap.sf.net/hg/
 * 1) write base depending on where the base url lives
 * 1) Send requests for files that exist to those files.
 * 1) Send requests for directories that exist to those directories.
 * 1) Send requests to hgweb.cgi, appending the rest of url.

chmod a+x "${HG_DIR}/hgweb.cgi" || exit 1 chmod go+x "${HG_DIR}"         || exit 1 pushd "${HG_DIR}" &>/dev/null  || exit 1 chmod go+r .htaccess           || exit 1 chmod go+rx hgweb.cgi          || exit 1 chmod go+r hgweb.conf          || exit 1 chmod go+x repos/              || exit 1 popd &>/dev/null               || exit 1
 * 1) Fix up permissions

pushd "${MY_DOMAIN_DIR}" &>/dev/null || exit 1 ln -s "${HG_DIR}" ./ &>/dev/null popd &>/dev/null || exit 1 popd &>/dev/null || exit 1
 * 1) Create symlink in the web directory

MY_DOMAIN="${MY_DOMAIN_DIR##*/}" echo -n "[+] Your mercurial repositories are now hosted at " echo "http://${MY_DOMAIN}/hg"

Create a New Repository
hg init ~/hg/repos/my_first_repo vi ~/hg/repos/my_first_repo/.hg/hgrc [web] contact =  description = My first Mercurial Repository push_ssl = false [ui] username = Firstname Lastname 
 * Login to your shell account
 * Create a repository called my_first_repo
 * Create a hgrc file for the repository
 * ...add the following lines to this file

charsets = utf-8
 * If you happen to need accents and/or tildes (áéíóú), also add to the [web] part:

cd ~/hg/repos/my_first_repo date >> my_first_file hg add hg commit -m "Added my_first_file to the repository"
 * Test your repository on DreamHost.  First, make a file in your repository.

On your home system, try to clone your repository. hg clone http:///hg/repos/my_first_repo local_repo_copy cat local_repo_copy/my_first_file
 * By default, no one is allowed to push your repository.  Read the next section, and review the Mercurial documentation on publishing repositories.
 * If you want to share the access via SSH and not HTTP, skip the next section, the following one should have all the answers you need. The only thing you could need (if you want of course) is to restrict access by adding the lines to the .htaccess on the beginning of the next section. Everything after that (inside that section) has to do with http authentication.

Securing your Repositories
'This hasn't been updated since a while, so I don't know if it's actually working as of 1.6.3 --Pablo Olmos de Aguilera Corradini 22:55, 30 September 2010 (UTC)

AuthUserFile /home/ /hg/hgweb.passwd AuthGroupFile /dev/null AuthName "My Mercurial Repository" AuthType Basic  # Remove GET to allow anonymous read-only access Require valid-user  htpasswd -c -m ~/hg/hgweb.passwd  htpasswd -m ~/hg/hgweb.passwd  ... vi ~/hg/repos/my_first_repo/.hg/hgrc allow_push =  touch ~/hg/failed_auth.html hg clone http:// : @/hg
 * Login to your shell account
 * Add this to the .htaccess file for the hg directory
 * Create hgweb.passwd
 * Set up user names in the repo hgrc
 * ...add the following line:
 * "Trick" Mercurial into asking for authentication:
 * You can avoid having to type in your user name and password each time by providing it when you clone the repository locally. If you did not clone the repository with a user name and password you can also update the .hg/hgrc of a local repository by updating the [paths] section.

Sharing access to the repositories through SSH
'''I installed Mercurial 2.0 from source, and am only sharing the repository with myself. If this situation fits you there's no need to mess around with hg-ssh. You can just use your ssh key and change the remotecmd on client to point to the absolute path of your hg installation. For example, I compiled mercurial-2.0 from source per the earlier instructions and set up my remotecmd on TortoiseHg to be "~/bin/hg". This works for push / pull now. Example command line would be: hg clone --verbose --debug ssh:// @ / --remotecmd "~/bin/hg" I spent a lot of time tracking this issue down, since my non-interactive ssh would not load my .bash_profile or .bashrc and kept referencing the system wide 0.9.1 version of Mercurial. By specifying the absolute path to my Mercurial install I was able to pull and push successfully.

Thanks to Ry4an and mpm1 at #mercurial on irc.freenode.net for pointing me in this direction. --Karlgrz 15:27, 7 November 2011 (PST)

'''I haven't tested this for 1.6.3, I'll updated as soon as I do it. The file still exists and (I think) it's the same so this should work if you change the directory name.''' --Pablo Olmos de Aguilera Corradini 23:06, 30 September 2010 (UTC)

There are at least three ways to do this according to the Mercurial Wiki:
 * Mercurial Server (Not the mercurial server, it's a piece of software that let's you configure your account to share the repository access with SSH)
 * hg-ssh
 * Hg-login

In this how-to I'm gonna use hg-ssh. It's the simplest way, but also the less sophisticated. Hg-login should work too, but I don't know why I couldn't make it work.

Be advised that this might be a not secure way and I have no doubt that should have many flaws, anyway I found it the most comfortable way since you don't have to send passwords in clear text through http. It could be a good idea to create a new user to just host the repositories so in the worst of the cases, someone could break in your repos and not your whole user directory.

Ok, let's get started:

cp ~/srcs/mercurial-1.5.4/contrib/hg-ssh ~/bin vim ~/.ssh/authorized_keys ssh-rsa [LONG STRING]== Collaborator1 #to: command="hg-ssh /home/username/hg/path/to/repo",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa [LONG STRING]== Collaborator1 command="hg-ssh /home/username/hg/path/to/repo",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa [LONG STRING]== Collaborator1 hg clone ssh://@domain.com/hg/repos/repo-name
 * Login to your shell account
 * Copy the hg-ssh script from the source to your bin directory
 * Get the public ssh key of the people you want to have access to the Shared SSH (you can check the SSH Dreamhost Wiki instructions about Passwordless Login to achieve that
 * Edit authorized_keys file to add hg-ssh so the collaborators can have only access through mercurial and no access to the shell
 * Before the previously added public keys add, but on the same line:
 * 1) So it will go from something like this:
 * Supposedly it should work with a line break between ssh-rsa and the key itself...:
 * ...but it didn't work for me
 * Now you just have to use the ssh:// protocol. Even if to access via web you don't have to write repos, you have to write it down or the command will fail

Well, that's it. Remember though that this method doesn't allow advanced permissions like give only read access or just pull, but not push changes into the repository. Probably Hg-login can.

How to Configure a Dedicated Subdomain with Cleaner URLS
This section (not the following) doesn't work in 1.6.3 since those lines doesn't exist in hgweb.cgi --Pablo Olmos de Aguilera Corradini 23:02, 30 September 2010 (UTC)

The  line doesn't exists, but you can the needed code after the   line --Miquelfire 14:14, 1 October 2010 (UTC)

This step can be done after the previously listed steps, and should be done after having verified all other aspects are working

If your domain directory is one you have made explicitly for serving mercurial at the root level (e.g. something like http://hg.domain.com/ some_repo), then you can do this by simply moving the .htaccess to your root public web directory (since it will rewrite to /hg/hgwebdir.cgi from root level, which is valid due to the ~/hg symlink): cd to your domain directory mv ~/hg/.htaccess ./ vi ~/hg/hgwebdir.cgi >Change this: #import os >to: import os # Force script name - needs webserver rewrite support os.environ["SCRIPT_NAME"] = ""
 * Now we make some modifications in hgwebdir.cgi:
 * Modify the following lines to override the script name (here I have given it a blank name so that nothing extra is prepended in links)
 * Now you should be able to navigate projects with a format like http://hg.domain.com/ some_repo instead of the existing format: http://hg.domain.com/hg/hgwebdir.cgi/ some_repo

Delete (only) the hgwebdir.cgi in URL
If you are using a subdomain like http://hg.domain.com/hg/hgweb.cgi/ some_repo and you just want to delete the annoying hgweb.cgi from the URL, but for some reason you want to keep the /hg : vim ~/hg/hgweb.config baseurl = /hg [collections] repos/ = repos/
 * Don't move the .htaccess from /hg to the root folder
 * Modify the hgweb.config:
 * Add below the [web] section the following:
 * So it will look something like this:

[web] style = gitweb baseurl = /hg
 * Now you should be able to see the projects in a format like http://hg.domain.com/hg/ some_repo