DEV Community

jidonglab
jidonglab

Posted on

AI Commit Messages Killed My git log. Here's the Autopsy

2 a.m., invoices are double-charging, and git bisect finally hands me the guilty commit. I read the subject line:

refactor: simplify retry logic in fetchInvoices
Enter fullscreen mode Exit fullscreen mode

Technically accurate. Completely useless. I wrote that message the way I'd written every message for the previous month: I hit a key, an AI read my staged diff, and it told me what my staged diff said. After thirty days of AI commit messages, my repo had a perfect, tidy, uniformly formatted history that could no longer answer a single question I actually had.

TL;DR

  • AI commit messages are generated from the diff, so they can only ever restate the what. The why was never in the input.
  • The why is the entire reason commit messages exist. git show already gives you the what, for free, forever.
  • Side effects I hit: git log --grep stopped finding things (vocabulary collapses to the same 40 verbs), and mislabeled refactor:/chore: prefixes poisoned my changelog and semver bumps.
  • They're genuinely great for mechanical commits: dep bumps, lockfiles, formatting, generated clients.
  • The fix that stuck: let the model draft the body, but require one human-written line starting with Why:, enforced by a commit-msg hook.

Why are AI commit messages useless for debugging?

Because a commit message generated from a diff is a lossy compression of information you already have. The diff is the ground truth. Summarizing it in English adds zero new bits.

Everything valuable in a commit message comes from outside the diff:

  • The vendor's rate limit changed from 100/min to 20/min at the start of the month.
  • We picked exponential backoff over a queue because the queue would have needed a new deploy target.
  • The retry count is 3 and not 5 because 5 blew past the gateway's 30s timeout.

None of that is in the patch. No model, at any parameter count, can extract it from the patch. This isn't a prompt problem. It's an input problem.

That mislabeled commit above? The real story was that our payment vendor started returning 202 Accepted instead of 200 for slow settlements. My retry logic treated any non-200 as retryable. Retry, retry, retry, charge, charge, charge. The word "vendor" appears nowhere in the diff. The AI never had a chance.

What actually broke in my git history?

Three things, roughly in order of how much they hurt.

1. git log --grep stopped working. Human commit messages are weird, and weird is searchable. I search for --grep=stripe, --grep=timeout, --grep=hotfix, --grep=DO NOT. The model doesn't write like that. It converges hard on the same small vocabulary: update, refactor, simplify, improve, handle, ensure, add support for. Run this on your own repo:

git log --format=%s -300 \
  | tr 'A-Z' 'a-z' | tr -cs 'a-z' '\n' \
  | sort | uniq -c | sort -rn | head -20
Enter fullscreen mode Exit fullscreen mode

On the AI-authored month, my top 20 words covered a depressing share of every subject line I'd written. On the year before it, the same top 20 covered far less. Search works on entropy. The model deletes the entropy.

2. Conventional commit prefixes got quietly wrong. The model classifies by shape, not by consequence. Change a default value from false to true? That looks like a one-line tweak, so it gets chore: or refactor:. It was a behavior change for every existing caller. My release tooling read the prefix, cut a patch version, and shipped a breaking change to people who had pinned ~. The AI didn't lie. It just doesn't know that a boolean flip is a feature and a rename is not.

3. git blame turned into wallpaper. Blame is only useful when the line you're pointing at leads to a message that surprises you. When every message is a fluent English translation of the line you're already staring at, blame becomes a very slow way to re-read your own code.

Can you fix AI commit messages with a better prompt?

Partly, and only by feeding the model things that aren't the diff. I tried the obvious escalations, in order:

  • "Explain why, not what." The model complies by inventing a why. fix: handle 202 responses to prevent duplicate charges sounds like causal knowledge. It's a plausible guess retro-fitted onto the patch, and a confident wrong why is worse than no why, because I'll believe it at 2 a.m.
  • Pipe in the branch name and the ticket ID. Real improvement. Suddenly the message has a fact from outside the diff. Your branch names have to be better than fix-thing-2.
  • Pipe in the failing test output or the issue body. Best result by far. The model becomes a summarizer of real context rather than a narrator of code, which is what it's good at.

That last one is the tell. AI commit messages get good exactly when you hand over the context you already had in your head. Which means the bottleneck was never the writing.

When are AI commit messages actually good?

Genuinely often, and I still use them:

  • Dependency bumps, lockfile churn, generated API clients. The what is the why. Nobody will ever ask why the lockfile changed.
  • Formatting and codemod sweeps across 400 files.
  • Subject-line hygiene: imperative mood, under 72 chars, consistent prefix. My handwritten ones were sloppier.
  • Drafting the body of a big commit as a bullet list of what changed, which I then edit. Editing beats staring at an empty buffer.

The rule I ended up with: if a future engineer would ever ask "wait, why?", a human writes that sentence. Otherwise, let the machine do it.

How do you enforce the "why" without becoming annoying?

One commit template and one hook. The template:

# <type>: <subject>
#
# Why:
Enter fullscreen mode Exit fullscreen mode

And a .git/hooks/commit-msg that refuses an empty Why::

#!/usr/bin/env bash
msg_file="$1"
grep -q '^Why: .\{15,\}' "$msg_file" && exit 0
case "$(head -n1 "$msg_file")" in
  chore*|build*|style*) exit 0 ;;   # mechanical commits get a pass
esac
echo "Commit rejected: add a 'Why: ...' line explaining the reason, not the change." >&2
exit 1
Enter fullscreen mode Exit fullscreen mode

Fifteen characters is a low bar on purpose. The point isn't essay length, it's forcing a context switch from describing to explaining. My Why: lines are mostly one sentence: Why: vendor started returning 202 for slow settlements on 2026-08-14. That single line would have saved me the entire bisect.

Want to know if your repo already has this problem? Count how many of your last 300 commits have any body at all:

git log --format='%H%n%b' -300 | grep -c '^$'
Enter fullscreen mode Exit fullscreen mode

If nearly all of your commits are a subject line and nothing else, your history is already a diff with extra steps, and AI just made it faster to produce.

So, do AI commit messages ruin git log?

They ruin it whenever you let the model see only the diff, because a commit message written from a diff can only restate the change, and the change was never the part worth writing down. git show already stores the what perfectly. The commit message is the only place in your entire repository where the why lives, and the why exists in your head, your ticket tracker, and your vendor's changelog, not in the patch. Use AI commit messages freely for mechanical work, feed the model issue text and test output when you want a real body, and hand-write one Why: line for anything a future engineer might question. That one line is the whole job. The AI was never doing it.

Top comments (0)