Skip to main content
hooksSource-backedReview first Safety · Privacy ·

Git Pre Commit Validator - Hooks

Comprehensive pre-commit hook that validates code quality, runs tests, and enforces standards.

by JSONbored·added 2025-09-16·
Claude Code
HarnessClaude Code
Trigger:PreToolUse
Review first review before installing

Open the source and read safety notes before installing.

Schema details

Install type
cli
Reading time
1 min
Difficulty score
0
Troubleshooting
Yes
Breaking changes
No
Runtime and command metadata
Trigger
PreToolUse
Script language
bash
Script body
#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# Only run on git commit commands
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi

echo "🔍 Running pre-commit validations..."

# Check for staged files
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
if [ -z "$STAGED_FILES" ]; then
  echo "No staged files to validate"
  exit 0
fi

echo "Validating staged files: $STAGED_FILES"

# Check for forbidden files
echo "Checking for forbidden files..."
if echo "$STAGED_FILES" | grep -E "\.(env|DS_Store)$|node_modules/"; then
  echo "❌ Forbidden files detected in staging area" >&2
  echo "Remove .env, .DS_Store, or node_modules files before committing" >&2
  exit 2
fi

# Check file sizes
echo "Checking file sizes..."
for file in $STAGED_FILES; do
  if [ -f "$file" ]; then
    size=$(wc -c < "$file")
    if [ "$size" -gt 10485760 ]; then  # 10MB limit
      echo "⚠️ Large file detected: $file ($(($size / 1024 / 1024))MB)" >&2
    fi
  fi
done

# Run linting if available
if command -v npm &> /dev/null && [ -f "package.json" ]; then
  echo "Running ESLint..."
  npm run lint 2>/dev/null || echo "⚠️ Linting issues found" >&2
fi

# Run formatting if available
if command -v prettier &> /dev/null; then
  echo "Running Prettier..."
  prettier --check $STAGED_FILES 2>/dev/null || echo "⚠️ Formatting issues found" >&2
fi

# Run tests if available
if command -v npm &> /dev/null && [ -f "package.json" ]; then
  echo "Running tests..."
  npm test 2>/dev/null || echo "⚠️ Tests failed" >&2
fi

echo "✅ Pre-commit validation completed" >&2
exit 0
Full copyable content
{
  "hooks": {
    "preToolUse": {
      "script": "./.claude/hooks/git-pre-commit-validator.sh",
      "matchers": [
        "git"
      ]
    }
  }
}

About this resource

Features

  • Code quality validation with linting and formatting using ESLint for JavaScript/TypeScript, Prettier for code formatting, RuboCop for Ruby, Black for Python, and language-specific linters with configurable rules and auto-fix capabilities
  • Security scanning for secrets and vulnerabilities with pattern matching for API keys, passwords, tokens, certificates, and sensitive data detection including .env files, private keys, and credential patterns with actionable warnings
  • Automated test execution before commits with support for multiple test frameworks (Jest, Mocha, pytest, RSpec, Go test) including test discovery, related test execution for changed files, and test timeout configuration
  • File validation and size limits with configurable file size thresholds (default 10MB), forbidden file detection (.env, .DS_Store, node_modules), binary file detection, and file type validation with customizable rules
  • Commit message format enforcement with conventional commit message validation (feat:, fix:, docs:, etc.), pattern matching for commit message formats, and commit message length validation with actionable error messages
  • Support for multiple programming languages (JavaScript, TypeScript, Python, Ruby, Go, Rust) with language-specific validation tools, automatic language detection based on file extensions, and multi-language project support
  • Integration with popular pre-commit frameworks (pre-commit, husky, lint-staged) with configuration file support (.pre-commit-config.yaml, package.json scripts), framework detection, and seamless integration with existing workflows
  • Configurable validation rules with environment variable overrides (SKIP_VALIDATION, SKIP_TESTS, SKIP_LINT), project-specific configuration files, and selective validation based on file types and project structure

Use Cases

  • Enforce code quality standards before commits automatically running linting and formatting checks to ensure consistent code style and quality across the team with actionable error messages
  • Automated testing in git workflows automatically executing tests before commits to catch bugs early and prevent broken code from entering the repository with test failure prevention
  • Prevent commits with security vulnerabilities automatically scanning for secrets, API keys, passwords, and sensitive data before commits to prevent accidental exposure of credentials
  • Maintain consistent code formatting across team automatically checking and optionally fixing code formatting issues before commits to ensure consistent style and reduce code review time
  • Validate commit message conventions automatically enforcing conventional commit message formats and commit message standards to maintain clear commit history and enable automated changelog generation
  • Development workflow integration seamlessly integrating pre-commit validation into development workflows without manual validation steps or separate quality checking tools

