Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

lefthook

evilmartians1.3mMIT1.11.2

Simple git hooks manager

git, hook, manager

readme

Build Status Coverage Status

Lefthook

The fastest polyglot Git hooks manager out there

A Git hooks manager for Node.js, Ruby, Python and many other types of projects.

  • Fast. It is written in Go. Can run commands in parallel.
  • Powerful. It allows to control execution and files you pass to your commands.
  • Simple. It is single dependency-free binary which can work in any environment.

📖 Introduction post

Sponsored by Evil Martians

Install

With Go (>= 1.23):

go install github.com/evilmartians/lefthook@latest

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.

Usage

Configure your hooks, install them once and forget about it: rely on the magic underneath.

TL;DR

# 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 '...'

More details

  • Configuration for lefthook.yml config options.
  • Usage for lefthook CLI options, supported ENVs, and usage tips.
  • Discussions for questions, ideas, suggestions.

Why Lefthook

  • Parallel execution

    Gives you more speed. docs
pre-push:
  parallel: true
  • Flexible list of files

    If you want your own list. Custom and prebuilt examples.
pre-commit:
  commands:
    frontend-linter:
      run: yarn eslint {staged_files}
    backend-linter:
      run: bundle exec rubocop --force-exclusion {all_files}
    frontend-style:
      files: git diff --name-only HEAD @{push}
      run: yarn stylelint {files}
  • Glob and regexp filters

    If you want to filter list of files. You could find more glob pattern examples here.
pre-commit:
  commands:
    backend-linter:
      glob: "*.rb" # glob filter
      exclude: '(^|/)(application|routes)\.rb$' # regexp filter
      run: bundle exec rubocop --force-exclusion {all_files}
  • Execute in sub-directory

    If you want to execute the commands in a relative path
pre-commit:
  commands:
    backend-linter:
      root: "api/" # Careful to have only trailing slash
      glob: "*.rb" # glob filter
      run: bundle exec rubocop {all_files}
  • Run scripts

If oneline commands are not enough, you can execute files. docs

commit-msg:
  scripts:
    "template_checker":
      runner: bash
  • Tags

    If you want to control a group of commands. docs
pre-push:
  commands:
    packages-audit:
      tags:
        - frontend
        - linters
      run: yarn lint
    gems-audit:
      tags:
        - backend
        - security
      run: bundle audit
  • Support Docker

If you are in the Docker environment. docs

pre-commit:
  scripts:
    "good_job.js":
      runner: docker run -it --rm <container_id_or_name> {cmd}
  • Local config

If you a frontend/backend developer and want to skip unnecessary commands or override something into Docker. docs

# lefthook-local.yml
pre-push:
  exclude_tags:
    - frontend
  commands:
    packages-audit:
      skip: true
  • Direct control

If you want to run hooks group directly.

$ lefthook run pre-commit
  • Your own tasks

If you want to run specific group of commands directly.

fixer:
  commands:
    ruby-fixer:
      run: bundle exec rubocop --force-exclusion --safe-auto-correct {staged_files}
    js-fixer:
      run: yarn eslint --fix {staged_files}
$ lefthook run fixer
  • Control output

You can control what lefthook prints with output option.

output:
  - execution
  - failure

Guides

Examples

Check examples

Articles

changelog

Change log

