Skip to content

Pre-commit Hooks Guide

This document explains the pre-commit hooks setup in the ERP-Unlocked monorepo and how to use them effectively.

The repository uses Husky and lint-staged to automatically format and lint your code before each commit. This ensures consistent code quality and style across all contributors.

When you run git commit, the following happens automatically:

1. Lint-Staged (Runs on Staged Files Only)

Section titled “1. Lint-Staged (Runs on Staged Files Only)”

The pre-commit hook runs these tools on your staged files:

TypeScript/JavaScript/Astro Files (*.{ts,tsx,js,jsx,astro})

Section titled “TypeScript/JavaScript/Astro Files (*.{ts,tsx,js,jsx,astro})”
  • ESLint with auto-fix (eslint --fix)
  • Prettier formatting (prettier --write)
  • Ruff linting with auto-fix (ruff check --fix)
  • Ruff formatting (ruff format)
  • Prettier formatting (prettier --write)

If you modify files in apps/ or packages/, the hook checks if a changeset exists:

  • Passes: If a changeset file exists in .changeset/
  • ⚠️ Warns: If no changeset found, prompts you to run pnpm changeset
  • 🔄 Skips: Automatically skipped for merge commits

When you clone the repository and run pnpm install, Husky is automatically initialized via the prepare script:

Terminal window
pnpm install

This installs all dependencies and sets up the Git hooks.

If hooks aren’t working, you can manually trigger setup:

Terminal window
pnpm prepare

Just commit as usual! The hooks run automatically:

Terminal window
git add .
git commit -m "feat: add new feature"

The hooks will:

  1. Format and lint your staged files
  2. Check for changesets (if needed)
  3. Complete the commit if everything passes

⚠️ Use sparingly! You can skip hooks if absolutely necessary:

Terminal window
git commit --no-verify -m "emergency hotfix"

When to bypass:

  • Emergency hotfixes that need immediate deployment
  • Fixing broken CI/CD pipelines
  • Addressing critical production issues

When NOT to bypass:

  • Regular feature development
  • Refactoring
  • Documentation updates

You can also run formatters manually:

Terminal window
# TypeScript/JavaScript/Astro/Markdown
pnpm format
# Python
pnpm format:python
# Check formatting without changing files
pnpm format:check
Terminal window
# Prettier
npx prettier --write path/to/file.ts
# Ruff
uv run ruff format path/to/file.py
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf"
}

Excludes generated files, build outputs, dependencies, and lock files from formatting.

{
"lint-staged": {
"*.{ts,tsx,js,jsx,astro}": ["eslint --fix", "prettier --write"],
"*.py": ["ruff check --fix", "ruff format"],
"*.md": ["prettier --write"]
}
}

For developers using the pre-commit framework (optional):

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.4
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

To use this:

Terminal window
# Install pre-commit (one-time)
pip install pre-commit
# Install hooks
pre-commit install
# Run manually on all files
pre-commit run --all-files
  1. Check if hooks are installed:

    Terminal window
    ls -la .husky/

    You should see a pre-commit file.

  2. Reinstall hooks:

    Terminal window
    pnpm prepare
  3. Verify Git hooks directory:

    Terminal window
    git config core.hooksPath

    Should output: .husky

If you get merge conflicts in formatted code:

  1. Accept the incoming changes
  2. Run the formatter:
    Terminal window
    pnpm format
    # or for Python
    pnpm format:python
  3. Stage and commit the formatted files

Some linting errors require manual fixes. If the pre-commit hook fails:

  1. Review the error messages
  2. Fix the issues manually
  3. Stage the fixes: git add .
  4. Try committing again

If hooks are slow on large commits:

  • Commit in smaller chunks to reduce the number of files checked
  • Use --no-verify only for emergency situations

If you get a changeset warning but don’t need one:

Terminal window
# For non-versioned changes (docs, configs, etc.)
git commit --no-verify -m "docs: update README"
# For versioned changes, create a changeset:
pnpm changeset
git add .changeset/*.md
git commit -m "feat: add new feature"
  1. Let the hooks run - They catch issues early
  2. Stage incrementally - Easier to review what’s changing
  3. Read error messages - They usually tell you exactly what to fix
  4. Format before reviewing - Makes diffs cleaner
  1. Don’t worry about style - Hooks ensure consistency
  2. Focus on logic - Style is automated
  3. Check for --no-verify - Flag commits that bypassed hooks
  1. Update pre-commit config when tools change
  2. Keep linter versions in sync with CI/CD
  3. Document exceptions if certain files need different rules

The same checks run in CI/CD pipelines:

Terminal window
# What runs in CI
pnpm lint # Lints all apps and packages
pnpm lint:python # Lints all Python code
pnpm format:check # Verifies formatting
pnpm test # Runs all tests

This ensures that even if someone bypasses local hooks, CI will catch issues.

If you encounter issues with pre-commit hooks:

  1. Check this documentation
  2. Review error messages carefully
  3. Ask in the team chat
  4. Create an issue in the repository

Remember: Pre-commit hooks are here to help, not hinder. They save time in code review and ensure consistent quality across the entire codebase.