Q39 of 40 · Git
As a QA lead, how would you configure branch protection rules for `main` and `release/*` branches to enforce quality gates without slowing down the team?
Short answer
Short answer: Protect `main` with: required PR reviews (1-2), required CI status checks (unit + integration), signed commits, and block force-pushes. For `release/*` add: manual QA approval gate, linear history, and no direct pushes. Use CODEOWNERS to auto-assign reviewers to test files.
Detail
Branch protection rules are the primary enforcement mechanism for a quality-first Git workflow. The goal is to make the safe path the default path, not to create bureaucracy.
main branch rules (every merge goes here):
- Require pull request before merging (min 1-2 reviews).
- Require status checks: unit tests, integration tests, linting, and security scan — all must pass.
- Require branches to be up to date before merging (prevents race conditions where two PRs pass CI independently but conflict when both land).
- Block direct pushes (including from admins — this is often controversial but important for audit trails).
- Block force-pushes (even
--force-with-lease). - Require signed commits (
-S) in high-compliance environments. - Enable
Require linear historyif the team uses squash or rebase merge strategy.
release/* branch rules (additional):
- Require approval from a named QA lead (via CODEOWNERS or a required reviewer team).
- Restrict who can push: only the release manager role.
- Require all conversations resolved on PRs.
CODEOWNERS (.github/CODEOWNERS): maps file patterns to GitHub teams. src/test/ @company/qa-team means every PR touching test files auto-requests review from the QA team. This ensures test changes are never merged without QA sign-off, even if the developer forgets to request review.
Performance considerations: slow CI is the biggest source of developer friction. Structure checks into fast (< 3 min, required) and slow (smoke/e2e, non-blocking) tiers to avoid making every PR wait 30 minutes.
// EXAMPLE
# .github/CODEOWNERS
# QA team must review any changes to test code
src/test/ @company/qa-team
test/ @company/qa-team
**/*Test.java @company/qa-team
**/*Spec.ts @company/qa-team
# Release manager must approve release config changes
.github/workflows/release* @company/release-managers
config/release/ @company/release-managers
# --- GitHub CLI: view current branch protection ---
gh api repos/company/repo/branches/main/protection
# --- Enforce signed commits globally (team .gitconfig) ---
git config --global commit.gpgsign true
git config --global user.signingkey YOUR_KEY_ID
# --- Verify your commits are signed ---
git log --show-signature -1
# --- Local pre-push hook to catch unsigned commits ---
#!/usr/bin/env bash
# hooks/pre-push
UNSIGNED=$(git log @{u}..HEAD --format="%H %G?" | grep -v " G$" | grep -v " U$")
if [[ -n "$UNSIGNED" ]]; then
echo "ERROR: unsigned commits detected. Sign with: git commit --amend -S"
exit 1
fi// WHAT INTERVIEWERS LOOK FOR
// Related questions
Your team has been using 'commit everything directly to main' for 2 years. How do you lead the transition to a PR-based workflow with branch protection, and what are the biggest risks?
Git
Design a Git branching and tagging strategy for a 5-team QA organisation that needs to test features independently and also run full regression across all features before release.
Git
What is a quality gate and what should it block on?
CI/CD & DevOps