Pre‑Commit Essentials - A Quick Guide to Setup, Hooks, and Usage

A practical guide to installing pre‑commit, configuring hooks, and using them effectively. Packed with practical examples and ready‑to‑copy snippets, it’s the fastest way to improve code quality with minimal effort.

Pre‑Commit Essentials - A Quick Guide to Setup, Hooks, and Usage
Photo by garrett parker / Unsplash

Overview

  • The 'pre-commit' command can be used to run other programs that will do some checks on a Git repository files, when a 'git commit' command is issued

  • The checks that run during the commit are called 'pre-commit' hooks

  • The commit will actually be performed once all 'pre-commit' hooks run successfully

  • Here is a list of some 'pre-commit' hooks that we can directly use in our projects: hooks list

Installation

Here is a link to the official installation page if needed: install pre-commit

Using pip

Pre-commit is developed with python and can be installed with 'pip'

$ pip install pre-commit

Using .pyz file

We can also directly run the 'pre-commit-#.#.#.pyz' file after getting one from the 'pre-commit' releases page: here

$ python pre-commit-#.#.#.pyz ...

Usage

Hooks configuration file

  • 'pre-commit' will look for configurations inside the following file: .pre-commit-config.yaml
  • A sample configuration can be generated as follows:
# Generate pre-commit sample configuration file
$ pre-commit sample-config

# Result

# 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
  • A description of each available configuration file fields can be found here: configuration fields descriptions

  • For a list of supported 'pre-commit' hooks, have a look at this page: hooks list

  • To try a 'pre-commit' repository before actually using it, have a look at this page: hooks dry-run

  • For info about updating the 'pre-commit' configuration (hooks versions) automatically, have a look at hooks versions autoupdate

Running hooks

Here is how you configure 'git' to run the 'pre-commit' hooks on commits:

# Without installing hooks environments.
# Hooks environments will be installed on first run
$ pre-commit install

# With hooks environments installation
$ pre-commit install --install-hooks

Hooks environments contain the required dependencies to run a specific 'pre-commit' hook. To only install hooks environments, run this:

# Only install the necessary for running hooks, 
# without telling Git to run pre-commit hooks on commits
$ pre-commit install-hooks

Here is how you run hooks:

# Run hooks on all files
# Hooks environments will be installed if not already done
$ pre-commit run --all-files

Configuration snippets

General purpose

---
# 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: v6.0.0
    hooks:
      # See https://github.com/pre-commit/pre-commit-hooks/blob/main/.pre-commit-hooks.yaml for more
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files

Secret detection

repos:
  # Detects well-known secrets patterns (AWS access key, Github token, etc)
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.30.0
    hooks:
      - id: gitleaks
        args: ["protect", "--verbose", "--redact"]

  # Detects the presence of private keys
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v6.0.0
    hooks:
      - id: detect-private-key

At this time, gitleaks default rules do not detect secrets from fields like 'password', 'token', etc. The following secrets won't be detected for instance:

# File: unencrypted-secrets.yml

password: mysuperpass
token: mytoken
key: mykey

To fix that, we can add custom rules configuration for gitleaks inside the Git repository as follows:

# File: .gitleaks.toml

[[rules]]
id = "generic-secret"
description = "Generic secret assignment"
regex = '''(?i)(password|token|key)\s*[:=]\s*.+'''

With the above custom rules configuration, here is the result:

$ pre-commit install
pre-commit installed at .git/hooks/pre-commit

$ git add unencrypted-secrets.yml

$ git commit -m "commiting a file containing secrets"
Detect hardcoded secrets.................................................Failed
- hook id: gitleaks
- exit code: 1

○
    │╲
    │ ○
    ○ ░
    ░    gitleaks

Finding:     REDACTED: mysuperpass
Secret:      REDACTED
RuleID:      generic-secret
Entropy:     2.750000
File:        unencrypted-secrets.yml
Line:        1
Fingerprint: unencrypted-secrets.yml:generic-secret:1

Finding:     REDACTED: myREDACTED
Secret:      REDACTED
RuleID:      generic-secret
Entropy:     2.321928
File:        unencrypted-secrets.yml
Line:        2
Fingerprint: unencrypted-secrets.yml:generic-secret:2

Finding:     REDACTED: mypreivateREDACTED
Secret:      REDACTED
RuleID:      generic-secret
Entropy:     1.584962
File:        unencrypted-secrets.yml
Line:        3
Fingerprint: unencrypted-secrets.yml:generic-secret:3

7:36PM INF 0 commits scanned.
7:36PM INF scanned ~56 bytes (56 bytes) in 3.72ms
7:36PM WRN leaks found: 3

detect private key.......................................................Passed

Gitlab CI

Automatically generate documentation of Gitlab CI components

repos:
  - repo: https://github.com/erNail/labdoc
    rev: 3.0.2
    hooks:
      - id: labdoc-generate
        args:
          - "--repoUrl=$CI_SERVER_FQDN/my-component-path"
          - "--outputFile=./README.md"

Helm

Automatically generate documentation of Helm Charts

repos:
  - repo: https://github.com/norwoodj/helm-docs
    rev: v1.14.2
    hooks:
      - id: helm-docs
        args:
          - --chart-search-root=.

You need to install the 'helm-docs' binary before running this configuration. Installation instructions here: install helm-docs

You can also run it through docker by using 'id: helm-docs-container' instead of 'id: helm-docs' in the above configuration.