$ Git Game

Who broke main

Something on main is wrong and you want the commit that did it, not the person. Git has three answers, each costing a little more: which commit last touched the line, which commit added the word, and which commit first made a test fail.

The line: git blame

$ git blame api.py
ab5768d4 (ana 2026-10-04 12:02:00 +0000 1) line 2
8498150e (ana 2026-10-04 12:03:00 +0000 2) line 3
7742196e (ana 2026-10-04 12:04:00 +0000 3) bug
d345f958 (ana 2026-10-04 12:05:00 +0000 4) line 5
56d85dcb (ana 2026-10-04 12:06:00 +0000 5) line 6
$ git log -S bug --oneline
7742196 api: handle the edge case

Each line of the file with the commit that last changed it, its author and the date. The line that reads bug came from api: handle the edge case. Blame knows only the last touch: a reformat makes the formatter the author of every line, which -w (ignore whitespace) and --ignore-rev (ignore that commit) work around. git log -S bug goes further back: every commit that added or removed the word, wherever in the file it was.

The commit: git bisect

When you know main was good a while ago and is bad now, bisect does the search: it checks out the commit halfway between, you say good or bad, and it halves again. With a script that exits 0 for good and anything else for bad, git bisect run does the saying. Here the script is two lines, and the bug is a line in a file:

#!/bin/sh
! grep -q bug api.py
$ git bisect start HEAD HEAD~4
Bisecting: 1 revision left to test after this (roughly 1 step)
[7742196e73c4f9d00384d5d5b6fd8497d2fff238] api: handle the edge case
$ git bisect run ./check.sh
running './check.sh'
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[8498150ec9ca1a65dbaa1d2658471bd99d3c9008] api: add the endpoint
running './check.sh'
7742196e73c4f9d00384d5d5b6fd8497d2fff238 is the first bad commit
commit 7742196e73c4f9d00384d5d5b6fd8497d2fff238
Author: ana <ana@example.com>
Date:   Sun Oct 4 12:04:00 2026 +0000

    api: handle the edge case

 api.py | 1 +
 1 file changed, 1 insertion(+)
bisect found first bad commit
$ git bisect reset
Previous HEAD position was 8498150 api: add the endpoint
Switched to branch 'main'
Your branch is up to date with 'origin/main'.

Four commits, two steps, and the first bad commit with its full record. git bisect reset returns to where you started. The usual script runs the test suite or the build; anything that can tell good from bad will do, and the search is the same for forty commits as for four, a few steps more.

The name

The command is called blame and the practice around it is called blameless, and both are right. The commit is the fact; the person is not the finding. A post-mortem that stops at a name learns nothing about why the line looked right to everyone who read it.

Why the game does this to you

In Git Game a bug is printed on a card, and only its holder sees it, so a commit on main may hide one until the release flips every commit face-up. blame is a card: play it on a face-down commit on main, and if it holds a bug its author takes -3 blame now, with the commit left face-up. bisect is in the tabletop deck, pointed at a range of main: its owner must say which half holds a bug. It isn't played online yet.

Play a day where this happens

One tap starts a game against the bot, whose commits hide bugs as yours do.

play the bot now

Output captured from Git 2.50.1 (Apple Git-155) by scripts/git-output.sh, in a scratch repository with two clones, ana's and bot's, and fixed dates, so the hashes are the same on every run. It is captured again at every Git release.