Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Git Tip of the Week: Assigning Blame

2011, git, gtotw, tip

This week's Git Tip of the Week is about playing the blame game. You can subscribe to the feed if you want to receive new instalments automatically.


Most version control systems have the concept of blame, but in a good way. This allows you to see who has made changes to a file, or when the file was last changed by someone. Git has the same feature as well. This can be used to find out what feature(s) were added in a release in a process known as blamestorming.

To find out who changed a file, you can run git blame against a single file, and you get a breakdown of the file, line-by-line, with the change that last affected that line. It also prints out the timestamp and author information as well:


$ git blame file
566a0863 (Alex Blewitt 2011-07-12 09:43:39 +0100 1) First line
ed0a7c55 (Alex Blewitt 2011-07-12 09:43:51 +0100 2) Second line
8372b725 (Alex Blewitt 2011-07-12 09:44:06 +0100 3) Third line
ed0a7c55 (Alex Blewitt 2011-07-12 09:43:51 +0100 4) 

The timestamps and abbreviated commit hashes show the changes were introduced sequentially, but in this contrived example it's easy to see. Since Git has full information about the committer, it can show you the person's name, or the persons e-mail address:


$ git blame -e file
566a0863 ( 2011-07-12 09:43:39 +0100 1) First line
ed0a7c55 ( 2011-07-12 09:43:51 +0100 2) Second line
8372b725 ( 2011-07-12 09:44:06 +0100 3) Third line
ed0a7c55 ( 2011-07-12 09:43:51 +0100 4) 

Sometimes you get extra noise when whitespace differences are introduced into the file. You can use -w to suppress reporting on changes that only affected whitespace.

There are also changes you can show on a subset of ranges as well (like git diff, but with lines annotated with the commit hash). For example:


$ git blame ed0a..566a -- file
^566a086 (Alex Blewitt 2011-07-12 09:43:39 +0100 1) First line

Finally, if you have large files, it can often generate more output than is necessary. You can post-filter the results, but it's more efficient to tell Git which lines you want to see so that it doesn't need to do more work than is necessary finding out. You can specify lines with an explicit line number, (start/end), an offset from the start line (valid for end only) or a regular expression. This can be useful to blame a specific function, if you are following a C-like formatting where the function begins in column zero. This allows us to see the blame of a specific function (that starting with ^bar) and to the next closing brace (ending with ^} after the ^bar):


$ git blame tst.c
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  1) foo() {
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  2)    // the foo function
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  3) }
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  4) 
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100  5) bar() { 
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100  6)    // the bar function 
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100  7) } 
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  8) 
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100  9) main() {
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100 10)    // the main function
6bee4066 (Alex Blewitt 2011-07-12 09:57:54 +0100 11) }
$ git blame -L/^bar/,/^}/ tst.c
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100 5) bar() { 
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100 6)     // the bar function 
0cdc3645 (Alex Blewitt 2011-07-12 09:58:15 +0100 7) } 

Come back next week for another instalment in the Git Tip of the Week series.