Claude Code is powerful, but that means it can also git push --force or git reset --hard before you realize what happened. This hook intercepts dangerous git commands and blocks them with an error message, so Claude has to ask you first.
Adapted from Matt Pocock's git guardrails skill.
What gets blocked
git push(all variants including--force)git reset --hardgit clean -f/git clean -fdgit branch -Dgit checkout ./git restore .
Setup
1. Create the hook script
Save this as .claude/hooks/block-dangerous-git.sh in your project (or ~/.claude/hooks/ for global):
#!/usr/bin/env bash
# Read the tool input from stdin (Claude Code passes JSON)
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')
# If no command, allow
if [ -z "$command" ]; then
exit 0
fi
# Patterns to block
dangerous_patterns=(
"git push"
"git reset --hard"
"git clean -f"
"git clean -fd"
"git branch -D"
"git checkout \."
"git restore \."
)
for pattern in "${dangerous_patterns[@]}"; do
if echo "$command" | grep -qE "$pattern"; then
echo "BLOCKED: '$command' is a destructive git operation. Ask the user for explicit permission before running this command." >&2
exit 2
fi
done
exit 0
Make it executable:
chmod +x .claude/hooks/block-dangerous-git.sh
2. Add the hook to settings
Add to .claude/settings.json (project-level) or ~/.claude/settings.json (global):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous-git.sh"
}
]
}
]
}
}
3. Test it
echo '{"tool_input":{"command":"git push origin main"}}' | .claude/hooks/block-dangerous-git.sh
Should print BLOCKED: ... and exit with code 2.
Customization
Add more patterns — append to the dangerous_patterns array. Consider blocking rm -rf, DROP TABLE, or whatever else makes you nervous.
Allow specific pushes — if you want to allow git push to a specific branch, modify the grep pattern to be more specific (e.g., block git push --force but allow git push origin feature-branch).
Project vs global — project-level hooks only apply when Claude Code is running in that project. Global hooks apply everywhere. Start with project-level, promote to global once you trust the config.