A Git hooks manager for Node.js, Ruby, Python and many other types of projects.
📖 Introduction post
With Go (>= 1.25):
go install github.com/evilmartians/lefthook/v2@v2.0.1
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 config options.Gives you more speed. docs
pre-push:
  parallel: true
If you want your own list. Custom and prebuilt examples.
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.rb"
        - "*/routes.rb"
      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 <container_id_or_name> {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