Installation

  1. Create hooks directory: mkdir -p .claude/hooks
  2. Create hook file: touch .claude/hooks/git-pre-commit-validator.sh
  3. Make executable: chmod +x .claude/hooks/git-pre-commit-validator.sh
  4. Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
  5. Alternative: Use the interactive /hooks command in Claude Code

Config paths

  • Local (not committed): .claude/settings.local.json
  • User settings (global): ~/.claude/settings.json
  • Project-wide (committed): .claude/settings.json

Requirements

  • Claude Code CLI installed
  • Project directory initialized
  • Git repository initialized
  • Bash shell available
  • npm/node (optional, for JavaScript/TypeScript projects)
  • Python (optional, for Python projects)
  • Ruby (optional, for Ruby projects)

Hook Configuration

{
  "hooks": {
    "preToolUse": {
      "script": "./.claude/hooks/git-pre-commit-validator.sh",
      "matchers": ["git"]
    }
  }
}

Hook Script

#!/usr/bin/env bash

# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')

# Only run on git commit commands
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi

echo "🔍 Running pre-commit validations..."

# Check for staged files
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
if [ -z "$STAGED_FILES" ]; then
  echo "No staged files to validate"
  exit 0
fi

echo "Validating staged files: $STAGED_FILES"

# Check for forbidden files
echo "Checking for forbidden files..."
if echo "$STAGED_FILES" | grep -E "\.(env|DS_Store)$|node_modules/"; then
  echo "❌ Forbidden files detected in staging area" >&2
  echo "Remove .env, .DS_Store, or node_modules files before committing" >&2
  exit 2
fi

# Check file sizes
echo "Checking file sizes..."
for file in $STAGED_FILES; do
  if [ -f "$file" ]; then
    size=$(wc -c < "$file")
    if [ "$size" -gt 10485760 ]; then  # 10MB limit
      echo "⚠️ Large file detected: $file ($(($size / 1024 / 1024))MB)" >&2
    fi
  fi
done

# Run linting if available
if command -v npm &> /dev/null && [ -f "package.json" ]; then
  echo "Running ESLint..."
  npm run lint 2>/dev/null || echo "⚠️ Linting issues found" >&2
fi

# Run formatting if available
if command -v prettier &> /dev/null; then
  echo "Running Prettier..."
  prettier --check $STAGED_FILES 2>/dev/null || echo "⚠️ Formatting issues found" >&2
fi

# Run tests if available
if command -v npm &> /dev/null && [ -f "package.json" ]; then
  echo "Running tests..."
  npm test 2>/dev/null || echo "⚠️ Tests failed" >&2
fi

echo "✅ Pre-commit validation completed" >&2
exit 0

Examples

Git Pre Commit Validator Hook Script

Complete hook script that performs pre-commit validation before Git commits

#!/usr/bin/env bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
if [ -z "$STAGED_FILES" ]; then
  exit 0
fi
echo "🔍 Running pre-commit validations..." >&2
if echo "$STAGED_FILES" | grep -E "\.(env|DS_Store)$|node_modules/"; then
  echo "❌ Forbidden files detected in staging area" >&2
  exit 1
fi
if command -v npm &> /dev/null && [ -f "package.json" ]; then
  if grep -q '"lint"' package.json; then
    npm run lint 2>/dev/null || exit 1
  fi
fi
echo "✅ Pre-commit validation completed" >&2
exit 0

Hook Configuration

Complete hook configuration for .claude/settings.json to enable pre-commit validation

{
  "hooks": {
    "preToolUse": {
      "script": "./.claude/hooks/git-pre-commit-validator.sh",
      "matchers": ["git"]
    }
  }
}

Security Scanning for Sensitive Files

Enhanced hook script for security scanning and sensitive file detection

#!/usr/bin/env bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
if [ -z "$STAGED_FILES" ]; then
  exit 0
fi
SENSITIVE_PATTERNS=(".env" "*secret*" "*password*" "*key*" "id_rsa" "id_ed25519" "*.pem")
SENSITIVE_FOUND=false
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
  if echo "$STAGED_FILES" | grep -q "$pattern"; then
    SENSITIVE_FOUND=true
    echo "⚠️ Potentially sensitive file detected: $pattern" >&2
  fi
done
if [ "$SENSITIVE_FOUND" = true ]; then
  echo "❌ Security: Sensitive files detected in staging area" >&2
  exit 1
