013-ADR: Git Hooks Manager¶
Architectural Decision Records (ADR) on implementing a Git Hooks Manager for Software Projects.
1. State¶
- Author(s): Sentenz
- Date: 2026-04-30
- Status: Proposed
2. Context¶
A Git hooks manager automates tasks during the Git workflow, such as linting, formatting, and enforcing commit message conventions. Managing raw Git hooks as shell scripts lacks consistency, portability, and ease of onboarding. A dedicated Git hooks manager will standardize hook definitions, improve developer experience, and integrate seamlessly with our multi-language toolchain.
-
Decision Drivers
-
Ease of Use
The tool should provide a simple setup and configuration experience across all team members.
-
Cross-Platform Support
The tool should work consistently on Linux, macOS, and Windows without requiring platform-specific workarounds.
-
Performance
Hook execution should be fast and support parallel execution to minimize friction in the developer workflow.
-
Language Agnostic
The tool should not be tied to a specific programming language or runtime, supporting our multi-language environment.
-
Scope Fit
The tool should align with a polyglot repository baseline and avoid introducing language-specific onboarding requirements.
-
Configuration
The configuration should be declarative, human-readable, and easy to maintain.
-
Integration
The tool should integrate with existing linters, formatters, and CI/CD workflows.
-
Community and Ecosystem
The tool should be actively maintained with good documentation and community support.
-
3. Decision¶
3.1. Lefthook¶
Lefthook is selected as the Git hooks manager due to its language-agnostic design, fast parallel execution, cross-platform support, and YAML-based declarative configuration that aligns with our existing toolchain conventions.
-
Rationale
-
Ease of Use
Lefthook uses a single
lefthook.ymlconfiguration file at the project root, making setup straightforward for all team members regardless of their primary programming language. -
Cross-Platform Support
Lefthook is distributed as a standalone binary with no runtime dependencies, ensuring consistent behavior on Linux, macOS, and Windows.
-
Performance
Lefthook supports parallel execution of hook commands and runs only on staged files by default, minimizing execution time and developer disruption.
-
Language Agnostic
Lefthook requires no specific runtime (e.g., Node.js or Python) and integrates with any tool or script available in the shell environment, making it suitable for our multi-language repository.
-
Scope Fit
Lefthook fits into the repository scope by providing one baseline for all contributors without requiring language-specific setup (e.g., PHP/Composer)
-
Configuration
The YAML-based
lefthook.ymlis declarative, version-controlled, and easy to read and update, consistent with other configuration files in the project. -
Integration
Lefthook integrates natively with CI/CD pipelines and can invoke any existing linting, formatting, or testing commands without additional wrappers.
-
Community and Ecosystem
Lefthook is actively maintained by Evil Martians, has comprehensive documentation, and supports a growing ecosystem of integrations.
-
4. Considered¶
4.1. Git Hooks¶
Git Hooks are native shell scripts placed in the .git/hooks/ directory (or a custom path configured via core.hooksPath) that Git executes automatically at specific points in the workflow.
-
Pros
-
No Dependencies
Requires no additional tooling beyond Git itself, with zero external dependencies.
-
Native Support
Built into Git and supported on all platforms without any installation step.
-
Full Control
Complete control over hook scripts with no abstraction layer or framework constraints.
-
-
Cons
-
Ease of Use
Hook scripts are not automatically shared with team members via version control, each developer must manually configure the hooks path or run a setup script.
-
Configuration
No declarative configuration format, each hook is a separate shell script requiring individual maintenance and duplication of shared logic.
-
Performance
No built-in support for parallel execution of multiple commands within a single hook.
-
Cross-Platform Support
Shell scripts may behave differently on Windows without a Unix-compatible shell environment (e.g., Git Bash or WSL).
-
Integration
Integrating multiple tools requires manual composition within shell scripts, increasing complexity and maintenance burden.
-
4.2. Husky¶
Husky is a widely used Git hooks manager for JavaScript and Node.js projects that relies on npm scripts and stores hook definitions in the .husky/ directory.
-
Pros
-
Ease of Use
Simple setup for Node.js projects via
npm install. -
Adoption
Widely adopted in the JavaScript ecosystem with extensive community resources.
-
Integration
Tight integration with
lint-stagedfor running checks only on staged files.
-
-
Cons
-
Runtime Dependency
Requires Node.js and
npmas a runtime dependency, which is not suitable for our multi-language environment. -
Configuration
Hook configuration is split across multiple shell scripts rather than a single declarative file.
-
Performance
Does not support parallel execution of hook commands natively.
-
4.3. Lefthook¶
Lefthook is a fast, language-agnostic Git hooks manager distributed as a standalone binary that uses a lefthook.yml configuration file to define hooks.
# lefthook.yml
pre-commit:
parallel: true
commands:
lint:
run: make run-linter-staged
spell:
run: make run-spell-check
commit-msg:
commands:
lint:
run: make run-linter-commit {1}
-
Pros
-
Language Agnostic
No runtime dependencies beyond the binary itself, making it suitable for multi-language environments.
-
Performance
Supports parallel execution of multiple commands within a single hook.
-
Configuration
Single declarative YAML configuration file for all hooks.
-
Cross-Platform Support
Cross-platform binaries available for Linux, macOS, and Windows.
-
Staged Files
Supports filtering commands to run only on staged or changed files.
-
Community and Ecosystem
Actively maintained with comprehensive documentation.
-
-
Cons
-
Binary Dependency
Requires installing the
lefthookbinary on all development machines. -
Adoption
Less established than Husky in the JavaScript ecosystem.
-
4.4. CaptainHook¶
CaptainHook is a Git hooks manager focused on PHP projects, distributed as a Composer package with hook orchestration, local actions, and optional CI integration.
-
Pros
-
Workflow Features
Provides rich hook orchestration, including local actions and conditional execution support.
-
Configuration
Offers a dedicated JSON configuration with reusable actions and plugin extension points.
-
PHP Ecosystem Integration
Integrates naturally with Composer-based PHP projects and tooling.
-
-
Cons
-
Runtime Dependency
Requires a PHP and Composer runtime, which does not align with a language-agnostic baseline for all contributors.
-
Scope Fit
Primary ecosystem focus is PHP projects, while this repository spans multiple languages and toolchains.
-
Onboarding
Adds language-specific setup steps for contributors who do not otherwise need PHP in their development environment.
-
4.5. Pre-commit¶
Pre-commit is a framework for managing and maintaining multi-language pre-commit hooks, configured via a .pre-commit-config.yaml file and pulling hook definitions from remote repositories.
# .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
-
Pros
-
Ecosystem
Rich ecosystem of ready-made hooks from the pre-commit community.
-
Language Agnostic
Hook definitions that can invoke tools from various runtimes.
-
Environment Management
Automatic virtual environment management for Python-based hooks.
-
-
Cons
-
Runtime Dependency
Requires Python as a runtime dependency for the framework itself.
-
External Dependencies
Hook definitions are fetched from remote repositories, introducing external dependencies and potential network latency.
-
Hook Coverage
Configuration is limited to the
pre-commithook by default, other hooks require additional setup. -
Performance
Slower compared to Lefthook due to virtual environment management overhead.
-
5. Consequences¶
-
Positive
-
Consistency
Standardized hook definitions in a single
lefthook.ymlfile improve consistency and reduce onboarding time for new team members. -
Performance
Parallel execution of hook commands reduces wait time for developers during the Git workflow.
-
Portability
No runtime dependency beyond the binary ensures hooks work identically across all supported operating systems and environments.
-
Maintainability
Declarative YAML configuration is easy to read, update, and review in code reviews.
-
-
Negative
-
Binary Dependency
All developers and environments must have the
lefthookbinary installed, requiring updates to onboarding documentation and setup scripts. -
Migration Effort
Existing raw shell-based Git hooks in the
.git/hooks/orgithooks/directory need to be migrated to Lefthook configuration, requiring testing to ensure equivalent behavior.
-
6. Implementation¶
-
Install Lefthook
Install the
lefthookbinary on all development machines and environments. -
Create Configuration
Create a
lefthook.ymlconfiguration file at the project root, defining hooks forpre-commit,commit-msg,pre-push,post-checkout, andpre-rebase. -
Migrate Existing Hooks
Migrate the existing hook logic from the
.git/hooks/orgithooks/shell scripts into the corresponding Lefthook commands. -
Register Hooks
Run
lefthook installto register the hooks in the local.git/hooks/directory. -
Update Documentation
Update the project
README.mdand onboarding documentation to include Lefthook setup instructions. -
Validate
Validate hook execution of staged files to ensure consistent behavior across environments.
7. References¶
- Sentenz Manager Tools article.
- Git Hooks Documentation page.
- Lefthook Official Documentation page.
- Lefthook GitHub Repository page.
- Husky Official Documentation page.
- CaptainHook GitHub Repository page.
- Pre-commit Official Documentation page.