A settings page that commits to your default branch
Type a domain into GitHub Pages settings and it writes a CNAME file to main, authored as you. Put that file there yourself and the settings field fills in. Neither side is labelled as the one that wins.
Facts cited
| Developers on GitHub | 180 million+ | GitHub Octoverse, 2025 |
|---|---|---|
| New repositories created | 230 per minute (~121M/yr) | GitHub Octoverse, 2025 |
| How a custom domain is stored | A CNAME file in the published branch | GitHub Pages documentation |
| This site's own history | commit 8452723 — "Update CNAME", committed by GitHub itself | PlanetaryCouncil/ux, 28 July 2026 |
| Global life expectancy | 73 years | World Bank, 2023 |
Assumptions low → high
| What we can't measure | low | likely | high |
|---|---|---|---|
| Custom domains set or changed per yearNo public figure for Pages sites on custom domains. Reasoned from repo volume. | 300,000 | 1 million | 3 million |
| Share who lose time to the mystery commitReading docs or history to work out what wrote to their branch. | 8% | 15% | 25% |
| Share who hit a real conflict or a blocked writeBranch protection, a long-lived branch touching the same file, or two writers. | 0.5% | 2% | 5% |
Who can fix it
- Owner
- GitHub (Pages settings, custom domain field)
- Channel
- GitHub Community / feedback
Setting a custom domain on GitHub Pages does something no other settings field does: it writes a commit to your default branch. Not a config store, not repo metadata — a file, in your tree, in your history, attributed to you.
This site’s own history has one:
Update CNAME · author: you · committer: GitHub
It works in the other direction too. Commit a CNAME file yourself and the settings field
fills itself in. Two paths to one value, and nothing on either screen says which one is
the source of truth.
The steelman, which is strong
Storing the domain as a file is good design, and the obvious complaint is wrong.
A file is portable. It survives a repo transfer, a fork, a rename, a migration to another
host. It can be reviewed, diffed, and set from a script without a token. Every other Pages
setting — the build source, HTTPS enforcement — is click-only state that exists nowhere in
your repository, so you cannot reproduce a working site from its own contents. The CNAME
file is the one part you can. It is the good half.
The problem isn’t the file. It’s the undeclared direction.
The principle
A two-way sync needs a stated winner. Either the file is authoritative and the field displays it, or the field is authoritative and the file is generated output. GitHub does neither: both sides accept writes, both silently overwrite the other, and one of them is a push to the branch your project protects most carefully.
Three costs follow, and only the first is small:
- The mystery commit. Someone reads
Update CNAMEin the log and goes looking for who ran it. Nobody ran it. A settings page did. - The conflict. A long-lived branch that also carries
CNAMEnow diverges frommainbecause of a UI action nobody recorded in a ticket. - The protected branch. A repository can require pull requests, linear history, or signed commits. A settings field that writes directly to that branch is either an exception to rules the team agreed on, or a failure with no obvious cause. GitHub’s web commits carry its own signature, so a signing rule likely passes — which is its own oddity, since the author is you and the signature is GitHub’s.
There is a fourth, and it is the one that produced this case. Two writers went for the same value: a file was pushed over git, then the settings field was opened to set the same thing by hand — because neither person involved could tell which one counted. That is not a knowledge gap. The screen does not say.
The fix
One sentence under the field:
This is stored as the
CNAMEfile in your default branch. Saving here commits to it.
That is the whole minimum. It converts an invisible write into an informed one, exactly as case 013 is fixed by naming the condition a command depends on. A better version shows the diff before committing, the way GitHub’s own file editor already does for every other change to your tree — and the best version makes the file authoritative and the field read-only, so there is one writer and no sync at all.
The math
~1M domains/yr × confusion & conflict = ≈0.02 lifetimes / year
The third micro case here, and it belongs with the others. Real cost, small population: most people set a domain once, it works, and they never notice what it wrote. Documenting it is worth something because the arithmetic says it is negligible — a metric that only ever returns “outrageous” is a complaint with decimals.
The reason to keep it anyway is that the shape generalises far past one text box. Every control that quietly edits state a user owns — a file, a branch, a history — is the same problem. This one is just unusually easy to point at, because it leaves a commit with its own name on it.
Estimates and one unverified claim. Repo and developer counts are GitHub’s own Octoverse figures. The number of custom domains set per year has no public source and is reasoned from repo volume. The behaviour when the default branch requires pull requests was not tested — the confident claim is that the write happens and is undisclosed, not what it does when it collides with a ruleset.
Difficulty to fix: none
The file is right. The silence about it isn’t. Say which side wins — one sentence — and a hidden write becomes a decision.
Read this case's source — _cases/015-settings-page-commits-to-your-branch.md