Fast and powerful Git hooks manager for any type of projects.

Overview

Build Status

Lefthook

The fastest polyglot Git hooks manager out there

Fast and powerful Git hooks manager for Node.js, Ruby or any other type of projects.

  • Fast. It is written in Go. Can run commands in parallel.
  • Powerful. With a few lines in the config you can check only the changed files on pre-push hook.
  • Simple. It is single dependency-free binary which can work in any environment.

📖 Read the introduction post

# On `git push` lefthook will run spelling and links check for all of the changed files
pre-push:
  parallel: true
  commands:
    spelling:
      files: git diff --name-only HEAD @{push}
      glob: "*.md"
      run: npx yaspeller {files}
    check-links:
      files: git diff --name-only HEAD @{push}
      glob: "*.md"
      run: npx markdown-link-check {files}
Sponsored by Evil Martians

Usage

Choose your environment:

Then you can find all Lefthook features in the full guide and explore wiki.


Why Lefthook

  • Parallel execution

If you want more speed. Example

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.rb|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. Example.

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

If you want to control a group of commands. Example.

pre-push:
  commands:
    packages-audit:
      tags: frontend security
      run: yarn audit
    gems-audit:
      tags: backend security
      run: bundle audit
  • Support Docker

If you are in the Docker environment. Example.

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

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

# 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
  • Optional output

If you don't want to see supporting information:

skip_output:
  - meta #(version and which hook running)
  - success #(output from runners with exit code 0)

Table of contents:

Guides

Migrate from

Examples

Benchmarks

Comparison list

Articles

