Programming often involves detective work. Properly fixing a problem often requires understanding how the problem came to be in the first place.

One of the best tools for code detectives is git blame. With it, you can trace the lineage of every line of code in your codebase. Armed with this knowledge, you can often find out why the code was added, or at least who added it (so you can inquire further about the offending code).

But git blame only works on existing lines of code. What about tracing the lineage of deleted code? How do you dig through the ghost of codebase past?

There's another tool for that: git log -S!


I'll demonstrate how it works with a real-life example.

A coworker recently asked me what the deal was with a state machine that was purposefully dropping some states on the floor:

fun handleAuthData(authData: AuthData) {
  when (authData.state()) {
    // ...A bunch of handled states...
    
    AuthData.State.ERROR_BAD_EMAIL,
    AuthData.State.ERROR_BAD_PASSWORD -> {
      // States we don't really care about
    }
  }
}

Weird, right? You'd think we'd want to tell the user if they entered a bad email or password. What's even stranger is that these enums aren't read anywhere else in the codebase - they're parsed from the server, but never used.

There are two possibilities here. Possibility one is that these states are no longer necessary and thus we should delete them entirely from the codebase. Possibility two is that these error states used to be handled somewhere but the handling code was deleted by accident. How do I know which case it is? How do I find out its past?

git log -S to the rescue!

You see, git log -S lets you find all instances of a string in your repo's history. It's fantastic for finding deleted code.

Let's use it to find out who was using this enum in the past:

$ git log -S ERROR_BAD_EMAIL

  commit 1a2b3c4d5e6f
  Author: Dan Lew <>
  Date:   Thu Oct 1 13:00:11 2015 -0500

      Clean out old unused auth code

Digging into the actual commit, I can see that I deleted code which I thought was unused, but it turns out was handling these states... Oops!

Once again, I have proven this adage:

Now we know why the code was removed: it was an accident! As such, we should start handling these error states again.


There are more complex ways to use git log -S - for example, specifying a subset of files to search, or searching via regex with git log -G - but honestly, all I've ever needed is a simple string query.

(It's worth noting that git log -S will not find commits wherein the serach string was moved within a file; if you need that, git log -G is preferable.)

git log -S is one of my favorite random git tools, I hope you find it valuable for your work as well.