Git Hooks vs CI Checks for Enforcing Code Quality
Quick answer
Quick answer: Git hooks run on a developer's machine and give fast feedback, but they can be skipped and are not shared automatically. CI checks run on a...
Quick answer: Git hooks run on a developer's machine and give fast feedback, but they can be skipped and are not shared automatically. CI checks run on a server, cannot be bypassed when paired with branch protection, and are the authoritative gate. Use hooks for quick checks like formatting and linting staged files, and CI for the full test suite and policy enforcement.
What Can Git Hooks Do and Not Do?
Hooks are scripts that Git runs at specific points, such as before a commit, when editing a commit message, or before a push. A pre-commit hook can format files, run a linter on staged changes, or scan for accidentally committed secrets. A commit-msg hook can validate the message format. Because they run locally, feedback arrives in seconds, before the problem leaves the developer's machine.
Their weakness is that they are voluntary. A developer can skip hooks with a command-line flag, and a fresh clone has no hooks installed, since the default hooks directory inside the repository metadata is not version controlled. Anyone using a GUI client, a different machine, or a new setup may be running without them. A hook is a convenience, not a guarantee.
You can make hooks shareable by storing them in a tracked directory and pointing Git at it with the hooks path setting. Many projects use a hook manager or a setup script run during onboarding. Even then, nothing forces use, so treat hooks as a helper that reduces CI failures.
git config core.hooksPath .githooks
# .githooks/pre-commit
#!/bin/sh
set -e
make lint-staged
Why Is CI the Authoritative Gate?
CI runs in a controlled environment on every push or pull request, regardless of what any developer's machine does. Combined with branch protection rules that require passing status checks and reviews before merging, it becomes impossible to land code that fails the checks without an explicit administrative override. That is the property you need for policy: tests passing, security scans clean, builds reproducible.
CI can also do work that is impractical locally. It can run the full test suite across multiple versions and platforms, build artifacts in a clean environment, run slower static analysis and dependency audits, and use secrets or services developers should not have on laptops. It provides a consistent environment, which avoids the classic problem of code that works only on one machine.
The trade-off is speed. CI feedback arrives minutes after a push, and a failed run costs a context switch. That delay is what hooks are for: catching cheap, common problems before they reach the pipeline.
How Should You Combine Them?
Split checks by cost and by importance. Run fast, deterministic checks in hooks and everything in CI:
- Hooks: code formatting, linting of staged files, commit message format, and simple secret detection.
- Pre-push hooks: a quick subset of unit tests, if it stays fast enough that nobody wants to skip it.
- CI: the full test suite, type checking, integration tests, builds, security scans, and license checks.
Keep hooks fast, ideally a few seconds. A slow hook trains people to bypass it. Operate on staged files rather than the whole repository, and avoid hooks that silently rewrite code in surprising ways unless the behavior is well understood, since unexpected modifications confuse developers.
Use the same commands in both places. If the hook runs a formatter check and CI runs the same command, a pass locally predicts a pass in the pipeline. Defining the checks in one script or task runner that both call prevents the two from drifting apart.
Frequently Asked Questions
Can developers bypass Git hooks?
Yes. Git offers an option to skip pre-commit and commit-msg hooks, and hooks are absent on fresh clones until installed. Never rely on hooks alone for enforcement.
Are hooks stored in the repository?
Not by default. The standard hooks directory is not tracked. Store scripts in a tracked folder and configure the hooks path, or use an installer step.
Should CI duplicate the hook checks?
Yes. CI should run every check hooks run, plus more, because hooks may be skipped. That duplication is intentional and provides the guarantee.
What is the best hook for formatting?
A pre-commit hook that checks or formats staged files only. It keeps the repository consistent and reduces noisy review comments about style.
Summary
Hooks give fast, local feedback but cannot enforce policy, while CI with branch protection is the real gate. Keep hooks quick and focused, run the full set of checks in CI, and share definitions so both stay consistent. Check the Git documentation for hook types and configuration in your version.