Back to Feed
article 3m read

Recorder dropped a borrowed commit, and my own server put it right back

Fresh branches were tagging sessions with the base branch's commit, so one error could match all of them. A merge-base check now drops that commit on the laptop, but the server's code-host lookup and backfill fill it straight back in for any pushed branch.

Article DepthPractice

Flow

What gets stored for each kind of branch

  1. 1New branch, not pushed

    Usually branch name only. The gate drops the commit, though a later push or an old pull request with the same name can bring one back.

  2. 2New branch, pushed

    The shared commit comes back from the server lookup.

  3. 3Branch with its own commit

    Its own commit is kept, as it should be.

  4. 4No branch name

    The check is skipped and the commit is kept unexamined.

  5. 5Old session, no commit in transcript

    Possibly today's commit from the working copy, which can be far too new.

A brand-new branch has no commits of its own, and my session recorder wrote one down for it anyway.

The recorder tags each coding session with its repo, branch and commit. When the error tracker says a bug came in with some commit, the tool looks for sessions with that commit. I trusted the commit more than the branch name, because names change and commits don't.

The catch is that a new branch with nothing committed points at the same commit as the branch it came from. The old recorder saved that shared commit. So every fresh session cut from the same spot got the same commit, and one error would match all of them equally. I haven't checked how often that sent me the wrong way.

Asking Git whether the commit is mine

What matters is whether this branch made the commit. Git can tell you by finding the merge base, the last commit both branches share.

If the current commit is the merge base with main, the branch has nothing of its own yet.

The recorder now does that check first. It finds the base branch by trying common names, then reads the remote's default from the locally stored remote HEAD. If the tip is the merge base, it drops the commit and keeps the branch name. Use the merge base, not the base's tip, because the base keeps moving.

If it can't tell, it keeps the commit. That happens when there's no base, the check fails, or I'm on the base itself. A checkout with no branch name skips the check too.

Branch names that go into shell commands now have to pass a plain character check, or they get dropped. It's safer, but some real names lose their tag.

The server put it right back

The server side of the same change undoes the gate for any branch I've pushed. When a session shows up with a branch but no commit, the server asks the code host for that branch's tip and fills it in. For a pushed empty branch, that's the same shared commit again. Mostly only unpushed branches keep the gate's answer.

A backfill job does this in bulk, and it looks for exactly the rows the gate leaves empty. It writes today's tip, so a fresh branch gets the shared commit back and a busy branch gets a commit from after the session. It only reads one page of branches, so the rest are skipped.

The importer falls back to today's checkout

The importer for old sessions used to leave the commit blank on purpose. Now it can fall back to whatever the working copy points at today. The gate catches the shared commit, but not a commit that's mine and simply too new.

If I were building this again, I'd run the "is this commit mine" check wherever a commit gets written, not just on the laptop. I'd mark where each commit came from, so a looked-up one counts for less. And I wouldn't fill a blank commit with a branch's current tip.

For old sessions, I'd rather store no commit than today's.

Keep reading

Pick up a connected idea or branch into a nearby one.

5 paths forward