wiki:manuals/Mercurial
Last modified 8 years ago Last modified on 10/01/10 11:56:02

Motivation

Why yet another version control system?

I like to commit when functionality is ready: each commit keeps repository functional.

I can still have my private branch ( what I do any way ), but even then on each step

i prefer to commit and revert changes if they went to dead end. Since we are using central

SVN repository ( same philosophy as CVS ) this approach is hard to achieve.

Mercurial allows to run two version control system in parallel - SVN for pushing/pulling changes from central repository

and mercurial for tracking local changes. This approach allow to commit into SVN final working code and keep all playing staff local.

Just Yet another toy to play :) .

Why not Git?

Mercurial has more SVN like command set, which will make learning process bit shorter. The main goal is the new concept which is hard enough. Once we hit Mercurial limitation we can switch ( oh my....).

How to Use Mercurial ( for dCache development ) on top of SVN

  1. Checkout from SVN
    $ svn co svn+ssh://svn.dache.org/store/dCache dCache
    
  1. initialize Mercurial
    $ cd dCache
    $ hg init
    $ cat > .hgignore <<EOF
    .svn/
    .hgignore$
    build/
    dist/
    .classpath$
    .project$
    EOF
    $ hg ci -Am "import sources into mercurial"
    
  1. edit ediT EDIT EDIT Edit edit
  1. modify code and commit changes into mercurial
    $ hg commit
    
  1. produce patch series for review:
      hg export -o ~/hp/%b-r\%r %n#%N.patch 0:tip
    
    where 0:tip is a begin and end revisions numbers ( tip is the name of the HEAD revision )
  1. as soon as functionality is there commit changes into SVN
    $ svn commit
    

How to Use plain Mercurial ( for dCache development and not only )

  1. Clone dCache repository ( ~900MB )
    $ hg clone http://www.dcache.org/hg/dcache-hg dCache-hg
    
  1. edit ediT EDIT EDIT Edit edit
  1. modify code and commit changes into mercurial
    $ hg commit
    
  1. produce patch series for review:
      hg export -o ~/hp/%b-r\%r %n#%N.patch 0:tip
    
  1. send patch to <patch at dcache dot org>

The most scary part of any VCS (and DVCS even more) is the merge.

  1. get changes from central repository:
      hg pull
    
    this will pull changes from remote repository but will not update your working directory!
  1. update your woking directory
      hg update
    

if you are lucky, then you are done. But very often you have to merge:

  1. merge
      hg merge
    

if there is no conflicts, mercurial will merge changes and you will need to commit into your local repository your 'merged' changes.

In case of mercurial failed to merge, you have to resolve conflicts by hand.

Howto do patchwork

You concentrate your self on some new functionality or fix, but have to switch to something new. Your uncommited changes laying around and probably even do not compile. Typical solution - fresh checkout ( yet another 400MB ). Mercurial way to do it:

#1
hg qinit # initiates patch queue. need to do it only once

#2
hg qnew <patch name>  # start a new patch work e.g. hg qnew pnfs-speedup.patch

#3
vi ... # hack hack hack

#4
hg qrefresh # safe current state of the patch e.g in file .hg/patches/pnfs-speedup.patch

#5
hg qpop pnfs-speedup.patch # remove patch from code

#6
hg qpush pnfs-speedup.patch # apply patch

Patches can be grouped according functionality or version or...

hg qguard pnfs-speedup.patch +pnfs

Use only one set of patches

hg qselect pnfs

Push all patched from pnfs group

hg qselect pnfs
hg qpush -a

Howto manage patches for two ( or more ) branches

Mercurial Queues have nice feature guards. The guards is a symbolic label to a set of patches. By choosing a guard you enable or disable patch group. By default, if no guard is selected, only unguarded patches apply.

I do have a separate repository for my patches:

$ mkdir myPaches
$ cd myPatches
$ hg init

clone dCache repository ( on any other ) and add patches to it:

