My "Git Blame" Stack

My job as an Engineering Manager requires me to use Git Blame every single day (this is really not an exaggeration!). In this post, I will go into a few different things:

  1. The GitLens VSCode Extension (my "Git Blame" stack)
  2. Optimizing code for Git Blame

Git History is essential for various day-to-day activities for me:

  • Triaging bugs (and more specifically, finding the right assignee for new issues)
  • Helping out with incidents and debugging problems with our systems
  • Diagnosing failing or flaky tests
  • (Passive) Building mental models of different parts of our various codebases as I scroll through code many times a day

This last bullet point might be a bit confusing, so I want to explain it further. As I scroll through code in my IDE, I have a tiny widget on the bottom right of my screen which tells me who last touched a line of code and when:

Whether I'm actively writing code or just browsing through, this widget helps me build a mental model of how fresh different parts of the codebase are and who has been working on them. This memory map will come in handy during incidents, or in other contexts where I might be asked who the right person to talk to is about a given issue. It also allows me to categorize certain parts of the codebase as "actively developed" or "dormant" which is useful for thinking about refactors or architecture changes.

The GitLens VSCode Extension

I use the GitLens VSCode Extension for most of my usage of Git Blame (but I also use the GitHub and GitLab UIs some times). This is my GitLens configuration:

"gitlens.hovers.currentLine.over": "line",
"gitlens.currentLine.enabled": false,
"gitlens.codeLens.enabled": false,
"gitlens.hovers.enabled": false,

I basically disable the inline Git Blame indicator in favor of the status bar widget because it is too distracting when reading code. But GitLens has a lot of interactive features around Git Blame as well:

When you inspect a line of code's Git Blame, it allows you to open that commit in GitHub/GitLab but it also offers a bunch of other features as you can see in the screenshot above.

Generally, the GitLens extension is fantastic and I highly recommend it. Its Git Blame features are just the tip of the iceberg, since it offers a lot more capabilities around exploring Git repositories.

Optimizing Code for Git Blame

Because Git Blame is so important, I believe in optimizing code style for Git Blame (not necessarily always, but whenever it makes sense). I want to give a few of examples of where this applies.

Example 1: Declaring multiple variables in a single line of code

When considering Option A vs Option B:

// Option A
let memoryAverage, memorySum, memoryTotal;

// Option B
let memoryAverage;
let memorySum;
let memoryTotal;

I strongly favor Option B since it allows us to modify these variable names down the road without breaking the Git History too much. In other words, by separating these declarations, we have a more fine-grained Git History.

Example 2: Aligning object literals

// Option A
//
type Props = {
    inputProps: React.HTMLProps<HTMLSelectElement>;
    className?: string;
    extremelyLongTestId?: string;
}

// Option B
//
type Props = {
    inputProps:                React.HTMLProps<HTMLSelectElement>;
    className?:                string;
    extremelyLongTestId?:      string;
}

I realize that Option B is probably easier on the eyes for most, but it is not good for Git Blame. As the object's shape changes over time, the whitespace changes will effectively break Git Blame.

Of course, it might be possible to get around this with proper tooling that ignores whitespace changes for Git Blame, but that's not how most tools work by default. Notice also that others and I use the GitHub/GitLab UIs for Git Blame as well and these currently do not ignore whitespace changes.


Final Note: Using .git-blame-ignore-revs

There is a convention to have a file called .git-blame-ignore-revs at the top of your repositories with a list of commit hashes that should be excluded from Git Blame. This is really important for making sure that big code style changes do not pollute your Git Blame history.

I'll just leave you with a link to a good blog post which explains everything about this: A better git blame with --ignore-rev.

Wrapping Up

It took me a few years into my career to really become proficient with Git History and Git Blame, but once I got the hang of it, I never looked back. It's a really powerful tool and I recommend everyone to invest some time in getting it set up properly in their development environments.