-
-
Save desyncr/4d5d36da44933bb88e63 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# NOTE! this is a work in progress. This is not tested or used regularly. | |
# Ensures we do not call destructive commands on protected branches. | |
# | |
# 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 force push to master, you should get a message `*** [Policy] never force push...` | |
# | |
# The commands below will not be allowed... | |
# `git push --force origin master` | |
# `git push --delete origin master` | |
# `git push origin :master` | |
# | |
# Nor will a force push while on the master branch be allowed... | |
# `git co master` | |
# `git push --force origin` | |
# | |
# Requires git 1.8.2 or newer | |
# | |
# Git 1.8.2 release notes cover the new pre-push hook: | |
# <https://github.com/git/git/blob/master/Documentation/RelNotes/1.8.2.txt> | |
# | |
# See Sample pre-push script: | |
# <https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--pre-push.sample> | |
# | |
# Also pulled ideas from: | |
# * http://blog.bigbinary.com/2013/09/19/do-not-allow-force-pusht-to-master.html | |
# * https://mug.im/how-to-prevent-yourself-from-force-pushing-to-master/ | |
class ProtectedBranchesHandler | |
def handle | |
if pushing_to_protected_branch? && command_is_destructive? | |
reject | |
else | |
exit 0 | |
end | |
end | |
def protected_branches | |
%w[master production] | |
end | |
private | |
def command_is_delete?(command) | |
command =~ /--delete/ | |
end | |
def command_is_destructive? | |
command_is_forced_push?(current_command) || command_is_delete?(current_command) | |
end | |
def command_is_forced_push?(command) | |
command =~ /--force|-f|--pfush/ | |
end | |
def current_branch | |
result = %x{git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,'} | |
if result =~ /^failure/ | |
exit_as_failure result | |
else | |
result | |
end | |
end | |
def current_command | |
$(ps -ocommand= -p $PPID) | |
end | |
def exit_as_failure(messages) | |
messages = Array(messages) | |
unless messages.empty? | |
puts "*"*40 | |
[messages].flatten.each do |message| | |
puts message | |
end | |
puts "*"*40 | |
end | |
exit 1 | |
end | |
def pushing_to_protected_branch? | |
protected_branches.include? current_branch | |
end | |
def reject | |
messages = ["Your attempt to run a destructive command on '#{current_branch}' has been rejected."] | |
messages << "If you still want to FORCE PUSH then you need to ignore the pre_push git hook by executing following command." | |
messages << "git push master --force --no-verify" | |
exit_as_failure messages | |
end | |
end | |
ProtectedBranchesHandler.new.handle |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment