Using mercurial for local FreeBSD development

For a long time The FreeBSD project used CVS as its version control system almost exclusively. Recently a number of more sophisticated version control systems were developed, and it's becoming quite common that the developer uses something other than CVS for local development work. It was shown over years that using CVS for big long-term work on FreeBSD source code, especially when it should be constantly synced with the main FreeBSD repo, can become a major pain. That's why, in part, the FreeBSD projects provides access to a Perforce repo to work on FreeBSD related projects.

This tiny tutorial shows how one can configure and use Mercurial to do his local development work in FreeBSD repo, while keeping in sync with the main development tree.

Checking out the source code

One of the most handy ways to obtain the FreeBSD source code is to use CVSup. This program uses sophisticated algorithms to efficiently transfer a large number of file over network. These also were specifically optimizes to use with CVS, so it tries to transfer deltas, not entire files, whenever possible.

You can find more information about CVSup in the FreeBSD Handbook.

For example, I use the following supfile to keep in sync with the FreeBSD repo.

*default base=/var/db/mercurial-cvsup/
*default prefix=/usr
*default release=cvs tag=.
*default delete use-rel-suffix
src-all tag=.           prefix=/work/src/mercurial/fbsd-src-HEAD
src-all tag=RELENG_7    prefix=/work/src/mercurial/fbsd-src-RELENG_7
src-all tag=RELENG_6    prefix=/work/src/mercurial/fbsd-src-RELENG_6
src-all tag=RELENG_5    prefix=/work/src/mercurial/fbsd-src-RELENG_5
src-all tag=RELENG_4    prefix=/work/src/mercurial/fbsd-src-RELENG_4

ports-all tag=. prefix=/work/src/mercurial/fbsd-ports

In this configuration all source files will be placed under /work/src/mercurial/. I use separate Mercurial repos for different FreeBSD branches, though you can probably use native Hg branches for this. I discovered that keeping different repositories works better for me as it's much lesser error probability and doesn't impact the speed much (if it does it at all).

Creating Mercurial repository

After obtaining the source you have to initialize Hg repository for the first time. It's very simple, luckily enough. Just enter into the each of repository folders, e.g. /work/src/mercurial/fbsd-src-HEAD from the above, and type the following commands:

% hg init       # will create .hg folder and initialize its contents
% hg add        # will schedule all new files for the addition
% hg forget .svn # Will ignore subversion housekeeping files
% hg commit -m 'Initial import of the FreeBSD tree'

After that all downloaded source code will be managed by Mercurial. If you need to ignore some files, use .hgignore(5) file for this.

Keeping repositories in sync

Obviously, you want to be in sync with the main FreeBSD development tree. In fact, it's not harder than creating the repo.

To update your repository you need to perform the following steps:

You can perform these steps from cron(8) to update your repos e.g. once a day. For example, I use the following script to do this:

set HG=/usr/local/bin/hg
set CSUP='/usr/bin/csup -L0'
set SUPFILE=/home/stas/mercurial-supfile
set BRANCHES=(fbsd-ports fbsd-src-RELENG_7 fbsd-src-RELENG_6 \
        fbsd-src-RELENG_5 fbsd-src-RELENG_4 fbsd-src-HEAD)
set REPOPATH=/work/src/mercurial


# Update sources via CVSUP


if ($status != 0) then
        echo "Error occurred during update"
        exit 1

# Add and commit changes into mercurial repo
foreach branch (${BRANCHES})
        cd ${REPOPATH}/${branch} && ${HG} addremove && ${HG} ci -m 'Update from upstream'

Performing local development work on the repositories

This is what we have done all the previous steps for.

Mercurial is the true distributed VCS and encourages the use of separate repository for the every project you work on. In fact, the repository clone operation is very fast and cheap - Mercurial uses copy-on-write technology to avoid unnecessary copies.

For example if you're going to do some work on the Project1 for the FreeBSD HEAD you start by creating the corresponding repository:

% hg clone /path/to/repo/fbsd-src-HEAD fbsd-HEAD-project1

After that you can safely use fbsd-HEAD-project1 for all project1-related development work, commit changes, rollback them, view the history. Refer to the Hg documentation to learn more about Mercurial and it's abilities.

In case if you need to merge with the recent HEAD after some time, you can easily do that:

% cd /path/to/fbsd-HEAD-project1
% hg pull /path/to/repo/fbsd-src-HEAD
% hg merge

resolve conflicts, etc

% hg commit -m 'Merge upstream'

You can do that whenever you want without any consequences. Mercurial keeps the history of merges, so you won't receive suspicious conflicts. Furthermore, after the merge operation Hg will integrate all the history from the merged tree into your tree, so you'll be able to easily check the difference between your tree and the main tree. Suppose, for example, after some development you've received the following:

changeset:   310:d44952c166fd
tag:         tip
user:        Stanislav Sedov <>
date:        Wed Jan 09 18:57:24 2008 +0300
summary:     - Add new files.

changeset:   309:937d50c4af02
user:        Stanislav Sedov <>
date:        Fri Nov 30 19:02:37 2007 +0300
summary:     - Fix build.

changeset:   308:610151747720
user:        Stanislav Sedov <>
date:        Wed Nov 28 11:45:56 2007 +0300
summary:     - Fix build.

changeset:   307:023d52500562
user:        Stanislav Sedov <>
date:        Tue Nov 27 23:17:43 2007 +0300
summary:     - Add forgotten file.

changeset:   306:af6c5a6c4ff4
parent:      235:28745515f10e
parent:      304:4724d224afe3
user:        Stanislav Sedov <>
date:        Tue Nov 27 21:40:58 2007 +0300
summary:     - Branch merge.

changeset:   305:4724d224afe3
user:        Stanislav Sedov <>
date:        Tue Nov 27 02:53:22 2007 +0300
summary:     Update master tree

changeset:   304:4d9fc65e6661
user:        Stanislav Sedov <>
date:        Mon Nov 26 02:52:57 2007 +0300
summary:     Update master tree

Now you can get the diff between the main tree as on Tue Nov 27 and your last revision by using the following command:

% hg diff -r 305 -r tip


Additional info

For additional information about Mercurial refer to the included manual pages. The Distributed revision control with Mercurial book also is the great source of information about Hg.

LocalMercurial (last edited 2013-10-06T06:02:45+0000 by WarnerLosh)