
Git Hooks: Tự động hóa kiểm tra code trước khi commit

Git hooks là script tự chạy ở các sự kiện cụ thể trong vòng đời Git. pre-commit và pre-push hooks giúp tự động kiểm tra code chất lượng trước khi commit hoặc push — loại bỏ sai sót human tại điểm nghiêm trọng nhất.
Git hooks hoạt động thế nào?
Mỗi hook là script đặt trong .git/hooks/. Git gọi hook ở sự kiện tương ứng. Hook trả về exit code 0 = cho phép, khác 0 = chặn:
- pre-commit: Chạy trước khi tạo commit — kiểm tra syntax, lint, test nhanh
- prepare-commit-msg: Sửa message commit tự động trước khi editor mở
- pre-push: Chạy trước khi push — kiểm tra branch, test toàn bộ
- post-commit: Chạy sau commit thành công — thông báo, sync
- post-merge: Chạy sau khi merge/clone — cài đặt dependencies

pre-commit hook thực hành
Hook phổ biết nhất là pre-commit. Ví dụ chạy lint và kiểm tra syntax trước khi cho phép commit:
#!/bin/bash
# .git/hooks/pre-commit
echo "🔍 Running pre-commit checks..."
# Lint staged files
STAGED=$(git diff --cached --name-only --diff-filter=ACM | grep '.py$')
for file in $STAGED; do
if [ -f "$file" ]; then
echo "Linting $file..."
ruff check "$file" || exit 1
fi
done
# Run fast tests
echo "Running tests..."
pytest tests/ -q --tb=short || exit 1
echo "✅ All checks passed!"
Hook này kiểm tra cú pháp Ruff (thay vì flake8 — nhanh hơn 5×) và chạy test. Nếu bất kỳ bước nào thất bại, commit bị chặn.
Quản lý hooks với pre-commit framework
Viết hook thủ công trong .git/hooks/ KHÔNG version-control được. Framework pre-commit giải quyết vấn đề này:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-merge-conflict
- id: check-xml
- id: check-yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.7
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/psf/black
rev: 24.3.0
hooks:
- id: black
Cài đặt:
pip install pre-commit
pre-commit install # kích hoạt hook trong repo
Mỗi lần commit, framework tự chạy toàn bộ hooks đã cấu hình. File hook chỉ cần cài 1 lần cho cả team.
Các trường hợp sử dụng thực tế
| Case | Hook | Tool | Mục đích |
|---|---|---|---|
| Format code | pre-commit | black, ruff | Đảm bảo style nhất quán |
| Phát hiện secret | pre-commit | detect-secrets | Chặn API key trong commit |
| Run test | pre-commit | pytest | Chặn commit nếu test fail |
| Update README | pre-commit | markdownlint | Kiểm tra docs syntax |
| Validate JSON | pre-commit | check-json | Chặn JSON lỗi |
| Bản đồ | pre-push | custom script | Kiểm tra branch tên trước push |

Nhóm kỹ thuật tại pre-commit duy trì 400+ hooks cho mọi ngôn ngữ. Cài đặt một hook mới chỉ cần thêm 5 dòng vào .pre-commit-config.yaml.
Tránh pitfall phổ biến
- Không chạy test chậm trong pre-commit: Test unit (60s) nên để ở CI.
- Bỏ qua non-staged files: Hook chỉ nên check
git diff --cached— files đã stage, không phải toàn repo. - Bypass emergency:
git commit --no-verifyvẫn dùng được khi cần. Đừng tạo hook không thể bỏ qua. - Version pin: Luôn pin
revtrong pre-commit config — tránh hook behavior thay đổi đột ngột.
Pre-push hook: Kiểm tra branch naming
Pre-push hook chạy sau khi user gõ git push nhưng trước khi data rời khỏi local. Ví dụ: enforce branch naming convention:
#!/bin/bash
# .git/hooks/pre-push
while read local_ref local_sha remote_ref remote_sha; do
branch=""
if [[ ! "" =~ ^(feature|fix|hotfix|release)/[a-z0-9-]+$ ]]; then
echo "❌ Branch name "" không đúng quy ước."
echo " Đúng: feature/ticket-id-description"
echo " Ví dụ: feature/JIRA-123-add-login"
exit 1
fi
done
exit 0
Hook này đảm bảo tất cả branches tuân theo quy ước: feature/, fix/, hotfix/, release/ + ticket ID + mô tả. Team 20 người sẽ không bao giờ có branch tên test hay updated.
Post-commit hook: Auto-generate changelog
Post-commit hook chạy sau mỗi commit thành công. Ví dụ tự động append commit vào changelog:
#!/bin/bash
# .git/hooks/post-commit
COMMIT_MSG=
COMMIT_HASH=
DATE="2026-09-12"
echo "- [] ()" >> CHANGELOG.md
echo "✅ Changelog updated"
Mỗi commit tự động ghi vào CHANGELOG.md — không cần chạy conventional commits tooling riêng.
Tích hợp với CI/CD
Git hooks bổ sung cho CI chứ không thay thế CI. Hooks kiểm tra nhanh ở local (lint, syntax); CI kiểm tra toàn diện (test suite, security scan, integration test). Pipeline tối ưu:
- Pre-commit: Ruff lint (2s), format check (1s) — local only
- Pre-push: Unit tests (10s), branch name check (0s) — local only
- CI pipeline: Integration tests (2min), security scan (5min), build (3min) — CI only
Khi developer push code đã qua hooks, CI pipeline nhanh hơn vì code đã sạch. Tránh tình huống CI fail vì lỗi lint mà pre-commit đã catch.
Kết luận
Git hooks là “bức tường cuối cùng” trước khi code xấu vào repo. pre-commit framework giúp quản lý tập trung, version control, và triển khai team-wide. Khi setup đúng, developer chỉ cần viết code — chất lượng tự động được đảm bảo ở từng commit. Cài đặt pre-commit install mất 30 giây nhưng ngăn hàng giờ debug sau này.

