Skip to content

Pre-commit Hooks Collection

pre-commit logo

This page explains what pre-commit hooks are, why they are used, and the specific selection I have decided to make for GOTem to keep your projects pristine with every commit. The source config file can be found here.

Pre-commit Final Result The final result.

What are Git hooks?

Git hooks are scripts that run automatically at some stage in the git-lifecycle. Most commonly, pre-commit hooks are used, running before a commit goes through. They act as a first line of defense for code quality by:

  • Catching formatting issues
  • Finding potential security risks
  • Validating configurations
  • Running quick tests
  • Enforcing team standards

Why use pre-commit?

Pre-commit is a framework that makes these Git hooks:

  1. Easy to share - Hooks are defined in a single YAML file
  2. Language-agnostic - Works with Python, JavaScript, and more
  3. Fast - Only runs on staged files and are much quicker than CI/CD
  4. Forgettable - Team members don't need to memorize QA tools; hooks run automatically
  5. Extendable - Large ecosystem of ready-to-use hooks

Pre-commit helps maintain code quality without slowing down development. While CI/CD pipelines might take minutes to run, pre-commit hooks provide instant feedback right when you commit. Despite the name, Pre-commit can install hooks at any stage (ex: Use a pre-push hook as a slightly more time-intensive pre-commit and push multiple commits at once.)

Common Use Cases

Pre-commit can be as strict as you want depending on your project's quality-time tradeoff. Here are cases where commit-level checks make more sense than pull-request level:

  1. Linting/formatting code and data files
  2. Re-building code or documentation
  3. Making database migrations
  4. Preventing secrets or large files from being committed
  5. Requiring commit messages to follow a standard (Like Commitizen)
  6. Running fast tests
Alternatives (Husky)

Husky is an alternative to pre-commit that's primarily designed for the NodeJS ecosystem. To my knowledge, while both tools handle Git hooks effectively, pre-commit offers broader multi-language support and has become standard in the Python community.

Installation

Projects generated with GOTem come with the .pre-commit-config.yaml file already configured as described below. If you would like to create your own, you can follow the instructions here.

Install the hooks with:

pre-commit install

You'll see hooks run automatically on every commit: Pre-commit Example

Useful Commands:

# Test hooks without committing
pre-commit run --all-files

# Commit without running hooks
git commit --no-verify
Note on security with `pre-commit autoupdate`

pre-commit autoupdate will bump all of your hook versions to the latest release. Although helpful, use with caution around untrusted hooks since security vulnerabilities or malware can be introduced between versions. This is mostly a non-issue which applies to basically all software but worth mentioning.


Hooks

This collection prioritizes best-in-class tools without redundancy. Rather than using multiple overlapping tools, we've selected the most effective option for each task. For example:

  • Python linting uses only Ruff instead of multiple separate linters
  • JSON/YAML/TOML validation uses specialized schema validators
  • Security scanning uses a single comprehensive tool

All hooks labeled with # STRICT are commented out by default and not recommended for every project. (Ex: Code style linters are typically desired for production-grade software but not research.)

01 ๐Ÿ”’ Security

GitLeaks is a fast, lightweight scanner that prevents secrets (passwords, API keys, tokens) from being committed to your repository.

Alternatives to GitLeaks (TruffleHog)

TruffleHog offers more comprehensive and continuous security scanning across a variety of platforms (not just files). However, it requires more setup time and resources than GitLeaks. Consider TruffleHog for expansive projects with strict security requirements.

- repo: https://github.com/gitleaks/gitleaks
  rev: v8.22.1
  hooks:
    - id: gitleaks
      name: "๐Ÿ”’ security ยท Detect hardcoded secrets"

02 ๐Ÿ” Code Quality

This section covers tools for code formatting, linting, type checking, and schema validation across different languages and file types. Best-in-class tools were chosen, avoiding redundant functionality. I opted for remote hook downloads over local commands to make the file more portable and self-updating.

๐Ÿ python

