Skip to content

Archive for January, 2011

Getting Mercurial Running on DreamHost Part II: Cloning an Existing Local Repo to the Server and Making it the Parent

Last time, we talked about getting Mercurial running on Dreamhost, which should be enough to allow you to start creating repos on the server (using hg init while ssh’d in) and cloning them locally. But what if you already have repos with a rich history on your local machine and want to clone them to the server? I promise it’s easy, but I’d like to make a quick digression because something’s been bugging me.

I’ve always wondered why Mercurial’s executable was called hg. I thought that maybe it was a holdover from an ancestor project- the way Firefox’s executable was called mozilla for a while. It turns out that I was selling Mercurial’s developers short and that they do, in fact, have their shit together:

Chemistry Nerds!

It was named after the elemental symbol for mercury, Hg. The Mercurial Logo even looks like a glop of Mercury.

Liquid at Room Temperature

The symbol Hg is short for hydrargyrum which comes from the Latinized Greek prefix hyrda- meaning watery or runny and the word argyros meaning silver. So it means runny silver. I can imagine the Greeks making prank phone calls: “Is your silver runny? Then you better go catch it!” and getting people all mad and Latinized over it. Anyway, back to

3. Clone my existing local repositories to the server and then make that server the parent

Should be easy, right? It is. Ned Batchelder’s answer to this Stack Overflow question nails it. First, ssh into your Dreamhost account, then create a new repository on the server to house the repo that’s already on your local machine. Make sure that it’s in the repo parent directory (specified in hgweb.config) so that hgweb.cgi will pick it up.

cd ~/hg/repos

mkdir HotPotato

cd HotPotato

hg init

Now logout of your ssh session and use Terminal to navigate to the local directory of the repository you want to clone to the server. Use the hg push command to get the local repo up to your newly created server repo.

hg push ssh://TheBestHuman@pr.ogra.ms/hg/repos/HotPotato

Make sure you put the ssh:// prefix on the URI or you’ll get a repository not found error message. Now you should be able to go to hgweb.cgi and see your new (old) repo.

Your "New" Repo!

Your repo is available on the server, but we need to make it so that when you hg push from your local repo, it remembers what server to push to. This will make it so you don’t have to specify the server repo’s URI every time you want to push your changes up.

vi .hg/hgrc

with vi open, add the following lines to the hgrc file.

[paths]
default = ssh://TheBestHuman@pr.ogra.ms/hg/repos/HotPotato

Any changes you commit locally from now on will get pushed to the server if you run hg push!

But wait, if you ssh back in to the server and ls in the new repo’s directory, you won’t see any files!

Dub Tee Eff

What was all that console output if it wasn’t uploading the repo to the server? And how come when you navigate to hgweb.cgi, there’s a bunch of history about files that don’t seem to exist? Well, it has to do with some Mercurial fundamentals. The repo’s root directory (~/hg/repos/HotPotato) contains the working copy of the repo. Mercurial, however, only cares about committed code. Since we hg pushed the local repo to the server, Mercurial is aware of the changes, but has not applied those changes to the working copy on the server. The changes are all sitting in the .hg subfolder (~/hg/repos/HotPotato/.hg). If you never want to work on code and commit changes from the server, this is fine. It doesn’t really matter what the working copy on the server contains. But if you ever want to be able to edit code directly from an ssh session on the server, you’ll have to bring the working copy up to date.

hg update

You’ll also have to do this from any repo that you clone from the server copy.

And that’s it! Don’t worry, the workflow seems like a lot to remember but it will start to feel really natural after a while.

Getting Mercurial Running on DreamHost

A while back, Joel Spolsky wrote a fantastic tutorial on distributed version control systems. It’s a really clear and honest overview of Mercurial from the perspective of a recently converted skeptic. DVCS has many advantages over the old client-server model of source control, but I think the one killer advantage is that it works with or without a central server. This means that whenever I’m working on a personal project, I can just type “hg init” in the directory and BOOM, I’m tracking my changes. Later on, if I want to go through the whole process of remembering passwords to my web host, installing Mercurial, and setting up my local copy to push to a central server, I can. The real magic of DVCS though is that central server really means anything here, I could start pushing code to my analog watch if I could get Mercurial running on it.

Terrorism is also distributed

Joel’s tutorial had me intrigued, Mercurious if you will. So when I finally got some time to work on personal projects, I started using it. And I’m hooked. I haven’t had much need for the D in DVCS yet though because I’m the only one committing any code. I’ve been using Mercurial as local revision control, but I’ve been using it for EVERYTHING; my resume redesign, Arduino code, even Movable Type theme modifications. I can’t get over how easy and quick it is to turn any normal project into a legitimate source controlled juggernaut. And there’s no guilt about polluting the codebase! After a while, I started thinking that maybe I should version control my OkCupid profile, or my Facebook friends. I know I’m addicted because sometimes when I’m at the bar, I think “I wish I could hg commit right now and revert if it turns out that I drank too much.”

I started to get nervous though. Any important data that’s not in the cloud makes me nervous. I had some time on my hands the other day, so I decided to try to install Mercurial on my DreamHost account and keep a main repository there. It would also give me a chance to commit code from different machines, or different partitions on a single machine without breaking the flow of work. I was thirsting for that all-powerful D.

