Monday, January 14, 2013

Managing Web Projects with Mercurial

A walk through of using mercurial for web application deployments

Many times I work on websites or web software projects where content management is not an option. Even when it is an option, I find myself wanting to maintain multiple copies of the site - one (or more) for testing plus a production site. Trying to maintain and keep track of these copies using FTP has many times left me confused, frustrated and often ends with me throwing my mouse across the room and then re-writing lots of code.
Enter Mercurial, an open source, cross-platform source control system which has made this task much easier for me. The good thing about using Mercurial to maintain a website is that once you get set up, IT WORKS! The downside is that, at least for me, it can be very confusing trying to figure out how to set it up. It took me four tries, lots of "Googling", posting to mailing lists, and a bit of trial and error before I was able to get my website updating the way that I wanted it to.
Since I don't want anyone to have to go through the same trouble that I went through I am going to try and shed a little light on how, from my understanding, Mercurial operates and how you can take what I did and adapt it to your own web project. This will just be a very basic setup to get you started, and I'm not going to explain anything that's not absolutely necessary.
For those of you who have worked with version control software such as CVS or Subversion, like I have, the first thing you need to forget is the traditional server-client relationship between a remote repository and the various local copies that are committing changes to the server. Mercurial is a single piece of software that can act as both a client or a server or both depending on how you use it. In other words, you install the same component on your local machine as you would on your web server. This allows you to theoretically set up a chain of "stages" on which to test your project. Your local machine could push changes to an alpha site, which could then push to a beta site, which would push to production and each process would be exactly the same other than the host address and file path (if you wanted to you could even push in reverse!).
Ok let's get started. Firstly here is a list of requirements/assumptions of things you need or should have set up in order to follow this tutorial.
  • Linux-based Web server to which you have SSH access and has Mercurial (hg) installed. To see how to install mercurial, check out the project site:
  • Local machine with any linux flavor. While Mercurial is available in all platforms and the process is fairly similar, I will be showing you using Linux, specifically Ubuntu.
  • Mercurial installed on your local machine. For Ubuntu users can install it using the package manager:
  • # sudo apt-get install mercurial
    Alternatively any Linux user who has the python-dev and python-setuptools installed can install mercurial using:
    # sudo easy_install -U mercurial
    Visit the mercurial project site for source downloads and other installation alternatives.
The first thing we need to do is to set up a directory on our web server for our new project. Open up a terminal window and log into your web server via Secure Shell. Enter your password when prompted.
# ssh
Change directories into the web root of your server.
# cd ./public_html
Create a directory for your web project and move into that directory. I will name it my_project.
# mkdir my_project
# cd my_project
Ok, now its time to create the repository in your new project directory.
# hg init
The hg command refers to Mercurial's executable file, named "hg" after the chemical symbol for mercury. Calling hg init creates a hidden directory called .hg in your my_project directory. This is where Mercurial will store all of the changes to your repository. To verify that this worked, just type ls -a to display all files (including hidden files). The output should look like this:
# ls -a
.  ..  .hg
Now logout of your web server by issuing an exit or logout command. You should now be back in your local terminal. Create a directory on your machine for your local project.
# mkdir ~/workspace/my_project
Create a local repository in your my_project directory the same way we did on the server.
# cd my_project
# hg init
# ls -a
.  ..  .hg
While I work on my web project, there will be certain files that are created in my project directory that I do not want to be pushed to the server. This includes temporary files and configuration files that are specific to my local environment and could potentially cause problems if they are pushed to the production site. Luckily, Mercurial allows us to create a file that allows us to define files that we would like to have ignored by the repository. This file is called .hgignore and goes in the main project directory, not the .hg directory. My .hgignore file looks like this:
# less ~/workspace/my_project/.hgignore
syntax: glob
It is now time to create a basic website. I made four files and a subdirectory - index.html, bio.html, contact.html, and css/main.css.
Once I have a site to manage, I need to run the add command which will search the main directory and all subdirectories and add all files not specified in my .hgignore file. Running hg add will flag the files that will be tracked by the repository and output a list of all included files. Mine looks like this:
# hg add
adding .hgignore
adding bio.html
adding contact.html
adding css/main.css
adding index.html
Now the files are flagged to be tracked. However, the repository will not contain the most current version of the tracked files until they are committed. This is done using the hg commit command. The commit command also allows you to specify filenames. The -m flag specifies the commit message.
# hg commit -m "Initial Commit" (to leave comment blank, hg commit -m "")
Ok, the files are now current in the local repository. Time to push the changes to the server. The hg push command takes the ssh server address as its argument. You will be prompted for your password and hg will output something similar to this:
# hg push ssh://username@myserver.tld/public_html/my_project
username@myserver.tld's password:
pushing to ssh://username@myserver.tld/public_html/my_project
searching for changes
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 5 changes to 5 files
You may optionally want to view a record of changes made in your repository. To do this enter hg log. This will display the user, date, and commit message of each repository event.
The hg update command looks for recent changes in the repository and updates the files in the main directory. If you open your project space in a browser you'll notice that nothing has been published yet. Running hg update will get the changes from the remote repository and copy them to the main project directory.
# ssh username@myserver.tld
# cd public_html/my_project
# hg update
5 files updated, 0 files merged, 0 files removed, 0 files unresolved
Now if you go back and refresh your browser, your project will be live.


  1. This comment has been removed by the author.