Ruff is a fast, comprehensive Python formatter and linter that replaces multiple traditional tools (Black, Flake8, isort, pyupgrade, bandit, pydoclint, mccabe complexity, and more.) While it's not yet at 100% parity with all these tools, its speed and broad coverage make it an excellent choice as the only Python linter/formatter:

Alternatives to Ruff (Too Many to Name)

ruff

Before Ruff, a typical Python project might use several separate tools:

While these tools are battle-tested and highly configurable, using Ruff provides several advantages:

  1. Speed: Ruff is 10-100x faster as it's written in Rust
  2. Simplicity: Single configuration file and consistent interface
  3. Active Development: Rapidly adding features and reaching feature parity
  4. Modern Defaults: Better handling of new Python features

Consider using individual tools if you need specific features not yet supported by Ruff or have complex existing configurations you need to maintain.

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.9.1
  hooks:
    - id: ruff-format
      name: "๐Ÿ python ยท Format with Ruff"
    # STRICT
    - id: ruff
      args: [ --fix ]


Microsoft's Pyright handles Python type checking:

  • VSCode Extension, but Pylance, the default extension for Python, has it built-in.
  • This is a community supported pre-commit hook, endorsed by microsoft
Alternatives to Pyright (MyPy)

Microsoft's Pyright is a faster and more featureful alternative to MyPy, but MyPy is the original type checker.

# STRICT
- repo: https://github.com/RobertCraigie/pyright-python
  rev: v1.1.391
  hooks:
    - id: pyright
      name: "๐Ÿ python ยท Check types"


validate-pyproject specifically handles pyproject.toml validation. In the future, I may have check-jsonschema do this as well.

- repo: https://github.com/abravalheri/validate-pyproject
  rev: v0.23
  hooks:
    - id: validate-pyproject
      name: "๐Ÿ python ยท Validate pyproject.toml"
      additional_dependencies: ["validate-pyproject-schema-store[all]"]

๐ŸŸจ JavaScript & Web Tools

Biome is a modern, fast formatter and linter for JS/TS ecosystems (JS[X], TS[X], JSON[C], CSS, GraphQL). It provides better defaults than ESLint.

Alternatives to Biome (ESLint & Prettier)

ESLint and Prettier are more established alternatives with broader plugin ecosystems. While Prettier supports many file types, it can be notably slow, sometimes produces unexpected formatting, and sometimes breaks code (which I find annoying). Since this is primarily a Python-focused project template and Biome handles our JavaScript needs efficiently, we prefer it over the traditional ESLint/Prettier setup. Consider ESLint and Prettier if you need plugins, support for specific JS frameworks, or formatting for languages unsupported elsewhere. (More linters here as well)

- repo: https://github.com/biomejs/pre-commit
  rev: "v0.6.1"
  hooks:
    - id: biome-check
      name: "๐ŸŸจ javascript ยท Lint, format, and safe fixes with Biome"
      additional_dependencies: ["@biomejs/biome@1.9.4"]

โœ… Data & Config Validation

check-jsonschema validates various configuration files using JSON Schema. It supports JSON, YAML, and TOML files, and includes specialized validators like the TaskFile and GitHub Actions checker.

- repo: https://github.com/python-jsonschema/check-jsonschema
  rev: 0.31.0
  hooks:
    - id: check-github-workflows
      name: "๐Ÿ™ github-actions ยท Validate gh workflow files"
      args: ["--verbose"]
    - id: check-taskfile
      name: "โœ… taskfile ยท Validate Task configuration"

๐Ÿ“ Markdown

mdformat for Markdown formatting with additional plugins for GitHub-Flavored Markdown, Ruff-style code formatting, and frontmatter support:

- repo: https://github.com/hukkin/mdformat
  rev: 0.7.21
  hooks:
    - id: mdformat
      name: "๐Ÿ“ markdown ยท Format markdown"
      additional_dependencies:
        - mdformat-gfm          # GitHub-Flavored Markdown support
        - mdformat-ruff         # Python code formatting
        - mdformat-frontmatter  # YAML frontmatter support
        - ruff                  # Required for mdformat-ruff

Markdownlint for Markdown linting.

