Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

lefthook

Per-project git-hooks manager template. Lefthook has no global config — this directory ships a lefthook.yml you can copy or extends: into new repos.

Table of contents

Layout

FilePurpose
lefthook/lefthook.ymlGo-dev baseline template (no symlink)

This package is not stowed — lefthook.yml is meant to live inside your project repos, not in $HOME.

Two ways to use it

1. Copy into a new repo

cp ~/dotfiles/lefthook/lefthook.yml ./lefthook.yml
lefthook install

lefthook install writes the .git/hooks/* shims that invoke lefthook. You only need to do this once per clone.

2. Extend it from your project’s lefthook.yml

# project/lefthook.yml
extends: ~/dotfiles/lefthook/lefthook.yml

pre-commit:
  commands:
    # project-specific addition
    api-spec-check:
      glob: "openapi.yaml"
      run: spectral lint {staged_files}

Then lefthook install and additions stack on top of the baseline.

What the template runs

pre-commit (parallel):

HookGlobWhat
gofmt*.gofail if any file isn’t gofmt’d
goimports*.gofail if imports aren’t sorted
golangci-lint*.gorun lint, only new findings since HEAD
govet*.gogo vet ./...
shellcheck*.{sh,bash}lint staged shell
shfmt*.{sh,bash}format-diff shell (2-space, switch-case indent)
yamllint*.{yml,yaml}YAML lint
hadolintDockerfile*Dockerfile lint

commit-msg: reject empty subjects.

pre-push (parallel):

HookGlobWhat
go-test*.gogo test ./...
go-build*.gogo build ./...

All the linters / formatters are in the Brewfile.

Adding repo-specific hooks

The most common pattern: extends: the baseline, then add or override. Anything you add lives in the project repo (versioned with the code).

Skipping a hook

LEFTHOOK_EXCLUDE=golangci-lint git commit -m "wip"
# or skip all hooks (use sparingly):
git commit --no-verify

Fresh-machine setup

brew install lefthook   # in the Brewfile
# In each repo where you want hooks:
lefthook install