Learning Mercurial

Who has used version control? CVS? Subversion?

Has anyone used distributed version control? Git? Mercurial? Bazaar? Darcs?

Why version control?

So you're writing a Super Awesome web app. You write your code on your laptop, test it, and when it works, you copy it up to the live server. Everybody is happy.

Then...

Then one day you copy up a change, and the live site breaks. Something on the server is different (different version of Python? Key dependency not installed? File permissions problem?) and code that works locally doesn't work there. You frantically try to debug it quick, no luck. This is going to take some time to solve. Meanwhile, your site is down and all your potential visitors are getting big nasty errors. You really, really wish you could just quickly rollback to the last version that worked. But oops, you just copied over it. Sorry.

or...

Or, your site gets popular and you get a friend to help you with coding. They've got a copy of the site, and you've got a copy of the site. You make some changes, they make some changes. You copy your version to the server, they copy their version to the server. And - they just overwrote your changes. Oops.

FAIL

u r doin it wrong

That's why.

Version control lets you track changes to your project, instantly restore any past version of your project, and merge changes with other people working on the project simultaneously.

Version control is one of the two most important software development tools, after the IDE or code editor. There is no reason to ever work on a software project without using version control.

It's also really good for non-programming tasks, like tracking versions of a static HTML web site, or server configuration files, or any text files. I even use version control on my todo lists :-)

Let's dive in.

Mercurial is already installed on the lab Macs. To create a Mercurial repository (a directory of version-tracked files), just type hg init myrepo. (Hg is the symbol for the element mercury). This will create the directory myrepo, which will be empty except for a hidden directory .hg (the initial dot makes a file or directory hidden in Unix, but you can see it with ls -a myrepo/.) This .hg directory is where Mercurial will store all the historical version data about your files. Otherwise, the myrepo directory is empty and ready for you to add some files to it.

Add a file.

You've probably had enough Python for one night, so we'll start by just tracking some text files. cd myrepo/, then emacs file1.txt and put a couple lines of text in it, whatever you want. Save the file and C-z to put emacs in the background.

hg status will summarize the current status of your repository. At the moment, it will tell you:

? file1.txt

which means it doesn't know what that file is. To tell it to start tracking that file, do hg add file1.txt. Then hg status will tell you:

A file1.txt

which means file1.txt is ready to be added.

Afraid of commitment?

At this point, Mercurial still hasn't committed any changes to your project's version history. It's still just telling you what it's ready to commit.

Before we actually commit, let's tell Mercurial what editor you prefer for entering your commit log messages. The default on these Macs is set to vi, which is fine for Paul Ortman, but the rest of you might want to run export EDITOR=emacs.

Now hg commit to commit your current changes (the addition of file1.txt) as a new version (the first version!) of your repo. Mercurial will bring up Emacs for you to enter a log message detailing what you did in this changeset. Enter something like "added file1.txt", save, and exit.

What happened?

Now hg status won't show you anything! This means that your files are exactly the same as the most recent committed version: because you just committed! If hg status doesn't list anything, that means you have no outstanding changes waiting to be committed.

Check the logs

Run hg log. It will show you the commit you just made, with the commit message:

changeset:   0:15747f0e0cb3
tag:         tip
user:        carljm@un004-imac25.goshen.edu
date:        Thu Sep 10 19:07:44 2009 -0400
summary:     added initial file

Change a file

Now let's bring up Emacs again (fg) and make some changes to file1.txt. Save your changes and C-z to get back to the shell. Run hg status - it will tell you M file1.txt, meaning that file1.txt has been modified.

Ignoring some files

hg status also probably lists ? file1.txt~; it doesn't know what to do with the backup file that Emacs automatically creates. Let's tell Mercurial to ignore all of those backup files. fg back into Emacs, C-x f and open a new file .hgignore. Put these lines into that file:

syntax: glob
*~

Commit once more

Now hg status won't show the backup file; it will list ? .hgignore, so run hg add .hgignore to add your .hgignore file to the project. Then run hg commit -m 'added .hgignore file' .hgignore.

This time it won't bring up Emacs, because you supplied the -m flag with a commit message, right on the command line. This is what you'll probably do most of the time; it's quicker than going into Emacs for every commit message.

Also, you gave a file name, .hgignore, on the command line. This tells Mercurial to only commit the changes to that file. If you run hg status again, you'll see that file1.txt is still listed as modified; the changes to it were not committed.

Viva la difference

Run hg diff, and Mercurial will show you the full changes that are ready to be committed:

diff -r b5a4ca908b84 file1.txt
--- a/file1.txt Thu Sep 10 19:33:09 2009 -0400
+++ b/file1.txt Thu Sep 10 19:33:18 2009 -0400
@@ -1,3 +1,3 @@
 Here is a text file.
-With some text in it.
+With some changed text in it.

Looks ok, so hg commit -m 'frobjammered the contrapulator'. hg log will now show three commits.

Reading

Chapters 1 and 2 in the Definitive Guide to Mercurial.

Homework

Nothing complicated: just put your Python homework for this week inside a Mercurial repository directory. I'd like to see several commits in your log at sensible versions (i.e. each time you reach a point where something is working) showing your progress as you moved through the assignments.