$ hg clone http://..../dCache
$ cd dCache/.hg
$ hg clone /patch/to/myPatches patches
$ cd ..

Now on you MQ is a mercurial repository itself. At any point you may do hg qcommit to commit your changes. If you work on several branches ( or if you use the same patch repository multiple projects ) at some point you will have patches which you want to exclude from your current 'working set'. The solution is guards :

$ hg gquard some-fix-for-a-branch.patch +myBranch
$ hg qguard some-work-on-trunk.patch +trunk

depending which set you want to use you may enable one or the other set

$ hg qselect trunk
$ hg qpush -a

only patches which have selected guard and all unguarded patches will apply

# real life example with my patches:
$ hg qapplied
$
$ hg qselect nfs
$ hg qpush fix-nfs4-mover.patch  
applying junit-test-for-chimera-provider.patch
skipping 1-9-0-build.patch - guarded by ['+19']
applying pnfs-hadler-cache.patch
skipping chimera-pnfs-prodider.patch - guarded by ['+commited']
skipping pnfs-parovider-fix-19.patch - guarded by ['+commited']
skipping log4j.patch - guarded by ['+mm']
skipping chimera-batch.patch - guarded by ['+commited']
skipping pool-migration-plugin.patch - guarded by ['+mm']
skipping petmission-handler-interface.patch - guarded by ['+acl2']
skipping abstrach-permission-handler.patch - guarded by ['+acl2']
skipping psux-match-fix.patch - guarded by ['+commited']
skipping pool-manager-acl.patch - guarded by ['+pm-acl']
skipping acl-branch-merge.patch - guarded by ['+acl']
skipping level-to-uri.patch - guarded by ['+migration']
applying fix-nfs4-mover.patch
Now at: fix-nfs4-mover.patch
$ hg qapplied
fix-nfs4-mover.patch
junit-test-for-chimera-provider.patch
pnfs-hadler-cache.patch
$

You may list all existing guards:

$ hg  qselect -s    
+19
+acl
+acl2
+acl2ik
+commited
+migration
+mm
+nfs
+obsolete
+pm-acl
+trunk

At some point, if you decide that guard is not require any more or you may want to change a guard:

$ hg gquard 1-9-0-build.patch -19 +commited

Cherry-Pick

e.g. merge some commits only

  1. enable transplant extension ( hg.transplant = )
  2. merge the changes :-)
    $ hg transplant -s <some other repository> <rev1>[:<rev2>] ...
    

Bisec ( or find commit)

There is an easy way to find commit which introduced a problem. It's only a four easy steps:

  1. write a script to return 0 when test pass and 1 other wise. Here is mine:
    grep -q "This should never be in code" && exit 1
    exit 0
    
  1. mark last know GOOD revision:
    $ hg bisec -g <last stable>
    
  1. mark first know BAD revision:
    $ hg bisec -b <here I found it!>
    
  1. let mercurial search for a commit which introduced the bug:
    $ hg bisec -c <my-test.sh>
    

my real code:

$ hg bisec -g 160
$ hg bisec -b tip
Testing changeset 174:34ec3850340e (29 changesets remaining, ~4 tests)
15 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg bisec -c ./bug-test.sh 
Changeset 174:34ec3850340e: good
Changeset 181:e09c9d832b49: bad
Changeset 177:82aba55b9609: bad
Changeset 175:16d61b5abd95: good
Changeset 176:dea80b59c4e0: good
The first bad revision is:
changeset:   177:82aba55b9609
user:        Tigran Mkrtchyan
date:        Wed Aug 18 12:31:38 2010 +0200
summary:     build: fix encoding
$

http://svn.dcache.org/cgi-bin/hgwebdir.cgi/

http://www.selenic.com/mercurial/wiki/

http://hgbook.red-bean.com/hgbook.html

http://video.google.com/videoplay?docid=-7724296011317502612


Last Modified : Thu Apr 26 11:43:57 2018 by Tigran