Skip to content

Instantly share code, notes, and snippets.

@vlucas
Created July 22, 2014 16:12
Show Gist options
  • Save vlucas/8009a5edadf8d0ff7430 to your computer and use it in GitHub Desktop.
Save vlucas/8009a5edadf8d0ff7430 to your computer and use it in GitHub Desktop.
Prevent Pushes Directly to Master
#!/bin/bash
# @link https://gist.github.com/mattscilipoti/8424018
#
# Called by "git push" after it has checked the remote status,
# but before anything has been pushed.
#
# If this script exits with a non-zero status nothing will be pushed.
#
# Steps to install, from the root directory of your repo...
# 1. Copy the file into your repo at `.git/hooks/pre-push`
# 2. Set executable permissions, run `chmod +x .git/hooks/pre-push`
# 3. Or, use `rake hooks:pre_push` to install
#
# Try a push to master, you should get a message `*** [Policy] Never push code directly to...`
#
# The commands below will not be allowed...
# `git push origin master`
# `git push --force origin master`
# `git push --delete origin master`
protected_branch='master'
policy="\n\n[Policy] Never push code directly to the "$protected_branch" branch! (Prevented with pre-push hook.)\n\n"
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
push_command=$(ps -ocommand= -p $PPID)
is_destructive='force|delete|\-f'
will_remove_protected_branch=':'$protected_branch
do_exit(){
echo -e $policy
exit 1
}
if [[ $push_command =~ $is_destructive ]] && [ $current_branch = $protected_branch ]; then
do_exit
fi
if [[ $push_command =~ $is_destructive ]] && [[ $push_command =~ $protected_branch ]]; then
do_exit
fi
if [[ $push_command =~ $will_remove_protected_branch ]]; then
do_exit
fi
# Prevent ALL pushes to protected_branch
if [[ $push_command =~ $protected_branch ]] || [ $current_branch = $protected_branch ]; then
do_exit
fi
unset do_exit
exit 0
Copy link

ghost commented Oct 10, 2015

How would you be able to do this via a pre-commit hook instead of a pre-push hook? I'm sort of thinking I'd rather not even let myself make commits to my master branch even if its on local. If I want to save my work it should be done (and committed) on my develop branch

[Edit: Now for example, I have a local repo that is separated from my remote repo, I want them to remain in sync completely]

@aaronhoffman
Copy link

@chrisdillenger you can add this as a pre-commit hook. via nvie/gitflow#330

branch=`git symbolic-ref HEAD`
if [ "$branch" = "refs/heads/master" ]; then
    echo "Direct commits to the master branch are not allowed."
    exit 1
fi

@basilmusa
Copy link

Not working for me on git for windows. It's giving an error on the following line:

 push_command=$(ps -ocommand= -p $PPID)

Error message:

ps: unknown option -- o

@ExplodingCabbage
Copy link

Lots of dubious stuff here. current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') fails if the branch name contains a /, the first two if blocks are redundant since the condition checked by the fourth one encompasses them both, and the use of =~ for comparing with master is dubious (since it'll match any branch name that contains the string master, like balance/decrease-master-mind-flayer-spawn-rate, not just master itself).

I'm also not sure about the portability of that ps incantation.

@jchoca
Copy link

jchoca commented Aug 4, 2020

I simplified this because I just wanted to avoid me accidentally doing git push when I'm on the master branch and don't know I am (and it didn't work with Windows/MINGW64).

protected_branch='master'

policy="\n\n[Policy] Never push code directly to the "$protected_branch" branch! (Prevented with pre-push hook.)\n\n"

current_branch=$(git rev-parse --abbrev-ref HEAD)

do_exit(){
  echo -e $policy
  exit 1
}

if [ $current_branch = $protected_branch ]; then
  do_exit
fi

unset do_exit

exit 0

@rubysolo
Copy link

With git 2.22+, you can do:

current_branch=$(git branch --show-current)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment