Hunting the Shmoo

Screencasts and blog posts on workflow, productivity, tools, Mozilla and whatever else tickles my fancy.

Absorbing Changes into a Commit Series with Mercurial

Imagine this scenario. You’ve pushed a large series of commits to your favourite review tool (because you are a believer in the glory of microcommits). The reviewer however has found several problems, and worse, they are spread across all of the commits in your series. How do you fix all the issues with minimal fuss while preserving the commit order?

If you were using the builtin histedit extension, you might make temporary “fixup” commits for each commit that had issues. Then after running hg histedit you’d roll them up into their respective parent. Or if you were using the evolve extension (which I definitely recommend), you might do something like this:

$ hg update 1
# fix issues in commit 1
$ hg amend
$ hg evolve
# fix issues in commit 2
$ hg amend
$ hg evolve
etc.

Both methods are serviceable, but involve some jumping around through hoops to accomplish. Enter a new extension from Facebook called absorb. The absorb extension will take each change in your working directory, figure out which commits in your series modified that line, and automatically amend the change to that commit. If there is any ambiguity (i.e multiple commits modified the same line), then absorb will simply ignore that change and leave it in your working directory to be resolved manually. So instead of the rather convoluted processes above, you can do this:

# fix all issues across all commits
$ hg absorb

It’s magic!

Installing Absorb

Note: As of Mercurial 4.8, absorb is included as a core extension! Simply add absorb= to the extensions section of your hgrc.

There’s one big problem. The docs in the hg-experimental repo (where absorb lives) are practically non-existent, and installation is a bit of a pain. So here are the steps I took to get it working on Fedora. They won’t hand hold you for other platforms, but they should at least point you in the right direction.

First, clone the hg-experimental repo:

$ hg clone https://bitbucket.org/facebook/hg-experimental

Absorb depends on a compiled python module called linelog which also lives in hg-experimental. In order to compile linelog, you’ll need some dependencies:

$ sudo pip install cython
$ sudo dnf install python-devel

Make sure the cython dependency gets installed to the same python your mercurial install uses. That may mean dropping the sudo from the pip command if you have mercurial running in user space. Next, compile the hg-experimental repo by running:

$ cd path/to/hg-experimental
$ sudo python setup.py install --component absorb

Again, be sure to run the install with the same python mercurial is installed with. Finally, add the following to your ~/.hgrc:

[extensions]
absorb =

The extension should now be installed! In the future, you can update the extension and python modules with:

$ cd path/to/hg-experimental
$ hg pull --rebase
$ make clean
$ sudo python setup.py install --component absorb

Let me know if there were other steps needed to get this working on your platform.


Share

Comments

Jun Wu
02/03/2017

FYI I had a note about absorb at files.lihdd.net/hgabsorb-no.... With `--component absorb` appended to setup.py, lz4-devel and openssl-devel could be unnecessary.

ahal
02/03/2017

Thanks, edited! Also thanks for the awesome extension, it works great.

Henrik Skupin
07/03/2017

Thank you for this great post! I will definitely switch using absorb now!

When
I tried to compile it on MacOS Sierra I still got the `'lz4.h' file not
found` failure listed even with using `--component` as layed out above.
So I had to run `brew install lz4` to get this fixed.

ahal
07/03/2017

Interesting, I verified I was able to compile without the lz4 dependency on Fedora. But added a note that it might be required on OSX. Thanks for mentioning it!

John Doe
17/03/2017

Did you by any chance use this extension together with the 'evolve' extension? I am not sure how those two are going to interact.

J. Ryan Stinnett
17/03/2017

Are there any known attempts at making the same thing for Git? I'd love to use something like this, but I'm almost always in Git as of late.

David Shepherd
09/06/2017

These instructions don't work with the latest version of the hg-experimental repository. I had to do `hg up 67b29af73e62` to get it to work (I picked that revision because it's one after the last commit modifying absorb before your post).

ahal
12/06/2017

Thanks yeah, looks like absorb is tracking the mercurial development branch. So you can either rollback fb-experimental to the commit you mentioned, or install the latest mercurial from source.

Leave a comment

Your comment has been submitted and will be published once it has been approved.