A Better Git Blame

TL;DR git blame rarely gives helpful results. Instead use specific flags on git log to find the true author of a change.

What Does git blame Actually Do?

git blame searches the commit history to find the last person who modified a line of code. Some editors have this feature integrated into the interface, but the easiest way is at the command line:

git blame path/to/file  

It prints an annotated list of lines to stdout with the commit hash and author of the last person to change each line:

e45ad3 (Tim 2016-01-01)      1) import x from y;  
8890d2 (Jeremy 2016-01-13)   2) import z from h;  
e73ab4 (Michelle 2015-12-26) 3) public static...  

What's Wrong with git blame?

git blame only shows the last person to modify a line. This is rarely what you want. More often what you want is the original author of a line. Here's a list of things which changes who git blame shows as the author of a line:

  • Changing line formatting or indenting
  • Moving a block of code around in the file
  • Renaming a file
  • Any trivial change to the line
  • Moving a file (god help you)

Do you want to find the person who changed all project tabs to spaces? Probably not. You probably want to find out who wrote the weird piece of logic you're looking at.

The Solution: git log Knowledge

Here's the swiss army knife command to start with:

git log -p -M --follow --stat -- path/to/your/file  

If you rely on your code editor program to manage git history, you're missing out on an important part of your codebase. It's important to understand each flag:

  • git log General command to show multiple commits

  • -p Show patches, as in show what actually changed for each commit.

  • -M Show file renames in a readable way. A file rename now looks like this in the logs:

    path/to/{oldName.css => newName.css}
  • --follow I'm not sure why this isn't turned on by default. If you specify a single file for git log (as we do here), and that file is renamed, this will keep following changes through the old file. Without this flag, git log would end where the file was renamed. You won't be able to see the original author of a line, because it will be in old file name.

  • --stat Optional: show a summary of the total additions and removals for that commit. Can be useful for getting a big picture idea.

  • -- path/to/file (Two dashes and a space) The -- is the convention for Git (and some other bash commands) to specify a single file. Remember we're using --follow so git will still treat any renames as a single file to follow.

Now What?

Now you're in a searchable list of commits being displayed through your shell's pager program (this is usually the less program).

For example, let's say you want to find the author of this line of the Three.js source code:

    this.quad.material.stencilTest = maskActive;

We want to search the output of the git log command for this line. Copy part of the line that's likely to be unique, like this.quad.material.stencilTest, then search for it in the pager output by pressing / (forward slash), then paste, then Enter to jump to the first result for that line.

Now, a trick is to press G (shift-g) to jump to the end of the log results, then press N (shift-n) to search backward from the end of the logs to the previous match. This will usually be the original change!

The line in the codebase found with git log

If not, you can bounce around the matches with n and N to keep looking.

To find the author of this commit, once your pager is focused on this line, a simple trick is to search backwards for the word commit. To make sure you don't lose your place, start a backwards search using ? instead of /. Just type ?commit then Enter.

Ta-da, our commit author!

Git commit author found using git log

I chose this specific example because in this case, git blame would have shown the commit which changed the indenting of this line which isn't helpful.

Now You Can Yell At Someone!

You can now ping the commit author with the commit hash and ask them your question!

That's It!

If this post helped you improve your Git fu, consider following me on Twitter or buying me a coffee :).

comments powered by Disqus