Files
gitea-custom/git-hooks/deny-binary
2025-12-18 11:44:03 +01:00

95 lines
2.9 KiB
Bash
Executable File

#!/bin/bash -eu
#
# Reject commits with binary files, which should have used LFS instead. Allow
# overriding when "override restrictions" is in the commit message.
#
# To enable this hook, rename this file to "pre-receive" or place it in
# a "pre-receive.d" folder.
# Use 'strict mode': http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -o pipefail
nullsha="0000000000000000000000000000000000000000"
status=0
# This is the message to include in your commit to override.
commit_override_msg="override restrictions"
handle_pipefails() {
# ignore exit code 141 from simple command pipes
# - use with: cmd1 | cmd2 || handle_pipefails $?
(( $1 == 141 )) && return 0
return $1
}
# Read stdin for ref information.
while read oldrev newrev refname; do
# Skip branch deletions.
if [ "$newrev" = "$nullsha" ]; then
continue
fi
# Set oldrev to HEAD if this is branch creation.
if [ "$oldrev" = "$nullsha" ]; then
oldrev="HEAD"
fi
# Check for branches and tags, but not pull requests in refs/pull. Otherwise Gitea
# fails to create a pull request without explaining why.
if [[ "$refname" == refs/heads/* ]]; then
:
elif [[ "$refname" == refs/tags/* ]]; then
:
else
exit 0
fi
# Loop over each commit.
for commit in $(git rev-list --objects ${oldrev}..${newrev} |
git cat-file --batch-check='%(objectname) %(objecttype) %(objectsize) %(rest)' | grep commit | awk '{print $1}'); do
# Get list of potentially binary files in this commit
mapfile -t binary_files < <(git log --diff-filter=d --pretty=format:%H -M100% --numstat ${commit}^! | grep -e "- - \w" | awk '{print $3}')
if [ ${#binary_files[@]} -eq 0 ]; then
continue
fi
# Check for override message
override=0
if git log --pretty=format:%B ${commit}^! | grep -qi "${commit_override_msg}"; then
override=1
fi
rejected_files=()
for file in "${binary_files[@]}"; do
# Check if it's an LFS pointer
# Use handle_pipefails as we may run into SIGPIPE error code
if git show "${commit}:${file}" | git lfs pointer --check --stdin || handle_pipefails $?; then
continue
fi
rejected_files+=("$file")
done
if [ ${#rejected_files[@]} -gt 0 ]; then
if [ "$override" -gt 0 ]; then
echo "Your push contains binary files but was accepted because of override commit message:"
else
status=1
echo "Your push was rejected because it contains binary files not tracked by Git LFS:"
fi
echo "Commit: $commit"
for file in "${rejected_files[@]}"; do
echo "File: $file"
done
fi
done
done
if [ "$status" -ne "0" ]; then
echo
echo "You must make sure that the binary files are tracked with Git LFS or seek help from the repo administrators."
echo "(Perhaps you did not setup Git LFS with 'git lfs install'?)"
echo
fi
exit $status