How do branch protection rules work in GitHub, and how would you configure them for a production repository?
Quick Answer
Branch protection rules are repository settings that enforce policies on specific branches, such as requiring pull request reviews, passing status checks, and linear commit history before merging. They are configured via Settings > Branches > Add Rule and can target branches by exact name or wildcard patterns.
Detailed Answer
Think of branch protection rules as the security protocol at a bank vault. Even the bank manager cannot walk in alone and grab the cash. There must be two keyholders present (required reviews), the alarm system must show green (passing status checks), the visit must be logged (signed commits), and no one can override the combination by force (no force pushes). GitHub branch protection rules enforce similar multi-layered gates on your most important branches.
Branch protection rules are per-repository settings that apply to branches matching a name or a fnmatch-style wildcard pattern. You can protect the exact branch named main, or use a pattern like release/* to protect all release branches at once. The key configurable requirements include: requiring a minimum number of approving pull request reviews before merging, requiring specific status checks (such as CI tests, linting, and security scans) to pass, requiring conversation resolution before merging, requiring signed commits, requiring linear history (which forces squash or rebase merges and disallows merge commits), and restricting who can push to matching branches. Each of these requirements can be independently toggled on or off.
Internally, GitHub evaluates branch protection rules every time someone attempts to push, merge, or perform administrative actions on a protected branch. When a developer pushes directly to a protected branch that requires pull request reviews, the push is rejected at the server level with an error message explaining the protection rule. When a pull request targets a protected branch, GitHub computes the list of required status checks from the rule configuration and compares them against the actual check runs reported by GitHub Actions or external CI systems. The merge button remains disabled until every required check shows a green checkmark and the required number of approvals is met. Administrators can optionally bypass these protections, but the Include administrators checkbox enforces rules even for repository admins. GitHub also evaluates the CODEOWNERS file against the changed files and adds code owner review requirements on top of the base review count.
In production, a team managing the checkout-service repository might configure the main branch with the following rules: require two approving reviews with stale review dismissal enabled so that new commits invalidate previous approvals, require the ci/tests, ci/lint, and security/codeql status checks to pass, enforce signed commits for audit compliance, require linear history to keep the commit log clean, restrict push access to only the release-managers team, and include administrators so that even org owners cannot bypass the gates. For release branches, the team might use a release/* pattern with similar but slightly relaxed rules, perhaps requiring only one approval. Rulesets, which are the newer GitHub feature replacing traditional branch protection, allow you to apply layered rules from the organization level down to individual repositories, making governance at scale much easier.
A critical gotcha is that required status checks reference check names, not workflow file names. If you rename a job in your GitHub Actions workflow, the status check name changes and the branch protection rule silently stops matching, effectively disabling the requirement. Always verify that your required check names exactly match the output of the Actions job names. Another pitfall is not enabling Dismiss stale pull request approvals when new commits are pushed, which allows an author to get approval, then push unreviewed code and merge immediately. Finally, note that branch protection rules on free plans for public repositories are unlimited, but private repositories require GitHub Pro or Team for full branch protection features.