romele / git-trace public
62 commits · 1 branch · 1 tag · 1 contributor (top: Romele) · first commit 3d ago · last push 17m ago
hooks/update
#!/bin/sh
# git-trace update hook — per-ref policy enforcement.
# Installed as <repo>.git/hooks/update by `git-trace mkrepo`.
# Args: refname oldrev newrev. Env: REMOTE_USER is set when the push
# arrives over HTTP/SSH (empty for local file pushes).
ref="$1"
old="$2"
new="$3"
case "$ref" in
refs/heads/*|refs/tags/*) ;;
*)
echo "git-trace: refusing to update '$ref'" >&2
exit 1
;;
esac
zero=0000000000000000000000000000000000000000
def=$(git symbolic-ref -q --short HEAD 2>/dev/null)
if [ "$new" = "$zero" ]; then
# ref deletion: the default branch is always protected
if [ -n "$def" ] && [ "$ref" = "refs/heads/$def" ]; then
echo "git-trace: refusing to delete the default branch" >&2
exit 1
fi
elif [ -n "$def" ] && [ "$ref" = "refs/heads/$def" ] && \
[ "$old" != "$zero" ]; then
# the default branch additionally rejects non-fast-forward pushes
if ! git merge-base --is-ancestor "$old" "$new" 2>/dev/null; then
echo "git-trace: refusing non-fast-forward push to $def" >&2
exit 1
fi
fi
# branch_rules + storage quota + push audit: run last so a rejected
# push is never journaled as accepted. Deletions reach branch-check
# too (no_delete rules). GIT_TRACE_BIN and env are baked in by mkrepo.
if [ -n "${GIT_TRACE_BIN:-}" ]; then
"$GIT_TRACE_BIN" branch-check "$ref" "$old" "$new" || exit 1
"$GIT_TRACE_BIN" quota-check "$ref" "$new" || exit 1
fi
exit 0