NullTerminator All articles
Developer Culture

git blame and the Art of the Digital Crime Scene

NullTerminator
git blame and the Art of the Digital Crime Scene

The call, as they say, is coming from inside the house.

You've been staring at a function for twenty minutes. It's doing something deeply, structurally wrong — the kind of wrong that suggests it was never right, not even on the day it was written. The logic is backwards. The variable names are cryptic. There is a comment that says // temporary fix dated three and a half years ago. Someone introduced this code into your codebase with intent and purpose, looked their colleagues in the eye, and said nothing.

You need answers. You need a name. You need [git](https://en.wikipedia.org/wiki/Git) blame.

The Forensic Toolkit: What You're Actually Working With

Git is, among other things, the most comprehensive surveillance system ever deployed on software developers. Every change is logged. Every author is tagged. Every timestamp is preserved with the kind of fidelity that should make you uncomfortable about that commit you pushed at 1:30 AM with the message "fix".

git blame [filename] is your first instrument. It annotates every line of a file with the commit hash, author name, and timestamp of the last modification. Run it on the file containing the cursed function and you will immediately know who touched it last. Note: who touched it last is not always who introduced the original sin. This distinction matters. We'll return to it.

git log is your case file. git log --oneline gives you the compressed version — a list of commits, hashes, and messages, scrolling back through time like a paper trail left by someone who didn't expect to be investigated. git log -p shows you the actual diffs. git log --author="[name]" lets you pull a specific developer's entire rap sheet.

git bisect is the tool you reach for when you know the code used to work and you need to find the exact commit that broke it. It performs a binary search through your commit history, checking out commits one by one until it isolates the culprit. Using git bisect feels like real detective work. It is methodical. It is satisfying. It is occasionally devastating when it lands on a commit you made.

git show [commit-hash] pulls up the full context of a single commit — the diff, the message, the author, the timestamp. This is where you read the crime scene narrative.

Reading Commit Messages as Evidence

A commit message is a window into the mental state of a developer at a specific moment in history. Learn to read them.

"Fixed bug" — Uninformative. The developer knew what they were doing but either didn't think documentation mattered or was in a hurry. Low accountability. Probably fine.

"Fix" — The developer was in a hurry and also slightly defeated. The commit may contain anything. Treat as unknown substance.

"WIP" — This was never supposed to be permanent. It is permanent.

"Hotfix for production" — Something was on fire. This commit was written while standing. Do not trust any of the assumptions baked into it.

"Should work now" — It did not work before. The author is not certain it works now. The phrase "should" is doing significant load-bearing work in this message.

"Not sure why this works but it does" — The most honest commit message in the history of software development. Treat the code within as sacred and untouchable. The author stumbled into a solution through means they cannot explain. Rewriting it will not produce the same result.

"Temp" — See: every "temporary" solution you have ever encountered that is now load-bearing infrastructure.

Tales From the Archaeology Pit

The community has stories. They always have stories.

One developer described running git blame on a particularly baffling authentication middleware at their previous job — the kind of code that had clearly been written by someone who understood neither the framework nor the security requirements, but had tremendous confidence in both. The blame pointed to a commit from eighteen months prior. The author field displayed their own name.

"I sat there for a full minute," they said. "Just reading my own name. On this code. That I clearly wrote. I have no memory of writing it. It is possible I was not okay at the time."

This is the great existential risk of git archaeology: you will eventually excavate yourself. Your past self is always somewhere in the commit history, cheerfully introducing technical debt and writing commit messages like "updated stuff" with the casual indifference of someone who genuinely believed they would remember what "stuff" meant.

Another developer found a comment in a decade-old Rails codebase that read: // I know this is wrong. Management said ship it. The commit message was per stakeholder request. The original author had been thorough enough to document both the wrongness and the reason, which is almost admirable. The code had been running in production, wrong and per stakeholder request, for nine years.

The Diplomacy of Blame (This Is the Hard Part)

You have found the commit. You have a name. You have a timestamp and a diff and a commit message that ranges from cryptic to confessional. Now what?

First, a principle: the person who last modified a line is not always the person who made it wrong. A developer who touched a function to add a single parameter three years ago did not necessarily author the structural problems in that function. git blame shows last-touch, not original sin. For deeper archaeology, you need git log -S "[code snippet]" to find when specific content was first introduced. This is the difference between finding the last person at the scene and finding who actually did it.

Second, a cultural reality: most bad code was written under bad conditions. The 1:30 AM commit. The hotfix before a product launch. The "we need this by Friday" feature request that arrived on Thursday. The commit history is also a record of the pressures your team was under, and those pressures were rarely created by the person writing the code.

This doesn't mean you can't ask questions. It means the question shouldn't be "why did you write this garbage" but rather "I found this in the history and I'm trying to understand the original intent before I refactor it — do you remember anything about the context here?"

This framing accomplishes two things. It treats the original author as a resource rather than a suspect. And it gives them the opportunity to say, "Oh, yeah, don't touch that — there's a weird dependency on that behavior in the billing module that isn't documented anywhere."

That information, right there, is worth more than the satisfaction of assigning blame.

The Final Verdict

Git archaeology is one of the most genuinely useful skills a developer can develop, and one of the most underused. The history is there. The evidence is preserved. Every decision your codebase has ever made is sitting in that log, waiting to explain itself.

Some of what you find will be inexplicable. Some of it will be the product of reasonable decisions made under unreasonable constraints. Some of it will be yours.

When you find yours, resist the urge to quietly amend the commit. The history is the history. Leave it. Learn from it. Write a better commit message today so that the developer who runs git blame on your code in 2027 has something to work with.

They're going to find you anyway.

All Articles

Related Articles

Why a $4 Plastic Duck Is the Best Debugging Tool You're Not Expensing

Why a $4 Plastic Duck Is the Best Debugging Tool You're Not Expensing

Skeletons in Your Repository: The Art of Pretending Those Commits Never Happened

Skeletons in Your Repository: The Art of Pretending Those Commits Never Happened

Fencepost Syndrome: The Bug That Keeps Humbling Every Programmer Who Ever Lived

Fencepost Syndrome: The Bug That Keeps Humbling Every Programmer Who Ever Lived