fi
exit 0

File Size Validation

Enhanced hook script for file size validation with Git LFS recommendations

#!/usr/bin/env bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null || echo "")
if [ -z "$STAGED_FILES" ]; then
  exit 0
fi
MAX_SIZE=10485760
for file in $STAGED_FILES; do
  if [ -f "$file" ]; then
    size=$(wc -c < "$file" 2>/dev/null || echo "0")
    if [ "$size" -gt "$MAX_SIZE" ]; then
      size_mb=$((size / 1024 / 1024))
      echo "⚠️ Large file detected: $file (${size_mb}MB)" >&2
      if [ "$size" -gt 52428800 ]; then
        echo "❌ File exceeds 50MB limit - consider using Git LFS" >&2
        exit 1
      fi
    fi
  fi
done
exit 0

Commit Message Format Validation

Enhanced hook script for commit message format validation with conventional commits

#!/usr/bin/env bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
if [[ "$COMMAND" != *"git commit"* ]]; then
  exit 0
fi
COMMIT_MSG=$(git log -1 --pretty=%B 2>/dev/null || echo "")
if [ -n "$COMMIT_MSG" ]; then
  if ! echo "$COMMIT_MSG" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?:"; then
    echo "⚠️ Commit message doesn't follow conventional format" >&2
    echo "Expected format: type(scope): description" >&2
    echo "Types: feat, fix, docs, style, refactor, test, chore" >&2
  fi
fi
exit 0

Troubleshooting

Hook blocks all git commits even when validation passes

Ensure script exits with exit 0 on success. Check that matchers pattern ['git'] doesn't intercept non-commit git commands like status or diff which should bypass validation. Verify command detection logic: 'if [["$COMMAND" != "git commit"]]; then exit 0; fi'. Test with different git commands to ensure only commits are validated.

npm run lint fails with 'script not found' error

Add existence check before running: '[ -f package.json ] && grep -q '"lint"' package.json' before npm run lint. Provide fallback or skip linting gracefully if unavailable. Check package.json for lint script: 'grep -q '"lint"' package.json'. Use conditional execution: 'if command -v npm &> /dev/null && [ -f package.json ] && grep -q '"lint"' package.json; then npm run lint; fi'.

Prettier check prevents commits due to formatting differences

Auto-fix formatting instead of blocking: 'prettier --write $STAGED_FILES && git add $STAGED_FILES'. Alternatively, set --warn-only flag to log issues without exit code. Use prettier --check for validation only. Consider using lint-staged for automatic formatting. Add SKIP_FORMAT environment variable for emergency overrides.

Test suite runs entire test set causing slow commit times

Run only tests related to changed files: 'npm test -- --findRelatedTests $STAGED_FILES'. Add timeout: 'npm test -- --maxWorkers=2 --bail' for faster feedback. Use test filtering: 'npm test -- --testPathPattern=$(echo $STAGED_FILES | tr ' ' '|')'. Consider using SKIP_TESTS environment variable for local development. Add test timeout limits.

Hook rejects large files but files are already in history

Check if file is new vs modified: 'git diff --cached --diff-filter=A' to detect additions only. Skip size check for existing tracked files to avoid retroactive enforcement. Use 'git ls-files --cached' to check if file is already tracked. Add logic to skip size validation for modified files: 'if git ls-files --error-unmatch "$file" &> /dev/null; then continue; fi'.

Security scanning false positives for legitimate files

Refine sensitive file patterns to avoid false positives. Use whitelist for known safe files: 'if echo "$file" | grep -qE "(test|spec|example|sample)"; then continue; fi'. Add configuration file for custom patterns. Use git-secrets or similar tools for more accurate detection. Consider using SKIP_SECURITY environment variable for development.

Commit message validation too strict for project conventions

Customize commit message patterns based on project requirements. Use environment variable for custom patterns: 'COMMIT_MSG_PATTERN'. Add project-specific configuration file. Make validation optional with SKIP_COMMIT_MSG environment variable. Support multiple commit message formats. Use case-insensitive matching for flexibility.

Validation fails in CI/CD environments with different tool versions

Use version pinning for validation tools. Check tool versions before running: 'eslint --version'. Add version compatibility checks. Use Docker containers for consistent environments. Consider using pre-commit framework for tool management. Add SKIP_VALIDATION environment variable for CI/CD overrides. Document required tool versions.

#git#validation#code-quality#testing#automation

Source citations

Signals

Loading live community signals…

More like this, weekly

A short, calm digest of reviewed Claude resources. Unsubscribe any time.