← Back to Branch Protection Drift Check
Most configuration in a software project lives in a file: a linter's rule set, a CI workflow, an environment's variable list. All of it goes through version control, so a change to it is a diff someone reviews before it takes effect, and a change nobody meant to make is visible in git blame forever.
GitHub branch protection is not that. It lives in repository settings — a live control panel a maintainer edits directly, with no commit, no pull request, and no reviewer. The audit log records that a setting changed and who changed it, but nothing compares the new state to what the team actually agreed the policy should be. There is no diff to notice, because there was never a file to diff.
It is rarely a decision to weaken security. It is an incident: production is down, the fix is ready, and required reviews or a status check are standing between the fix and the deploy. Someone with admin access turns the rule off, ships the fix, and means to turn it back on once things calm down. The incident ends; the follow-up task to re-enable the rule does not get the same urgency the incident itself had, and it quietly falls off the list.
Months later, a different change — one that genuinely needed review — merges without it, because the rule that would have required a review has been off the whole time. Nobody decided that outcome. Nobody would have agreed to it if asked directly. It happened because the gap between the setting changing and the setting mattering can be arbitrarily long, and nothing in GitHub's own UI narrows that gap by reminding anyone what is currently off.
The settings page shows the current state accurately. What it cannot show is whether the current state matches what your team decided the policy should be, because GitHub has no concept of your declared policy — only of whatever the toggles currently say. Reading the page tells you the branch is unprotected in some way; it does not tell you that unprotected way is a deviation from anything, unless you already remember, precisely, what every toggle used to be.
That is the gap a declared policy closes: write down, once, what every rule is supposed to be — required reviewer count, admin enforcement, force-push and deletion rules, required status checks — and compare the live settings against that written statement whenever you have reason to check, rather than against memory.
Compare your own repository's actual settings against a declared policy →