๐ช Hooksmith
Hooksmith is a lightweight, easy-to-use tool that simplifies Git hook management. Define your hooks in a simple YAML file and let Hooksmith handle the rest.
๐ Table of Contents
- โจ Features
- โก Why Hooksmith?
- ๐ง Installation
- ๐ Quick Start
- ๐ Usage
- โฑ๏ธ Performance Monitoring
- ๐๏ธ Path-based Blocks
- ๐ Command Reference
- ๐ค Contributing
- ๐ License
โจ Features
- โ๏ธ Automatic Installation - Set up hooks through your build scripts with
build.rs - ๐งช Local Testing - Run hooks manually without triggering Git events
- โฑ๏ธ Performance Monitoring - Track execution times for hooks and individual commands
- ๐ Dry Run Mode - Preview what would happen without making changes
- โ Hook Validation - Ensure your hooks comply with Git standards
- ๐ Simple Configuration - Define all your hooks in a clean YAML format
- ๐จ Beautiful CLI - Enjoy a polished terminal interface with clear output
- ๐ Shell Completion - Built-in Fish shell completions for improved productivity
- ๐ Version Control - Easily track hook changes with your repository
- ๐ฆ Error Handling - Robust error handling with clear, actionable messages
โก Why Hooksmith?
- Minimal Dependencies - Lightweight with only essential dependencies
- Rust Powered - Fast, reliable, and type-safe
- Team Friendly - Version control your hook configurations
- Seamless Integration - Works naturally with your Git workflow
- Low Learning Curve - Simple commands and clear documentation
๐ง Installation
Using Cargo
As a Build Dependency
Add to your Cargo.toml:
[]
= "1.10.0"
Create a build.rs file:
use Path;
๐ก Note: Hooksmith includes shell completions for Fish. After installation, they become available automatically.
Dependencies
Hooksmith is built with minimal but powerful dependencies:
clap: For robust command-line argument parsingconsole&dialoguer: For beautiful terminal interfacesserde&serde_yaml: For YAML configuration handlingthiserror: For ergonomic error handling
๐ Quick Start
- Create a
hooksmith.yamlfile in your project root:
pre-commit:
commands:
- cargo fmt --all -- --check
- cargo clippy -- --deny warnings
pre-push:
commands:
- cargo test
- Install the hooks:
That's it! Your Git hooks are now ready to use.
๐ Usage
Configuration File
Hooksmith uses a YAML configuration file (default: hooksmith.yaml) to define your hooks:
# Format and lint code before committing
pre-commit:
commands:
- cargo fmt --all -- --check
- cargo clippy --workspace --all-features -- --deny warnings
# Run tests before pushing
pre-push:
commands:
- cargo test --all-features
- cargo build --verbose
# Validate commit messages
commit-msg:
commands:
# Use custom script to validate commit messages
- ./scripts/verify-commit-message.sh $1
Named Commands
You can optionally assign names to your commands for better readability and clearer output. This is especially useful for long or complex commands:
pre-commit:
commands:
- cargo fmt --all -- --check
- clippy-linter: cargo clippy --workspace --release --all-targets --all-features -- --deny warnings -D warnings -W clippy::correctness -W clippy::suspicious -W clippy::complexity -W clippy::perf -W clippy::style -W clippy::pedantic
- typos
pre-push:
commands:
- cargo build -q
- test-suite: cargo test -q
Benefits of named commands:
- Better readability: Long commands show their purpose clearly
- Improved monitoring: Performance reports display meaningful names instead of truncated commands
- Enhanced dry-run output: See at a glance what each command does
When you use named commands, both the dry-run output and performance monitoring will display the command name followed by the actual command in parentheses.
Common Commands
# Install all hooks defined in configuration
# Run a specific hook manually
# Run a hook with performance monitoring
# Uninstall all hooks or a specific one
# Compare installed hooks with configuration
# Validate hook configuration against Git standards
Add --dry-run to any command to preview changes without applying them:
โฑ๏ธ Performance Monitoring
Hooksmith includes built-in performance monitoring to help you optimize your hook execution times. Use the --profile flag with the run command to see detailed timing information:
This will show you:
- Individual command execution times (showing command names when available)
- Total hook execution time
- Overall execution time when running multiple hooks
Example Output
โฑ๏ธ Hook execution summary:
Hook 'pre-commit' (768ms)
cargo fmt --all -- --check: 146ms
clippy-linter: 394ms
typos: 226ms
Total: 768ms
Use Cases
Performance monitoring is particularly useful for:
- Identifying slow commands in your hook chains
- Optimizing CI/CD pipelines by understanding bottlenecks
- Debugging performance issues in complex hook configurations
- Tracking improvements after optimizing your toolchain
๐๏ธ Path-based Blocks
Define commands that only run when files within specific paths have changed. This lets you scope expensive checks to the parts of the repository they affect.
YAML structure
pre-commit:
# Global commands: always run
commands:
- cargo fmt --all -- --check
# Path-based blocks: run only if matching files changed
paths:
src/:
commands:
- cargo clippy --workspace -- -D warnings
crates/api/:
working_directory: crates/api
commands:
- npm ci
- npm test
How it works
- Matching: A block runs when any changed file path starts with its key (simple prefix match). Use paths relative to the repo root; prefer a trailing slash (e.g.,
src/). - Supported hooks: Change detection is implemented for
pre-commitandpre-push.pre-commit: usesgit diff --name-only --cached.pre-push: diffs@{u}..HEADwhen upstream exists, otherwise falls back toHEAD~1..HEAD.
- Order: All matching path-based blocks run first, then global
commandsrun. - Working directory: Inside a path block,
working_directory(optional) sets the directory for those commands only. Global commands run in the current directory. - No matches: If no paths match, only global commands run. Omit
commandsif you want nothing to run in that case. - Multiple matches: If a file matches several prefixes, all matching blocks run. The order between blocks is not guaranteed; the order of commands within a block is preserved.
๐ Command Reference
| Command | Description |
|---|---|
install |
Install all hooks from configuration file |
run <hook> |
Run a specific hook manually |
run <hook> --profile |
Run a hook with performance timing information |
uninstall [hook] |
Uninstall all hooks or a specific one |
compare |
Compare installed hooks with configuration |
validate |
Validate hook configuration against Git standards |
Global Options
| Option | Description |
|---|---|
--config-path <PATH> |
Specify a custom configuration file path |
--dry-run |
Preview changes without applying them |
--verbose |
Show detailed output during execution |
--help |
Display help information |
Run Command Options
| Option | Description |
|---|---|
--interactive or -i |
Interactively select hooks to run |
--profile or -p |
Show performance timing for hook execution |
๐ค Contributing
Contributions are welcome! Feel free to:
- Report bugs and suggest features
- Submit pull requests
- Improve documentation
- Share your use cases and feedback
๐ License
This project is dual-licensed under either:
at your option.