Skip to content

Commit c9426fa

Browse files
fix: guard-git hook validates branch name on gh pr create
The branch name validation only triggered on `git push` and used a pattern that missed commands prefixed with `cd "..." &&` (common in worktree sessions). Now validates on both `git push` and `gh pr create`, and handles the cd prefix pattern for all checks.
1 parent 937b60f commit c9426fa

1 file changed

Lines changed: 33 additions & 7 deletions

File tree

.claude/hooks/guard-git.sh

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ if [ -z "$COMMAND" ]; then
2121
exit 0
2222
fi
2323

24-
# Only act on git commands
25-
if ! echo "$COMMAND" | grep -qE '^\s*git\s+'; then
24+
# Act on git and gh commands (may appear after cd "..." &&)
25+
if ! echo "$COMMAND" | grep -qE '(^|\s|&&\s*)(git|gh)\s+'; then
2626
exit 0
2727
fi
2828

@@ -74,21 +74,47 @@ if echo "$COMMAND" | grep -qE '^\s*git\s+stash'; then
7474
deny "BLOCKED: 'git stash' hides all working tree changes including other sessions' work. In worktree mode, commit your changes directly instead."
7575
fi
7676

77-
# --- Branch name validation on push ---
77+
# --- Branch name validation helper ---
78+
79+
validate_branch_name() {
80+
# Try to get branch from the working directory where the command runs
81+
# Extract cd target if command starts with cd "..." && ...
82+
local work_dir=""
83+
if echo "$COMMAND" | grep -qE '^\s*cd\s+'; then
84+
work_dir=$(echo "$COMMAND" | sed -nE 's/^\s*cd\s+"?([^"&]+)"?\s*&&.*/\1/p')
85+
fi
86+
87+
local BRANCH=""
88+
if [ -n "$work_dir" ] && [ -d "$work_dir" ]; then
89+
BRANCH=$(git -C "$work_dir" rev-parse --abbrev-ref HEAD 2>/dev/null) || true
90+
fi
91+
if [ -z "$BRANCH" ]; then
92+
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || true
93+
fi
7894

79-
if echo "$COMMAND" | grep -qE '^\s*git\s+push'; then
80-
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) || true
8195
if [ -n "$BRANCH" ] && [ "$BRANCH" != "main" ] && [ "$BRANCH" != "HEAD" ]; then
82-
PATTERN="^(feat|fix|docs|refactor|test|chore|ci|perf|build|release|dependabot|revert)/"
96+
local PATTERN="^(feat|fix|docs|refactor|test|chore|ci|perf|build|release|dependabot|revert)/"
8397
if [[ ! "$BRANCH" =~ $PATTERN ]]; then
8498
deny "BLOCKED: Branch '$BRANCH' does not match required pattern. Branch names must start with: feat/, fix/, docs/, refactor/, test/, chore/, ci/, perf/, build/, release/, revert/"
8599
fi
86100
fi
101+
}
102+
103+
# --- Branch name validation on push ---
104+
105+
if echo "$COMMAND" | grep -qE '(^|\s|&&\s*)git\s+push'; then
106+
validate_branch_name
107+
fi
108+
109+
# --- Branch name validation on gh pr create ---
110+
111+
if echo "$COMMAND" | grep -qE '(^|\s|&&\s*)gh\s+pr\s+create'; then
112+
validate_branch_name
87113
fi
88114

89115
# --- Commit validation against edit log ---
90116

91-
if echo "$COMMAND" | grep -qE '^\s*git\s+commit'; then
117+
if echo "$COMMAND" | grep -qE '(^|\s|&&\s*)git\s+commit'; then
92118
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
93119
LOG_FILE="$PROJECT_DIR/.claude/session-edits.log"
94120

0 commit comments

Comments
 (0)