Getting tests into git core

Aug 3, 2026

git merge-base --is-ancestor A B answers a yes/no question — is A an ancestor of B? — and returns it as an exit code: 0 for yes, 1 for no. Shell scripts lean on it constantly (“has this branch been merged yet?”). It’s load-bearing plumbing.

It also had no tests.

I noticed while reading t/t6010-merge-base.sh for something unrelated. There were tests for --all, for the octopus cases, for the plain merge-base — but nothing exercising --is-ancestor at all. No test pinned the exit-code contract that every script depends on. So I wrote some.

What the tests actually cover

Three things, all about the contract rather than the happy path:

Plus two guard cases: --is-ancestor can’t be combined with --all, and the error message names both options so the user knows what conflicted; and it requires exactly two commits (too few is a usage error, too many is rejected explicitly).

None of this changes behavior. It documents and locks the behavior that was already there — the kind of test that only matters the day someone refactors the option parser and quietly breaks the exit codes.

Contributing to git is not a pull request

Here’s the part that surprised people when I described it: git doesn’t take GitHub pull requests. The github.com/git/git repo is a read-only mirror. Development happens on a mailing list — you send patches as emails, and review happens as email replies.

I used GitGitGadget, a bot that bridges the two: you open a PR against its fork, it turns your commits into a properly-formatted patch series and posts them to the list for you, then relays the review back onto the PR. It handles the mechanics (git format-patch, threading, the Signed-off-by trailer) so you can focus on the change.

The review itself is old-school and exacting. Two rounds:

The “cooking” pipeline

git integrates changes through a sequence of branches, and watching your topic move through them is oddly satisfying:

  1. seen — proposed, integrated for testing. (Your patch shows up here first.)
  2. next — accepted, cooking toward the next release.
  3. master — shipped.

My topic, ns/merge-base-is-ancestor-tests, went the whole distance: after cooking in next, Junio merged it to master. The tests are now part of git itself.

Why bother

A test-only change to a 20-year-old tool isn’t glamorous. But it’s exactly the kind of contribution that’s welcome — it’s low-risk, it’s obviously correct, it fills a real gap, and it respects the maintainers’ time. That’s the whole trick to contributing to a project you didn’t start: find the thing that’s clearly missing, make it small, make it verifiable, and follow the local customs to the letter — even when the local customs are a mailing list and a bot from 2019.

More on how I pick those changes — and how I’ve landed 30-odd of them across the CNCF, Python, and Rust ecosystems — in a later post.

← All posts