Public GitHub repos
this is basically the default behavior for public GitHub repos, you just need to lock down a couple of settings to be sure.
How it works
When your repo is public, anyone can fork it and open a Pull Request from their fork into your main. They cannot push to your repo or click "Merge" unless you've explicitly given them write access. So as long as you never add random public contributors as collaborators, they're structurally limited to "propose changes via PR" — only you (or people you add) can merge.
Steps to set this up properly:
Make the repo public
Repo → Settings → General → scroll to "Danger Zone" → Change repository visibility → Public.Don't add outside contributors as Collaborators
Settings → Collaborators and teams. Only people listed here (with Write/Admin role) can push directly or merge PRs. Leave this to just yourself/your team.Lock down
mainwith a branch protection rule (this is the important safety net)
Settings → Branches → Add branch protection rule → branch name patternmain:- ✅ "Require a pull request before merging" — disables direct pushes to
mainentirely, even for people with write access (forces everything through a PR). - ✅ "Require approvals" (e.g. 1) — so a PR needs your sign-off before it can be merged.
- ✅ "Restrict who can push to matching branches" — optionally lock this to just yourself/maintainers, as extra insurance.
- ✅ "Do not allow bypassing the above settings" — even admins follow the rule (or leave unchecked if you want yourself exempt).
- Optionally: "Require status checks to pass" if you have CI.
- ✅ "Require a pull request before merging" — disables direct pushes to
With this setup: anyone in the world can fork your repo and submit a PR. Nobody but you (or whoever you explicitly add) can merge that PR or push to main directly — and even you'll be required to go through the PR flow rather than pushing straight to main, if you check that last box.
One thing to flag since it's not strictly a coding question: if your repo currently has secrets, API keys, or sensitive history in old commits, scrub those before flipping it to public — visibility changes don't rewrite git history.
Upvoted! Thank you for supporting witness @jswit.