winget install --id=evilmartians.lefthook -e
Fast and powerful Git hooks manager for any type of projects.
Lefthook is a Git hooks manager designed to streamline development workflows by automating code quality checks, linting, and other pre-commit or pre-push tasks. It supports multiple programming languages and project types, making it versatile for teams working with Node.js, Ruby, Python, and more.
Key Features:
Audience & Benefit:
Ideal for developers and teams managing projects in Node.js, Ruby, Python, and other languages, Lefthook helps enforce code quality and consistency without adding complexity to your workflow. By automating repetitive tasks, it saves time and reduces human error during the commit process.
Lefthook can be installed via winget, making it easy to integrate into any development environment.
A Git hooks manager for Node.js, Ruby, Python and many other types of projects.
With Go (>= 1.24):
go install github.com/evilmartians/lefthook@latest
go get -tool github.com/evilmartians/lefthook
With NPM:
npm install lefthook --save-dev
For Ruby:
gem install lefthook
For Python:
pip install lefthook
Installation guide with more ways to install lefthook: apt, brew, winget, and others.
Configure your hooks, install them once and forget about it: rely on the magic underneath.
# Configure your hooks
vim lefthook.yml
# Install them to the git project
lefthook install
# Enjoy your work with git
git add -A && git commit -m '...'
lefthook.yml
Gives you more speed. docs
pre-push:
parallel: true
pre-commit:
jobs:
- name: lint frontend
run: yarn eslint {staged_files}
- name: lint backend
run: bundle exec rubocop --force-exclusion {all_files}
- name: stylelint frontend
files: git diff --name-only HEAD @{push}
run: yarn stylelint {files}
If you want to filter list of files. You could find more glob pattern examples here.
pre-commit:
jobs:
- name: lint backend
glob: "*.rb" # glob filter
exclude: '(^|/)(application|routes)\.rb$' # regexp filter
run: bundle exec rubocop --force-exclusion {all_files}
If you want to execute the commands in a relative path
pre-commit:
jobs:
- name: lint backend
root: "api/" # Careful to have only trailing slash
glob: "*.rb" # glob filter
run: bundle exec rubocop {all_files}
If oneline commands are not enough, you can execute files. docs
commit-msg:
jobs:
- script: "template_checker"
runner: bash
If you want to control a group of commands. docs
pre-push:
jobs:
- name: audit packages
tags:
- frontend
- linters
run: yarn lint
- name: audit gems
tags:
- backend
- security
run: bundle audit
If you are in the Docker environment. docs
pre-commit:
jobs:
- script: "good_job.js"
runner: docker run -it --rm {cmd}
If you are a frontend/backend developer and want to skip unnecessary commands or override something in Docker. docs
# lefthook-local.yml
pre-push:
exclude_tags:
- frontend
jobs:
- name: audit packages
skip: true
If you want to run hooks group directly.
$ lefthook run pre-commit
If you want to run specific group of commands directly.
fixer:
jobs:
- run: bundle exec rubocop --force-exclusion --safe-auto-correct {staged_files}
- run: yarn eslint --fix {staged_files}
$ lefthook run fixer
You can control what lefthook prints with output option.
output:
- execution
- failure
Check examples