#!/bin/bash # This script checks gnome.org policy about how people are supposed to # use git; the intent of the policy is to keep people from shooting # themselve in the foot. # # Eventually, we'd like to have an ability to override policy; one way # it could work is that if you did 'git push --exec=force' and you # were a member of the right group, then run-git-or-special-cmd # would set an environment variable that this script would interpret. # Used in some of the messages server=git.labs.libre-entreprise.org GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) in_import() { test -e "$GIT_DIR/pending" } forced() { test -n "$GNOME_GIT_FORCE" } check_commit() { commit=$1 email="$(git log $commit -1 --pretty=format:%ae)" case "$email" in *localhost.localdomain|*\(none\)) if ! in_import && ! forced ; then cat <&2 --- The commits you are trying to push contain the author email address '$email'. Please configure your username and email address. See: http://live.gnome.org/Git/Help/AuthorEmail For instructions about how to do this and how to fix your existing commits. --- EOF exit 1 fi ;; esac subject="$(git log $commit -1 --pretty=format:%s)" if expr "$subject" : ".*Merge branch.*of.*\(git\|ssh\):" > /dev/null 2>&1; then if ! in_import && ! forced ; then cat <&2 --- The commit: EOF git log $commit -1 >&2 cat <&2 Looks like it was produced by typing 'git pull' without the --rebase option when you had local changes. Running 'git pull --rebase' now will fix the problem. Then please try, 'git push' again. Please see: http://live.gnome.org/Git/Help/ExtraMergeCommits --- EOF exit 1 fi fi } check_ref_update() { oldrev=$1 newrev=$2 refname=$3 change_type=update if expr $oldrev : "^0\+$" > /dev/null 2>&1; then change_type=create fi if expr $newrev : "^0\+$" > /dev/null 2>&1; then if [ x$change_type = xcreate ] ; then # Deleting an invalid ref, allow return 0 fi change_type=delete fi case $refname in refs/heads/*) # Branch update branchname=${refname#refs/heads/} range= case $change_type in create) range="$newrev" ;; delete) # We really don't like to allow deleting any branch, but # people need to do it to clean up accidentally pushed # branches. Deleting master, however, has no purpose other # than getting around the no-fast-forward restrictions if [ "x$branchname" = xmaster ] ; then cat <&2 --- You are trying to delete the branch 'master'. --- EOF exit 1 fi ;; update) range="$oldrev..$newrev" if [ `git merge-base $oldrev $newrev` != $oldrev ] && ! forced ; then # Non-fast-forward update. Right now we have # receive.denyNonFastforwards in the git configs for # our repositories anyways, but catching it here would # allow overriding without having to change the config # temporarily. cat <&2 --- You are trying to update the branch '$branchname' in a way that is not a fast-forward update. Please see: http://live.gnome.org/Git/Help/NonFastForward --- EOF exit 1 fi ;; esac # For new commits introduced with this branch update, we want to run some # checks to catch common mistakes. # # Expression here is same as in post-receive-notify-cia; we take # all the branches in the repo, as "^/ref/heads/branchname", other than the # branch we are actualy committing to, and exclude commits already on those # branches from the list of commits between $oldrev and $newrev. if [ -n "$range" ] ; then for merged in $(git rev-parse --symbolic-full-name --not --branches | \ egrep -v "^\^$refname$" | \ git rev-list --reverse --stdin "$range"); do check_commit $merged done fi ;; refs/tags/*) # Tag update tagname=${refname#refs/tags/} case $change_type in create) object_type=`git cat-file -t $newrev` case $object_type in commit) # Lightweight tag; we allow an import containing these # tags, but forbid them in general if ! in_import && ! forced ; then cat <&2 --- You are trying to push the lightweight tag '$tagname'. You should use a signed tag instead. See: http://live.gnome.org/Git/Help/LightweightTags --- EOF exit 1 fi ;; tag) # Annotated tag ;; *) # git is happy to allow tagging random objects, we aren't cat <&2 --- You are trying to push the tag '$tagname', which points to an object of type $object_type. (It should point to a commit or tag object.) --- EOF exit 1 ;; esac ;; delete) # Deleting a tag is probably someone trying to work-around # not being able to update a tag. Disallowing lightweight # tags will cut down on accidentally pushing tags called 'list' # or whatever. During import we allow the user to clean up # accidentally pushed tags. if ! in_import && ! forced ; then cat <&2 --- You are trying to delete the tag '$tagname'. http://live.gnome.org/Git/Help/TagUpdates --- EOF exit 1 fi ;; update) if ! forced ; then cat <&2 --- You are trying to replace the tag '$tagname' with a new tag. Please see: http://live.gnome.org/Git/Help/TagUpdates --- EOF exit 1 fi ;; esac ;; refs/remotes/*) # Remote tracking branch cat <&2 --- You are trying to push the remote tracking branch: $refname to $server. --- EOF exit 1 ;; *) # Something else cat <&2 --- You are trying to push the ref: $refname to $server. This isn't a branch or tag. --- EOF exit 1 ;; esac return 0 } if [ $# = 3 ] ; then check_ref_update $@ else while read oldrev newrev refname; do check_ref_update $oldrev $newrev $refname done fi exit 0