Git hooks are scripts Git runs at points in its workflow, such as pre-commit before a commit and pre-receive before a push is accepted. Client hooks speed up the inner loop; server hooks enforce policy that a developer cannot skip with --no-verify.
Before you start
You should be comfortable with commits and the .git directory. This article covers hook categories and sharing them; it assumes basic shell scripting.
Step-by-step walkthrough
Step 1: Know which hook runs where
Client hooks (pre-commit, commit-msg, pre-push) run on the developer’s machine and are not versioned in the repository by default. Server hooks (pre-receive, update) run on the remote and cannot be bypassed, which is why CI checks and server hooks are the enforcement layer.
Step 2: Share client hooks with a framework
Because .git/hooks is not committed, teams use a tool such as Husky or lefthook that installs hooks on npm install and versions the configuration. Keep hooks fast — lint staged files, not the whole project — so commits stay quick.
Step 3: Enforce the important rules remotely
Anything that must be guaranteed belongs in CI or a server hook: running tests, checking commit message format, or scanning for secrets. Client hooks are a convenience; they can be skipped or missing on a fresh clone.
Worked scenario
A pre-commit hook lints only the staged files and blocks the commit on failure.
#!/bin/sh
# .git/hooks/pre-commit
npx lint-staged || exit 1Walk through the example
Git runs the script before creating the commit, passing no arguments. lint-staged reads the staged file list and lints just those files, so the check is fast. A non-zero exit stops the commit, so a lint failure cannot be committed unless the developer fixes it or overrides with --no-verify, which is exactly why CI must run the same check.
Common mistake
Relying on client hooks as the only quality gate, since --no-verify bypasses them and a fresh clone has none until the framework installs them. Another is running the full test suite in pre-commit, which makes commits slow enough that people disable hooks.
Verify the behavior
Stage a file with a lint error and confirm the commit is blocked, then confirm git commit --no-verify skips it. Clone the repo fresh, run install, and check the hooks are present. Confirm the same check runs in CI and fails the pipeline when the local hook was bypassed.
Interview exercise
Should a secret scan live in a client hook or in CI?
Answer and reasoning
Both, with CI as the source of truth. A client pre-commit scan gives fast feedback and stops most mistakes before they leave the machine, but it can be bypassed or absent. The CI scan is the guarantee, running on every push where it cannot be skipped, so a leaked secret is caught before it reaches the main branch.
Continue learning
Compare release automation in CI required checks and signal handling in Git secret management. Read the Git hooks documentation and try the Git interview questions.