Mercurial bookmarks as feature branches
Use 'python3 -mpip' to install hg-evolve
Also install python3-setuptools

heads

tip
browse log

clone

read-only
https://hg.sr.ht/~ahal/bookbinder
read/write
ssh://hg@hg.sr.ht/~ahal/bookbinder

#Bookbinder

builds.sr.ht status

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 vein, 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 the 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.

#Installing

Clone this repository somewhere on your local machine:

$ hg clone https://hg.sr.ht/~ahal/bookbinder

Edit your ~/.hgrc and add the following to enable the extension:

[extensions]
bookbinder = /path/to/bookbinder

#Usage

If -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?

The name 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:

  1. C is R or C is an ancestor of R
  2. C is not public
  3. C is not a merge commit
  4. C is not obsolete
  5. no bookmarks exist in [C, R) for C != R
  6. 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.

#Configuration

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 have $HGPLAIN set.

#Running Tests

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