Usually when I want to do something new with DreamHost, I pray that they have a one-click install in their web panel and if they don’t I give up. I’ve been writing software for most of my life and am embarrassed to say, installing things in Unix baffles me. I wasn’t so lucky on this one, there is no one-click install, but they did have the next best thing. One of the great things about DreamHost is that they have a large user base and their support wiki is packed with enough documentation to hang yourself. Sure enough, there’s a page on installing Mercurial. That’s not the end of the story though, there are really three things I want to do here:

  1. Install Mercurial on my DreamHost account
  2. Configure Mercurial to allow me to push and pull code from the server
  3. Clone my existing local repositories to the server and then make that server the parent

1. Install Mercurial on my DreamHost account

Turtles are shell users too

In order to do this, we’re going to need a shell account and we’re going to need to log in to it. If you don’t already have a shell account, go to the DreamHost web panel and click Users > Manage Users. Now click Add User and set the Type of User Account to Shell.

Next, we need to SSH into the account. Our trusty DreamHost support wiki also has an entry for configuring SSH for passwordless login, which you can do to make it dead simple to login to your DreamHost shell:

ssh TheBestHuman@pr.ogra.ms

Now that we’re logged in, we can actually install Mercurial from the source code. This part is pretty much just following the instructions from this page of the support wiki. I’m going to repeat the steps here with some explanations so we’ll have everything in one place.

First, make a directory for the Mercurial source and download it. I wanted to make things easier for myself so I went with the same version that’s in the tutorial.

mkdir -p ~/srcs
cd ~/srcs
wget http://mercurial.selenic.com/release/mercurial-1.6.3.tar.gz

Mercurial’s latest stable release is 1.7.3, so we’re not that far off. Or are we? Who cares, I’m new to Mercurial, I won’t notice the difference. Next, unzip, make and make install it.

tar xvzf mercurial-1.6.3.tar.gz
cd mercurial-1.6.3
make all
make install-home

Now do some bash configuration stuff, changing the default path for Python and the Mercurial configuration file or something.

vi ~/.bash_profile

* add these lines at the bottom:
export PYTHONPATH=~/lib/python
export PATH=~/bin:$PATH
export HGRCPATH=TheBestHuman/.hgrc

Make sure to replace TheBestHuman with your DreamHost username because, well, there can be only one. After all this, you should be able to do

hg --version

and get 1.6.3 or whatever version you decided to go rogue and install.

So now we have Mercurial installed on the server. Badass. It’s only accessible if we’re shelled into our account though; we want to be able to push and pull code from Malaysia if we happen to be there and the McDonald’s has free wifi.

2. Configure Mercurial to allow us to push and pull code from the server

The heart of Mercurial’s code publishing capabilities is a Python script called HgWeb.cgi. It’s a nice little piece of code that not only serves the repos up to remote users, but also provides you with a slick read-only web interface to your revisions (basically a friendly web version of the hg log command). Sounds awesome, right? Let’s set it up!

First, make a subdirectory for your repos.

mkdir -p ~/hg/repos

Now create the configuration file for the publishing script.

vi ~/hg/hgweb.config

* ...and add the following lines:
[collections]
repos/ = repos/
[web]
style = gitweb

The default script is packaged with the Mercurial source, so copy it from there to your hg directory and add execute privileges to the copied file.

cp ~/srcs/mercurial-1.6.3/hgweb.cgi ~/hg
chmod +x ~/hg/hgweb.cgi

At this point, the wiki tells you to change the python version in hgweb.cgi, but I followed the directions and eventually (after a painful 20 minutes) had to switch this back to its original value. I’d recommend leaving the script as-is at first. If you’re getting a 500 error trying to access the hgweb.cgi page later on, you can go back and force the script to use python 2.4.

Next, change the following lines in hgweb.cgi

config = "/path/to/repo/or/config"
#import sys; sys.path.insert(0, "/path/to/python/lib")

to:

config = "/home/TheBestHuman/hg/hgweb.config"
import sys; sys.path.insert(0, "/home/TheBestHuman/lib/python")

Remember to replace TheBestHuman with your shell user name. Next, do some Apache crap:

vi ~/hg/.htaccess

* ...add the following lines (Comments optional) and then save the file 

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

After that, all that’s left to do is map the hg directory to somewhere on your domain. You can do this by creating a symbolic link to it from a sub directory of your domain.

cd ~/pr.ogra.ms
ln -s ~/hg

You might need to change some permissions.

 chmod 755 ~
 find ~/pr.ogra.ms -type d -print0 | xargs -0r chmod 755
 find ~/pr.ogra.ms -type f -print0 | xargs -0r chmod 644

At this point, you should be able to see an empty Mercurial page if you navigate to http://yourdomain/hg. Don’t worry, when you get some projects in there, it’ll look like this:

A preview of what's to come

So right now, we have an empty Mercurial installation with no repositories that’s absolutely useless. Mission Accomplished!

Not really, the next post will show you how to move an existing repo to your newly pimped Mercurial server and making it the root repo.

Continue on to Getting Mercurial Running on DreamHost Part II: Cloning an Existing Local Repo to the Server and Making it the Parent