DEV Community

pixiebrix
pixiebrix

Posted on

Disable a direct push to GitHub main branch

On a development team, you never want to push directly to the main branch. Instead, you want to require changes to be made through pull requests so they can be properly reviewed by other developers.
Some developers, including myself, occasionally forget to stuff their changes into a branch so I like to have an automated check to prevent this mistake. Here are two methods to block direct pushes to the GitHub main branch.

Pre-commit hook

The pre-commit framework includes a no-commit-to-branch hook which blocks direct commits to specific branches. By default, it blocks the master and main branches.
You can implement this by adding the following .pre-commit-config.yaml file to the repository root:



repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.1.0
    hooks:
      - id: no-commit-to-branch


Enter fullscreen mode Exit fullscreen mode

Then run pre-commit install. Now commits to main will result in an error:



$ git commit -m "Update again"
don't commit to branch...................................................Failed
- hook id: no-commit-to-branch
- exit code: 1


Enter fullscreen mode Exit fullscreen mode

Note, you can work around this check by uninstalling the pre-commit hook so it’s not foolproof.

Branch protection rule

GitHub has branch protection rules which allow you to enforce workflows for a one or more branches.
To create a branch protection rule, navigate to your repository’s settings. Click Branches and then Add rule under the “Branch protection rules” section.

Enter “main” under Branch name pattern. Then check Require a pull request before merging.
You’ll notice some additional features pop up. I generally check Require approvals so developers can’t sneak a change through without a proper sign-off.

Lastly, you may want to check Include administrators so the rule applies to repository admins. Keep in mind, however, that some git tools, such as Flux, need this access or they won’t work. So be cognizant of the tools you’re using and the privileges they need.

When you’re done, your rule should look like this:
image

Now direct pushes to main will result in an error:



$ git push
...
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Changes must be made through a pull request.
To github.com:johnnymetz/my-repo.git
 ! [remote rejected] main -> main (protected branch hook declined)
error: failed to push some refs to 'github.com:johnnymetz/my-repo.git'


Enter fullscreen mode Exit fullscreen mode

I prefer the second method because it’s foolproof and includes additional features.

Top comments (2)

Collapse
 
cicirello profile image
Vincent A. Cicirello

I prefer the branch protection rules approach as well. There are additional advantages such as the abiliity to require status checks to pass before merging. So if you build and run tests in a GitHub workflow on PRs, you can require build and tests to pass, or other checks like static analysis tools, etc.

Collapse
 
lawlawson profile image
Lawrence Narh-Lawson

Thanks for this, I went with the branch protection rules.