- repo: https://github.com/markdownlint/markdownlint
    rev: v0.12.0
    hooks:
      - id: markdownlint
        name: "๐Ÿ“ markdown ยท Lint markdown"

๐Ÿš Shell

ShellCheck lints your shell scripts.

# STRICT
- repo: https://github.com/shellcheck-py/shellcheck-py
  rev: v0.10.0.1
  hooks:
    - id: shellcheck
      name: "๐Ÿš shell ยท Lint shell scripts"

bashate checks your shell script code style.

# STRICT
- repo: https://github.com/openstack/bashate
  rev: 2.1.1
  hooks:
    - id: bashate
      name: "๐Ÿš shell ยท Check shell script code style"

๐Ÿฎ Makefile

Checkmake for linting your Makefile.

- repo: https://github.com/mrtazz/checkmake.git
  rev: 0.2.2
  hooks:
    - id: checkmake
      name: "๐Ÿฎ Makefile ยท Lint Makefile"

๐Ÿ“Š SQL Code

SQLFluff can be used to lint and attempt to auto-fix any of your *.sql files automatically.

- repo: https://github.com/sqlfluff/sqlfluff
  rev: 3.3.0
  hooks:
    - id: sqlfluff-fix
      name: "๐Ÿ“Š SQL ยท Attempts to fix rule violations."
    # STRICT
    - id: sqlfluff-lint
      name: "๐Ÿ“Š SQL ยท Lint SQL code files"

๐Ÿ““ Notebooks

nbQA for Jupyter notebook quality assurance, allowing us to use our standard Python tools on notebooks.

ruff supports notebooks by default

Ruff has built-in support for Jupyter Notebooks, so this has been excluded from nbQA since it would be redundant. nbQA has nbqa-ruff-format and nbqa-ruff-check hooks, but these appear to be redundant.

- repo: https://github.com/nbQA-dev/nbQA
  rev: 1.9.1
  hooks:
    - id: nbqa
      entry: nbqa mdformat
      name: "๐Ÿ““ notebook ยท Format markdown cells"
      args: ["--nbqa-md"]
      types: [jupyter]
      additional_dependencies:
        - mdformat
        - mdformat-gfm
        - mdformat-ruff
        - mdformat-frontmatter
        - ruff
    # STRICT
    # TODO: Convert to pyright
    - id: nbqa-mypy
      name: "๐Ÿ““ notebook ยท Type-check cells"

๐Ÿ–ผ๏ธ Image Optimization

oxipng is a PNG optimizer written in Rust with lossy and lossless options. (The selection of arguments below are slightly lossy):

- repo: https://github.com/shssoichiro/oxipng
  rev: v9.1.3
  hooks:
    - id: oxipng
      name: "๐Ÿ–ผ๏ธ images ยท Optimize PNG files"
      args: [
        "-o", "4",
        "--strip", "safe",
        "--alpha"
      ]

โœจ Additional File Types

Prettier (HTML, YAML, CSS) handles formatting for various file types not covered by other tools. While it can be slow, sometimes produces code-breaking formatting, and I personally dislike it - it remains the standard for these file types.

Future Improvements

