GitHub 12 ๐ Branch Protection Rules and CODEOWNERS
A repository is only as safe as the gates that guard its main branch. Branch protection rules are those gates: they define who can push, what must pass before a merge, and whether history can be rewritten. CODEOWNERS is the routing table that ensures the right people review the right files. Used together, they turn a repository from a shared folder into a governed workflow. The GitHub exam tests both the settings and the syntax, but more importantly, it tests the distinction between “review requested” and “review required.”
Key point: CODEOWNERS only requests reviews. It does not enforce them. Enforcement requires enabling “Require review from Code Owners” in the branch protection rule. Without that checkbox, CODEOWNERS is advisory.
Why branch protection and CODEOWNERS exist
The direct push problem. Without protection, any collaborator with write access can push directly to main. A broken commit, an accidental force push, or a deleted branch can erase work or break the build. Branch protection rules restrict these actions: they can block force pushes, prevent deletion, require pull requests, and mandate that status checks pass before merging .
The review quality problem. A required approval is not enough if the approver does not understand the code. CODEOWNERS solves this by mapping file paths to users or teams. When a pull request modifies a file matching a pattern, the corresponding code owner is automatically requested for review . If “Require review from Code Owners” is enabled, that approval becomes mandatoryโthe pull request cannot merge without it .
The bypass problem. By default, administrators can bypass branch protection rules. The “Do not allow bypassing the above settings” (or “Include administrators”) checkbox closes this loophole. Without it, an admin can merge without reviews, push directly, or force push despite the rule .
The stale review problem. If a developer pushes new commits after an approval, the approval may no longer reflect the current code. The “Dismiss stale pull request approvals when new commits are pushed” setting resets approvals on every push, forcing a re-review. This prevents the “hijack” scenario where unapproved changes are added to an already-approved pull request .
The ruleset evolution. Classic branch protection rules are being superseded by rulesets. A ruleset can target multiple branch patterns, stack with other rulesets, and be toggled on or off without deletion. GitHub now provides a “Convert to ruleset” button to migrate existing protections . The exam may still test classic rules, but rulesets are the future.
a. Configuring branch protection rules
Branch protection rules are configured in the repository settings under “Branches.” A rule targets a branch name pattern (e.g., main, release/**). The core settings fall into three categories: merge requirements, push restrictions, and bypass controls.
Settings โ Branches โ Add branch protection rule
Branch name pattern: main
[x] Require a pull request before merging
[x] Require approvals: 1
[x] Dismiss stale pull request approvals when new commits are pushed
[x] Require review from Code Owners
[x] Require status checks to pass before merging
[x] Require branches to be up to date before merging
[x] Require conversation resolution before merging
[x] Do not allow bypassing the above settings
[x] Restrict deletions
[x] Block force pushes
The “Require status checks” setting names specific CI jobs (e.g., build, test). A pull request cannot merge until those checks report success, skipped, or neutral . The “Require branches to be up to date” checkbox (strict mode) forces the head branch to be rebased or merged with the base branch before the checks are evaluated againโthis prevents the “merge train” problem where two PRs pass independently but conflict when merged together .
The “Restrict who can push” setting, if enabled, limits direct pushes to a specified list of users, teams, or apps. This is separate from the pull request requirement: even if a user is allowed to push, they may still be blocked from merging without reviews .
b. Writing the CODEOWNERS file
The CODEOWNERS file lives in the repository root, .github/, or docs/ directory. GitHub searches in that order and uses the first file it finds . The syntax is a file pattern followed by one or more owners, using @username or @org/team-name format. Comments start with #.
# Default owners for everything in the repo
* @core-team
# Documentation owners
/docs/ @technical-writers
*.md @technical-writers
# Security-sensitive paths
/security/ @security-team
# CI/CD workflows
/.github/workflows/ @platform-team
The order of patterns matters: the last matching pattern has the highest precedence . In the example above, a pull request modifying docs/README.md matches both * and *.md. The *.md pattern appears later, so @technical-writers is the only owner requestedโthe default @core-team is not .
A CODEOWNERS file must be on the base branch of the pull request to take effect. If a pull request targets main, the CODEOWNERS file on main is used, not the one on the feature branch . The file size limit is 3 MB; larger files are ignored entirely .
c. Enforcing CODEOWNERS reviews
CODEOWNERS alone does not block merges. It only triggers review requests. To make the review mandatory, the branch protection rule must enable “Require review from Code Owners” . When this is active, every file in the pull request that has a code owner must receive an approval from that owner before the merge button becomes active.
Branch protection rule for main:
[x] Require a pull request before merging
[x] Require review from Code Owners
The distinction is critical for the exam. A repository with a CODEOWNERS file but no “Require review from Code Owners” setting will automatically request reviews, but a reviewer with write access can still merge without the code owner’s approval. The file is advisory. The branch protection rule is the enforcement mechanism .
If a code owner is unavailable, there is no built-in fallback in GitHub. The pull request stalls. Some organizations implement a policy where a core team member can provide a fallback approval after a specified period, but this requires a manual process or a botโGitHub does not enforce time-based fallbacks .
Complete Example Session
# ============================================
# PART 1: CREATE THE CODEOWNERS FILE
# ============================================
# In the repository root, create CODEOWNERS
# (or .github/CODEOWNERS)
cat > CODEOWNERS <<'EOF'
* @core-team
/docs/ @technical-writers
*.md @technical-writers
/security/ @security-team
EOF
# ============================================
# PART 2: COMMIT AND PUSH TO MAIN
# ============================================
git add CODEOWNERS
git commit -m "Add CODEOWNERS"
git push origin main
# CODEOWNERS must be on the base branch to take effect.
# ============================================
# PART 3: CONFIGURE BRANCH PROTECTION
# ============================================
# Settings โ Branches โ Add rule
# Branch name pattern: main
# Enable:
# Require a pull request before merging
# Require approvals: 1
# Require review from Code Owners
# Require status checks to pass
# Do not allow bypassing the above settings
# ============================================
# PART 4: VERIFY CODEOWNERS ROUTING
# ============================================
# Create a branch and modify a markdown file.
git checkout -b docs-update
echo "New docs" >> README.md
git add README.md
git commit -m "Update README"
git push -u origin docs-update
# Open a pull request.
# @technical-writers should be automatically requested for review.
# ============================================
# PART 5: TEST ENFORCEMENT
# ============================================
# Without approval from @technical-writers:
# The merge button is disabled.
# The merge box says: "Review required from code owners."
# ============================================
# PART 6: TEST STALE REVIEW DISMISSAL
# ============================================
# If "Dismiss stale approvals" is enabled:
# 1. Approve the pull request.
# 2. Push a new commit to the branch.
# 3. The approval is dismissed.
# The merge button is disabled until re-approved.
# ============================================
# PART 7: TEST ADMIN BYPASS
# ============================================
# With "Do not allow bypassing" unchecked:
# An admin can merge without review.
# With it checked:
# The admin is subject to the same rules.
# ============================================
# PART 8: MIGRATE TO RULESETS (OPTIONAL)
# ============================================
# Settings โ Rules โ New ruleset
# Or: Settings โ Branches โ Convert to ruleset
# Rulesets can target multiple branches and be toggled.
The eight parts trace the configuration and verification: creating CODEOWNERS, committing it to the base branch, enabling the branch protection rule, verifying automatic review requests, testing enforcement, testing stale review dismissal, testing admin bypass, and migrating to rulesets.
Quick Reference
Branch Protection Settings
| Setting | Effect |
|---|---|
| Require a pull request | Blocks direct pushes to main |
| Require approvals | Merge blocked until N approvals |
| Dismiss stale approvals | Approvals reset on new commits |
| Require review from Code Owners | CODEOWNERS approval becomes mandatory |
| Require status checks | Merge blocked until CI passes |
| Require branches to be up to date | Strict mode; rebase before merge |
| Do not allow bypassing | Admins subject to the same rules |
| Block force pushes | History cannot be rewritten |
| Restrict deletions | Branch cannot be deleted |
CODEOWNERS Syntax
| Pattern | Meaning |
|---|---|
* @team | Default owner for all files |
*.md @team | All Markdown files |
/docs/ @team | Directory and contents |
/docs/* @team | Directory contents only (no subdirs) |
docs/ @team | Any directory named docs anywhere |
CODEOWNERS Location
| Path | Priority |
|---|---|
CODEOWNERS (root) | First |
.github/CODEOWNERS | Second |
docs/CODEOWNERS | Third |
Best Practices
โ Do This:
# .github/CODEOWNERS
* @core-team
/security/ @security-team
- โ Use a default owner and override for sensitive paths
[x] Require review from Code Owners
- โ Enable enforcement in branch protection
[x] Do not allow bypassing the above settings
- โ Apply rules to administrators
โ Don’t Do This:
# CODEOWNERS file exists
# But "Require review from Code Owners" is unchecked
- โ CODEOWNERS is advisory only
# Admin bypasses branch protection
- โ Defeats the purpose of the gate
# CODEOWNERS pattern order ignored
* @core-team
/docs/ @writers
- โ
/docs/appears after*, so it takes precedenceโthis is correct, but reversing the order breaks it
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| CODEOWNERS not requesting review | File not on base branch | Commit to main, then open PR |
| Merge allowed without code owner | “Require review from Code Owners” unchecked | Enable in branch protection |
| Default owner requested for all files | No specific pattern matched | Add specific patterns after * |
| CODEOWNERS ignored | File larger than 3 MB | Reduce with wildcards |
| Stale review not dismissed | Setting disabled | Enable “Dismiss stale approvals” |
Real-World Examples
1. Default Owner
* @core-team
2. File Type Owner
*.md @technical-writers
3. Directory Owner
/docs/ @technical-writers
4. Security Path
/security/ @security-team
5. Workflow Owner
/.github/workflows/ @platform-team
6. Branch Protection Rule
Branch name pattern: main
[x] Require a pull request
[x] Require review from Code Owners
7. Status Checks
[x] Require status checks to pass
Required: build, test
8. Strict Mode
[x] Require branches to be up to date
9. Admin Bypass Block
[x] Do not allow bypassing
10. Ruleset Migration
Settings โ Branches โ Convert to ruleset
Visual
CODEOWNERS Routing
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Pull request modifies: โ
โ - README.md โ
โ - /security/auth.rs โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CODEOWNERS evaluation โ
โ โ
โ README.md โ *.md โ @technical-writers โ
โ auth.rs โ /security/ โ @security-team โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Review requests sent to both owners โ
โ If "Require review from Code Owners": โ
โ Both must approve before merge. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The last matching pattern wins. The enforcement depends on the branch protection checkbox.
Branch Protection Gate
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Pull request ready to merge โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Check: Required reviews? โ
โ โโ YES โ approved? โ
โ โ โโ YES โ continue โ
โ โ โโ NO โ BLOCK โ
โ โโ NO โ continue โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Check: Status checks passed? โ
โ โโ YES โ continue โ
โ โโ NO โ BLOCK โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Check: Code Owner approval (if enabled)? โ
โ โโ YES โ continue โ
โ โโ NO โ BLOCK โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Merge button enabled โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Every gate must open before the merge is allowed.
Summary
| Item | Value |
|---|---|
| Branch protection location | Settings โ Branches |
| CODEOWNERS location | Root, .github/, or docs/ |
| CODEOWNERS enforcement | “Require review from Code Owners” |
| Pattern precedence | Last match wins |
| Admin bypass | Controlled by “Do not allow bypassing” |
| Stale review dismissal | “Dismiss stale approvals” |
| Ruleset migration | Settings โ Branches โ Convert to ruleset |
| File size limit | 3 MB |
Key takeaways:
- Branch protection rules are the gates. They block direct pushes, require reviews, enforce status checks, and prevent force pushes and deletions .
- CODEOWNERS is routing, not enforcement. It requests reviews from the right people. The “Require review from Code Owners” setting makes those reviews mandatory .
- The last matching pattern wins. Place specific patterns after the default
*to override it . - Administrators can bypass by default. The “Do not allow bypassing” setting closes this loophole .
- Rulesets are the future. Classic branch protection rules are being replaced by rulesets, which support multiple branch patterns and stacking .
Remember: A branch protection rule without CODEOWNERS requires someone to approve. A CODEOWNERS file without branch protection requires no one to approve. The two features are complementary: one enforces the review, the other routes it to the person who knows the code. Configure both, and enforce both.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!