Chapter 4.8 — Branch Protection Rules☕ 15 min read

Branch Protection Rules

Main pe direct push? BLOCKED. Club ka bouncer — No ID, no entry!

01Branch Protection: Bouncer at the Door

Branch protection rules are the bouncer at the door of your most important branches. Without them, anyone with push access can do whatever they want to main, develop, or release/* branches.

Without protection, any developer can:

  • Push directly to main — no review, no CI, just raw code going live
  • Force push to main — rewrite history, destroy commits
  • Delete the main branch entirely

With branch protection enabled:

  • Must use a Pull Request — no direct pushes allowed
  • Must get code review approval from teammates
  • CI must pass — tests green before merging
  • No force push — history is safe
  • No deletion — the branch cannot be removed

Configured in GitHub Settings > Branches > Branch protection rules. Protect these branches: main, develop, release/* — any branch that should not be modified directly.

GitLab calls them "Protected Branches", Bitbucket calls them "Branch Permissions". Same concept, different names.

# Without protection (DANGEROUS):
git push origin main        # anyone can push directly
git push --force origin main # anyone can rewrite history
git push origin --delete main # anyone can delete

# With protection (SAFE):
git push origin main
# ERROR: protected branch — must use PR
Branch protection is non-negotiable for production branches. One accidental force push to main can destroy your entire deployment history. One unreviewed direct push can introduce a bug that takes down production. Protection rules make these scenarios impossible by design.
02The 6 Essential Protection Rules

The 6 essential branch protection rules every team should enable on main:

  • 1. Require pull request before merging — no direct pushes to the branch. All changes must come through a PR. This is the most fundamental rule.
  • 2. Require approvals — 1 or more reviewers must approve the PR before it can be merged. Two pairs of eyes catch bugs that one misses.
  • 3. Require status checks to pass — CI pipeline (build, test, lint) must be green. No merging broken code.
  • 4. Require signed commits — commits must be signed with GPG key. Verifies that the person who committed is actually who they claim to be.
  • 5. Require linear history — no merge commits allowed. All PRs must be rebased before merging. Clean, readable history.
  • 6. Disable force pushes — no git push --force on the branch. History cannot be rewritten.

Additional options: restrict who can push to specific teams, require review from Code Owners, dismiss stale reviews when new commits are pushed.

# GitHub Protection Settings:
# 1. Require a pull request before merging
#    - Require approvals (1-6)
#    - Dismiss stale reviews on push
#    - Require review from Code Owners
#
# 2. Require status checks to pass
#    - CI checks: build, test, lint
#    - Require branches to be up to date
#
# 3. Require signed commits (GPG)
#
# 4. Require linear history (no merge commits)
#
# 5. Include administrators (or not)
#
# 6. Allow force pushes (usually OFF)
#    Allow deletions (usually OFF)
💡 Pro Tip: Start with just "Require PR" and "Require approvals: 1" for new teams. Add more rules as the team matures. Going from zero protection to all 6 rules overnight will frustrate developers. Gradual adoption works better.
03Setting Up Protection in GitHub UI

Setting up branch protection in the GitHub web interface:

  • Step 1: Navigate to your repository on GitHub
  • Step 2: Click Settings tab (you need admin access)
  • Step 3: Click Branches in the left sidebar
  • Step 4: Click Add rule under Branch protection rules
  • Step 5: Enter the branch name pattern: main
  • Step 6: Check the protection rules you want
  • Step 7: Click Create

Branch name patterns support wildcards: main (exact match), release/* (all release branches), feature/** (all feature branches).

"Include administrators" — when checked, even repository admins must follow the same protection rules. This is critical for consistent enforcement.

For organizations: use branch protection templates to apply the same rules across multiple repositories consistently.

# GitHub UI Setup:
# 1. Go to repo Settings
# 2. Click "Branches" in sidebar
# 3. Click "Add rule"
# 4. Branch name pattern: main
# 5. Check desired protections
# 6. Save changes

# Common setup for main:
# ✅ Require a pull request before merging
# ✅ Require approvals: 1
# ✅ Require status checks: ci/lint, ci/test
# ✅ Require linear history
# ❌ Allow force pushes
# ❌ Allow deletions
# ✅ Include administrators
The "Include administrators" checkbox is the most important setting. Without it, admins can bypass every protection rule by pushing directly. If protection doesn't apply to admins, it's security theater — looks good but doesn't actually protect. Always enable this.
04GitHub CLI: Protection via Terminal

Using the GitHub CLI (gh) to set branch protection programmatically is essential for:

  • Infrastructure as code — protection rules defined in scripts, not just UI clicks
  • Team onboarding — new repos get protection automatically
  • Consistency — same rules across all repositories in an organization
  • Audit trail — changes to protection are tracked in scripts

The GitHub REST API endpoint for branch protection: PUT /repos/:owner/:repo/branches/:branch/protection

Using gh api you can create, read, update, and delete protection rules from the terminal.

# Install GitHub CLI
gh auth login

# Set branch protection via API
gh api repos/:owner/:repo/branches/main/protection \
  --method PUT \
  --field required_status_checks='{"strict":true,"contexts":["ci/test","ci/lint"]}' \
  --field enforce_admins=true \
  --field required_pull_request_reviews='{"required_approving_review_count":2}' \
  --field restrictions=null

# View current protection
gh api repos/:owner/:repo/branches/main/protection

# Delete protection
gh api repos/:owner/:repo/branches/main/protection \
  --method DELETE
💡 Pro Tip: Add branch protection setup to your repository bootstrap script. When a new repo is created, protection is applied automatically. No more "we forgot to protect main" incidents. Combine with CODEOWNERS for complete governance.
05Common Protection Mistakes

Even with branch protection enabled, teams make these common mistakes:

  • Enabling protection without telling the team — developers suddenly can't push and don't know why. Communicate BEFORE enabling rules.
  • Setting approval count too high (5+) — PRs wait weeks for enough approvals. 1-2 is usually enough for most teams.
  • Status check name typo — CI job is named test but protection requires tests. PRs are blocked forever because the check never passes.
  • Not including administrators — admins bypass all rules, making protection meaningless.
  • Forgetting CODEOWNERS — reviews assigned randomly instead of to domain experts who understand the code.
  • Protection is not a substitute for code review culture — forcing approval is not the same as thoughtful review.
# MISTAKE 1: Wrong status check name
# CI job is named "test" but protection says "tests"
# PR blocked forever!

# MISTAKE 2: Too many required approvals
# 5 approvals = PR waits weeks

# MISTAKE 3: Not including admins
# Admin can push directly to main, bypassing all rules
# Always enable "Include administrators"

# MISTAKE 4: No CODEOWNERS file
# Reviews assigned randomly, not to domain experts

# Create CODEOWNERS
cat > .github/CODEOWNERS << 'EOF'
# Default reviewers
* @team-leads

# Payment module must be reviewed by payment team
/src/payment/ @payment-team

# Auth must be reviewed by security
/src/auth/ @security-team
EOF
The most dangerous mistake: protection without culture. If developers approve PRs in 5 seconds without reading, protection is theater. Rules force the mechanics (PR exists, approval exists, CI passes). Culture ensures the quality (review is thoughtful, approval means "I read this", CI is trusted). You need BOTH.

Lo kar liya — Key Points:

  • ✅ Branch protection rules prevent dangerous operations on important branches (main, develop, release)
  • ✅ 6 essential rules: require PR, require approvals, require CI, require signed commits, linear history, no force push
  • ✅ Set up in GitHub: Settings > Branches > Add rule — enter branch name pattern and check desired protections
  • ✅ Use GitHub CLI (gh api) for programmatic setup and consistency across repos
  • ✅ Always enable "Include administrators" — no one should bypass protection, not even admins
  • ✅ Status check names must match CI job names exactly — a single typo blocks all PRs permanently
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase