Concepts
Git Hooks Deep Dive
Understand Git Hooks types, lifecycle, sharing mechanisms, and CI/CD integration practices.
- Readers who want the history model before advanced commands
- A basic sense that commits are not just a file list
- Treating a concepts page like a command how-to
Citations & Further Reading
- Githooks [Official]
- Customizing Git Git Hooks [Book]
What you will learn
- Understand the core purpose of Git Hooks Deep Dive
- Master the basic usage and common options of Git Hooks Deep Dive
- Understand Git Hooks types, lifecycle, sharing mechanisms, and CI/CD integration practices.
- Understand key concepts: Overview
- Know when to use this feature and when to avoid it
Start with a problem
You've encountered a conceptual question while using Git — you roughly know what it means, but you're not entirely sure about its precise definition and boundaries.
Overview
Git Hooks are custom scripts triggered at key points during Git operations. They're not built-in Git features but leverage Git's event notification mechanism to run external programs.
Hook Lifecycle
flowchart LR
subgraph Local
A[pre-commit] --> B[prepare-commit-msg]
B --> C[commit-msg]
C --> D[post-commit]
end
subgraph Push
D --> E[pre-push]
end
subgraph Remote
E --> F[pre-receive]
F --> G[update]
G --> H[post-receive]
end
Core Hooks
Client-Side Hooks
| Hook | Trigger | Return Value Effect |
|---|---|---|
pre-commit | Before git commit | Non-zero aborts commit |
prepare-commit-msg | Before editor opens | Can modify default message |
commit-msg | After message is saved | Non-zero aborts commit |
post-commit | After commit completes | Return ignored |
pre-push | Before git push | Non-zero aborts push |
pre-rebase | Before git rebase | Non-zero aborts rebase |
post-checkout | After git checkout | Return ignored |
post-merge | After git merge | Return ignored |
Server-Side Hooks
| Hook | Trigger | Description |
|---|---|---|
pre-receive | Before receiving ref updates | Can reject pushes |
update | Before each ref update | Per-branch control |
post-receive | After ref updates complete | Trigger CI, notifications |
Practical Hook Examples
pre-commit: Code Quality
#!/bin/bash
# .git/hooks/pre-commit
echo "Running linter..."
npm run lint
if [ $? -ne 0 ]; then
echo "Lint failed. Commit aborted."
exit 1
fi
commit-msg: Message Convention
#!/bin/bash
# .git/hooks/commit-msg
PATTERN="^(feat|fix|docs|style|refactor|test|chore|ci)(\(.+\))?: .{1,72}"
msg=$(cat "$1")
if ! [[ "$msg" =~ $PATTERN ]]; then
echo "Error: commit message must match Conventional Commits format"
echo " e.g. feat(api): add login endpoint"
exit 1
fi
pre-push: Protected Branch Check
#!/bin/bash
# .git/hooks/pre-push
protected_branches="main master develop"
while read local_ref local_sha remote_ref remote_sha; do
for branch in $protected_branches; do
if [[ "$remote_ref" == "refs/heads/$branch" ]]; then
echo "Error: pushing to $branch is not allowed via hook"
exit 1
fi
done
done
exit 0
Sharing Hooks
Method 1: In-Repository (Recommended)
# Project structure
my-repo/
├── .githooks/
│ ├── pre-commit
│ └── commit-msg
└── .gitignore
# Configure custom hooks directory
git config core.hooksPath .githooks
Method 2: Global Hooks
# Create global hooks directory
mkdir -p ~/.git-hooks
git config --global core.hooksPath ~/.git-hooks
Method 3: husky (Node.js Projects)
npx husky init
# .husky/pre-commit
npx lint-staged
CI Integration
# GitHub Actions
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- name: Check commit messages
run: |
git log --format=%s -1 | grep -E '^(feat|fix|docs)'
Security Notes
- Server-side hooks first: Client hooks can be bypassed (
git commit --no-verify) - Don't rely on client hooks for security: Server-side
pre-receiveis the real defense - Hook script permissions: Ensure hooks have execute permission (
chmod +x) - Performance impact: Complex hooks can significantly slow Git operations
Try it yourself
- Practice the git-hooks-deep command in a test repository and observe state changes before and after
- Experiment with different options and compare the output differences
- Simulate a real scenario where you would need to use this, and walk through the full process
Continue Learning
concepts/git-hooks— Git Hooks basicsworkflows/pre-commit-hook-workflow— Pre-commit hook workflowconcepts/git-lfs-deep— Git LFS deep dive
Further reading
Keep going on the same topic: