Git Guardrails for Claude Code

Skill

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 --hard
  • git clean -f / git clean -fd
  • git branch -D
  • git 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.