How to be a more effective git historian with recursive-blame

The ability in Git to search through the commit history locally is one of the major reasons why I never want to work with SVN again. With Git there is no waiting on the server. Git also provides some powerful tools to search that local history, like git-bisect. If you haven’t used bisect, this is super efficient at finding the change that introduced a bug.

Another history tool is git-blame. On its own, its much less efficient for me than bisect, since I mostly have to use it recursively to find the revision that introduced the change I’m looking for. Too often, running ‘blame’ just once doesn’t help. Even worse, the line in question might not even exist in the latest revision anymore, so using blame directly won’t work. When doing a recursive search with blame manually, with Git locally or on GitHub, it can be tricky to track down something with blame since the line in question moved around the file from change to change.

Can we do better? Of course. If one program isn’t efficient enough, write another to compensate. That’s what my friend and colleague Scott González did on his trip to Russia, resulting in recursive-blame. This is a command line tool, written in nodejs, installed via npm (which both run well on Windows, Linux and OSX, a huge plus over other platforms).

Assuming you have node and npm installed, the setup couldn’t be any easier:

npm install -g recursive-blame

Afterwards you can use it likes this:

recursive-blame <pattern> <path>

The pattern is a regular expression, so you may have to escape some characters.

As a simple example, today I was reviewing a pull request against jQuery UI, which removed an unnecessary argument from a method call (PR 1104). I wanted to know why that argument was there in the first place. With recursive-blame, that was easy to figure out, and took only a few seconds. To start, I ran this command:

recursive-blame 'values: function\(' ui/jquery.ui.slider.js

Since parentheses indicate a group in regular expressions, I escape it with a backslash.

The output is this (I only trimmed the commit message to fit here):

Commit: 87ba795467ee447eb2ab7d95ada42de097c7946f
Author: Richard Worth <[email protected]>
Date:   Fri Apr 2 23:16:46 2010 -0400 (3 years, 7 months ago)
Path:   ui/jquery.ui.slider.js
Match:  1 of 2

    slider: jslint cleanup (thanks for the start zhaoz) and style changes to [...]

381)        return this._value();
382)    },
384)   values: function( index, newValue ) {
385)        var vals,
386)            newValues,
387)            i;

Next action [r,n,p,c,d,q,?]?

This points at the last commit that modified this line. Since its just a code style cleanup, I type “r” for “recurse” to continue searching (the other commands are explained by typing “?”; this is the same interface as you get with “git add -p“):

Next action [r,n,p,c,d,q,?]? r

Commit: 2c5d327debfdc2696267f7d4dba5c0a4335bc165
Author: Richard Worth <[email protected]>
Date:   Mon Oct 12 11:23:59 2009 +0000 (4 years ago)
Path:   ui/jquery.ui.slider.js
Match:  1 of 2

    slider: Removed undocumented noPropagation last arg from values method as [...]

446)        return this._value();
448)    },
450)   values: function(index, newValue) {
452)        if (arguments.length > 1) {
453)            this.options.values[index] = this._trimAlignValue(newValue);
454)            this._refreshValue();

Next action [r,n,p,c,d,q,?]?

This is much more interesting: “Removed undocumented noPropagation last arg from values method”. Exactly what I’ve been looking for. Let’s look at the diff for that commit, via “d”:

