stackademic

The leading education platform for anyone with an interest in software development.

Git Hooks

Automate checks and actions by running scripts on Git lifecycle events

Overview

Git hooks are scripts that Git runs automatically at defined points in its lifecycle, such as before a commit or after a push is received. Client-side hooks (like pre-commit and commit-msg) enforce local quality checks, while server-side hooks (like pre-receive) enforce policy on shared repositories. Hooks live in .git/hooks, are not committed by default, and must be executable to run.

Syntax / Usage

Create an executable script named after the hook event. A non-zero exit code aborts the operation for "pre" hooks.

# Hooks live in the repository's hooks directory
ls .git/hooks/            # sample hooks end in .sample

# Create a pre-commit hook
cat > .git/hooks/pre-commit <<'EOF'
#!/bin/sh
npm run lint || exit 1
EOF
chmod +x .git/hooks/pre-commit

# Share hooks with the team by pointing Git at a tracked directory
git config core.hooksPath .githooks

Examples

Block commits that fail linting or tests with a pre-commit hook:

#!/bin/sh
# .githooks/pre-commit
npm run lint && npm test
# exit code propagates: non-zero aborts the commit

Enforce a commit-message convention with commit-msg:

#!/bin/sh
# .githooks/commit-msg — $1 is the path to the message file
grep -qE '^(feat|fix|docs|chore): ' "$1" || {
  echo "Message must start with feat:, fix:, docs:, or chore:"
  exit 1
}

Bypass hooks intentionally for an emergency commit:

git commit --no-verify -m "hotfix: skip checks"

Common Mistakes

  • Forgetting chmod +x, so the hook is silently ignored
  • Expecting hooks in .git/hooks to be shared—they are not tracked or pushed
  • Writing slow pre-commit hooks that frustrate developers into using --no-verify
  • Relying only on client-side hooks for security, which anyone can skip
  • Not setting core.hooksPath to distribute team hooks from a tracked folder

See Also

commit git-workflows remote