Appendix Episode 28 10-12 min

Branch Protection and Rulesets

Required reviews, status checks, rulesets, and diagnosing blocked merges.

Listen

Transcript

Alex: Welcome back. Today we're talking about branch protection and repository rulesets, which are the reason a pull request can look finished and still not be mergeable.

Jamie: That is such a familiar moment. You've written the change, opened the pull request, maybe even fixed feedback, and then the Merge button is disabled. It can feel like GitHub is just saying no.

Alex: Usually it is saying not yet, and it is giving you clues. A branch protection rule is a set of requirements that must be satisfied before changes can enter an important branch, usually main.

Jamie: So this is about protecting main from accidental changes, not about making contributors jump through hoops for fun.

Alex: Exactly. Protection can require review, passing tests, signed commits, an up-to-date branch, or a pull request instead of a direct push. Contributors mostly experience those rules in the merge box at the bottom of the pull request, while maintainers and facilitators configure the rules behind the scenes.

Jamie: Let's make the classic version concrete. What are the rules people run into most often?

Alex: The most common one is required reviews. A maintainer can say that a pull request needs one approval, or two approvals, or approval from a code owner before it can be merged.

Jamie: And if someone already approved, but then I push another commit, does that approval still count?

Alex: Sometimes yes, sometimes no. If the repository dismisses stale reviews, a new push withdraws the old approval, because the reviewer approved an earlier version of the work. If a reviewer requested changes, you respond, push the fix, and re-request review.

Jamie: Status checks are the other big one, right?

Alex: Right. A status check is an automated report attached to your commit. It might come from GitHub Actions, or from a third-party continuous integration service, which is software that builds, tests, or scans the project after you push.

Jamie: What names might a learner hear or see in the checks list?

Alex: Common examples are ci / build, ci / test, lint, accessibility-check, CodeQL, and deploy previews from services like Netlify. If a check is required, pending or failing means the merge stays blocked until that check succeeds.

Jamie: Then there is the message about the branch being out of date with the base branch.

Alex: That means main moved after you created your branch, and the repository requires your pull request branch to include the latest main before merging. GitHub may offer an Update branch button, or you may update locally with fetch and rebase if the project allows that and you're comfortable doing it.

Jamie: What about signed commits? That one can sound a little mysterious.

Alex: A signed commit has a verified cryptographic signature, often using GPG or SSH signing. If a repository requires signed commits, every commit in the pull request needs that Verified status, or the pull request cannot be merged.

Jamie: And there are a few rules that shape the history itself.

Alex: Yes. Requiring a linear history means the project does not allow merge commits into that branch, so maintainers usually squash merge or rebase merge instead. A push restriction says only listed people, teams, or apps can push to the branch. A locked branch is stricter: it is effectively read-only, often during a release freeze or for an archived project.

Jamie: Classic branch protection still exists, but GitHub also has repository rulesets. What changed?

Alex: Repository rulesets are the newer, more flexible approach GitHub introduced in late 2023. They can apply rules to patterns of branches or tags, and in organizations they can be managed across multiple repositories from one place.

Jamie: So instead of one rule for one branch in one repo, a maintainer can say, apply this to main, release branches, or version tags.

