Github does not make it obvious how to protect your primary branch from direct pushes.

(Nowadays the primary branch is usually named main, but you wil still see the name master in the wild. For this post I’m going to reference main.)

The problem, with a typical setup, Administrators are allowed to push to main. Force pushing is protected by default, but not regular old pushing.

The other problem is we’re all human, especially us Administrators. I’ve more than once accidentally pushed to main thinking I was on a feature branch. But alas I wasn’t.

So I argue preventing all users, even Admins, pushing to main is the ideal. I guess Github doesn’t see it my way.

Option 1: Update the Repo Settings

Navigate to your project’s settings and change the branch protection rules.

Check this box:

David Nix Avatar

Now when you push to main you’ll see this error:

! [remote rejected] main -> main (protected branch hook declined)

But there’s some gotchas.

First, Github repos on the free plan may not have this option. Gotta pay to protect yourself from yourself, I guess.

Second, you will no longer see the admin override checkbox on PRs.

David Nix Avatar

I like that checkbox. I don’t use it often. You shouldn’t use it often. But sometimes, you have to get an emergency PR out the door.

There are less-ideal workarounds. An admin can temporarily disable the push protection. But then you have the onerous task of remembering to turn it back on when you’re done.

Option 2: Hack your Git Config

git config branch.main.pushRemote push_to_main_not_allowed

This is a hack that sets the remote to a bogus repository.

The hack works well, but my only issue is you get a confusing error message when it fails:

fatal: 'push_to_main_not_allowed' does not appear to be a git repository
fatal: Could not read from remote repository.

To undo:

git config --edit

And delete the pushRemote line(s).

You could set this in your global git config. And I almost did. But, I have several side projects (like this blog) where I often push directly to main.

Option 3: Git Hooks

Create this file as .git/hooks/pre-commit

#!/bin/sh

branch="$(git rev-parse --abbrev-ref HEAD)"

if [ "$branch" = "main" ]; then
  echo "main branch commit is blocked"
  exit 1
fi

This stops you from making any commits to main.

Option 4: All the Rest