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
@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