Summary
Split out from #2386 while fixing that issue's branch-validation bug — a related but distinct gap in the same file.
guard-git.sh's commit-validation section (the block starting if echo "$NCOMMAND" | grep -qE '...git[[:space:]]+commit') resolves its target directory via WORK_DIR=$(detect_work_dir commit), then falls back to the hook's own ambient cwd when WORK_DIR is empty:
else
PROJECT_DIR=$(git rev-parse --show-toplevel 2>/dev/null) || PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
STAGED_FILES=$(git diff --cached --name-only 2>/dev/null) || true
...
This is the same root cause #2386 fixed for validate_branch_name: a bare git commit <files> -m "msg" relying on the Bash tool's persistent cwd from an earlier, separate tool call (rather than an explicit git -C <dir> commit or cd <dir> && git commit) leaves WORK_DIR empty, and the fallback resolves against the wrong repo.
Why this is lower severity than #2386 (and worth a separate issue)
Unlike the branch-validation case, this doesn't currently produce a false deny: if the wrong repo's git diff --cached --name-only comes back empty (likely, since nothing is staged in the unrelated repo), the check hits its existing if [ -z "$STAGED_FILES" ]; then exit 0 early-out and silently allows. So the observable symptom today is "the edit-log check gets silently skipped" rather than "a valid commit gets wrongly blocked" — milder, but still means the edit-log protection this check exists to provide (catching another session's files sneaking into your commit) doesn't actually run when it should.
Suggested fix
Apply the same $HOOK_CWD fallback #2386 introduces for validate_branch_name to this section too — guard-git.sh already extracts HOOK_CWD from the hook's top-level cwd JSON field as of that fix; reuse it here:
WORK_DIR=$(detect_work_dir commit)
if [ -z "$WORK_DIR" ] && [ -n "$HOOK_CWD" ] && [ -d "$HOOK_CWD" ]; then
WORK_DIR="$HOOK_CWD"
fi
Remember to keep .claude/hooks/guard-git.sh and docs/examples/claude-code-hooks/guard-git.sh byte-identical (enforced by tests/unit/hook-guard-git-clean.test.ts).
Related
Summary
Split out from #2386 while fixing that issue's branch-validation bug — a related but distinct gap in the same file.
guard-git.sh's commit-validation section (the block startingif echo "$NCOMMAND" | grep -qE '...git[[:space:]]+commit') resolves its target directory viaWORK_DIR=$(detect_work_dir commit), then falls back to the hook's own ambient cwd whenWORK_DIRis empty:This is the same root cause #2386 fixed for
validate_branch_name: a baregit commit <files> -m "msg"relying on the Bash tool's persistent cwd from an earlier, separate tool call (rather than an explicitgit -C <dir> commitorcd <dir> && git commit) leavesWORK_DIRempty, and the fallback resolves against the wrong repo.Why this is lower severity than #2386 (and worth a separate issue)
Unlike the branch-validation case, this doesn't currently produce a false deny: if the wrong repo's
git diff --cached --name-onlycomes back empty (likely, since nothing is staged in the unrelated repo), the check hits its existingif [ -z "$STAGED_FILES" ]; then exit 0early-out and silently allows. So the observable symptom today is "the edit-log check gets silently skipped" rather than "a valid commit gets wrongly blocked" — milder, but still means the edit-log protection this check exists to provide (catching another session's files sneaking into your commit) doesn't actually run when it should.Suggested fix
Apply the same
$HOOK_CWDfallback #2386 introduces forvalidate_branch_nameto this section too —guard-git.shalready extractsHOOK_CWDfrom the hook's top-levelcwdJSON field as of that fix; reuse it here:Remember to keep
.claude/hooks/guard-git.shanddocs/examples/claude-code-hooks/guard-git.shbyte-identical (enforced bytests/unit/hook-guard-git-clean.test.ts).Related
$HOOK_CWD