Mercurial - DVCS (Decentralized Version Control System) - intro and basic usage guide¶
A version control system (VCS) is a piece of software that tracks changes made to specified files. It allows you to save sets of changes made to these files and revert to previous versions whenever needed, much like saving a game. A DVCS is decentralized and means that you do not need to rely on a central server to save revisions, unlike a CVCS (Centralized VCS). Mercurial is a free Python based DVCS available for Windows, Linux and OSX platforms.
Repository: A directory containing all project files and information on version history. Repo for short.
Working directory: The root directory of your repository.
Commit: Save the current state of the working directory as a revision.
Version/Revision/Change-set: A saved state of the working directory. The words version, revision and change-set can be used interchangeably.
Getting Started with Mercurial using Windows¶
TortoiseHg is a shell extension and set of tools for Mercurial. We will use TortoiseHg to make Mercurial a little easier to use. The first step is to download and install TortoiseHg with Mercurial. Download here .
Once you have installed TortoiseHg with Mercurial, we can begin creating our first repository. Create a new directory to hold our repository, C:\repo. Now open a command prompt in this directory (Win+R -> cmd -> enter -> cd c:\repo -> enter). Run the command "hg init". This initialises a repository by creating a ".hg" folder. All the information for your repository including settings and version history is stored in here. This is opposed to a database as some other VCS' use. It means that you can move your whole repository folder wherever you want and there's no need to reconfigure anything.
Create a new text file in your directory called "test.txt". Now run "hg status". This command checks the status of all the files contained within your working directory. It should show "? test.txt". The question mark shows that Mercurial doesn't know what to do with the file at the moment.
To make Mercurial track the file and save version history for it, we need to run "hg add <filename>".
Now when you run "hg status", you will see "A test.txt". This shows that the file is new to the repository. Now we need to "commit" the very first version of our repository using "hg commit -m "comment" -u "your username"". Change history will be stored so that things can easily be reverted at a later date. -m designates a comment to describe the commit. "your username" is used to identify which user committed that revision and is used in multi-user environments. It is not important if you are working alone on one machine but must be included in the command or else Mercurial will return an error.
hg add test.txt
The commit command will not give a response unless there is an error, however if you run "hg log", you can see that a new change-set has been created.
hg commit -m "First commit" -u "your username"
Now open the text file, type some text and save it. Now commit a new revision using the "hg commit" command as you did before. View the log using "hg log". You will now see an additional changeset.
hg commit -m "Added text" -u "your username".
Now to revert to a previous revision, use the command "hg update <revision number>". This will revert your working directory to the state that it was in when you committed the corresponding revision. So if you run
hg update 0
the test.txt file will be relaced with the empty one that we had when we commited revision 0. No progress will be lost between "updates" as long as you commit before updating.
When committing files to the repo, only differences between files are changed. This means if you have a very large source file and you only change a few lines, only those few lines of code are stored in the change-set. This greatly reduces the overhead of saving many change-sets for plain-text files. Unfortunately, it is not possible for Mercurial to detect such changes in binary files such as .pdf or .exe. These files are simply copied during a commit. You can view the difference between revisions using the "hg diff --rev <revision number>" command. This will show you the difference between the current working directory and the specified revision. You will notice in the screenshot below, the line "-Hi". This shows that the line "Hi" does not exist in the current working directory, however it does in the specified revision.
hg diff --rev 1
Now let's revert to our latest version, add a new document "code.c", tell Mercurial to track it and commit a revision.
hg update 1
hg add code.c
hg commit -m "Added som code" -u "your username"
For the commit command, Mercurial will give an error as test.txt does not exist after running the update command. Just type "c" and press enter and Mercurial will create the missing file.
Now we have 3 revisions saved. If we revert to revision 1, code.c will be removed from the working directory. Don't worry, we can easily get it back by updating to revision 2.
hg update 1
If there are certain files we wish to exclude from our repository, we can choose not to add them with the "hg add" command. However these files will still show up in hg status.
We can make Mercurial ignore files in this situation using a .hgignore file. Create this in your working directory and add it to your repository. It's contents should be as follows to ignore all .tmp files. You can use various wildcards or specific filenames in this file.
Notice below how random.tmp no longer shows up in hg status and will not be tracked.
The hg clone command allows us to clone a repository easily. For the purpose of this tutorial, we will clone a repository from a remote server in order to demonstrate push/pull commands. Remember, Mercurial does not use a client-server structure, it is decentralized. Thus our "server" actually acts just like a regular user. We use it for convenience so that users don't have to be online at the same time to synchronize work.
First, let's delete the contents of C:\repo. This will also destroy our Mercurial repository. Next we'll clone the ARM-camp repository here at Xdevs.
hg clone http://dev.xdevs.com/hg/armcamp c:\repo
As you can see, the clone command fetches all change-sets and files from the given path.
Now we have a repository set up which will allow us to test push (and pull) commands. Let's add a file to our repository, make a commitment and push to the Xdevs server.
hg commit -u "Owl" -m "demo push"
hg push http://dev.xdevs.com/hg/armcamp
Now if you look here:"http://dev.xdevs.com/projects/armcamp/repository" you should see that your file is now in the remote repository.
The "hg pull" command fetches new change-sets and files from a remote user. Use this command to synchronize your local repository before beginning work. After using the pull command, we must update our working directory using hg update. Using hg update with no arguments will update to the newest change-set.
We can use hg diff as before to find changed files. Here you can see I added the line "Owl says hi!" followed by an empty line.
Making things more convenient¶
Inside the .hg folder of every repository, there is a "hgrc" file. This file contains settings specific to the repository. We can add some things to this to speed things up. If we add;
username = <your username>
then we no longer need to specify the -u argument when using hg commit. We simply use instead:
hg commit -m "message"
If we add:
cipushafter = default-push
TortoiseHg will automatically push after every commitment you make. We can also enable some extensions:
The "color" extension adds colour to certain Mercurial commands in the command line to allow for easier reading. "graphlog" adds an extra command: "hg gl", this allows us to display a tree of change-sets within the command line. "highlight" adds syntax highlighting to the "hg diff" command.
An example hgrc file for the ARM-camp repository:
default = http://dev.xdevs.com/hg/armcamp
cipushafter = default-push
username = Tom Jones <email@example.com>
hg init: Create a new repository in the current directory.
hg add <filename>: Add the specified file to the repository and track it's changes. Running only "hg add" will add all files in the working directory that are not already tracked.
hg status: List the current status of all files in the repository. Can be shortened to "hg st"
hg commit -m "<comment>" -u "<username>": Save the current state of the working directory as a revision. "hg ci -m "<comment>" -u "<username>" for short.
hg log: Display a log of revisions for the repository.
hg update <rev number>: Revert the working directory to the state of the revision specified. Running just "hg update" will revert to the latest revision. The command can be shortened to "hg up <rev number>" or "hg up" respectively.
hg diff --rev <rev number>: Display all differences between files in the working directory and the revision specified. "hg diff --rev <rev number> <filename>" can be used to view the difference of only the file specified.
hg pull <address>: Retrieve new change-sets from another PC. Where <address> can be given as an IP address or HTTP web address.
hg push <address>: Send new change-sets from your PC to another. Where <address> can be given as an IP address or HTTP web address.
hg merge <revision>: Merge the specified change-set with the current working directory.
hg clone <clone from path> <clone to path>: Clone the repository found at <clone from path> to <clone to path>. <clone from path> can be given by a local or remote path (network/HTTP).