Free

Git-Workflows mit Hooks verwalten: Claude auch zur Regeleinhaltung bringen

Mit PreToolUse Hooks git-Befehle in Bash abfangen — direkte Commits nach main, falsche Nachrichtenformate und gefährliche Operationen blockieren.


Claude Code hat die Berechtigung, git commit, git push und git checkout direkt auszuführen. Das ist meistens praktisch, kann aber dazu führen, dass direkt auf main committed, beliebige Commit-Messages geschrieben oder unerwünschte Force-Pushes durchgeführt werden. Hooks greifen vor diesen Operationen ein.


Regel 1: Direkte Commits auf main blockieren

#!/bin/bash
input=$(cat); cmd=$(echo "$input" | jq -r '.tool_input.command')
echo "$cmd" | grep -qE '^git (commit|push)' || exit 0
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if [[ "$current_branch" == "main" || "$current_branch" == "master" ]]; then
  echo "Direkte Commits auf $current_branch sind nicht erlaubt. Wechseln Sie zuerst zu einem Feature-Branch." >&2; exit 2
fi

Regel 2: Commit-Message-Format erzwingen

#!/bin/bash
input=$(cat); cmd=$(echo "$input" | jq -r '.tool_input.command')
echo "$cmd" | grep -qE '^git commit' || exit 0
msg=$(echo "$cmd" | grep -oP '(?<=-m )["\x27].*?["\x27]' | tr -d '"'"'" || true)
[[ -z "$msg" ]] && exit 0
if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{3,}'; then
  echo "Commit-Message-Format ist falsch. Format: <type>(<scope>): <description>" >&2; exit 2
fi

Regel 3: Gefährliche Operationen blockieren

#!/bin/bash
input=$(cat); cmd=$(echo "$input" | jq -r '.tool_input.command')
if echo "$cmd" | grep -qE 'git push.*--force|git reset --hard|git push.*--delete'; then
  if ! echo "$cmd" | grep -q '# ALLOW:'; then
    echo "Gefährliche Operation blockiert. Fügen Sie # ALLOW: <Grund> hinzu, um fortzufahren." >&2; exit 2
  fi
fi

Vollständige Konfiguration

.claude/hooks/git-guard.sh:

#!/bin/bash
set -e
input=$(cat); cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
[[ -z "$cmd" ]] && exit 0
echo "$cmd" | grep -q '^git' || exit 0
current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")

if echo "$cmd" | grep -qE '^git (commit|push)'; then
  if [[ "$current_branch" == "main" || "$current_branch" == "master" ]]; then
    echo "Auf $current_branch — direkte Commits und Pushes blockiert. Wechseln Sie zum Feature-Branch." >&2; exit 2
  fi
fi

if echo "$cmd" | grep -qE '^git commit.*-m'; then
  msg=$(echo "$cmd" | grep -oP '(?<=-m )["\x27][^\x27"]*["\x27]' | tr -d '"'"'" || true)
  if [[ -n "$msg" ]] && ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{3,}'; then
    echo "Falsches Format. Format: <type>(<scope>): <description>" >&2; exit 2
  fi
fi

if echo "$cmd" | grep -qE 'git push.*--force|git reset --hard|git push.*--delete'; then
  if ! echo "$cmd" | grep -q '# ALLOW:'; then
    echo "Gefährliche Operation blockiert. Fügen Sie # ALLOW: <Grund> hinzu." >&2; exit 2
  fi
fi

Zusammenfassung

PreToolUse + Bash-Matcher + git-Befehlserkennung. Drei wichtigste Regeln: Commits auf main blockieren, Message-Format validieren, Force Push und Reset --hard abfangen.