Created
March 8, 2012 06:07
-
-
Save freshtonic/1999083 to your computer and use it in GitHub Desktop.
Git hook to disallow non-fastforward updates (also disallows merges into feature branches in order to keep them cleanly rebaseable)
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 | |
# This update hook enforces the following policies | |
# 1) release and master branches are fast-forward only | |
# 2) feature branches cannot contain merges | |
$refname = ARGV[0] | |
$oldrev = ARGV[1] | |
$newrev = ARGV[2] | |
puts "Enforcing Policies... \n(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})" | |
# Enforce fast-forward-only branches. | |
NO_NON_FASTFORWARD_BLACKLIST = [/\brelease\b/, /\bmaster\b/] | |
# Disallow merges in feature branches. | |
NO_MERGE_BLACKLIST = [/\bfeature\b/] | |
def abort_on_non_fastforward(blacklist) | |
if blacklist.any?{ |pattern| $refname =~ pattern} | |
missed_refs = `git rev-list #{$newrev}..#{$oldrev}` | |
missed_ref_count = missed_refs.split("\n").size | |
if missed_ref_count > 0 | |
puts "[POLICY] Cannot push a non fast-forward reference" | |
exit 1 | |
end | |
end | |
end | |
def abort_on_merge(blacklist) | |
if blacklist.any?{|pattern| $refname =~ pattern} | |
feature_commits = `git rev-list #{$refname} ^master ^$(git merge-base master #{$refname})`.lines.map do |l| | |
l.strip | |
end | |
if feature_commits.any?{|sha| is_merge_commit?(sha.strip) } | |
STDERR.puts <<-MSG | |
[ POLICY ] There are merge commits on #{$refname}. Feature branches should not | |
contain merge commits. In order to keep a feature branch up to date with | |
master, rebase it. Once you have rebased your feature branch to remove the | |
merge commits, you will be able to push it here. | |
MSG | |
exit 1 | |
end | |
end | |
end | |
def is_merge_commit?(sha) | |
`git cat-file -p #{sha}`.lines.select{|l| l =~ /^parent/}.count > 1 | |
end | |
abort_on_non_fastforward(NO_NON_FASTFORWARD_BLACKLIST) | |
abort_on_merge(NO_MERGE_BLACKLIST) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment