Mercurial in complex workflows


in complex workflows


Who I am

Alexander Solovyov

  • Paylogic employee
  • Python developer for 5 years
  • Mercurial contributor for 3 years
  • ...and author and contributor to several other projects

Traditional workflow

  • Everybody has write access to central repository
  • Code review post factum
  • Centralized VCS, linear history

What's wrong

  • Too much conflicts
  • Post factum never works
  • Unfinished work hard to manage

Where to look

World has invented a great model for developer interaction:

Open Source

Open Source

  • Core team (gatekeepers)
  • Contributors (developers)
  • Disconnected development


  • Developers submit changes
  • Gatekeepers review them
  • Changes are merged in main line

What's the point

  • Experience exchange
  • Prevent sad code
  • Collective code ownership


  • Changesets in repository instead of patches
  • Zero effort branching and merging
  • Full history of development
  • Total control of situation


  • Started in April 2005
  • Very fast
  • 94% Python, 6% C (30k lines)
  • Simple and clean Python API for extensions

How it applies

  • Track features with branches in a single repository
  • Have developers' repositories on a server
  • Tag branches with bookmarks (or use named branches)
  • Use all hg's power to help you


hg serve

  • Embedded web-server for viewing and sharing
  • Zero configuration
project> hg serve
listening at http://hostname:8000/ (bound to *:8000)

# this requires zeroconf extension enabled
~> hg paths
zc-hostname-project =

Revision sets

  • What do I have in my branch?
project> hg log -r 'ancestors(branchname) - ancestors(master)'
  • What is not merged yet?
project> hg log -r 'bookmark() - ancestors(master)' --template '{bookmarks}\n'


  • Suddenly need a fix in an older release?
  • Use hg transplant!
  • Merge will take care

Other stuff

  • color
  • pager
  • progress
  • schemes (url shortcuts)
  • rebase (uh-huh)

Mercurial API

  • Very simple and clean
  • Extensive
    • hooks
    • helpers for wrapping functions
    • adding commands
  • Improve your workflow with writing extensions

Bookmarks pushing

def bookpush(orig, ui, repo, dest=None, **opts):
    if '.' in opts.get('bookmark', ()) and repo._bookmarkcurrent:
        n = opts['bookmark'].index('.')
        opts['bookmark'][n] = repo._bookmarkcurrent
    return orig(ui, repo, dest, **opts)

def uisetup(ui):
    extensions.wrapcommand(commands.table, 'push', bookpush)

And suddenly you don't need to copy-paste:

> hg push -B . # instead of "-B bookmark-name"

What do we have

  • check you're in the right branch
  • check you're not resolving file with conflicts
  • start working on a case
  • stop working on a case, merge with target branch, submit changes

Making life easier

Automate and structure it


It's the time for them. :)

Alexander Solovyov, PyGrunn, 2011