Home/Engineer/Git / CI·CD/Git Hooks in Practice — Auto…
Git / CI·CDIntermediateUbuntuDebianmacOSgitgit-hookspre-commit

Git Hooks in Practice — Automating Code Quality with pre-commit

Explains how to write pre-commit, commit-msg, and pre-push hooks yourself, or use the pre-commit framework to automatically run linting, formatting, and tests before a commit.

Contents
  1. Git Hooks Location
  2. Writing a pre-commit Hook Yourself
  3. commit-msg Hook — Enforcing Commit Message Format
  4. pre-push Hook — Push Only After Tests Pass
  5. The pre-commit Framework (Recommended)
  6. Bypassing Hooks (Emergencies Only)

Git Hooks Location

Bash
ls .git/hooks/
# pre-commit.sample, commit-msg.sample, pre-push.sample ...

Hook files must be saved without an extension and granted execute permission.


Writing a pre-commit Hook Yourself

Bash
# .git/hooks/pre-commit
#!/usr/bin/env bash
set -e

echo "Running pre-commit checks..."

# ESLint
if ! npx eslint --max-warnings 0 $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts)$'); then
  echo "ESLint failed. Fix errors before committing."
  exit 1
fi

# Prettier check
if ! npx prettier --check $(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|json|css)$'); then
  echo "Prettier check failed. Run: npx prettier --write ."
  exit 1
fi

echo "Pre-commit checks passed."
Bash
chmod +x .git/hooks/pre-commit

commit-msg Hook — Enforcing Commit Message Format

Bash
# .git/hooks/commit-msg
#!/usr/bin/env bash
COMMIT_MSG_FILE="$1"
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

# Conventional Commits
PATTERN='^(feat|fix|docs|style|refactor|test|chore|perf|ci)(\(.+\))?: .{1,72}'
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
 echo "❌ when "
 echo " : feat: "
 echo " : feat|fix|docs|style|refactor|test|chore|perf|ci"
  exit 1
fi

pre-push Hook — Push Only After Tests Pass

Bash
# .git/hooks/pre-push
#!/usr/bin/env bash
set -e

echo "Running tests before push..."
npm test -- --passWithNoTests

echo "All tests passed. Pushing..."

To share hooks across a team, use the pre-commit framework.

Bash
pip install pre-commit
YAML
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-json
      - id: check-merge-conflict

  - repo: https://github.com/pre-commit/mirrors-eslint
    rev: v8.56.0
    hooks:
      - id: eslint
        files: \.(js|ts)$
        additional_dependencies:
          - eslint@8.56.0

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
Bash
# ( run)
pre-commit install
pre-commit install --hook-type commit-msg

# run
pre-commit run --all-files

# file
pre-commit run --files src/index.ts

Bypassing Hooks (Emergencies Only)

Bash
git commit --no-verify -m "hotfix: "
git push --no-verify

Do not use this routinely. Agree on team rules so that bypasses leave an audit trail.

#git#git-hooks#pre-commit
Editorial note

AI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us

Topic-related official docs (auto-linked · not per-claim sources)Git documentation ↗

Questions & answers

Ask a question about this guide. We'll review and reply.