Next action [r,n,p,c,d,q,?]? d
diff --git a/ui/jquery.ui.slider.js b/ui/jquery.ui.slider.js
index d27d9af..14e92f6 100644
--- a/ui/jquery.ui.slider.js
+++ b/ui/jquery.ui.slider.js
@@ -421,12 +421,12 @@ $.widget("ui.slider", $.extend({}, $.ui.mouse, {


-      values: function(index, newValue, noPropagation) {
+      values: function(index, newValue) {

        if (arguments.length > 1) {
            this.options.values[index] = newValue;
-           if(!noPropagation) this._change(null, index);
+         this._change(null, index);

        if (arguments.length) {

So this removed the noPropagation argument, along with the if-statement. Afterwards this._change() is always called.

I could dig further to figure out when that flag was introduced, but in this case I’m sure that the flag wasn’t removed by accident, so removing the argument in the call to this.values() must be valid as well. Problem solved!

If you use recursive-blame and run into issues, report them against Scott’s GitHub repo. If you like the tool and want to show some appreciation, donate to Scott on GitTip.

Update 1:

An alternative to recursive-blame might be git-log with the -L option, a rather recent addition that isn’t yet covered widely. The syntax looks like this:

-L <start>,<end>:<file>, -L :<regex>:<file>

The example near the end of the page is this:

git log -L '/int main/',/^}/:main.c

Shows how the function main() in the file main.c evolved over time.

For the example above, the following command seems to be somewhat effective:

git log -L '/values: function/',/\}/:ui/jquery.ui.slider.js

I haven’t yet figured out how to use the <end> argument properly.

It looks like this has some overlap with recursive-blame, but it doesn’t support multiple matches. The rather poor documentation certainly doesn’t help either.

What is wrong with the world?

“What is wrong with the world?” – that is a question I’ve been coming back to in the last few days. Whenever I read about some problem that stirs a lot of discussion, arguments and – all too often – anger, I wonder: Don’t we have more important problems to solve?

The more time I spend thinking about “figuring out what problems are important”, the more difficult it seems to get to actually answer that question. There’s so many problems, so many contexts, so many scopes, to consider – how would you ever be able to rank those?

One idea to approach: To make well-structured list that forces to gather certain data to help answer interesting questions. So far I’ve came up with the following fields:

  • Abstract – a free form description of the problem, preferably very succinct for quick digestion
  • Scope – Where does this problem apply geographically? A region, country, continent, world?
  • Context – In which context does this problem apply? Something like health, gaming, consumerism
  • References – where can I read more about this?
  • Rating, within the given Scope and Context

The Rating is probably the most problematic, even if restricted to Scope and Context. Maybe a way to approach that is to order just relative to other problems within it’s category. “X is more important than Y, less important than Z”.

Handling scope and context properly requires a categorisation system that helps avoid duplicates and ambiguity. The ranking system would also need some way to gather input from multiple sources, then presenting an average or mean to the viewer.

One interesting datasource for the ranking might be insurance data: Especially big reinsurance companies know quite well what events in the world cause the most damage, since they insure insurers that insure more or less everything. Of course the costs that they insure against are very specific and will ignore a lot of problems that don’t have a direct cost attached, say, global warming.

Maybe one day I’ll put together a prototype for this. If you have any interest in that and would like to chat, let me know.

Update 1:

Chris Bannon suggests to use a logarithmic scale, like the Richter magnitude scale. “You would measure the energy released (aka impact).” I like the idea, since a linear scale would not be effective at capturing a wide range like this.

When reading about the Richter scale, I learned that while this is still referenced a lot, the actual scale in use for measuring earthquakes is the moment magnitude scale (MMS). This has been in use in most countries since the mid-20th century. Though to make adoption easy, they adjusted the formula with some constants to yield the same scale as the Richter scale, only replacing the underlying formula, but not the output range.

That seems like a useful concept as well: Ranking problems from 0 to 10, on a logarithmic scale, is one thing. How to actually calculate the ranking another, independent of the output. That way the ranking can be adjusted again and again, without affecting the output scale.

Update 2:

My friend Enes, via email, brings up two interesting points, which I’d like to reproduce here, with some of my interpretation:

  1. Who’s the audience for such ranking system? An “average Joe” would judge issues quite differently than someone with active political involvement, as one of many potential backgrounds.
  2. Every culture will rate issues differently. This might depend on geographical location, on language, on status, whatever contributes to cultures. In order to make things comparable, a rating likely needs to involve the culture from where it comes.

Including audience as an additional field could tell us who’s supposed to be interested in this problem. Culture might be more useful as a property of the rating, though figuring out the culture of a voter is probably itself a pretty hard problem to solve.

Update 3, in April 2014:

After reading parts of Thinking, Fast and Slow, I’ve been coming back to this idea again. Our inability to intuitively deal with statistics seems to cause so much misunderstanding and violated expectations. For example, we are pretty bad at rating risk for different forms of travel, where we’re much more likely to get hurt or killed in a car than in a plane. Based on this unintuitiveness of statistics I’d extend the ideas outlined above with an integration of relevant statistics. While its easy to mislead readers with statistics, I think having verifiable statistics available would still be much better than having no statistics at all.

Release: Validation Plugin 1.11.1

A new version of the jQuery Validation Plugin is available. This is a bugfix release, mostly addressing regressions from the 1.11.0 release. The biggest one was related to the min/max methods, which would compare numbers to strings, in an attempt to make these methods work for date inputs as well. That’s now fixed. More details in the changelog below.

You can also find this plugin on the jQuery Plugins site.

Download this release.

If you use the plugin, please donate or ask your boss to make a donation!

Click here to lend your support to: jQuery Validation Plugin and make a donation at !

Eleven people contributed code to this release. A big thank you to: Bogdan Litescu, Burkhard Reffeling, DexterPark, Erik van Konijnenburg, James Thompson, Nick Schonning, Niklas Nilsson, Paul Cichonski, Robbert Wethmar, g1smd and jcbowman. Also thank you to everyone who reported issues on GitHub or commented on them.

The full changelog:

  • Revert to also converting parameters of range method to numbers. Closes gh-702
  • Replace most usage of PHP with mockjax handlers. Do some demo cleanup as well, update to newer masked-input plugin. Keep captcha demo in PHP. Fixes #662
  • Remove inline code highlighting from milk demo. View source works fine.
  • Fix dynamic-totals demo by trimming whitespace from template content before passing to jQuery constructor
  • Fix min/max validation. Closes gh-666. Fixes #648
  • Fixed ‘messages’ coming up as a rule and causing an exception after being updated through rules(“add”). Closes gh-670, fixes #624
  • Add Korean (ko) localization. Closes gh-671
  • Improved the UK postcode method to filter out more invalid postcodes. Closes #682
  • Update messages_sv.js. Closes #683
  • Change grunt link to the project website. Closes #684
  • Move remote method down the list to run last, after all other methods applied to a field. Fixes #679
  • Update plugin.json description, should include the word ‘validate’
  • Fix typos
  • Fix jQuery loader to use path of itself. Fixes nested demos.
  • Update grunt-contrib-qunit to make use of PhantomJS 1.8, when installed through node module ‘phantomjs’
  • Make valid() return a boolean instead of 0 or 1. Fixes #109 – valid() does not return boolean value
As usual:
  • Please post questions to the official Using jQuery Plugins Forum, tagging your question with (at least) “validate”. Keep your question short and succinct and provide code; a testpage makes it much more likely that you get an useful answer in no time.
  • Please post bug reports and other contributions (enhancements, features, eg. new validation methods) to the GitHub issue tracker

Informal reputation systems

Sites like Stackoverflow have formal reputation systems, where every user gets assigned public visible points that increase for actions deemed good, and decrease and some cases considered bad. A score of 10 indicates someone new to the platform, a score of 10.000 someone who’s been around for a long time. Someone new to the platform has an easy time figuring out who’s oldschool and who the other newbies are.

But then there’s endless platforms with informal reputation systems, where there is no explicit number or even rules to increase or decrease your reputation. Yet reputation has a lot of influence on those other platforms as well. Consider web standard processes. If you know anything about them, you’ll recognize the name Hixie. But if you’re new, Hixie is just another name. When you’re new and post to a standards mailing list the first time and no one recognizes your name, you’re much more likely to get ignored.

I wonder if there’s any platform that’s used daily that doesn’t have some form of reputation system. Is there any where reputation really doesn’t matter?

Also, is there a way to convert informal reputation systems like those around web standards into formal ones? Could we build a service that lists people involved in web standards and gives them points for good deeds?