Comments
  • Download binary on npm postinstall hook

    Download binary on npm postinstall hook

    As was discussed in issue #16 the lefthook npm package contains all the binaries, this postinstall hook downloads only the appropriate binary for the host OS (or in case of CI: none).

    Note: I submit my PR in accordance to https://github.com/Arkweid/lefthook/issues/16#issuecomment-517672355. Note 2: I did not run any go/ruby command as this PR mainly changes the postinstall script in the .npm directory. If this is still necessary I will update my PR, just let me know what is missing. :v:

    opened by fleischie 22
  • Pass local and remote branch names as arguments / env variables to pre-push

    Pass local and remote branch names as arguments / env variables to pre-push

    Is it possible to access the local / remote ref names in the pre-push hook?

    Git passes the information as STDIN to the pre-push hook. But lefthook is not passing it to the actual hook.

    opened by JoyceBabu 18
  • Fixers do not stop commits

    Fixers do not stop commits

    Here's a trivial example:

    FROM ubuntu:bionic
    RUN : \
        && apt-get update \
        && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
            ca-certificates \
            curl \
            git \
            python3-pip \
            python3-setuptools \
        && apt-get clean
    RUN : \
        && curl --location --silent --output /tmp/lefthook.gz https://github.com/Arkweid/lefthook/releases/download/v0.6.3/lefthook_0.6.3_Linux_x86_64.gz \
        && echo '0876ae7a862cb26aa5bd50173502dfd836cd16317f7af18be0797deeb3e1cfcd  /tmp/lefthook.gz' | sha256sum --check \
        && gunzip /tmp/lefthook.gz \
        && mv /tmp/lefthook /usr/local/bin \
        && chmod +x /usr/local/bin/lefthook \
        && which lefthook
    
    RUN pip3 install autopep8
            
    WORKDIR /src
    
    COPY lefthook.yml .
    
    ENV \
        [email protected] \
        GIT_AUTHOR_NAME='A A' \
        [email protected] \
        GIT_COMMITTER_NAME='A A'
    
    RUN : \
        && git init . \
        && echo 'print(1    +1)' > t.py \
        && lefthook install \
        && git add .
    
    CMD ["bash", "-xc", "git commit -m test && git status && cat t.py"]
    
    pre-commit:
      commands:
        autopep8:
          files: git diff --staged --name-only -- '*.py'
          run: autopep8 -i {files}
    
    docker build -t test .
    docker run --rm -ti test
    
    $ docker run --rm -ti test
    + git commit -m test
    Lefthook v0.6.3
    RUNNING HOOKS GROUP: pre-commit
    
      EXECUTE > autopep8
    
    SUMMARY: (done in 0.17 seconds)
    ✔️  autopep8
    [master (root-commit) 2858089] test
     2 files changed, 6 insertions(+)
     create mode 100644 lefthook.yml
     create mode 100644 t.py
    + git status
    On branch master
    Changes not staged for commit:
      (use "git add <file>..." to update what will be committed)
      (use "git checkout -- <file>..." to discard changes in working directory)
    
    	modified:   t.py
    
    no changes added to commit (use "git add" and/or "git commit -a")
    + cat t.py
    print(1 + 1)
    

    The commit should have been blocked as autopep8 modified a file

    opened by asottile 17
  • Npm: download the required binaries during installation

    Npm: download the required binaries during installation

    • The binaries are now downloaded upon installation. This reduces the package size significantly, which is very important for open-source repositories.

    • Fixes finding the binaries on Windows inside the hooks. Previously the code fell back to using npx

    Closes #43

    opened by aminya 16
  • Don't run tool if no file to work on

    Don't run tool if no file to work on

    Hello,

    Possible bug I saw during test lefthook.

    Actual behavior

    When no {staged_files} is empty (SKIP. NO FILES FOR INSPECTING) is output but the command is called.

    Waited behavior

    The command is not called

    Herve-M

    help wanted Windows 
    opened by Herve-M 15
  • Lefthook for Dart

    Lefthook for Dart

    Hello! I want to use lefthook with Dart. I can make a PR for that, but I have a couple of questions.

    Do you publish all packages manaully? Who will publish new versions to pub (Dart package registry)?

    P.S. Thanks for lib, it is really great! 😻

    enhancement help wanted 
    opened by igorkamyshev 15
  • Speed up on Node

    Speed up on Node

    Now we have 3 binaries in npm and script which run necessary binary depends on the current platform.

    There are 2 big problems with current behavior:

    1. npm package size is huge (26 MB)
    2. Node.js startup time is not great.

    Solution:

    1. postinstall script download necessary binary (many npm packages use this approach, for instance puppeter).
    2. npm runs binary directly without index.js
    enhancement help wanted good first issue 
    opened by ai 14
  • wiki: Comparison page

    wiki: Comparison page

    opened by docwhat 13
  • npm Scope package naming

    npm Scope package naming

    Since this project moved into Evil Martians a long time ago, I would like to propose to rename or alias the npm package scope to just "lefthook".

    opened by muuvmuuv 11
  • Documentation to work with commitlint?

    Documentation to work with commitlint?

    Unfortunately the commitlint documentation only has these instructions:

    {
      "husky": {
        "hooks": {
          "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
        }
      }
    }
    

    And it's unclear whether lefthook exposes whatever HUSKY_GIT_PARAMS are in such a way that it works with commitlint.

    opened by radiosilence 10
  • Add logrus integration

    Add logrus integration

    1. Added logrus for this project
    2. I've added flag for rootCmd with log-level, but seems it does not work :( could you please check it? Because I found out that other flags for rootCmd also doesn't work

    closes #78

    opened by rbUUbr 10
  • Error using {push_files}

    Error using {push_files}

    Summary

    Whenever I pass the {push_files} argument to a run: in the pre-push section I just get this error message that says error replacing {push_files}: exit status 128

    Steps to reproduce

    Here's the relevant sections my lefthook.yaml file:

    ---
    skip_output:
      - meta       # Skips lefthook version printing
      - success    # Skips successful steps printing
    pre-push:
      parallel: true
      commands:
        shellcheck:
          tags: sast
          glob: "*.sh"
          run: scripts/shellcheck.sh {push_files}
    

    Contents of shellscheck.sh though I'm sure it doesn't matter because it happens no matter what I use but adding for completeness sake:

    #!/usr/bin/env bash
    set -euo pipefail
    
    if ! command -v shellcheck > /dev/null; then
      echo "WARN: shellcheck is not installed. Installing....."
      if [[ "$(uname)" == "Darwin" ]]; then
        if ! command -v brew > /dev/null; then
          echo "ERROR: Homebrew isn't installed. Please see https://docs.brew.sh/Installation for instructions."
          exit 1
        else
          brew install -q shellcheck
        fi
      else
        echo "ERROR: Non macOS operating systems not supported at this time. Feel free to open a PR and extend this check :)"
      fi
    fi
    
    for file in "[email protected]"
    do
      shellcheck -o all "${file}"
    done
    

    Expected results

    I expect it to not error? lol. I know the file i'm testing should cause an error to return from my script. I've also tried other scripts in the run directive and the same results.. anytime I reference the {push_files} I get that same error.

    Actual results

    I make adjustments to a *.sh file and when I try to push up the change to remote up I get the error [snipped branch name details]:

    ➜  git push origin BRANCH_NAME
    error replacing {push_files}: exit status 128
    shellcheck: (SKIP. ERROR)
    
    refs/heads/style/BRANCH_NAME branch_sha refs/heads/style/BRANCH_NAME branch_sha
    
    SUMMARY: (done in 0.09 seconds)
    

    Possible Solution

    🤷🏻

    bug 
    opened by cloudmatt 3
  • No stderr git output in VS Code

    No stderr git output in VS Code

    Summary

    If a pre-commit fails, VS Code is not showing the errors in Log (Git) panel.

    Steps to reproduce

    lefthook.yml

    pre-commit:
      commands:
        pretty:
          glob: '*.dart'
          run: flutter format {staged_files} && git add {staged_files}
        tests:
          run: flutter test
    

    Click commit in VS Code

    Git (Log) output

    2022-11-18 08:35:38.146 [info] > git ls-tree -l HEAD -- [redacted path]/lefthook.yml [8ms]
    2022-11-18 08:35:38.151 [info] > git ls-files --stage -- [redacted path]/lefthook.yml [5ms]
    2022-11-18 08:35:38.158 [info] > git cat-file -s 461e407f04bb403412fde4ee641f9af9cb61b6a1 [1ms]
    2022-11-18 08:35:38.173 [info] > git show --textconv HEAD:lefthook.yml [8ms]
    2022-11-18 08:35:38.174 [info] > git show --textconv :lefthook.yml [2ms]
    2022-11-18 08:35:43.339 [info] > git -c user.useConfigOnly=true commit --quiet --allow-empty-message --file - [6368ms]
    2022-11-18 08:35:43.348 [info] > git config --get-all user.name [1ms]
    2022-11-18 08:35:43.356 [info] > git config --get-all user.email [2ms]
    

    Expected results

    Runninglefthook run pre-commit in terminal:

    Lefthook v1.2.1
    RUNNING HOOK: pre-commit
    
    EXECUTE > pretty
    Formatted 1 file (0 changed) in 0.14 seconds.
    
    EXECUTE > tests
    [redacted]
    00:03 +3 -1: Some tests failed.                                                                                                                                                                        
    
    SUMMARY: (done in 5.73 seconds)
    ✔️  pretty
    🥊  tests
    
    

    git: 2.34.1 lefthook: 1.2.1 VS Code: 1.73.1

    bug 
    opened by bogdanmarinescu 1
  • Removing a ref after lefthook install fails to fetch from the main branch

    Removing a ref after lefthook install fails to fetch from the main branch

    Summary

    When you remove a ref option from remote configuration, and you already had lefthook install-ed, the remote syncing fails.

    Steps to reproduce

    remote:
      git_url: https://github.com/evilmartians/lefthook
      ref: v1.1.1
      config: examples/complete/lefthook.yml
    
    $ lefthook install
    SYNCING
    SERVED HOOKS: commit-msg, pre-commit, pre-push
    $ git -C .git/info/lefthook-remotes/lefthook/ log --oneline
    55f4381 (grafted, HEAD, tag: v1.1.1) 1.1.1: Quote path to script
    
    remote:
      git_url: https://github.com/evilmartians/lefthook
      config: examples/complete/lefthook.yml # assumed to fetch from master branch 
    
    $ lefthook install
    SYNCING
    SERVED HOOKS: commit-msg, pre-commit, pre-push
    $ git -C .git/info/lefthook-remotes/lefthook/ log --oneline
    55f4381 (grafted, HEAD, tag: v1.1.1) 1.1.1: Quote path to script # (!) must be master branch
    

    Expected results

    Expected to checkout to the main branch of the repository. May be master or main branch at least.

    Possible Solution

    Provide a default value for the ref.

    bug 
    opened by mrexox 0
  • support new config file format

    support new config file format

    It will be really cool to add .lefthook.yml (with dot in the beginning) config file format support. Just to align with other libs:

    opened by fantua 2
  • Git submodules doesn't appear in changed files

    Git submodules doesn't appear in changed files

    post-checkout:
      commands:
        update-submodules:
          run: printf '%s\n' {all_files}
    

    I expected the submodules we're using to appear in the {all_files} but it wasn't the case. I think it should display the submodules as well.

    opened by BasixKOR 1
  • prepush runs all on setting upstream

    prepush runs all on setting upstream

    I will not say that the problem is with Lefthook. But the examples you can find in the documentation are just that.

    I would like to ask for advice or a solution to this situation.


    Suppose we have a mono repository.

    We have set up something like this

    pre-push:
      commands:
        a:
          root: "libs/a/"
          files: git diff --name-only HEAD @{push}
          run: npm run test
        b:
          root: "libs/b/"
          files: git diff --name-only HEAD @{push}
          run: npm run test
    

    The problem is that when I create a new branch and make changes only for a and push it, all the tests run. In subsequent pushes, this behavior is not observed.

    Perhaps there is a more robust way to get the names of the changed files then git diff --name-only HEAD @{push}, taking into account root.

    opened by mhozhynewscorp 4
