The tiny git-notes habit that saved review context in our worst PRs

How I used git notes to attach reviewer context to commits, the automation that made it reliable, and the squash-merge gotcha that nearly erased months of history.

Written by: Arjun Malhotra

Hands typing on a laptop keyboard with a code editor visible on the screen
Photo by Annie Spratt on Unsplash

The PR had ballooned to 18 commits and four reviewers. We were on a call, screen-sharing the diff, and every time someone asked “why this change?”, I had to re-open old messages, search Slack, or scroll through thirty commits to find the context. The worst part: the explanation often lived in a review comment tied to a now-rebased commit SHA. Nobody could tell whether a behavior was deliberate or accidental. We wasted minutes — sometimes hours — re-explaining decisions.

That was the moment I stopped relying on scattered PR comments and started attaching the context directly to commits: git notes. Small change, big friction reduction. Here’s what I actually did, why it worked for us in an Indian startup with flaky office internet and hurried reviewers, and the one mess-up you should plan for.

Why git notes, not PR comments I wanted review context close to the code and versioned with it. Commit messages are for intent. PR comments are ephemeral and tied to GitHub’s UI. Git notes are just refs/notes that sit in the repo and attach free-form text to a commit SHA. They don’t change the commit object, so they’re safe, searchable locally, and part of the git workflow.

Practical wins in week one:

The workflow we actually used We kept it deliberately tiny so people would adopt it. No UI, no extra apps — just three commands you already have.

  1. Add a reviewed note: git notes —ref=review add -m “LGTM after fixing null-case. See: discussion thread #42”

  2. Read it: git notes —ref=review show

  3. Push notes: git push origin refs/notes/review

That last step is crucial. By default notes live only locally. We automated the push inside a tiny git alias and a GitHub Action that, on PR update, pulled refs/notes/review and appended a one-line summary to the PR body if the repo had a protected merge strategy (more on that later). The result: even people who never ran git had the notes accessible via the PR.

The automation that made it stick People will adopt only if friction is near zero. We built two tiny automations:

The real tradeoff: rebases, squashes, and the week we almost lost history We learned the hard way that git notes bind to commit SHAs. That’s also their strength — immutable link to a snapshot. But when a team rebases or uses squash-and-merge, those SHAs change or disappear. One Friday we did a cleanup: squashed and force-pushed a long-running feature branch. The git notes were still in the remote under refs/notes/review, but they were attached to commits that no longer existed in the branch. The GitHub Action appended a bunch of now-orphaned summaries to the PR body, and our local git notes looked stale.

We nearly lost months of contextual history because:

Fixes we implemented:

Limitations and the Indian dev-context realities

One honest failure We tried to capture full review threads into notes for completeness. It grew fast and became unreadable in the terminal. The habit died quickly. The right balance was a one-paragraph decision summary in the note and a link to the long thread. Brevity matters.

What I walked away with Attach context to commits close to the code, but don’t treat git notes as magic. They save time when used sparingly and with a clearly documented merge strategy. For us, the tiny win was not the notes themselves but the habit: stop re-explaining decisions. Put a one-line summary where someone can find it without reopening Slack.

If you try this, start with a two-command habit: add the note, push the ref. Add an automation that copies a minimal summary to the PR before any destructive merge. That one extra minute per review saves an afternoon of lost context later.