1.11.2 (2025-02-26)

  • fix: do not inherit envs in remote Git commands (#963) by @mrexox

1.11.1 (2025-02-25)

1.11.0 (2025-02-23)

1.10.11 (2025-02-21)

  • deps: bump github.com/spf13/cobra from 1.8.1 to 1.9.1 (#952) (#958) by @mrexox
  • fix: add $schema property (#942) by @mst-mkt
  • deps: bump github.com/briandowns/spinner from 1.23.1 to 1.23.2 (#935) (#940) by @mrexox

1.10.10 (2025-01-21)

  • feat: allow providing a list of globs (#937) by @mrexox
  • fix: properly inherit exclude options when not overwritten (#936) by @mrexox

1.10.9 (2025-01-20)

  • fix: make uninstall --remove-configs description more accurate (#934) by @scop

1.10.8 (2025-01-17)

  • feat: add custom plain templates (#930) by @mrexox
  • fix: unique names for nested operations (#931) by @mrexox

1.10.7 (2025-01-15)

  • fix: use lefthook option in ghost hook too (#929) by @mrexox
  • feat: add schema.json to npm packages (#928) by @mrexox
  • fix: increase timeout for self-update to 2 mins by @mrexox

1.10.5 (2025-01-14)

  • feat: add lefthook option for custom path or command (#927) by @mrexox
  • chore: update config template with new jobs by @mrexox

1.10.4 (2025-01-13)

  • fix: avoid skipping pre commit when deleted files staged (#925) by @mrexox
  • fix: use roots from jobs for possible npm package location (#924) by @mrexox
  • deps: January 2025 (#926) by @mrexox

1.10.3 (2025-01-10)

1.10.2 (2025-01-10)

  • feat: add validate command (#915) by @mrexox
  • feat: inherit exclude option in groups (#916) by @mrexox
  • chore: auto generate json schema (#914) by @mrexox
  • feat: run --jobs completion (#913) by @scop
  • ci: add gzipped linux aarch64 binary to release artifacts (#908) by @mrexox -

    1.10.1 (2024-12-26)

  • feat: add ability to specify job names for command run (#904) by @mrexox

  • ci: add linux aarch64 binary to release (#903) by @mrexox
  • ci: fix aur build (#905) by @mrexox

1.10.0 (2024-12-19)

1.9.3 (2024-12-18)

1.9.2 (2024-12-12)

  • fix: use correct remote scripts folder (#891) by @mrexox

1.9.1 (2024-12-12)

1.9.0 (2024-12-06)

1.8.5 (2024-12-02)

  • ci: automate publishing to cloudsmith (#875) by @mrexox
  • feat: add option to skip running LFS hooks (#879) by @zachah

1.8.4 (2024-11-18)

1.8.3 (2024-11-18)

  • fix: use absolute paths when cloning remotes (#873) by @mrexox

1.8.2 (2024-10-29)

1.8.1 (2024-10-23)

  • chore: bump Go to 1.23 (#856) by Valentin Kiselev
  • fix: skip git lfs hook when calling manually (#855) by Valentin Kiselev

1.8.0 (2024-10-22)

  • fix: [breaking] don't auto-install lefthook with npx if not found (#602) by @anthony-hayes
  • fix: [breaking] execute files command within configured root (#607) by @mrexox
  • fix: calculate hashsum of the full config (#854) by @mrexox
  • feat: support globs in extends (#853) by @mrexox
  • docs: simplify configuration docs (#851) by @mrexox

1.7.22 (2024-10-18)

1.7.21 (2024-10-17)

1.7.19 and 1.7.20 – failed to build

1.7.18 (2024-09-30)

1.7.17 (2024-09-26)

  • feat: skip LFS hooks when pre-push hook is skipped (#818) by @zachahn

1.7.16 (2024-09-23)

1.7.15 (2024-09-02)

1.7.14 (2024-08-17)

Fix lefthook NPM package to include OpenBSD package as optional dependency.

1.7.13 (2024-08-16)

1.7.12 (2024-08-09)

1.7.11 (2024-07-29)

1.7.10 (2024-07-29)

  • deps: July 2024 (#795) by @mrexox
  • packaging(npm): try direct reference for lefthook executable (#794) by @mrexox

1.7.9 (2024-07-26)

  • fix: typo CGO_ENABLED instead of GCO_ENABLED (#791) by @mrexox

1.7.8 (2024-07-26)

1.7.7 (2024-07-24)

1.7.6 (2024-07-24)

1.7.5 (2024-07-22)

1.7.4 (2024-07-19)

1.7.3 (2024-07-18)

1.7.2 (2024-07-11)

  • fix: add missing sub directory in hook template (#768) by @nikeee

1.7.1 (2024-07-08)

  • fix: use correct extension in hook.tmpl (#767) by @apfohl

1.7.0 (2024-07-08)

1.6.18 (2024-06-21)

  • fix: allow multiple levels of extends (#755) by @mrexox

1.6.17 (2024-06-20)

  • fix: apply local extends only if they are present (#754) by @mrexox
  • chore: setting proper error message for missing lefthook file (#748) by @Cadienvan

1.6.16 (2024-06-13)

  • fix: skip overwriting hooks when fetching data from remotes (#745) by @mrexox
  • fix: fetch remotes only for non ghost hooks (#744) by @mrexox

1.6.15 (2024-06-03)

  • feat: add refetch option to remotes config (#739) by @mrexox
  • deps: June, 3, lipgloss (0.11.0) and viper (1.19.0) (#742) by @mrexox
  • chore: enable copyloopvar, intrange, and prealloc (#740) by @scop
  • perf: delay git and uname commands in hook scripts until needed (#737) by @scop
  • chore: refactor commands interfaces (#735) by @mrexox
  • chore: upgrade to 1.59.0 (#738) by @scop

1.6.14 (2024-05-30)

1.6.13 (2024-05-27)

1.6.12 (2024-05-17)

  • fix: more verbose error on versions mismatch (#721) by @mrexox
  • fix: enable interactive scripts (#720) by @mrexox

1.6.11 (2024-05-13)

  • feat: add run --no-auto-install flag (#716) by @mrexox
  • fix: add --porcelain to git status --short (#711) by @110y
  • chore: bump go to 1.22 (#701) by @mrexox

1.6.10 (2024-04-10)

1.6.9 (2024-04-09)

  • fix: enable interactive inputs for windows (#696) by @mrexox
  • fix: add batching to implicit commands (#695) by @mrexox
  • fix: command argument count validations (#694) by @scop
  • fix: re-download remotes when called install with -f (#692) by @mrexox
  • chore: remove redundant parallelisation (#690) by @mrexox
  • chore: refactor Result handling (#689) by @mrexox

1.6.8 (2024-04-02)

1.6.7 (2024-03-15)

  • fix: don't apply empty patch files on pre-commit hook (#676) by @mrexox
  • docs: allow only comma divided tags (#675) by @mrexox

1.6.6 (2024-03-14)

1.6.5 (2024-03-04)

1.6.4 (2024-02-28)

1.6.3 (2024-02-27)

1.6.2 (2024-02-26)

  • fix: respect roots in commands for npm packages (#616) by @mrexox
  • fix: don't capture STDIN without interactive or use_stdin options (#638) by @technicalpickles
  • fix: handle LEFTHOOK_QUIET when there is no skip_output in config by @prog-supdex
  • docs: add stage_fixed to the examples by @mrexxo
  • docs: clarify the difference between piped and parallel options by @mrexox

1.6.1 (2024-01-24)

  • fix: files from stdin only null separated (#615) by @mrexox
  • docs: add a new article link by @mrexox

1.6.0 (2024-01-22)

1.5.7 (2024-01-17)

1.5.6 (2024-01-12)

  • feat: shell completion improvements (#577) by @scop
  • fix: safe execute git commands without sh wrapper (#606) by @mrexox
  • fix: use lefthook package with npx (#604) by @mrexox
  • feat: allow setting a bool value for skip_output (#601) by @nsklyarov
  • docs: update exception case about interactive option by @mrexox

1.5.5 (2023-11-30)

1.5.4 (2023-11-27)

  • chore: add typos fixer by @mrexox
  • fix: drop new argument for git diff compatibility (#586) by @mrexox

1.5.3 (2023-11-22)

  • fix: don't check checksum file when explicitly calling lefthook install (#572) by @mrexox
  • chore: skip summary separator if nothing is printed (#575) by @mrexox
  • docs: update info about root option by @mrexox

1.5.2 (2023-10-9)

  • fix: correctly sort alphanumeric commands (#562) by @mrexox

1.5.1 (2023-10-6)

  • feat: add force flag to run command (#561) by @mrexox
  • fix: do not enable export when sourcing rc file (#553) by @hyperupcall
  • chore: wrap shell args in quotes for consistency by @mrexox
  • docs: add a note that files template supports directories by @mrexox
  • feat: initial support for Swift Plugins (#556) by @csjones

1.5.0 (2023-09-21)

1.4.11 (2023-09-13)

  • docs: update docs and readme with tl;dr instructions (#548) by @mrexox
  • fix: add use_stdin option for just reading from stdin (#547) by @mrexox
  • chore: refactor commands passing (#546) by @mrexox
  • fix: fail on non existing hook name (#545) by @mrexox

1.4.10 (2023-09-04)

  • fix: split command with file templates into chunks (#541) by @mrexox
  • chore: add git-cliff config for easier changelog generation by @mrexox
  • fix: allow empty staged files diffs (#543) by @mrexox

1.4.9 (2023-08-15)

1.4.8 (2023-07-31)

1.4.7 (2023-07-24)

1.4.6 (2023-07-18)

  • fix: do not print extraneous newlines when executionInfo output is hidden (#519) by @hyperupcall
  • fix: uninstall all possible formats (#523) by @mrexox
  • fix: LEFTHOOK_VERBOSE properly overrides --verbose flag (#521) by @hyperupcall
  • feat: support .lefthook.yml and .lefthook-local.yml (#520) by @hyperupcall

1.4.5 (2023-07-12)

1.4.4 (2023-07-10)

  • fix: don't render bold ANSI sequence when colors are disabled (#515) by @adam12
  • deps: July 2023 (#514) by @mrexox

1.4.3 (2023-06-19)

1.4.2 (2023-06-13)

1.4.1 (2023-05-22)

1.4.0 (2023-05-18)

1.3.13 (2023-05-11)

1.3.12 (2023-04-28)

  • fix: allow skipping execution_out with interactive mode (#476) by @mrexox

1.3.11 (2023-04-27)

  • feat: add execution_out to skip output settings (#475) by @mrexox
  • chore: add debug logs when hook is skipped (#474) by @mrexox

1.3.10

1.3.9 (2023-04-04)

  • feat: allow extra hooks in local config (#462) by @fabn
  • feat: pass numeric placeholders to files command (#461) by @fabn

1.3.8 (2023-03-23)

  • fix: make hook template compatible with shells without source command (#458) by @mdesantis

1.3.7 (2023-03-20)

  • fix: allow globs in skip option (#457) by @mrexox
  • deps: dependencies update (March 2023) (#455) by @mrexox
  • fix: don't fail on missing config file (#450) by @mrexox

1.3.6 (2023-03-16)

  • fix: stage fixed when root specified (#449) by @mrexox
  • feat: implitic skip on missing files for pre-commit and pre-push hooks (#448) by @mrexox

1.3.5 (2023-03-15)

1.3.4 (2023-03-13)

  • fix: don't extra extend config if lefthook-local.yml is missing (#444) by @mrexox

1.3.3 (2023-03-01)

1.3.2 (2023-02-27)

1.3.1 (2023-02-27)

  • fix: Force creation of git hooks folder (#434) by @mrexox

1.3.0 (2023-02-22)

  • fix: Use correct branch for {push_files} template (#429) by @mrexox
  • feature: Skip unstaged changes for pre-commit hook (#402) by @mrexox

1.2.9 (2023-02-13)

1.2.8 (2023-01-23)

  • fix: Don't join info path with root (#418) by @mrexox

1.2.7 (2023-01-10)

1.2.6 (2022-12-14)

1.2.5 (2022-12-13)

1.2.4 (2022-12-05)

1.2.3 (2022-11-30)

1.2.2 (2022-11-23)

1.2.1 (2022-11-17)

1.2.0 (2022-11-7)

1.1.4 (2022-11-1)

1.1.3 (2022-10-15)

1.1.2 (2022-10-10)

1.1.1 (2022-08-22)

1.1.0 (2022-08-13)

1.0.5 (2022-07-19)

1.0.4 (2022-06-27)

1.0.3 (2022-06-25)

  • Fix NPM package
  • Update email information

1.0.2 (2022-06-24)

1.0.1 (2022-06-20) Ruby gem and NPM package fix

  • Fix folders structure for [@evilmartians](https://github.com/evilmartians)/lefthook and [@evilmartians](https://github.com/evilmartians)/lefthook-installer packages
  • Fix folders structure for lefthook gem

1.0.0 (2022-06-19)

0.8.0 (2022-06-07)

0.7.7 (2021-10-02)

0.7.6 (2021-06-02)

  • Fix lefthook binary extension on Windows. @aminya
  • PR #193 Fix path for searching npm-installed binary when in worktree. @Envek
  • NPM, RPM, and DEB packaging fixes. @Envek

0.7.5 (2021-05-14)

0.7.4 (2021-04-30)

0.7.3 (2021-04-23)

  • PR Package versions for all architectures (x86_64, ARM64, x86) into Ruby gem and NPM package @Envek
  • PR Fix golang 15+ build @skryukov

0.7.2 (2020-02-02)

0.7.1 (2020-02-02)

  • PR Fix sh dependency on windows when executing git. Thanks @lionskape

  • PR Add possibility for using yaml and yml extension for config. Thanks @rbUUbr

0.7.0 (2019-12-14)

  • PR Support relative roots for monorepos. Thanks @jsmestad

0.6.7 (2019-12-14)

0.6.6 (2019-12-03)

  • PR Use eval instead of exec; Enable tty for the shell. Thanks @ssnickolay

0.6.5 (2019-11-15)

  • PR Add support for git-worktree. Thanks @f440

  • Commit Commands and Scripts now can catch Stdin

  • Commit Add partial support for monorepos and command execution not from project root

0.6.4 (2019-11-08)

  • PR Fix return value from shell exit. Thanks @HaiD84

  • PR Support postinstall script for npm installation for monorepos. Thanks @sHooKDT

  • PR Now relative path to scripts supported. Thanks @AlexeyMatskevich

  • Commit Option extends for top level config added. Now you can merge some settings from different places:

    extends: $HOME/work/lefthook-extend.yml
  • Commit Add examples to generated lefthook.yml

0.6.3 (2019-07-15)

  • Commit Add -a means aggressive strategy for install command

    lefthook install -a # clear .git/hooks dir and reinstall lefthook hooks
  • Commit Add Lefthook version indicator for commands and script execution

  • Commit Remove npx as dependency from node wrapper

Now we will call directly binary from ./node_modules

  • Commit Add -f means force strategy for install command
lefthook install -f # reinstall lefthook hooks without sync info check
  • PR #27 Move LEFTHOOK env check in hooks files

Now if LEFTHOOK=0 we will not call the binary file

Add shortcut {push_files}

pre-commit:
  commands:
    rubocop:
      run: rubocop {push_files}

It same as:

pre-commit:
  commands:
    rubocop:
      files: git diff --name-only HEAD @{push} || git diff --name-only HEAD master
      run: rubocop {push_files}
  • Commit Add min_version option

You can mark your config for minimum Lefthook version:

min_version: 0.6.1

0.6.0 (2019-07-10)

  • PR #24 Wrap run command in shell context.

Now in run option available sh syntax.

pre-commit:
  commands:
    bashed:
      run: rubocop -a && git add

Will be executed in this way:

sh -c "rubocop -a && git add"
  • PR #23 Search Lefthook in Gemfile.

Now it's possible to use Lefthook from Gemfile.

# Gemfile

gem 'lefthook'