Pre-commit Hook Configuration for Containerized Workflows
Introduction
Git pre-commit hooks executed within containers guarantee that code quality standards are applied identically across all developer machines and CI systems. This section covers configuring the pre-commit framework for deterministic hook execution, multi-language support, and reproducible linting pipelines.
Sections
1. Pre-commit Framework Installation & Dependencies
Use the pre-commit Python package to manage multi-language hook definitions. Define hooks in .pre-commit-config.yaml with explicit versioning to ensure identical execution across machines.
Pin the pre-commit framework version in your requirements.txt or Pipfile to guarantee consistency. Include language-specific interpreters (Python, Node, Ruby) in the DevContainer to support hooks across all languages.
2. Hook Definition & Language Coverage
Define hooks for common code quality patterns: YAML validation, JSON parsing, trailing whitespace removal, secret detection, and language-specific linters.
Configure each hook with exact versions and arguments. Use stages: [commit, push] to control when hooks execute. Document the purpose and auto-fix behavior of each hook for team reference.
3. Container Execution & Cache Management
Execute pre-commit hooks via postCreateCommand to install and cache hook environments. Use Docker named volumes to persist hook cache across container rebuilds, reducing reinstall overhead.
Configure additional_dependencies in .pre-commit-config.yaml to inject language-specific tools (ESLint, Prettier, Black) without modifying hook definitions.
4. CI/CD Integration & Bypass Strategies
Run pre-commit checks in GitHub Actions or similar CI systems with identical configuration. Use --all-files flag to validate all repository files during CI, not just changed files.
Document safe bypass scenarios (e.g., --no-verify for emergency fixes) and require explicit commit options to prevent accidental code quality violations.
Code Blocks
.pre-commit-config.yaml with multi-language hooks
# Pre-commit hook configuration
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-json
- id: detect-private-key
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
language_version: python3.11
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-docstrings]
args: [--max-line-length=100]
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.40.0
hooks:
- id: eslint
files: \.(js|ts|jsx|tsx)$
types: [file]
additional_dependencies:
- eslint@8.40.0
- eslint-config-airbnb-base
- eslint-plugin-import
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.0-alpha.9-for-vscode
hooks:
- id: prettier
types_or: [javascript, typescript, json, yaml, markdown]
devcontainer.json with pre-commit setup
{
"image": "mcr.microsoft.com/devcontainers/python:3.11",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "18.17.0" }
},
"postCreateCommand": "pip install pre-commit==3.3.3 && pre-commit install && pre-commit run --all-files || true",
"mounts": [
"source=pre-commit-cache,target=/root/.cache/pre-commit,type=volume"
]
}
.github/workflows/pre-commit.yml CI integration
name: Pre-commit Checks
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install pre-commit==3.3.3
- run: pre-commit run --all-files
Common Pitfalls
- Hook cache pollution: Pre-commit caches can accumulate stale dependencies, causing mysterious failures. Use Docker named volumes for persistent cache with explicit versioning.
- Python version conflicts: Hooks expecting Python 3.9 but running on 3.11 cause import errors. Specify
language_versionexplicitly in.pre-commit-config.yaml. - Missing additional_dependencies: Hooks requiring external packages (ESLint plugins, Black for Python) fail if dependencies are not declared. Document all dependencies in
additional_dependencies. - Bypass temptation: Using
git commit --no-verifyto skip hooks undermines quality standards. Establish team policies and use aliases to prevent accidental bypasses. - Untracked large files: Pre-commit scanning large binary files or vendor directories causes performance issues. Use
.pre-commit-args: [--max-file-size]to skip large files.
FAQ
How do I exclude files from pre-commit checks?
Use exclude: pattern in .pre-commit-config.yaml. Common patterns: exclude vendor files, generated code, and large binaries. Document exclusions for team clarity.
Should I run pre-commit locally or only in CI?
Run pre-commit run --all-files locally to catch issues before pushing. Use same configuration in CI as a safety net. This prevents CI feedback loops and improves developer velocity.