Automating Code Checks with Git Pre-commit Hooks
Learn how Git pre-commit hooks work, how to share hooks across team repositories, and format/lint code automatically before committing.
Imagine writing great code, running git commit, and pushing directly to your remote repository—only for CI/CD to break minutes later due to a missing comma or linting error.
This happens all too often. How can we catch these minor issues locally before they enter the Git commit history? The solution is Git Pre-commit Hooks.
Introduction to Git Pre-commit Hooks#
Git Hooks are built-in scripts that run automatically at key points in the Git workflow (such as before committing, before pushing, or after checking out branches).
The pre-commit hook runs immediately when you execute git commit, right before Git creates the commit object. If the script exits with a non-zero status (!= 0), the commit process is aborted immediately.
graph LR
A[git commit command] --> B{Pre-commit Hook}
B -->|Exit code = 0| C[Commit Created]
B -->|Exit code != 0| D[Abort Commit & Report Error]
The Sharing Problem & core.hooksPath#
By default, Git hooks live inside the hidden .git/hooks/ directory. However, .git is not version-controlled. This introduces two major drawbacks:
- Hard to share across teams: Every developer has to copy hook scripts into
.git/hooks/manually. - Easy to forget: New team members joining the project often forget to set up the local hooks.
The core.hooksPath Solution#
Since Git 2.9, Git supports the core.hooksPath configuration, allowing you to point hook execution to any directory.
You can store hooks in a version-controlled folder (e.g., .githooks/) and configure Git:
git config core.hooksPath .githooksbashIn a Node.js/Bun project, automate this setup for team members using the prepare script in package.json:
{
"scripts": {
"prepare": "git config core.hooksPath .githooks"
}
}jsonWhenever anyone runs npm install or bun install, Git automatically configures .githooks for the repository.
Practical Example: Auto-formatting Markdown with agent-md#
Here is a real-world pre-commit hook script that checks if agent-md CLI is available, formats staged Markdown files, and re-stages them automatically:
#!/usr/bin/env bash
# 1. Check if agent-md CLI exists on system
if command -v agent-md >/dev/null 2>&1; then
# 2. Extract staged markdown files (excluding deleted ones)
STAGED_MD_FILES=$(git diff --cached --name-only --diff-filter=d | grep -E '\.(md|mdx)$')
if [ -n "$STAGED_MD_FILES" ]; then
echo "[git-hook] Formatting staged Markdown files with agent-md..."
for file in $STAGED_MD_FILES; do
if [ -f "$file" ]; then
agent-md "$file"
git add "$file"
fi
done
fi
fibashRemember to grant execution permissions to your hook script:
chmod +x .githooks/pre-commitbashBypassing Pre-commit Hooks#
In urgent cases (such as saving a temporary work-in-progress commit before switching branches), you can bypass the hook using --no-verify (or -n):
git commit -m "WIP: temporary save" --no-verifybash[!TIP] Use
--no-verifysparingly to maintain consistent code quality across your repository.