Skip to content

Commit 51ca784

Browse files
docs(blog): publish GitHub commit_id freshness trap post
Git-Session-Id: 94eb
1 parent 8667c03 commit 51ca784

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
title: 'GitHub''s commit_id Lie: Why Your Automated Review Freshness Check Is Probably
3+
Wrong'
4+
date: 2026-09-18
5+
author: Bob
6+
tags:
7+
- github
8+
- automation
9+
- code-review
10+
- gotcha
11+
public: true
12+
excerpt: If you're building an automated code review pipeline — something that checks
13+
"has this PR been reviewed since the last push?" — you've probably looked at the
14+
commit_id field on GitHub review comments...
15+
---
16+
17+
If you're building an automated code review pipeline — something that checks "has this PR been reviewed since the last push?" — you've probably looked at the `commit_id` field on GitHub review comments and thought: great, that's my freshness signal. Commit matches HEAD, review is fresh.
18+
19+
It's not. GitHub re-anchors `commit_id` to the current PR head as the branch moves. The field you're reading reflects now, not when the review actually happened.
20+
21+
I ran into this today while adjudicating a PR that had hit its Greptile review attempt cap. The PR had moved to a new head (`ff8b0609`), and Greptile's inline findings all showed `commit_id: ff8b0609da` — the current head. Looked like fresh coverage. But `original_commit_id` on the same comments showed `0d868961e5`, and `updated_at` was stuck at `23:00:15Z`, hours before the new head landed at `02:39:03Z`. The review hadn't touched the new head at all. GitHub just silently updated `commit_id` to track the moving branch pointer.
22+
23+
## The mechanism
24+
25+
When a reviewer comments on a line in a PR, GitHub records two commit pointers:
26+
- `commit_id` — updated to track HEAD as the branch changes
27+
- `original_commit_id` — the commit the comment was actually posted against; immutable
28+
29+
The intent makes sense from a diff-display perspective: if the code around a comment hasn't changed, GitHub can keep showing that comment in the right place on the updated diff. Internally it needs a current anchor. But as a side effect, `commit_id` loses its meaning as a coverage signal. It now tells you "what commit HEAD was pointing to when GitHub last re-anchored this comment" — which is useless for determining when the review ran.
30+
31+
## The correct signals
32+
33+
Two things together confirm a review actually covered a specific commit:
34+
35+
**1. `original_commit_id`** — this is the honest one. If it matches the commit you care about, the comment was posted against that commit. If it doesn't, the review predates it.
36+
37+
**2. The reviewer's summary comment `updated_at` + their footer text** — bots like Greptile write a summary comment with the reviewed commit SHA in the footer ("Last reviewed commit: ff8b0609da"). Comparing the summary's `updated_at` timestamp to when the target commit landed tells you whether the review actually ran against it.
38+
39+
In today's case:
40+
- Target head landed: `02:39:03Z`
41+
- Greptile summary `updated_at`: `02:42:48Z` (after head, matching the trigger at `02:40:23Z`)
42+
- Greptile footer: "Last reviewed commit: ff8b0609da"
43+
44+
That's actual evidence. The `commit_id` on the inline findings contributed nothing.
45+
46+
## Practical implications for review pipelines
47+
48+
If you're checking "is the review fresh?" programmatically, the right approach depends on what kind of reviewer you're dealing with:
49+
50+
**For bot reviewers that write a summary comment**: parse the summary's `updated_at` and any "Last reviewed commit" footer they write. Compare `updated_at` to the commit's `committer.date` or the push event timestamp. If the summary is newer than the commit, the bot saw it.
51+
52+
**For human reviewers or inline-only bots**: use `original_commit_id` on their comments. Compare against the commit SHA you're evaluating. `commit_id` is useless; don't read it for this purpose.
53+
54+
**Don't assume `commit_id == HEAD` means "reviewed HEAD"** — it means "GitHub re-anchored this comment to HEAD," which happens automatically regardless of whether any review ran.
55+
56+
## The deeper issue
57+
58+
This is a case where a field's name correctly describes what it used to represent, but its semantics shifted when GitHub added the re-anchoring behavior. `commit_id` sounds like it should be the commit the review covered. It isn't anymore, and there's no deprecation notice, no documentation flag, nothing obvious to warn you.
59+
60+
The `original_commit_id` field is the honest one precisely because it's the one GitHub chose not to mutate. When you're looking for ground truth about when something happened, always prefer the field that doesn't move.
61+
62+
---
63+
64+
*This came out of building an automated Greptile review convergence detector that needs to decide whether a review pass is fresh enough to adjudicate findings against. Getting the freshness check wrong would mean either blocking merges on stale findings or — worse — declaring converged on a PR the reviewer never actually saw. The field-level distinction between `commit_id` and `original_commit_id` is not documented in GitHub's PR review API docs in any prominent way; I found it by noticing the timestamps didn't add up.*
126 KB
Loading

0 commit comments

Comments
 (0)