Bookbinder is a mercurial extension to simplify many bookmark based workflows.
A book binder is a person or machine which binds pages to books. In a similar
bookbinder binds commits to bookmarks.
It does this by implementing a
feature revset which returns all revisions
"within" a particular bookmark. This allows bookbinder to subvert all
commands that have a REV argument and replace any detected bookmark names with
feature revset. In other words, if you pass in
-r my_bookmark to a
command, it will replace
my_bookmark with a revset containing all
changesets "within" the bookmark.
Clone this repository somewhere on your local machine:
$ hg clone https://firstname.lastname@example.org/halbersa/bookbinder
Edit your ~/.hgrc and add the following to enable the extension:
[extensions] bookbinder = /path/to/bookbinder
-r <bookmark> is passed into a command, replace the bookmark's
revision with a revset containing all changesets in the bookmark. E.g:
$ hg log -r <bookmark> $ hg rebase -r <bookmark> -d <destination> $ hg prune -r <bookmark> $ hg fold -r <bookmark>
Bookbinder detects when bookmarks are based on top of one another, so you can rebase distinct features and easily keep track of them:
$ hg rebase -r bookmark_2 -d bookmark_1 $ hg rebase -r bookmark_3 -d bookmark_2 $ hg log -r bookmark_1 $ hg log -r bookmark_2 $ hg log -r bookmark_3
If rebasing bookmarks on top of one another, it's highly recommended to use the evolve extension, which can get you out of trouble if you mutate a bookmark that has descendants.
If you want bookbinder to treat a bookmark as a label to a revision, it's still possible by escaping the bookmark name with a period:
$ hg log -r .my_bookmark
What is a feature?
feature comes from the fact that bookmarks are often used to track
feature work. This word is misleading, please help me come up with a better
one! It can be used like so:
$ hg log -r "feature(bookmark_1) or feature(bookmark_2)"
While it was primarily designed for bookmarks, it works just as well with any arbitrary revisions.
A commit C is within feature branch ending at revision R if all of the following conditions are met:
- C is R or C is an ancestor of R
- C is not public
- C is not a merge commit
- C is not obsolete
- no bookmarks exist in [C, R) for C != R
- all commits in (C, R) are also within R for C != R
In other words, all ancestors of a revision that aren't public, a merge commit
or part of a different bookmark, are within that revision's 'feature'. One thing
to be aware of, is that applying a bookmark to a public commit results in an
'empty' feature. Running
hg log -r <bookmark> on one of these will not result
in any output.
You can change the escape sequence used by setting bookbinder.escape. The escape character can appear either before or after the bookmark (or both). In your hgrc, add:
[bookbinder] escape = %s~
Make sure to include the '%s' string to denote where the bookmark text should be.
This changes the escape sequence to
hg log -r my_feature~.
Finally you can invert the behaviour of the escape sequence by adding:
[bookbinder] invert_escape = True
This keeps original behaviour by default, and bookmarks will only be expanded if
you specify the escape sequence. For example,
hg log -r <bookmark> will continue
to be a simple pointer to a commit, whereas
hg log -r .bookmark will contain the
entire series of commits in the feature. Inverse behaviour will also be enabled if you
To run the tests, first clone mercurial. Then run:
$ HGROOT=path/to/hgrepo make tests
Run a against a specific version of hg with:
$ HGROOT=path/to/hgrepo make tests-4.9
To update the expected output of the tests:
$ HGROOT=path/to/hgrepo HGTESTFLAGS=-i make tests