Releases(v1.2.3)
Owner
Abroskin Alexander
Abroskin Alexander
Gum - Git User Manager (GUM) - Switch between git user profiles

Git User Manager (GUM) Add your profile info to config.yaml Build project: go bu

Mehmet Tevfik YÜKSEL 6 Feb 14, 2022
Git with a cup of tea, painless self-hosted git service

Gitea - Git with a cup of tea View the chinese version of this document Purpose The goal of this project is to make the easiest, fastest, and most pai

Gitea 33.5k Dec 2, 2022
ReGit: A Tiny Git-Compatible Git Implementation written in Golang

ReGit is a tiny Git implementation written in Golang. It uses the same underlying file formats as Git. Therefore, all the changes made by ReGit can be checked by Git.

null 167 Oct 31, 2022
A Git RPC service for handling all the git calls made by GitLab

Quick Links: Roadmap | Want to Contribute? | GitLab Gitaly Issues | GitLab Gitaly Merge Requests | Gitaly is a Git RPC service for handling all the gi

null 1 Nov 13, 2021
A simple cli tool for switching git user easily inspired by Git-User-Switch

gitsu A simple cli tool for switching git user easily inspired by Git-User-Switch Installation Binary releases are here. Homebrew brew install matsuyo

Masaya Watanabe 202 Nov 9, 2022
Removes unnecessarily saved git objects to optimize the size of the .git directory.

