Skip to content

Commit e1c65de

Browse files
authored
Merge pull request #818 from The-DevOps-Daily/issue-750-pre-commit-hooks-guide
feat: Add Pre-commit Hooks guide
2 parents 6166cf2 + ac57fbe commit e1c65de

File tree

6 files changed

+1555
-0
lines changed

6 files changed

+1555
-0
lines changed

app/roadmap/devsecops/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ const milestones: DevSecOpsMilestone[] = [
187187
icon: GitBranch,
188188
priority: 'important',
189189
estimatedHours: 8,
190+
link: '/guides/pre-commit-hooks',
190191
},
191192
{
192193
name: 'Code Review for Security',
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
---
2+
title: 'Pre-commit Framework'
3+
description: 'Learn to install and configure the pre-commit framework for managing git hooks across your development team.'
4+
---
5+
6+
The pre-commit framework is a language-agnostic tool for managing git hooks. It handles installation, updates, and execution of hooks from a simple YAML configuration file.
7+
8+
## Installation
9+
10+
Install pre-commit using pip (Python's package manager):
11+
12+
```bash
13+
# Install pre-commit
14+
pip install pre-commit
15+
16+
# Verify installation
17+
pre-commit --version
18+
# pre-commit 3.6.0
19+
```
20+
21+
Alternative installation methods:
22+
23+
```bash
24+
# Using Homebrew (macOS/Linux)
25+
brew install pre-commit
26+
27+
# Using pipx (isolated environment)
28+
pipx install pre-commit
29+
30+
# Using conda
31+
conda install -c conda-forge pre-commit
32+
```
33+
34+
## Basic Configuration
35+
36+
Create a `.pre-commit-config.yaml` file in your repository root:
37+
38+
```yaml
39+
# .pre-commit-config.yaml
40+
repos:
41+
# Built-in hooks from pre-commit
42+
- repo: https://github.com/pre-commit/pre-commit-hooks
43+
rev: v4.5.0
44+
hooks:
45+
- id: trailing-whitespace
46+
- id: end-of-file-fixer
47+
- id: check-yaml
48+
- id: check-added-large-files
49+
args: ['--maxkb=500']
50+
- id: check-merge-conflict
51+
- id: detect-private-key
52+
```
53+
54+
Install the hooks into your git repository:
55+
56+
```bash
57+
# Install hooks defined in .pre-commit-config.yaml
58+
pre-commit install
59+
60+
# Output: pre-commit installed at .git/hooks/pre-commit
61+
```
62+
63+
## How Pre-commit Works
64+
65+
When you run `git commit`, pre-commit intercepts the command and runs your configured hooks:
66+
67+
```
68+
Commit Flow with Pre-commit
69+
---------------------------
70+
71+
git commit -m "message"
72+
|
73+
v
74+
[pre-commit hook triggered]
75+
|
76+
v
77+
[Run each configured hook]
78+
|
79+
+---+---+
80+
| |
81+
Pass Fail
82+
| |
83+
v v
84+
[Commit [Commit blocked,
85+
proceeds] show errors]
86+
```
87+
88+
Hooks only run on staged files by default, making them fast even in large repositories.
89+
90+
## Security-Focused Configuration
91+
92+
Here's a comprehensive configuration for security-focused pre-commit hooks:
93+
94+
```yaml
95+
# .pre-commit-config.yaml
96+
repos:
97+
# Standard pre-commit hooks
98+
- repo: https://github.com/pre-commit/pre-commit-hooks
99+
rev: v4.5.0
100+
hooks:
101+
- id: detect-private-key
102+
- id: check-added-large-files
103+
- id: check-merge-conflict
104+
- id: check-yaml
105+
args: [--unsafe] # Allow custom tags
106+
- id: check-json
107+
- id: check-xml
108+
- id: check-toml
109+
110+
# Secrets detection with gitleaks
111+
- repo: https://github.com/gitleaks/gitleaks
112+
rev: v8.18.1
113+
hooks:
114+
- id: gitleaks
115+
116+
# Alternative: detect-secrets from Yelp
117+
- repo: https://github.com/Yelp/detect-secrets
118+
rev: v1.4.0
119+
hooks:
120+
- id: detect-secrets
121+
args: ['--baseline', '.secrets.baseline']
122+
123+
# Security linting for Python
124+
- repo: https://github.com/PyCQA/bandit
125+
rev: 1.7.7
126+
hooks:
127+
- id: bandit
128+
args: ['-c', 'pyproject.toml']
129+
additional_dependencies: ['bandit[toml]']
130+
131+
# Dockerfile security
132+
- repo: https://github.com/hadolint/hadolint
133+
rev: v2.12.0
134+
hooks:
135+
- id: hadolint
136+
```
137+
138+
## Running Hooks Manually
139+
140+
You can run hooks without committing:
141+
142+
```bash
143+
# Run all hooks on all files
144+
pre-commit run --all-files
145+
146+
# Run a specific hook
147+
pre-commit run gitleaks --all-files
148+
149+
# Run hooks on specific files
150+
pre-commit run --files src/config.py src/auth.py
151+
152+
# Run hooks on staged files only (default behavior)
153+
pre-commit run
154+
```
155+
156+
## Updating Hooks
157+
158+
Keep your hooks up to date to get the latest security rules:
159+
160+
```bash
161+
# Update all hooks to latest versions
162+
pre-commit autoupdate
163+
164+
# Update a specific repo
165+
pre-commit autoupdate --repo https://github.com/gitleaks/gitleaks
166+
```
167+
168+
## Skipping Hooks (When Necessary)
169+
170+
Sometimes you need to bypass hooks (use sparingly):
171+
172+
```bash
173+
# Skip all hooks for this commit
174+
git commit --no-verify -m "Emergency fix"
175+
# Or use the short flag
176+
git commit -n -m "Emergency fix"
177+
178+
# Skip specific hooks
179+
SKIP=gitleaks git commit -m "Commit with known false positive"
180+
181+
# Skip multiple hooks
182+
SKIP=gitleaks,bandit git commit -m "Commit message"
183+
```
184+
185+
**Warning:** Skipping hooks should be rare and documented. Consider using allowlists instead of skipping entirely.
186+
187+
## Team-Wide Installation
188+
189+
Ensure everyone on your team uses pre-commit:
190+
191+
### Option 1: Document in README
192+
193+
```markdown
194+
## Development Setup
195+
196+
1. Install pre-commit: `pip install pre-commit`
197+
2. Install hooks: `pre-commit install`
198+
```
199+
200+
### Option 2: Makefile Target
201+
202+
```makefile
203+
# Makefile
204+
.PHONY: setup
205+
setup:
206+
pip install pre-commit
207+
pre-commit install
208+
pre-commit install --hook-type commit-msg
209+
```
210+
211+
### Option 3: Post-clone Hook Script
212+
213+
```bash
214+
#!/bin/bash
215+
# scripts/setup-dev.sh
216+
217+
echo "Setting up development environment..."
218+
219+
# Install pre-commit if not present
220+
if ! command -v pre-commit &> /dev/null; then
221+
echo "Installing pre-commit..."
222+
pip install pre-commit
223+
fi
224+
225+
# Install hooks
226+
pre-commit install
227+
pre-commit install --hook-type commit-msg
228+
229+
echo "Pre-commit hooks installed successfully!"
230+
```
231+
232+
## CI Integration
233+
234+
Run pre-commit in your CI pipeline as a backup:
235+
236+
```yaml
237+
# .github/workflows/pre-commit.yml
238+
name: Pre-commit
239+
240+
on:
241+
push:
242+
branches: [main]
243+
pull_request:
244+
branches: [main]
245+
246+
jobs:
247+
pre-commit:
248+
runs-on: ubuntu-latest
249+
steps:
250+
- uses: actions/checkout@v4
251+
- uses: actions/setup-python@v5
252+
with:
253+
python-version: '3.12'
254+
- uses: pre-commit/action@v3.0.1
255+
```
256+
257+
This catches any commits where developers bypassed local hooks.
258+
259+
## Hook Stages
260+
261+
Pre-commit supports different git hook stages:
262+
263+
```yaml
264+
repos:
265+
- repo: local
266+
hooks:
267+
# Runs before commit (default)
268+
- id: unit-tests
269+
name: Run unit tests
270+
entry: pytest tests/unit -q
271+
language: system
272+
stages: [commit]
273+
274+
# Runs before push
275+
- id: integration-tests
276+
name: Run integration tests
277+
entry: pytest tests/integration
278+
language: system
279+
stages: [push]
280+
281+
# Validates commit message format
282+
- id: commit-msg-check
283+
name: Check commit message
284+
entry: scripts/check-commit-msg.sh
285+
language: script
286+
stages: [commit-msg]
287+
```
288+
289+
Install hooks for different stages:
290+
291+
```bash
292+
# Install pre-push hooks
293+
pre-commit install --hook-type pre-push
294+
295+
# Install commit-msg hooks
296+
pre-commit install --hook-type commit-msg
297+
```
298+
299+
## Caching and Performance
300+
301+
Pre-commit caches hook environments to speed up subsequent runs:
302+
303+
```bash
304+
# View cache location
305+
pre-commit --cache-dir
306+
# Default: ~/.cache/pre-commit
307+
308+
# Clear cache if hooks misbehave
309+
pre-commit clean
310+
311+
# Reinstall hook environments
312+
pre-commit install-hooks
313+
```
314+
315+
For large repositories, use `files` and `exclude` patterns:
316+
317+
```yaml
318+
repos:
319+
- repo: https://github.com/gitleaks/gitleaks
320+
rev: v8.18.1
321+
hooks:
322+
- id: gitleaks
323+
# Only scan source files, not generated code
324+
exclude: '^(vendor/|node_modules/|dist/)'
325+
```
326+
327+
## Troubleshooting
328+
329+
### Hook Fails with No Output
330+
331+
Run in verbose mode:
332+
333+
```bash
334+
pre-commit run --verbose
335+
```
336+
337+
### Hook Environment Issues
338+
339+
Reinstall the hook environment:
340+
341+
```bash
342+
pre-commit clean
343+
pre-commit install-hooks
344+
```
345+
346+
### Hook Runs Too Slowly
347+
348+
Check which files are being scanned:
349+
350+
```bash
351+
pre-commit run --verbose --all-files 2>&1 | head -50
352+
```
353+
354+
Add exclusions for large generated files or vendor directories.
355+

0 commit comments

Comments
 (0)