Skip to content

Git Hooks and Automation โ€‹

Introduction โ€‹

Git hooks are scripts that run at specific lifecycle events, enabling automation for quality, security, and compliance. This tutorial covers local hooks, server-side hooks (conceptually), and modern tooling wrappers.

Hook Categories โ€‹

TypeRuns WhenExample Use
Client (local)Developer actionsLint before commit
Server-sidePush / receiveEnforce commit policy

Location โ€‹

.git/hooks/ directory contains sample scripts (with .sample suffix). Enable by removing suffix and making executable.

Common Client Hooks โ€‹

HookTriggerExample
pre-commitBefore committing staged snapshotLint / format / test subset
commit-msgAfter message enteredEnforce conventional commits
pre-pushBefore pushRun fast test suite
post-mergeAfter mergeInstall dependencies
prepare-commit-msgBefore editor opensInject template

Simple Pre-Commit Example โ€‹

.git/hooks/pre-commit:

bash
#!/usr/bin/env bash
echo "Running lint..."
eslint . || exit 1

Make executable:

bash
chmod +x .git/hooks/pre-commit

Commit Message Validation โ€‹

.git/hooks/commit-msg:

bash
#!/usr/bin/env bash
MSG_FILE=$1
PATTERN='^(feat|fix|docs|refactor|test|chore|perf)(\(.+\))?: .+'
if ! grep -Eq "$PATTERN" "$MSG_FILE"; then
  echo "Commit message must follow conventional format" >&2
  exit 1
fi

Sharing Hooks (Problem & Solution) โ€‹

Local hooks are not versioned by default. Solutions:

  1. Use a wrapper tool (Husky, Lefthook, pre-commit)
  2. Custom script: store hooks in ./hooks and symlink/copy

Husky Example (JavaScript Project) โ€‹

bash
npx husky add .husky/pre-commit "npm test"

Creates .husky/pre-commit maintained in repo.

Python pre-commit Framework Example โ€‹

.pre-commit-config.yaml snippet:

yaml
repos:
  - repo: https://github.com/psf/black
    rev: 24.3.0
    hooks:
      - id: black

Install:

bash
pre-commit install

Server-Side Hooks (Overview) โ€‹

Exist on remote (bare) repos: pre-receive, update, post-receive for enforcing policy (signed commits, size limits). Usually managed by platform (GitHub Actions / GitLab push rules).

What to Automate โ€‹

  • Lint & format
  • Type check
  • Secret scanning
  • Unit tests (fast subset)
  • Commit message quality
  • License header insertion

What NOT to Automate in Hooks โ€‹

  • Long integration tests (push/CI instead)
  • Heavy builds (slow dev loop)
  • External deployments (use CI/CD triggers)

Failing Fast Philosophy โ€‹

Catch low-effort issues locally; keep CI green and reviewers focused on logic, not style.

Security Considerations โ€‹

Only run trusted hook code. Review third-party hook frameworks pinned to versions.

Disabling Temporarily โ€‹

bash
git commit --no-verify

Use sparingly; investigate why a hook fails.

Auditing Hook Performance โ€‹

Log durations; if pre-commit > 2โ€“3s, developers will bypass. Optimize by scoping (e.g., lint changed files only).

Example Fast Lint Script (Changed Files) โ€‹

bash
#!/usr/bin/env bash
CHANGED=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$') || true
if [ -z "$CHANGED" ]; then
  echo "No JS/TS changes."; exit 0
fi
eslint $CHANGED || exit 1

Summary โ€‹

Hooks raise baseline quality, shift feedback left, and encode cultural standards. Keep them fast, versioned, and transparent.

Next Steps โ€‹

  • Team practices (git-best-practices-for-team-collaboration.md)
  • Submodules (git-submodules-and-large-repositories.md)

Key Commands

bash
git config core.hooksPath hooks
chmod +x .git/hooks/<hook>