Mercurial bookmarks

Please note that this blog post is outdated. please refer to the mercurial help for more information about bookmarks.

A few month ago, Matt Mackall the maintainer of the Mercurial version control system, came up with the idea to implement so called bookmarks for mercurial.
Basic idea
The basic idea of these bookmarks is simple. Instead of referring to a commit by it’s linear rev number or it’s SHA1 key, the user should be able to set a bookmark on a commit and use this name to refer to the commit. So you can do:

$ hg bookmark -r 132 my-bookmark
$ hg update my-bookmark

Further thoughts
Just referring to a commit by a given name is nice, but it is not quite why we finally introduced bookmarks. A lot of people using both git and Mercurial like Mercurial for it’s simplicity and it’s clear interface. Nevertheless they are missing certain features from git and one of the most often requested are git-styled branches. Let me just give you a short overview of the differences between the branch implementation of both systems:

Mercurial branches
Mercurial branches have a lot in common with branches in Subversion or CVS. If you commit to a branch, the name of the branch is stored in the changeset and therefore an immutable part of the history. This means, unlike bookmarks, branches can not be deleted if you created them, and that you will always know to which branch a certain commit belongs.

git branches
In git’s notion of branches a branch is just a fork in the directed acyclic graph (DAG) of the history. Therefore the branch name is not recorded in the changeset. Branches are just pointers to a certain head of a DAG branch that move forward with every commit to that branch. This gives you the opportunity to create branches just for testing purposes or with stupid names that might be merged or rebased later. If you delete the branch name, the branch in the DAG resides, but the name is gone.

As bookmarks are also just pointers to commits in the history, it is quite obvious that it is easy to implement a mechanism equal to the branch mechanism of git. Therefore bookmarks are not just pointers, but they move forward to the next commit if you create a child commit on a commit that is referred by a bookmark.

Problems
As the branch notion in mercurial is different from git, it is clear the the internal design of mercurial makes some assumptions that rely on this behavior. This leads to some design decisions that might confuse people that come from git. If you switch to a branch in git and commit to it, only the branch that you are on is moved forward even though the parent commit has two branch names. Mercurial bookmarks are always forwarded if the parent commit is referred by a bookmark. Therefore you might forward bookmarks on commit without evening knowing. We don’t have a notion of a current bookmark. Furthermore bookmarks are local. There is no way to push or pull bookmarks. This is a limitation by the wire protocol of mercurial. There are patches floating around that implement a way to bring push/pull mechanism for various data including bookmarks, but as the wire protocol is a critical part of mercurial, the developer usually don’t like to enhance or change the protocol. You can use bookmarks remotely and do a lookup on them, but it requires a certain amount of deep knowledge.

Implementation
As already mentioned, we have a working bookmark implementation now. I worked on these bookmark stuff for several months. With the help of the mercurial community we finally made our way to the main tree (mpm’s and the crew tree) and therefore my extension will be part of the upcoming Mercurial 1.1 release. I’m currently maintaining the bookmarks on bitbucket.org and a crew member is usually merging changes from me into the crew tree from time to time.

Example
Let’s give you a short example how bookmarks work. First of all we have to checkout recent versions of Mercurial. You can get an hourly snapshot here. Then we have to setup the extension by adding the following lines to our ~/.hgrc:

[extensions]
hgext.bookmarks =

Now let’s go into a Mercurial repository. You can run hg help bookmarks to show the available flags.
Let’s start with a basic listing of available bookmarks:

$ hg bookmarks
no bookmarks set

Create a bookmark on the current tip of the repository:

$ hg bookmark my-tip
$ hg bookmarks
+ my-tip 7348:1a5c9ca2bfd5

Let’s create a bookmark on an other revision in the history:

$ hg bookmark -r 7300 hgweb-fix
$ hg bookmarks
+ my-tip 7348:1a5c9ca2bfd5
hgweb-fix 7300:591767e6ea7a

We can than update to the revision:

$ hg update hgweb-fix
82 files updated, 0 files merged, 31 files removed, 0 files unresolved
$ hg bookmarks
my-tip 7348:1a5c9ca2bfd5
+ hgweb-fix 7300:591767e6ea7a

We also can now commit to this bookmark and create a new head:

…hack..hack..
$ hg commit -m’Another hgweb bugfix’
$ hg bookmarks
my-tip 7348:1a5c9ca2bfd5
+ hgweb-fix 7349:ca3fbad32554

Let’s go back to our tip and merge our change into it:

$ hg update my-tip
$ hg merge hgweb-fix
$ hg commit -m’Merge bookmark hgweb-fix’

Now we can just delete our bookmarks

$ hg bookmark -d hgweb-fix
$ hg bookmarks
+ my-tip 7350:3acda44343da

You can use bookmarks in every rev lookup. This means you can also do hg log my-tip or hg qimport -r my-tip. It is even possible to look them up using hg id -r . I hope you enjoy it. If you encounter any bugs don’t hesitate to file an issue at the mercurial bugtracker.

Thanks to
A lot of people were involved in the development of the bookmarks extension either by giving ideas or by actually patching it. Thanks to ronny, mpm, tonfa, piranha, parren, joel, dimitriy and #mercurial.

Links

Mercurial is a fast decentralized version control system used by projects like Mozilla and OpenJDK for their software development. It is written in python and currently maintained by Matt Mackall.

6 thoughts on “Mercurial bookmarks

  1. Jesper Noehr

    Nice! This is one of my new favorite features in mercurial.

    One thing I personally think is a huge advantage over named branches is the ability to delete bookmarks. I didn’t see this mentioned in your post, but perhaps you can give it a quick mention?

    Great work!

    Reply
  2. poko

    this looks fantastic!

    i have one quick question though:

    “…This means you can also do hg log my-tip or hg qimport -r my-tip. ”

    zsuzss-macbook:f zs$ hg bookmarks
    my-tip 3:9dc73b7ed083
    * orig 8:2587f34b8edf

    zsuzss-macbook:f zs$ hg -v
    Mercurial Distributed SCM (version 1.1+20081202)

    zsuzss-macbook:f zs$ hg add test-orig
    zsuzss-macbook:f zs$ hg commit -m “test-orig”

    zsuzss-macbook:f zs$ hg log orig
    zsuzss-macbook:f zs$
    ——
    should not “hg log orig” show the log for this commit?

    (interestingly enough “hg view orig” works as expected)

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>