GitHub allows you to configure your repository so that users can't force push to master, but is there a way to prevent pushing to master entirely? I'm hoping to make it so that the only way of adding to commits to master is through the GitHub pull request UI.


Solution 1:

Since the original question / answer, Github has added a new option for this to the restricted branches UI which allows you to set this up.

Require pull request reviews before merging When enabled, all commits must be made to a non-protected branch and submitted via a pull request with the required number of approving reviews and no changes requested before it can be merged into a branch that matches this rule.

To find it go to Settings > Branches > Branch Protection Rules and click 'Add Rule'. Github UI after following instructions Then, enter the name of the branch you want to protect and click the checkbox to require pull request reviews before merging. Github UI with the button to click By default, this only stops people who are not moderators. There is also another checkbox later down for ensuring that even moderators cannot merge. Github UI with the other button to click

Solution 2:

The current accepted answer is actually correct but if you are an organization owner or have admin privileges, which is the case if you created the repo, you can still push to protected branches. From Github documentation at https://help.github.com/en/articles/about-branch-restrictions:

Organization owners and people with admin permissions for a repository are always able to push to a protected branch.

For any other type of collaborator, git push will fail.

If you really want to disable pushing at all, then you have to set that up locally either by configuring an invalid pushRemote for a branch as mentioned before:

git config branch.master.pushRemote no_push

or by creating a pre-push hook as shown here: https://gist.github.com/vlucas/8009a5edadf8d0ff7430

Solution 3:

Directly pushing to remote's master is rejected when status checks are enabled, meaning that the only way to add commits on remote's master is merging pull requests (which pass the status checks) on GitHub.

Here is my experiment result for the master branch requiring status checks:

  1. Create a commit on the master branch on my PC.
  2. Push to remote's master.
  3. A rejection message appears. The commit is not pushed to remote in the end.
C:\GitRepo\GitHub\TomoyukiAota\photo-location-map [master ↑1]> git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 305 bytes | 305.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
remote: error: GH006: Protected branch update failed for refs/heads/master.
remote: error: 3 of 3 required status checks are expected.
To https://github.com/TomoyukiAota/photo-location-map.git
 ! [remote rejected] master -> master (protected branch hook declined)
error: failed to push some refs to 'https://github.com/TomoyukiAota/photo-location-map.git'
C:\GitRepo\GitHub\TomoyukiAota\photo-location-map [master ↑1]>

Solution 4:

You can enable branch restrictions and decide who (in terms of users and teams of the organization) are allowed to push.

https://help.github.com/articles/about-branch-restrictions/

«Note: If the "Include administrators" is checked and you've enabled required status checks on the branch and they fail, any attempt to push changes to the base branch will also fail, regardless of a user or team's permission status.»

Solution 5:

If you are using free-plan on private repo in Github, you may not be able to use protected branch feature. So you need to block any push / commit from local.

This is what I did to make it work locally and distributed to all repo's members.

First of all, you need to install husky to control pre-commit and pre-push hook. Then, I made a pre-push bash script and commit it inside the repository. Then call this script from husky pre-push hook with husky parameter.

This is my husky configuration inside package.json (you can set separated config if you want)

"husky": {
    "hooks": {
        "pre-commit": "./commands/pre-commit",
        "pre-push": "./commands/pre-push $HUSKY_GIT_STDIN"
    }
},

as you can see I have 2 scripts, one for pre-push and one for pre-commit.

And this is my commands/pre-push bash script

#!/bin/bash

echo -e "===\n>> Talenavi Pre-push Hook: Checking branch name / Mengecek nama branch..."

BRANCH=`git rev-parse --abbrev-ref HEAD`
PROTECTED_BRANCHES="^(master|develop)"

if [[ $1 != *"$BRANCH"* ]]
then
  echo -e "\n🚫 You must use (git push origin $BRANCH) / Anda harus menggunakan (git push origin $BRANCH).\n" && exit 1
fi

if [[ "$BRANCH" =~ $PROTECTED_BRANCHES ]]
then
  echo -e "\n🚫 Cannot push to remote $BRANCH branch, please create your own branch and use PR."
  echo -e "🚫 Tidak bisa push ke remote branch $BRANCH, silahkan buat branch kamu sendiri dan gunakan pull request.\n" && exit 1
fi

echo -e ">> Finish checking branch name / Selesai mengecek nama branch.\n==="

exit 0

The script basically will do 2 things:

  • This script will block anybody who tries to push to a certain branch (in my case I don't want anybody -including myself- to push directly to master and develop branch). They need to work in their own branch and then create a pull request.
  • This script will block anybody who tries to push to a branch that is different from their current active branch. For example you are in branch fix/someissue but then you mistakenly type git push origin master.

For more detailed instructions you can follow from this article:
https://github.com/talenavi/husky-precommit-prepush-githooks