I might replace Prettier with more focused tools in the future (Perhaps HTMLHint for HTML validation but it's hardly a linter.)

However, this would require managing multiple tools and dependencies, so I'm sticking with Prettier for now.

My disatisfaction with prettier is humorously shared by pre-commit, as they themselves no longer support the prettier hook because "prettier made some changes that breaks plugins entirely"

- repo: https://github.com/pre-commit/mirrors-prettier
  rev: v4.0.0-alpha.8
  hooks:
    - id: prettier
      name: "โœจ misc-files ยท Format misc web files"
      types_or: [yaml, html, scss]
      additional_dependencies:
        - prettier@3.4.2

03 ๐Ÿ“ Filesystem

Pre-commit hooks are collection of hooks managed by the pre-commit team. These hooks help maintain repository hygiene by preventing common file-related issues:

  • check-case-conflict - Prevents issues on case-insensitive filesystems (Windows/MacOS)
  • check-symlinks & destroyed-symlinks - Maintains symlink integrity
  • check-executables-have-shebangs - Ensures scripts are properly configured
  • check-illegal-windows-names - Check for files that cannot be created on Windows.
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v5.0.0
  hooks:
    - id: check-executables-have-shebangs
      name: "๐Ÿ“ filesystem/โš™๏ธ exec ยท Verify shebang presence"
    - id: check-shebang-scripts-are-executable
      name: "๐Ÿ“ filesystem/โš™๏ธ exec ยท Verify script permissions"
    - id: check-case-conflict
      name: "๐Ÿ“ filesystem/๐Ÿ“ names ยท Check case sensitivity"
    - id: check-illegal-windows-names
      name: "๐Ÿ“ filesystem/๐Ÿ“ names ยท Validate Windows filenames"
    - id: check-symlinks
      name: "๐Ÿ“ filesystem/๐Ÿ”— symlink ยท Check symlink validity"
    - id: destroyed-symlinks
      name: "๐Ÿ“ filesystem/๐Ÿ”— symlink ยท Detect broken symlinks"
    # ... More Below ...

04 ๐ŸŒณ Git Quality

๐Ÿชต Repo Constraints

Pre-commit hooks again, this time for branch protection restricting unwanted actions.

  • forbid-new-submodules - Prevent addition of new git submodules (repo-in-a-repo). (Imo, Git submodules are a perfectly find practice, but
  • check-merge-conflict - Prevents committing unresolved merge conflicts
  • no-commit-to-branch - Protects main branches from direct commits (GitHub branch protections are for enterprise members only (sad))
  • check-added-large-files - Prevents committing files larger than 5000KB (Git Large File Storage (LFS) or Data Version Control (DVC) should instead be used)
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v5.0.0
  hooks:
    # ... More Above ...
    - id: check-merge-conflict
      name: "๐ŸŒณ git ยท Detect conflict markers"
    - id: forbid-new-submodules
      name: "๐ŸŒณ git ยท Prevent submodule creation"
    - id: no-commit-to-branch
      name: "๐ŸŒณ git ยท Protect main branches"
      args: ["--branch", "main", "--branch", "master"]
    - id: check-added-large-files
      name: "๐ŸŒณ git ยท Block large file commits"
      args: ['--maxkb=5000']

๐Ÿ—’๏ธ Commit Message Standards

Commitizen enforces high-quality standardized commit messages that enable automatic changelog generation and semantic versioning

Accompanying Improved Git Commit Interface

Commitizen comes with a built-in and customizable CLI that will walk you through making one of these standard commits. If you're using GOTem, this is preinstalled and you can run cz commit instead of git commit.

As an alternative to commitizen, there is also czg (cz-git improved) which has a great implementation of AI-generated commits. However, it's extremely painful to configure outside of non-javascript projects whereas commitizen is more mature in this area.. It's also worth noting that Cursor has its own AI generated commits, try Cmd + Shift + P Generate Commit Message

czg interface

Alternatives to Commitizen (Commitlint)

commitlint is a similar project to commitizen. Many articles claim that the difference between the two are that commitizen is more of a tool to generate these fancy commits while commitlint is meant to lint the commits. However, considering cz check is a thing, I'm confused what the difference is. The tools can be used together. Seems like commitizen has better python support than commitlint. Projects equally popular. More research to be done on the differences!

Click to learn how to remove **cz-conventional-gitmoji**

Remove the name line from pyproject.toml which sets cz_gitmoji as the default for commitizen (confusingly, this is the name for cz-conventional-gitmoji)

# pyproject.toml
[tool.commitizen]
name = "cz_gitmoji"

And remove it as dependency from your hooks:

# .pre-commit-config.yaml
default_install_hook_types:
  - pre-commit
  - commit-msg
repos:
# ... other hooks ...
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v4.1.0
    hooks:
      - id: commitizen
        name: "๐ŸŒณ git ยท Validate commit message"
        stages: [commit-msg]
        # DELETE LINE BELOW
        additional_dependencies: [cz-conventional-gitmoji]
default_install_hook_types:
  - pre-commit
  - commit-msg
repos:
# ... other hooks ...
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v4.1.0
    hooks:
      - id: commitizen
        name: "๐ŸŒณ git ยท Validate commit message"
        stages: [commit-msg]
        additional_dependencies: [cz-conventional-gitmoji]

05 ๐Ÿงช Fast Tests (Local)

While extensive tests may be too time consuming for a pre-commit hook, it can be helpful to run fast local tests to detect unexpected failures in your code before you are 10 commits in and unsure which one broke your code.

The example below uses pytest. The first hook checks that the tests don't contain any syntax errors and can be successfully collected. This should always pass.

The second hook runs all fast pytests using my custom pytest option which leverages the pytest-timeout feature you can read about here

- repo: local
  hooks:
    - id: pytest-collect
      name: ๐Ÿงช test ยท Validate test formatting
      entry: ./.venv/bin/pytest tests
      language: system
      types: [python]
      args: ["--collect-only"]
      pass_filenames: false
    # STRICT
    - id: pytest-fast
      name: ๐Ÿงช test ยท Run fast tests
      entry: ./.venv/bin/pytest tests
      language: system
      types: [python]
      args: ["--max-timeout=3"]
      pass_filenames: false

Conclusion

This is by no means an exhaustive list of great hooks. Your encouraged to pick-and-choose as desired. Hooks don't exist for all tools, so if you want to run those you can always use a local hook:

- repo: local
  hooks:
    - id: make-lint
      name: Run 'make lint'
      entry: make
      args: ["lint"]
      language: system

Check below for even more wonderful pre-commit hooks!

View final `.pre-commit-config.yaml` file
exclude: |
  (?x)^(
      .*\{\{.*\}\}.*|     # Exclude any files with cookiecutter variables
      docs/site/.*|       # Exclude mkdocs compiled files
      \.history/.*|       # Exclude history files
      .*cache.*/.*|       # Exclude cache directories
      .*venv.*/.*|        # Exclude virtual environment directories
  )$
fail_fast: true
default_language_version:
  python: python3.12
default_install_hook_types:
  - pre-commit
  - commit-msg
repos:
  #
  # Documentation Here:
  # https://gatlenculp.github.io/gatlens-opinionated-template/pre-commit/
  #
  # ---------------------------------------------------------------------------- #
  #                              ๐Ÿ”„ Pre-Commit Hooks                             #
  # ---------------------------------------------------------------------------- #

  # ----------------------------- ๐Ÿ”’ Security Tools ---------------------------- #

  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.22.1
    hooks:
      - id: gitleaks
        name: "๐Ÿ”’ security ยท Detect hardcoded secrets"

  # --------------------------- ๐Ÿ” Code Quality Tools -------------------------- #

  ### Python Tools ###
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.1
    hooks:
      - id: ruff-format
        name: "๐Ÿ python ยท Format with Ruff"
      # STRICT
      # - id: ruff
      #   args: [--fix]

  # STRICT
  # - repo: https://github.com/RobertCraigie/pyright-python
  #   rev: v1.1.391
  #   hooks:
  #     - id: pyright
  #       name: "๐Ÿ python ยท Check types"

  - repo: https://github.com/abravalheri/validate-pyproject
    rev: v0.23
    hooks:
      - id: validate-pyproject
        name: "๐Ÿ python ยท Validate pyproject.toml"
        additional_dependencies: ["validate-pyproject-schema-store[all]"]

  ### Javascript & Web Tools ###
  - repo: https://github.com/biomejs/pre-commit
    rev: "v0.6.1"
    hooks:
      - id: biome-check
        name: "๐ŸŸจ javascript ยท Lint, format, and safe fixes with Biome"
        additional_dependencies: ["@biomejs/biome@1.9.4"]

  ### Data & Config Validation ###
  - repo: https://github.com/python-jsonschema/check-jsonschema
    rev: 0.31.0
    hooks:
      - id: check-github-workflows
        name: "๐Ÿ™ github-actions ยท Validate gh workflow files"
        args: ["--verbose"]
      - id: check-taskfile
        name: "โœ… taskfile ยท Validate Task configuration"

  ### Markdown ###
  - repo: https://github.com/hukkin/mdformat
    rev: 0.7.21
    hooks:
      - id: mdformat
        name: "๐Ÿ“ markdown ยท Format markdown"
        additional_dependencies:
          - mdformat-gfm
          - mdformat-ruff
          - mdformat-frontmatter
          - ruff

  # STRICT
  # - repo: https://github.com/markdownlint/markdownlint
  #   rev: v0.12.0
  #   hooks:
  #     - id: markdownlint
  #       name: "๐Ÿ“ markdown ยท Lint markdown"

  ### Shell ###

  # STRICT
  # - repo: https://github.com/shellcheck-py/shellcheck-py
  #   rev: v0.10.0.1
  #   hooks:
  #     - id: shellcheck
  #       name: "๐Ÿš shell ยท Lint shell scripts"

  # STRICT
  # - repo: https://github.com/openstack/bashate
  #   rev: 2.1.1
  #   hooks:
  #     - id: bashate
  #       name: "๐Ÿš shell ยท Check shell script code style"

  ### Makefile ###
  - repo: https://github.com/mrtazz/checkmake.git
    rev: 0.2.2
    hooks:
      - id: checkmake
        name: "๐Ÿฎ Makefile ยท Lint Makefile"

  ### SQL ###

  - repo: https://github.com/sqlfluff/sqlfluff
    rev: 3.3.0
    hooks:
      - id: sqlfluff-fix
        name: "๐Ÿ“Š SQL ยท Attempts to fix rule violations."
      # STRICT
      # - id: sqlfluff-lint
      #   name: "๐Ÿ“Š SQL ยท Lint SQL code files"

  ### Notebooks ###
  - repo: https://github.com/nbQA-dev/nbQA
    rev: 1.9.1
    hooks:
      - id: nbqa
        entry: nbqa mdformat
        name: "๐Ÿ““ notebook ยท Format markdown cells"
        args: ["--nbqa-md"]
        types: [jupyter]
        additional_dependencies:
          - mdformat
          - mdformat-gfm
          - mdformat-ruff
          - mdformat-frontmatter
          - ruff
      # STRICT
      # TODO: Convert to pyright
      - id: nbqa-mypy
        name: "๐Ÿ““ notebook ยท Type-check cells"

  ### PNG Images ###
  - repo: https://github.com/shssoichiro/oxipng
    rev: v9.1.3
    hooks:
      - id: oxipng
        name: "๐Ÿ–ผ๏ธ images ยท Optimize PNG files"
        args: ["-o", "4", "--strip", "safe", "--alpha"]

  ### Additional File Types ###
  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v4.0.0-alpha.8
    hooks:
      - id: prettier
        name: "โœจ misc-files ยท Format misc web files"
        types_or: [yaml, html, scss]
        additional_dependencies:
          - prettier@3.4.2

  # ---------------------------- ๐Ÿ“ Filesystem Tools --------------------------- #

  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      # Filesystem Checks
      - id: check-executables-have-shebangs
        name: "๐Ÿ“ filesystem/โš™๏ธ exec ยท Verify shebang presence"
      - id: check-shebang-scripts-are-executable
        name: "๐Ÿ“ filesystem/โš™๏ธ exec ยท Verify script permissions"
      - id: check-case-conflict
        name: "๐Ÿ“ filesystem/๐Ÿ“ names ยท Check case sensitivity"
      - id: check-illegal-windows-names
        name: "๐Ÿ“ filesystem/๐Ÿ“ names ยท Validate Windows filenames"
      - id: check-symlinks
        name: "๐Ÿ“ filesystem/๐Ÿ”— symlink ยท Check symlink validity"
      - id: destroyed-symlinks
        name: "๐Ÿ“ filesystem/๐Ÿ”— symlink ยท Detect broken symlinks"
      # ------------------------------- ๐ŸŒณ Git Tools ------------------------------- #
      - id: check-merge-conflict
        name: "๐ŸŒณ git ยท Detect conflict markers"
      - id: forbid-new-submodules
        name: "๐ŸŒณ git ยท Prevent submodule creation"
      - id: no-commit-to-branch
        name: "๐ŸŒณ git ยท Protect main branches"
        args: ["--branch", "main", "--branch", "master"]
      - id: check-added-large-files
        name: "๐ŸŒณ git ยท Block large file commits"
        args: ["--maxkb=5000"]

  # ---------------------------------------------------------------------------- #
  #                            ๐Ÿ“ Commit Message Hooks                           #
  # ---------------------------------------------------------------------------- #
  #
  # --------------------------- โœ๏ธ Git Commit Quality -------------------------- #

  ### Commit Message Standards ###
  - repo: https://github.com/commitizen-tools/commitizen
    rev: v4.1.0
    hooks:
      - id: commitizen
        name: "๐ŸŒณ git ยท Validate commit message"
        stages: [commit-msg]
        additional_dependencies: [cz-conventional-gitmoji]

  # ---------------------------------------------------------------------------- #
  #                             ๐Ÿงช Fast Tests (Local)                            #
  # ---------------------------------------------------------------------------- #

  - repo: local
    hooks:
      - id: pytest-collect
        name: ๐Ÿงช test ยท Validate test formatting
        entry: ./.venv/bin/pytest tests
        language: system
        types: [python]
        args: ["--collect-only"]
        pass_filenames: false
      # STRICT
      - id: pytest-fast
        name: ๐Ÿงช test ยท Run fast tests
        entry: ./.venv/bin/pytest tests
        language: system
        types: [python]
        args: ["--max-timeout=3"]
        pass_filenames: false

Other hooks to consider

Here are some other hooks I haven't added but would consider adding!

Individual Hooks

  • buildbuf - Protobuf Linter
  • Clang - C++ linter
  • gitlint - Alternative to commitlint, may actually be preferred.
  • typos or codespell - Finds common misspellings in code and documentation. One blog post preferred Typos over codespell because it found more typos (and apparently has VSCode support?)
  • yamllint - YAML linter
  • yamlfmt - YAML formatter by Google
  • actionlint - Lints github action files, may be a better checker than the currently selected one.
  • uv pre-commits - A collection of pre-commits for uv by Astral
  • Vulture or Deadcode - Detect unused code in Python
  • Hadolint - Lint Dockerfiles
  • sync-pre-commit-deps - Sync pre-commit hook dependencies based on other installed hooks (to avoid installing multiple versions I assume).
sync-pre-commit-deps hook here
  - repo: https://github.com/mxr/sync-pre-commit-deps
    rev: v0.0.2
    hooks:
      - id: sync-pre-commit-deps
        name: "๐Ÿช pre-commit ยท Sync hook dependencies based on other hooks"


Hook lists


What's Missing?

  • File optimizers for more than just PNGs (JPG, GIF, etc.)
  • Profanity checker (You'll be surprised with the amount of profanity on repos you're about to make public). This can possibly be done with GitLeaks
  • ... This list could go on and on ...

Ensemble Hooks (Linters, Formatters, etc.)

I went a bit overboard with cherry picking my favorite formatters, linters, etc. This may lead to maintaining more hooks than is worthwhile. It's on my todo list to look at ensemble linters and formatters such as Megalinter and Superlinter which would GREATLY reduce the amount of overhead for code QA and provide support to languages without hunting down mutliple hooks for each of them. These also have the added benefit of better integration to other CI/CD tools, pre-built container images, and security scanning.

๐Ÿฆ™ MegaLinter analyzes 50 languages, 22 formats, 21 tooling formats, excessive copy-pastes, spelling mistakes and security issues in your repository sources with a GitHub Action, other CI tools or locally.

I'm slightly concerned that these ensemble linters might be an additional annoying piece of software to learn and configure that sets off small teams from using them entirely. Additionally, this software may not support your favorite linters - some of which mentioned in this guide include Biomejs and mdformat. I'm sure the list of available tools is extendable although I'm unsure how much effort is needed to do so.