1001Ferramentas
๐ŸชGenerators

Git pre-receive hook

Generate bash pre-receive Git server hook with branch/author/size checks.


  

Git pre-receive hooks: server-side gatekeepers for every push

Git hooks are executable scripts that Git runs automatically at specific events in the lifecycle of a repository. Local hooks live in .git/hooks/; server-side hooks live in the hooks/ directory of a bare repository on the Git server. Any file in those directories whose name matches a known hook event and that is marked executable (chmod +x) becomes the handler for that event. Scripts can be written in any language as long as they start with a proper shebang: #!/bin/bash, #!/usr/bin/env python3, #!/usr/bin/env node โ€” Git just forks and executes.

The pre-receive hook is the most powerful enforcement point in the entire Git protocol. It runs once per push, on the server, before any ref is updated. It receives one line per ref on stdin, formatted as <old-sha> <new-sha> <ref-name>. If the script exits with a non-zero status, the entire push is rejected โ€” every branch, every tag, atomically. There is no partial accept.

Skeleton script

#!/bin/bash
# .git/hooks/pre-receive  (chmod +x)
while read oldrev newrev refname; do
  if [ "$refname" = "refs/heads/main" ]; then
    echo "Direct pushes to main are not allowed" >&2
    exit 1
  fi
  # Reject commits whose message does not follow Conventional Commits
  for sha in $(git rev-list "$oldrev".."$newrev"); do
    msg=$(git log --format=%s -n 1 "$sha")
    if ! echo "$msg" | grep -Eq '^(feat|fix|docs|chore|refactor|test)(\(.+\))?: '; then
      echo "Commit $sha violates Conventional Commits: $msg" >&2
      exit 1
    fi
  done
done
exit 0

Common policies enforced by pre-receive

  • Block direct pushes to main, master, or release/* โ€” force every change through a pull request.
  • Validate commit messages against Conventional Commits, Jira ticket IDs, or a custom regex.
  • Reject secrets with gitleaks detect --staged or trufflehog before they leak into history.
  • Cap commit / push size to avoid 5 GB binary dumps polluting the server.
  • Require code review approval via API call back to the platform.
  • Enforce signed commits using git verify-commit on every revision.

The full hook family

  • pre-commit โ€” runs locally before git commit creates the commit object; perfect place for linters.
  • commit-msg โ€” receives the path to the message file; lets you validate or rewrite it.
  • pre-push โ€” runs locally before transferring objects to the remote.
  • pre-receive โ€” runs on the server before any ref update; rejects the whole push.
  • update โ€” runs on the server once per ref; can accept some refs and reject others.
  • post-receive โ€” runs on the server after refs are updated; ideal for CI triggers and deploys.
  • post-merge, post-checkout, post-rewrite โ€” local notification hooks for IDE plugins or dependency installers.

Platform support and alternatives

Server-side hooks depend entirely on the hosting platform. Raw Git (self-hosted bare repo over SSH) gives full freedom. Gitea, Gogs, and Forgejo expose pre-receive through their admin UI. GitHub Enterprise Server supports pre-receive hooks at the instance level, but GitHub.com does not โ€” you must replicate the same checks via GitHub Actions, branch protection rules, and required status checks. GitLab offers push rules (Premium) and custom server-side hooks; Bitbucket Data Center has its own SDK. Always test the matrix you target before relying on bash for enforcement.

Because local hooks are not versioned with the repository (anything under .git/ is ignored), they cannot be trusted as a security boundary. Husky, lefthook, pre-commit, and simple-git-hooks ship hooks via files committed to the repo and rebound to core.hooksPath, but a malicious contributor can still bypass them with git commit --no-verify. The only reliable enforcement layer is the server side โ€” which is why pre-receive matters.

FAQ

Does GitHub.com accept custom pre-receive hooks? No. Use Actions with required status checks, plus branch protection rules and CODEOWNERS for review enforcement.

How do I install the hook? Copy the script into the bare repo's hooks/ directory and run chmod +x pre-receive. Git executes it on the next push.

Can I call external programs from the hook? Yes โ€” bash, python, node, even compiled binaries are fine. Keep startup cheap; the hook runs on every push and slow hooks make developers angry.

Why does my push hang forever? Hook output goes back to the client over the network. If your script writes to /dev/tty or prompts for input, it will block indefinitely โ€” always read input only from stdin and write user messages to stderr.

How do I bypass the hook for emergencies? Server-side hooks cannot be bypassed by the client. Add a break-glass flag (e.g. a [emergency] trailer the hook recognizes) gated by group membership, or temporarily disable the hook with root access on the server.

Related Tools