Git Repo Cleaner Optimizes the size of the .git directory by removing all of the files that are unnecessarily-still-saved as part of the git history.

Omar Yasser 2 Mar 24, 2022
Git-now-playing - Git commits are the new AIM status messages

git-now-playing git-now-playing is an attempt to bring some of the panache of th

Paddy 1 Apr 4, 2022
Git-Go is a supposed cross platform website blocker that will block any web domain by looping the connection to the loopback

git-go Git-Go is a supposed cross platform website blocker that will block any web domain by looping the connection to the loopback ______ _____ ____

RE43P3R 1 May 19, 2022
A Simple and Comprehensive Vulnerability Scanner for Container Images, Git Repositories and Filesystems. Suitable for CI

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI. Abstract Trivy (tri pronounced like trigger, vy

Aqua Security 15k Nov 27, 2022
A tool to monitor git repositories and automatically pull & push changes

git-o-matic A tool to monitor git repositories and automatically pull & push changes Installation Packages & Binaries Arch Linux: gitomatic Binaries f

Christian Muehlhaeuser 1k Nov 18, 2022
go mod vendor lets you check in your dependencies to git, but that's both bloaty (for developers) and tedious (remembering to update it).

go-mod-archiver Afraid of being unable to build historical versions of your Go program? go mod vendor lets you check in your dependencies to git, but

Tailscale 85 Oct 9, 2022
A single Git repository that holds two microservices (Python and GO)

A single Git repository that holds two microservices (Python and GO)

null 0 Nov 19, 2021
Installs git repos onto your system and keeps them up-to-date

Gitfile Installs git repos onto your system and keeps them up-to-date. It's a lightweight package manager for things that haven't been published to a

Brad Urani 18 Jan 16, 2021
Sync tags in your git repository and a changelog in Keep a Changelog format with releases of your GitLab project.

Automatic GitLab releases Sync tags in your git repository and a changelog in Keep a Changelog format with releases of your GitLab project. Features:

null 1 Nov 12, 2022
Gogs is a painless self-hosted Git service

Gogs - A painless self-hosted Git service 简体中文 ?? Vision The Gogs (/gɑgz/) project aims to build a simple, stable and extensible self-hosted Git servi

Gogs 41.3k Nov 25, 2022
A highly extensible Git implementation in pure Go.

go-git is a highly extensible git implementation library written in pure Go. It can be used to manipulate git repositories at low level (plumbing) or

go-git 4k Nov 23, 2022
commit/branch/workdir explorer for git

gitin gitin is a commit/branch/status explorer for git gitin is a minimalist tool that lets you explore a git repository from the command line. You ca

Ibrahim Serdar Acikgoz 1.8k Nov 26, 2022
A command-line tool that makes git easier to use with GitHub.

hub is a command line tool that wraps git in order to extend it with extra features and commands that make working with GitHub easier. For an official

GitHub 22.2k Dec 1, 2022
SQL interface to git repositories, written in Go. https://docs.sourced.tech/gitbase

gitbase gitbase, is a SQL database interface to Git repositories. This project is now part of source{d} Community Edition, which provides the simplest

source{d} 2k Nov 18, 2022