This should make sure we avoid merge commits from branches outside of PA (we don't really have any, so this should avoid all merge commits). This also catches "WIP" and such in the title to prevent accidental pushing of those. --- scripts/pre-receive.hook | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 scripts/pre-receive.hook diff --git a/scripts/pre-receive.hook b/scripts/pre-receive.hook new file mode 100755 index 0000000..7240c27 --- /dev/null +++ b/scripts/pre-receive.hook @@ -0,0 +1,89 @@ +#!/usr/bin/env python2 +import sys +import os +import subprocess + +# Based on the same file in: https://cgit.freedesktop.org/gstreamer/common +# Manually deployed to /srv/git.freedesktop.org/git/pulseaudio/pulseaudio.git/hooks + +# checks whether the push contains merge commits and if so, makes sure that +# the merge is only between branches present on the repository. +def contains_valid_merge(old, new, ref): + sub = subprocess.Popen(["git", "rev-list", "--parents", "%s..%s" % (old, new, )], + stdout=subprocess.PIPE) + stdout, stderr = sub.communicate() + + res = True + + print "=> Checking for merge commits" + + for line in stdout.split('\n'): + if res == False: + break + splits = line.strip().split() + if len(splits) > 2: + # the commit has more than one parent => it's a merge + commit = splits[0] + for parent in splits[1:]: + if not commit_in_valid_branch(parent): + print + print " /!\\ Commit %s" % commit + print " /!\\ is a merge commit from/to a branch not" + print " /!\\ present on this repository" + print + print " Make sure you are not attempting to push a merge" + print " from a 3rd party repository" + print + print " Make sure you have properly rebased your commits against" + print " the current official branches" + print + res = False + break + + if res: + print " [OK]" + print + return res + +# checks whether the first line of any commit message contains a marker +# that indicates that it's work-in-progress that shouldn't be pushed +def contains_wip_commits(old, new): + # Get the commit message header + sub = subprocess.Popen(["git", "log", "--format=%s", "%s..%s" % (old, new, )], stdout=subprocess.PIPE) + stdout, stderr = sub.communicate() + if stdout != "": + for line in stdout.strip().rsplit('\n',1): + if line.startswith("!"): + return True + if line.startswith("WIP:") or line.startswith("wip:"): + return True + return False + +pushvalid = True +error_badcommit = False + +for line in sys.stdin.readlines(): + # ref is the ref to be modified + # old is the old commit it was pointing to + # new is the new commit it was pointing to + old, new, ref = line.split(' ', 2) + + pushvalid = contains_valid_merge(old, new, ref) + if pushvalid == False: + break + if contains_wip_commits(old, new): + error_badcommit = True + pushvalid = False + break + +if pushvalid: + print " Incoming packet valid, proceeding to actual commit" + print + sys.exit(0) +else: + if error_badcommit: + print " Attempting to push commits with commit messages that start" + print " with '!' or 'WIP:'. Such commit messages are reserved for" + print " private branches and work in progress to prevent the commits" + print " from accidentally being pushed to the main repository." + sys.exit(-1) -- 2.9.3