#!/bin/bash -eu # # Blender: modified version of update.sample in hooks directory to: # - Deny merge commits to release branches # - Deny merge of non-release branches to main # # This indirectly checks for accidentally merging main into release # branches, as main is almost certain to contain merge commits not # in the release branch. # # To enable this hook, rename this file to "pre-receive" or place it in # an "pre-receive.d" folder. # No revision indicator. zero_revision="0000000000000000000000000000000000000000" # Check if we need to verify merge commits for this branch. need_verify_merge_commit() { local branch="$1" local old_revision="$2" if [ "$old_revision" = "$zero_revision" ]; then # New branch, always ok to push. false elif [ "$branch" = "main" ]; then # Some merge commits allowed in main branch. true elif (echo "${branch}" | grep -Eq ^blender-v[0-9]\.[0-9][0-9]?-release$); then # No merge commits in release branch. true else false fi } # Check if this is an invalid merge commit. is_invalid_merge_commit() { local branch="$1" local revision="$2" # Detect if this revision is a merge commit. It's based on the commit merge # message which is weak, but not clear how to do it otherwise. if git show -s --format=%B ${revision} | grep -Eq "Merge (remote-tracking )?branch '"; then if (echo "${branch}" | grep -Eq ^blender-v[0-9]\.[0-9][0-9]?-release$); then # In release branch, all merge commits are invalid. true elif [ "$branch" = "main" ]; then # In main branch, only merge commits from release branches. if git show -s --format=%B ${revision} | grep -Eq "Merge (remote-tracking )?branch '(origin\/)?blender-v[0-9]\.[0-9][0-9]?-release'"; then false else true fi else false fi else false fi } # Read stdin for ref information. while read oldrev newrev refname; do # Detect type of update. if [ "$newrev" = "$zero_revision" ]; then newrev_type=delete else newrev_type=$(git cat-file -t $newrev) fi case "$refname","$newrev_type" in refs/tags/*,commit) # un-annotated tag ;; refs/tags/*,delete) # delete tag ;; refs/tags/*,tag) # annotated tag ;; refs/heads/*,commit) # branch branch=${refname##refs/heads/} if need_verify_merge_commit "$branch" "$oldrev"; then for r in $(test "$oldrev" = $zero_revision \ && git rev-list $newrev \ || git rev-list $newrev ^$oldrev); do is_invalid_merge_commit ${branch} ${r} && { printf "error: *** %s\n" \ "You may only merge release branches into main, no other merge commits are allowed." \ "See Blender's release branch developer documentation for details." >&2 exit 1 } done fi ;; refs/heads/*,delete) # delete branch ;; refs/remotes/*,commit) # tracking branch ;; refs/remotes/*,delete) # delete tracking branch ;; *) # Anything else (is there anything else?) ;; esac done exit 0