Alex: Exactly. Classic branch protection is usually single repository, single branch. Rulesets can target patterns like main, release/*, or v*, include bypass lists, show violation insights, and run in Active, Evaluate, or Disabled mode.

Jamie: Evaluate mode sounds useful. Is that like a trial run?

Alex: Yes. It logs what would have been blocked without actually blocking it. That gives maintainers a safer way to test a policy before enforcing it.

Jamie: Where would someone look for rulesets?

Alex: If you have access, you may find them under the repository's Insights tab, then Rulesets, or under Settings, Rules, Rulesets for admins. Contributors often do not have that access, and that's okay, because the pull request merge box still explains what is blocking the merge.

Jamie: If I were configuring one, what would the shape of that workflow be?

Alex: An admin opens repository settings, goes to Rules, creates a new ruleset, gives it a name, and chooses whether it targets branches or tags. Then they add patterns, such as main for the default branch, release/* for release branches, or v* for version tags. After that they choose rules, set enforcement to Active or Evaluate, review any bypass entries, and save.

Jamie: Tag patterns are important because releases are often tied to tags, aren't they?

Alex: They are. A project may protect tags so people cannot delete a release tag or create version tags outside the release process. That is especially helpful when packages, documentation sites, or deployments trust those tags.

Jamie: Let's go back to the contributor experience. The pull request is open, the merge button is unavailable, and the page says reviews are required. What now?

Alex: First, check how many approvals are required and whether a code owner or maintainer needs to review. Use the Reviewers area in the right sidebar to request review if that is appropriate for the project. If changes were requested, respond, push the update, and ask for another look.

Jamie: What if the message says checks have not completed, or checks were not successful?

Alex: Go to the merge box and expand Show all checks if the list is collapsed. Find the failing check, open Details, and read the log for the error. Then fix the underlying problem in your branch and push again, which usually reruns the checks automatically.

Jamie: And if it is just sitting there forever?

Alex: Most workshop and small project checks finish in a few minutes. If a required check stays in progress for a long time, say more than 30 minutes, it may be a runner or service problem, so contact the maintainer. If the same check passes on main but fails on your pull request, assume your change triggered something and read the log carefully.

Jamie: The out-of-date message is less scary once you know what it means.

Alex: Yes. If GitHub shows Update branch, that button merges the latest main into your pull request branch. The local alternative is usually git fetch upstream, then rebase onto upstream/main, followed by a push, but only use that path when you understand the project's expectations around rebasing.

Jamie: And for verified signatures?

Alex: You need to set up commit signing, usually with GPG or SSH signing, then replace the unsigned commits with signed ones. That may mean recommitting, cherry-picking, or asking a maintainer which recovery path they prefer.

Jamie: Sometimes the page just says merging is blocked, which is not very soothing.

Alex: When that happens, read the status lines directly above the merge button. The cause may be missing review, failed checks, an out-of-date branch, required signatures, a locked branch, or a rule that restricts who can push or merge. The closest status text is usually more useful than the button label itself.

Jamie: The merge box matters a lot here. How should a screen reader user get to the part of the page that explains the block?

Alex: Open the pull request's Conversation tab, then move to the bottom of the page. Pressing End is often the fastest way to land near the merge area, and then heading navigation can help you find the merge heading. Listen for status lines such as 1 review required, checks pending, or branch out of date before trying the button.

Jamie: Can we be a little more specific for NVDA and JAWS users?

Alex: With NVDA, browse mode heading navigation is often a good path: press H until you reach the merge area, then use the arrow keys to read line by line. With JAWS, the virtual cursor works similarly, and the headings list can also help if the page is long. Once you find a Details link for a check, activate it to open the log.

Jamie: Low vision users get some visual cues too, but they are easy to miss.

Alex: The merge area uses green, yellow, and red indicators, but the text next to the icons is what you should trust. Zooming to 150 percent or more can make the checkmarks, X icons, and secondary Update branch button easier to find. Sighted users will also see a vertical checklist above the merge button, and Show all checks expands the full list when GitHub only shows a summary.

Jamie: Those check details pages can be noisy.

Alex: They can. GitHub Actions opens a run page with jobs, steps, and log output, while third-party checks may open an external dashboard. Start with the failed job name, then the first error message, because later errors can be side effects of the first failure.

Jamie: Let's define status checks a bit more, because they show up everywhere in protected branches.

Alex: A status check is a pass, fail, or pending report for a specific commit. In GitHub Actions, those reports usually come from workflow files in .github/workflows, such as .github/workflows/ci.yml. A workflow can run when someone opens a pull request, pushes to a branch, or updates the pull request.

Jamie: So a project might run tests every time I push to my pull request branch.

Alex: Exactly. The check may be queued, in progress, successful, failed, cancelled, or skipped. For a required check, the important result is successful; anything else may block the merge depending on how the rule is configured.

Jamie: And not every check comes from GitHub Actions.

Alex: Right. Services like Netlify, Vercel, CircleCI, security scanners, accessibility scanners, and code quality tools can all post checks back to GitHub. To the merge box, they all become signals about whether the current commit is ready.

Jamie: Who actually gets to configure all of this?

Alex: Repository admins and maintainers with the right permissions can configure branch protection in a repository. Organization owners can create organization-level rulesets, depending on the GitHub plan and organization settings. Contributors usually cannot change the rules, but they can still read the merge box and ask informed questions.

Jamie: You mentioned bypass lists earlier. Are those just exceptions?

Alex: Yes, but they should be deliberate exceptions. A ruleset can allow specific users, teams, roles, or apps to bypass selected rules, such as a release bot that needs to create a protected tag. Good projects keep bypass lists small and review them because bypassing a rule is a powerful action.

Jamie: How do these choices look in real project configurations?

Alex: For a small team, a practical setup might protect main, require pull requests, require one approval, and require the basic test workflow to pass. For an open source project, maintainers may add code owner review, dismiss stale reviews, restrict direct pushes, and require security or accessibility checks. In an enterprise, rulesets may be managed at the organization level with required scans, linear history, release tag protection, and Evaluate mode before a new rule becomes active.

Jamie: And in the workshop environment, learners are not usually trying to become repository admins on day one.

Alex: Right. The Learning Room repository is provisioned per learner, and it is where Day 1 contributions happen: issue, branch, commit, pull request, and merge. Facilitators can keep protections light for practice, or intentionally demonstrate a blocked merge so learners can hear and inspect the clues.

Jamie: If someone wants the most current reference, where should they go?

Alex: Use GitHub's documentation on protected branches, repository rulesets, Actions status checks, and commit signing. GitHub changes screens over time, so trust the current docs and the live messages in the pull request. If you can explain what rule is blocking you and what evidence would satisfy it, you're in good shape.

Jamie: I like that framing. A blocked merge is not a dead end. It is a checklist from the repository.

Alex: Exactly. Read the merge box, open the details when needed, make the next change, and verify that the status changed. That is how protected branches turn from a mystery into a normal part of collaboration.

Workshop Content

Full chapter content from the Git Going with GitHub workshop guide.

Companion Podcast and Transcript

Use audio and transcript companions to review concepts in a conversational format.

Branch Protection and Rulesets

Companion audio: this episode reinforces key ideas and may not be a word-for-word reading of this page.

Transcript preview

Alex: Welcome back. Today we're talking about branch protection and repository rulesets, which are the reason a pull request can look finished and still not be mergeable.

Jamie: That is such a familiar moment. You've written the change, opened the pull request, maybe even fixed feedback, and then the Merge button is disabled. It can feel like GitHub is just saying no.

Alex: Usually it is saying not yet, and it is giving you clues. A branch protection rule is a set of requirements that must be satisfied before changes can enter an important branch, usually main.

Jamie: So this is about protecting main from accidental changes, not about making contributors jump through hoops for fun.

Appendix O: Branch Protection Rules and Repository Rulesets

Listen to Episode 28: Branch Protection and Rulesets - a conversational audio overview of this chapter. Listen before reading to preview the concepts, or after to reinforce what you learned.

Reference companion to: Chapter 08: Open Source Culture | Also relevant: Chapter 14

Authoritative source: GitHub Docs: Protected branches

How Merging Rules Work and Why Your PR May Be Blocked

Who this is for: Contributors who have submitted a PR and are wondering why it cannot be merged yet, as well as workshop facilitators who configure branch protection for practice repositories.

Quick Navigation

  1. What Branch Protection Does
  2. Common Branch Protection Rules
  3. Repository Rulesets - The Modern Approach
  4. Why Your PR Cannot Be Merged - Diagnosis Guide
  5. Navigating the Merge Box with a Screen Reader
  6. Status Checks - What They Are and What They Mean
  7. Who Can Configure Branch Protection
  8. Workshop Repository Configuration Reference

1. What Branch Protection Does

A branch protection rule is a set of requirements that must be satisfied before a PR can be merged into a specific branch (typically main). Branch protection exists to:

  • Require that code is reviewed before it enters the default branch
  • Require that automated tests pass before merging
  • Prevent direct pushes to main without a PR
  • Ensure the branch is up-to-date before merging
  • Require commits to be signed (GPG or SSH signatures)

Think of branch protection as the quality gate for a repository's primary branch.

Learning Cards: What Branch Protection Does

Screen reader users
  • The merge box at the bottom of every PR page is where branch protection surfaces its requirements — press End to jump to the bottom, then use H to find the merge heading
  • Each requirement is announced as a status line: "1 review required," "Some checks haven't completed yet," etc. — listen for these before attempting to merge
  • If the Merge button says "disabled" or "grayed out," branch protection is blocking — the status lines immediately above explain exactly what is needed
Low vision users
  • The merge box uses green (ready), yellow (pending), and red (blocked) indicators — zoom in on the merge area to read the text labels next to each colored icon
  • The "Update branch" button appears as a secondary button above the merge button when your PR is behind main — it can be easy to miss at high zoom
  • Required checks show checkmark or X icons that are small at default size — browser zoom to 150%+ makes the pass/fail status easier to distinguish
Sighted users
  • Look at the bottom of the PR Conversation tab for the merge box — a green "Merge pull request" button means all requirements are met; grey means something is blocking
  • The list of requirements appears as a vertical checklist above the merge button — each item shows a green checkmark, yellow spinner, or red X
  • Click "Show all checks" to expand the full list of status checks if only a summary is visible

2. Common Branch Protection Rules

Required Reviews

The most common rule. The maintainer requires a minimum number of approving reviews before the PR can be merged.

Example: "Require 1 approving review"

What this means for you:

  • Your PR shows a "1 review required" notice in the merge box
  • If a reviewer requests changes, their approval is revoked - you need at least one new approval after your latest push
  • After you push new commits, re-request review from the original reviewer

Dismiss stale reviews: Some repos have this enabled - whenever you push a new commit, all existing approvals are automatically withdrawn and you need a fresh review. This prevents sneaking in bad code after approval.

Required Status Checks

Automated workflows (GitHub Actions or third-party CI) must complete successfully before merging is allowed.

Example checks you may see

  • ci / build - compiles the code
  • ci / test - runs the test suite
  • lint - code style checks
  • accessibility-check - automated accessibility scanning
  • CodeQL - security analysis
  • netlify/deploy-preview - preview deployment must succeed

What "Required" means: The merge button is grayed out (or shows an error) until all required checks show a green checkmark. A failing or pending check blocks the merge.

Require Branches to Be Up to Date

Before merging, your PR branch must include all changes from main. This prevents merge conflicts from being introduced silently.

If your PR is behind main:

  • The merge box shows: "This branch is out of date with the base branch"
  • Button: "Update branch" - merges current main into your branch
  • Alternative: Rebase your branch (only if the maintainer permits rebase merges)

Require Signed Commits

All commits in the PR must have a Verified badge (see Appendix D: Git Authentication). If your commits are unverified, the PR cannot be merged until you re-commit with signing enabled.

Require Linear History

Only squash merges or rebase merges are permitted - no merge commits. This keeps the commit history linear and readable.

If you see: "This repository requires a linear history" - the maintainer will squash or rebase merge your PR, not create a merge commit.

Lock Branch

A locked branch cannot receive any merges - it is effectively read-only. This is sometimes used for archived repositories or during release freezes.

3. Repository Rulesets - The Modern Approach

Repository Rulesets (introduced in late 2023) are the next generation of branch protection. They extend branch protection rules with:

  • Organization-level rules - apply across all repos in an org from one place
  • Bypass lists - specific users or roles can be exempted from rules (e.g., release bots)
  • Target multiple branches - one ruleset can target a pattern like release/* or v*
  • Violation insights - audit log of when rules were bypassed and by whom
  • Rule enforcement - Active (enforced), Evaluate (only log violations, don't block), Disabled

Rulesets vs. Branch Protection Rules

Feature Branch Protection Rules Repository Rulesets
Scope Single branch, single repo Patterns, multi-branch, cross-org
Bypass No bypass capability Configurable bypass list
Enforcement modes Active only Active, Evaluate, Disabled
Organization-level No Yes (org rulesets)
Status Classic (still supported) Current/modern approach

Most repositories you encounter still use classic branch protection rules. Rulesets will become more common as maintainers migrate.

Finding and Reading Rulesets

If you want to understand why certain rules apply to a branch:

Repository → Insights tab → Rulesets (if you have access - contributors usually don't)
Or: Repository → Settings → Rules → Rulesets (admin only)

Alternatively, PR merge box messages describe which rules are blocking - you don't need admin access to understand what's required.

4. Why Your PR Cannot Be Merged - Diagnosis Guide

When you open a PR and the merge button is grayed out or shows an error, the merge box tells you exactly what needs to happen. Here is how to read it.

"X review required / X reviews required"

What it means: The required number of approvals hasn't been reached yet.

What to do

  1. Request review from a codeowner or maintainer (right sidebar → Reviewers → request)
  2. Check if any reviews exist but requested changes - those count against you
  3. Wait for the reviewer to submit their review
  4. Respond to requested changes by pushing new commits, then re-requesting review

"Some checks haven't completed yet" or "Some checks were not successful"

What it means: A required status check is pending or failing.

What to do

  1. Scroll down to the merge box - expand "Show all checks"
  2. Find the failing check → click "Details" to see the full log
  3. Fix the underlying issue (test failure, lint error, build error) in your branch
  4. Push new commits - checks re-run automatically
  5. Wait for checks to complete (typically 1-5 minutes for most CI)

If checks pass on main but fail on your PR: The issue is specific to your changes. Read the check log carefully.

If checks are stuck "in progress" for over 30 minutes: The workflow runner may have an issue - contact the maintainer.

"This branch is out of date with the base branch"

What it means: New commits were pushed to main after you created your PR branch. The maintainer requires everything to be current.

What to do

  • Click "Update branch" in the merge box - GitHub does a merge commit from main into your branch
  • Or locally: git fetch upstream && git rebase upstream/main then force-push (only if you are comfortable with rebase)

"Commits must have verified signatures"

What it means: Branch protection requires signed commits (see Appendix D: Git Authentication).

What to do

  1. Enable commit signing locally before making more commits
  2. For existing unsigned commits, you need to rebase-rewrite them - this is advanced; ask the maintainer if there is a workaround

"Merging is blocked"

What it means: A ruleset or branch protection has explicitly blocked merging for a reason not covered by other messages. Check the PR for a pinned comment from the mergeable status check or a GitHub Actions check that posts a comment explaining the block.

Learning Cards: Why Your PR Cannot Be Merged

Screen reader users
  • Navigate to the merge box (End key, then H key to find "Merge" heading) and read each status line with arrow keys — the messages tell you exactly what action to take
  • When a check fails, Tab to the "Details" link next to the failing check name and press Enter to open the log — use Ctrl+F to search for "error" or "failed"
  • After pushing a fix, the checks re-run automatically — return to the PR page and listen for the status to change from "pending" to "passed"
Low vision users
  • Failed checks show a red X icon that can be tiny — zoom to 150%+ and look for the word "failing" or "failed" next to each check name
  • The "Update branch" button (for out-of-date PRs) is a secondary action that blends in at low zoom — look for it directly above the main merge button
  • The Details link next to each check opens a log page with monospace text — increase your editor or browser font size before reading long CI logs
Sighted users
  • Scroll to the bottom of the PR page and scan the checklist in the merge box — red X items are blocking, yellow spinners are still running, green checks are done
  • Click the "Details" link next to any red X to see the full error log — the failing step is highlighted with a red icon in the left sidebar
  • If "This branch is out of date," click the blue "Update branch" button and wait for checks to re-run before merging

5. Navigating the Merge Box with a Screen Reader

The merge box lives at the bottom of every PR page. With a screen reader, navigating to it efficiently is important.

Reaching the Merge Box

PR page → End key (jump to bottom of page)
Or: B key (NVDA Browse Mode) → navigate buttons → look for "Merge pull request" button
Or: H key → navigate to "Merge" heading area

Reading the Merge Box Status

From the merge box area:
H → section heading ("Merging is blocked" or "This branch has no conflicts")
↓ → first status message
↓/Tab → each requirement listed (required reviews, required checks, etc.)

NVDA specific path

NVDA+F7 → Elements list → Filter by type: Headings
Find "Merge" related heading → move focus to that section
Then ↓ through the section content

JAWS specific path

H → navigate to merge section
Then ↓ key → read each item in the requirements list

Checking Status Checks

Merge box area → Tab → "Show all checks" link or button → Enter
Expands to show: each check name, its status (passed/failed/pending), "Details" link
Tab through each check → "Details" link → Enter to open the check log

Reading Check Details

The check log is a text-heavy page in a pre-formatted block.

Check log page: H → "Summary" heading → ↓ to read summary
To read the full log: F → form controls → step dropdown (if multi-step)
Or: Tab → each step accordion → Enter to expand → ↓ to read log lines
Log content is usually in a scrollable region: ↓ key scrolls through lines

6. Status Checks - What They Are and What They Mean

Status checks come from two sources:

GitHub Actions Status Checks

Defined in .github/workflows/*.yml in the repository. Each job: in a workflow file becomes a status check. Example:

# .github/workflows/ci.yml
jobs:
  test:            this creates the "test" status check
    runs-on: ubuntu-latest
    steps:
      - name: Run tests
        run: npm test

Third-Party Status Checks

Services like Netlify, Vercel, Codecov, and Snyk post status checks via the GitHub API. You will recognize them by their app name prefix (e.g., netlify/deploy-preview - Deploy Preview ready).

Status Check States

Icon State Meaning
Yellow circle Pending Running now or queued
Green checkmark Success Passed, no issues
Red X Failure Failed - PR cannot be merged until fixed
Red circle Error Unexpected error in the check runner (not your code's fault)
Grey circle Skipped Not relevant for this PR (conditional run)
Neutral Neutral Informational - does not block merge

7. Who Can Configure Branch Protection

Role Can view requirements Can modify requirements
Public viewer No (only via PR merge box) No
Contributor PR merge box only No
Triage PR merge box only No
Write Settings → Rules (read-only in most cases) No
Maintain Yes Partial
Admin Yes Yes - full control
Org admin Yes Yes - including org-level rulesets

As a workshop participant, you are typically a contributor to the main community-access/accessibility-agents repo and an admin of your own fork. On your fork, you can configure branch protection however you like - including disabling it entirely for practice purposes.

8. Workshop Repository Configuration Reference

The community-access/accessibility-agents repository uses the following branch protection configuration on main:

Rule Setting
Required reviews 1 approving review
Dismiss stale reviews Yes - new commits require re-review
Require status checks ci / build and ci / test
Up-to-date requirement Yes
Signed commits No (to reduce friction for workshop participants)
Restrict direct pushes Yes - all changes must come through PRs

Workshop tip: Your personal fork of accessibility-agents has no branch protection by default. If you want to practice the full "review before merge" workflow with a partner, you can add branch protection to your fork:

Your fork → Settings → Branches → Add branch protection rule
Branch name pattern: main
Check: Require a pull request before merging
Check: Require approvals → 1
Save changes

Then practice opening a PR on your fork and requesting your workshop partner's review.


Next: Appendix P: Security Features
Back: Appendix N: Advanced Search
Teaching chapter: Chapter 08: Open Source Culture

Authoritative Sources

Use these official references when you need the current source of truth for facts in this chapter.

Section-Level Source Map

Use this map to verify facts for each major section in this file.