setup

install pre-commit

$ python -m pip install --user pipx && pipx ensurepath
$ pipx install pre-commit

# or
$ brew install --HEAD pre-commit

init hook in repo

$ pre-commit install

# or
$ pre-commit install --install-hook
pre-commit installed at .git/hooks/pre-commit

[!TIP|labels:with different stages:]

  • references:
    • default_install_hook_types : a list of --hook-types which will be used by default when running pre-commit install
    • default_stages : a configuration-wide default for the stages property of hooks. This will only override individual hooks that do not set stages
  • priority : --hook-type (CLI flag) takes precedence over default_install_hook_types (top-level yml config)
    • The --hook-type CLI flag overrides default_install_hook_types: when --hook-type is given, pre-commit installs exactly those hook types and ignores default_install_hook_types entirely
  • .pre-commit-config.yaml

    ---
    
    default_install_hook_types: [pre-commit, commit-msg]
    default_stages: [pre-commit]
    
    repos:
      - repo: https://github.com/crate-ci/typos
        rev: v1.49.0
        hooks:
          - id: typos
            name: Typos
            args: ['--write-changes', '--force-exclude']
          # scan the commit message itself; no --write-changes -> only fail, never rewrite the message
          - id: typos
            name: Typos (commit message)
            alias: typos-commit-msg
            stages: [commit-msg]
            args: ['--force-exclude']
    
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/commit-msg

# install manually without top level settings
$ pre-commit install --hook-type commit-msg --hook-type pre-commit

automatic upgrade to latest version

$ pre-commit autoupdate
[https://github.com/pre-commit/pre-commit-hooks] already up to date!
[https://github.com/psf/black] already up to date!

# or
$ pre-commit autoupdate --repo https://github.com/pre-commit/pre-commit-hooks
[https://github.com/pre-commit/pre-commit-hooks] updating v4.6.0 -> v6.0.0

migrate-config

$ pre-commit migrate-config

check yaml validation

# validate .pre-commit-config.yaml
$ pre-commit validate-config

# validate .pre-commit-hooks.yaml
$ pre-commit validate-manifest

clean and uninstall

[!NOTE]

  • default PRE_COMMIT_HOME is ~/.cache/pre-commit
# clean pre-commit outdated cache
$ pre-commit gc

# clean pre-commit cache and environment ( $PRE_COMMIT_HOME )
$ pre-commit clean

# uninstall pre-commit hook from git repo
$ pre-commit uninstall

run

# -- all files --
$ pre-commit run --all-files
# or
$ pre-commit run --all-files --show-diff-on-failure --color always

# -- all files with specific hook --
$ pre-commit run <HOOK_ID> --all-files
# i.e.: trailing-whitespace
$ pre-commit run trailing-whitespace --all-files

# -- from ref -> to ref --
$ pre-commit run --show-diff-on-failure --color=always --from-ref "${START_REF}" --to-ref "${END_REF}"

# to check all files under folder recursively
$ pre-commit run --files $(git ls-files folder/path/) -v
$ pre-commit run <HOOK_ID> --files $(git ls-files folder/path/) -v

[!TIP|label:references:]

  • --hook-stage commit-msg must be used with --commit-msg-filename to specify the commit message file
# run with commit-msg hook
$ tmp=$(mktemp) && git log -1 --format=%B > "${tmp}"
$ pre-commit run --hook-stage commit-msg --commit-msg-filename "${tmp}"

# run `typos-commit-msg` runner in commit-msg hook stage
$ pre-commit run typos-commit-msg --hook-stage commit-msg --commit-msg-filename "${tmp}"

run with manual stage

$ cat .pre-commit-config.yaml
...
hooks:
  - id: end-of-file-fixer
    stages: [manual]

$ pre-commit run --hook-stage <stage_name> --all-files
# e.g.:
$ pre-commit run --hook-stage manual --all-files

hooks

[!NOTE|labels:reference:]

  • Supported hooks
  • sample config
    $ pre-commit sample-config
    # See https://pre-commit.com for more information
    # See https://pre-commit.com/hooks.html for more hooks
    repos:
    -   repo: https://github.com/pre-commit/pre-commit-hooks
        rev: v3.2.0
        hooks:
        -   id: trailing-whitespace
        -   id: end-of-file-fixer
        -   id: check-yaml
        -   id: check-added-large-files
    

[!NOTE|labels:reference:]

# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/marslo/cr-manager
    rev: v4.0.0
    hooks:
      - id: update-copyright
        args: ["--update"]

checker and fixer

# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: trailing-whitespace
        name: Trim Trailing Whitespace
      - id: end-of-file-fixer
        name: End Of File Fixer
      - id: check-yaml
        name: Check YAML
        args: ["--unsafe"]
      - id: check-json
        name: Check JSON
      - id: check-merge-conflict
        name: Check Merge Conflict
      - id: check-case-conflict
        name: Check Case Conflict
      - id: mixed-line-ending
        name: Mixed Line Ending
        args: ["--fix=lf"]

mixed-line-ending

--fix OPTIONS COMMENTS
auto auto-detect line-ending
no no change line-ending
cr force use \r(legacy Mac)
crlf force use \r\n(Windows)
lf force use \n(Unix/Linux/macOS)

convert tab to spaces

  • expand + sponge

    # yamllint disable rule:indentation
    ---
    repos:
      - repo: local
        hooks:
          - id: tab-to-space
            name: Convert Tabs to 2 Spaces
            entry: bash -c 'expand -t 2 "$@" | sponge "$@"' --
            language: system
            types: [text]
            exclude: \.(py|groovy|jenkinsfile/.*)$
    
          - id: tab-to-4-spaces
            name: Convert Tabs to 4 Spaces
            entry: bash -c 'expand -t 4 "$@" | sponge "$@"' --
            language: system
            files: \.py$
    
          - id: tab-to-2-spaces
            name: Convert Tabs to 2 Spaces
            entry: bash -c 'expand -t 2 "$@" | sponge "$@"' --
            language: system
            files: (\.groovy$|jenkinsfile/.*)
    
  • python solution

    tab_converter.py
    import argparse
    import fileinput
    
    def convert_tabs(file_path, spaces):
        with fileinput.FileInput(file_path, inplace=True) as file:
            for line in file:
                print(line.expandtabs(spaces), end='')
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('--spaces', type=int, required=True)
        parser.add_argument('files', nargs='*')
        args = parser.parse_args()
    
        for file in args.files:
            convert_tabs(file, args.spaces)
    
    repos:
      - repo: local
        hooks:
          - id: tab-to-space
            name: Convert Tabs to 2 Spaces [ DEFAULT ]
            entry: python tab_converter.py --spaces 2
            language: system
            types: [text]
            exclude: \.(py|groovy)$
            pass_filenames: true
    
          - id: tab-to-4-spaces
            name: Convert Tabs to 4 Spaces
            entry: python tab_converter.py --spaces 4
            language: system
            files: \.py$
            pass_filenames: true
    
          - id: tab-to-2-spaces
            name: Convert Tabs to 2 Spaces
            entry: python tab_converter.py --spaces 2
            language: system
            files: (\.groovy$|jenkinsfile/.*)
            pass_filenames: true
    

typos

[!NOTE|labels:reference:]

# yamllint disable rule:indentation
---
repos:
  - repo: https://github.com/crate-ci/typos
    rev: v1.45.1
    hooks:
        - id: typos
          name: Typos
          description: Finds and corrects spelling mistakes among source code.
          exclude: \.git
Copyright © marslo 2020-2026 all right reserved,powered by GitbookLast Modified: 2026-09-01 23:42:44

results matching ""

    No results matching ""