Branch protection & CODEOWNERS
Tripathi almost erased two days of Anvesha's work with one panicked command. The only reason it didn't work is a setting, not a habit.
Tripathi's fixing something on his own branch, gets tangled in a rebase, and — following the first StackOverflow answer he finds — decides the fastest way out is to just force his local branch's state onto main directly:
git push origin main --force
His local main is two days stale. If this succeeded, it would silently overwrite everything Anvesha has pushed since, including work Ishaan's PR already built on top of. Nobody would even get a warning — force-push, by definition, means "trust me, don't check."
GitHub refuses the push outright:
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Cannot force-push to a protected branch
Not because Tripathi is careless — he isn't, usually. Because two days of someone else's real work were never actually one panicked command away from disappearing. That protection exists as a setting on the repository, sitting quietly in the background the entire time, completely independent of whether anyone remembered to be careful in the moment.
What "branch protection" is, mechanically
It's a set of rules GitHub enforces on a specific branch — almost always main — regardless of who's pushing. Crucially, it doesn't remove anyone's permissions; Tripathi still has push access to the repo. It just narrows which kinds of pushes are allowed to land on that one branch. Everything still has to come in through the front door: a pull request that satisfies the rules.
The rules actually turned on for `.github`, `website`, and `resources`
| Rule | What it stopped, in this story |
|---|---|
| Require a PR before merging | No one — not even you, back in Chapter 2 — can push straight to main anymore once this is on. Everything goes through review, the way Ishaan's typo fix did. |
| Require 1 approval | Ishaan's PR couldn't merge until Vidha approved it. One person's opinion, even the author's own, isn't enough by itself. |
| Dismiss stale reviews on new commits | If Ishaan had pushed another change after Vidha's approval, her approval would reset — she has to look again at what's actually there now, not what she saw an hour ago. |
| Block force-pushes | Exactly what stopped Tripathi just now. |
| Block branch deletion | Nobody, including an Owner, can delete main by accident or otherwise. |
CODEOWNERS — making sure the right person gets asked
Branch protection stops the wrong kind of push. It doesn't, by itself, make sure the right person reviews a given change — Vidha happened to review Ishaan's PR because she runs the beginner track and was already in the room. A file named CODEOWNERS automates that instead of leaving it to chance:
# .github/CODEOWNERS
# Fallback — anything not matched below
* @accelerate-muj/executive-board
# Constitution and governance — the people actually accountable for it
CONSTITUTION.md @accelerate-muj/executive-board
GOVERNANCE.md @shashwat-deep @TheQMLGuy
# Website source — Core Committee's territory
/src/ @accelerate-muj/core-committee
# CI and deploy workflows — don't let these change quietly
/.github/workflows/ @TheQMLGuy @sahil-handle
# Beginner Git-track docs — Vidha owns the content
/git-guide/ @vidha-handle
With this in place and combined with branch protection's "Require review from Code Owners" rule, a PR touching /git-guide/ automatically requests Vidha specifically, the moment it's opened — nobody has to remember to tag her.
Status checks — a machine's approval, not just a human's
Once Chapter 17 wires up automated checks, branch protection can require them to pass too, not just a human approval. A PR that fails a required check simply can't be merged — the button stays disabled — regardless of how many humans approved it. Typical required checks for a project like this: lint, test, build.
Rulesets — the newer, more flexible version
GitHub's newer "Rulesets" feature covers everything classic branch protection does, plus wildcard branch patterns (release/*, not just main), multiple composable rulesets, and a dry-run "evaluate" mode that reports what would be blocked before actually enforcing anything. For an org this size, classic branch protection is enough — rulesets earn their complexity once there are many branch patterns to manage at once.
website repo. Why did his force-push get rejected?Every rule in this chapter has been about the code itself — who can push it, who has to review it, what has to pass first. But a huge amount of the club's actual coordination — what needs doing, who's doing it, what's blocked on what — has been happening entirely in a group chat this whole time, with no record anywhere in GitHub at all. That's about to change.