Thursday, May 26, 2011

Mercurial revision sets query



In a big project there are a lot of temporary branches, so called "feature branches" which sometimes are annoying when you want to understand the skeleton of your development graph. It is a good practice to "close" branches, but it becomes a problem on its own. Sometimes you find a bug after you closed the branch and you wish you didn't do it.


At first you may think of showing only "active" branches, but you will be disappointed because it shows not what you expected.For example "production" branch will be considered inactive just because there exists a hotfix branch off it.


Mercurial and TortoiseHg documentation is surprisingly short on this great feature. Mercurial since version 1.6 supports a query language which can select nodes of interest.
What I am interested in is to build a query which would remove branches which were merged into some other branch and to keep branches which have not been merged into.
Here is the query:


not :p2(merge()) and not closed()

How it works? Lets start from the inner query: "merge()" will return merge nodes. Merge nodes are special because they have 2 parents: p1() is the branch which merged into, and p2() is the branch which merged from. I want to drop branch which was merged from and leave branch which was merged into. Semicolon marks revisions range and :p2() is the same as 0:p2() which means from the beginning of the times and until the last node in merged branch. Now add "not" prefix to drop "noise" nodes, add "and not closed()" nodes if you have some abandoned branches and enjoy your essential project structure.


This is just an example which shows you how to start writing queries of interest. Start writing your collection of useful queries.