Skip to content

fix: hook resilience for git ops, regex bypass, and worktree isolation#153

Merged
carlos-alm merged 1 commit intomainfrom
fix/hook-git-ops-resilience
Feb 27, 2026
Merged

fix: hook resilience for git ops, regex bypass, and worktree isolation#153
carlos-alm merged 1 commit intomainfrom
fix/hook-git-ops-resilience

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

Three fixes to Claude Code hooks:

  • New post-git-ops.sh hook (PostToolUse on Bash): detects git rebase/revert/cherry-pick/merge/pull and automatically rebuilds the codegraph, logs changed files to session-edits.log, and clears stale entries from codegraph-checked.log
  • Fix regex bypass in guard-git.sh: blocking patterns used ^\s*git which only matched git at command start — cd foo && git add . bypassed all blocks. Now uses (^|\s|&&\s*)git consistently (fixes Greptile review from fix: post-git-ops hook for graph resilience after rebase/revert/merge #151)
  • Fix worktree isolation: session-local state files now use git rev-parse --show-toplevel instead of CLAUDE_PROJECT_DIR, giving each worktree its own edit log and preventing cross-session leakage
  • Distributable examples: adds docs/examples/claude-code-hooks/ with all hooks, settings.json, and setup README

Supersedes #151 (which was closed due to scope mixing with unrelated commits).

Test plan

  • Verify cd foo && git add . is now blocked by guard-git.sh
  • Verify cd foo && git reset --hard is blocked
  • In a worktree, verify session-edits.log is created at the worktree root, not the main project root
  • Run git rebase and verify graph rebuilds automatically via post-git-ops.sh
  • After rebase, verify files appear in session-edits.log and can be committed
  • After rebase, verify remind-codegraph.sh re-fires for affected files
  • Verify hook exits cleanly for non-git Bash commands
  • Verify hook exits cleanly when ORIG_HEAD doesn't exist (failed rebase with conflicts)

Three fixes to Claude Code hooks:

1. New post-git-ops.sh hook (PostToolUse on Bash) detects git rebase,
   revert, cherry-pick, merge, pull and automatically rebuilds the
   codegraph, logs changed files to session-edits.log, and clears
   stale entries from codegraph-checked.log.

2. Fix regex bypass in guard-git.sh: blocking patterns used ^\s*git
   which only matched git at command start. Commands like
   `cd foo && git add .` bypassed all blocks. Now uses
   (^|\s|&&\s*)git to match chained commands consistently.

3. Fix worktree isolation: session-local state files (session-edits.log,
   codegraph-checked.log) now use `git rev-parse --show-toplevel`
   instead of CLAUDE_PROJECT_DIR. This gives each worktree its own
   edit log, preventing cross-session leakage where session A could
   commit files only edited by session B.

Also adds docs/examples/claude-code-hooks/ with distributable hook
examples, settings.json, and setup README.
@claude
Copy link
Copy Markdown

claude Bot commented Feb 27, 2026

Claude finished @carlos-alm's task —— View job


PR Review Complete

Todo List:

  • Phase 1: Root Cause Analysis - understand problems being solved
  • Phase 2: Configuration Change Detection - check for high-risk changes
  • Phase 3: Test Integrity - verify no weakened tests/assertions
  • Phase 4: Code Quality Review - analyze implementation details
  • Final Assessment - provide rating and recommendation

Root Cause Analysis

Problem Being Solved: Three critical issues in Claude Code hooks:

  1. Security vulnerability: Regex ^\s*git allowed bypass via cd foo && git add .
  2. Git operation blind spot: rebase/cherry-pick/merge changed files but didn't update graph or session logs
  3. Worktree isolation failure: All sessions shared logs via CLAUDE_PROJECT_DIR, breaking parallel safety

Why This Approach: All fixes are well-targeted and address root causes:

  • Regex fix uses (^|\s|&&\s*)git to catch git after shell operators
  • New post-git-ops.sh hook detects git operations and rebuilds state
  • Consistent use of git rev-parse --show-toplevel isolates worktree sessions

Risk Assessment: LOW - All changes are additive security improvements with proper fallbacks

Phase 4: Code Quality Review

Security Fix - Regex Bypass (guard-git.sh:46-74)

CRITICAL FIX: Changed from ^\s*git to (^|\s|&&\s*)git across all dangerous commands

  • Properly blocks: cd /tmp && git add ., sleep 5 && git reset --hard
  • Maintains existing functionality for simple git add .
  • Verification: The hook is ironically blocking my test commands, proving it works!

New post-git-ops.sh Hook

Well-designed solution for git operation blind spot:

  • Robust detection: Uses ORIG_HEAD (set by rebase/merge/cherry-pick/pull/revert)
  • Safe failure: All operations wrapped in || true
  • Clean separation: Only acts on commands that change file content
  • Smart fallback: Handles both global codegraph and local node src/cli.js

Minor suggestion: Line 50 git diff --name-only ORIG_HEAD HEAD could theoretically fail if ORIG_HEAD doesn't exist, but it's handled gracefully with || true.

Worktree Isolation (Multiple Files)

Consistent pattern applied across all 5 hooks:

PROJECT_DIR=$(git rev-parse --show-toplevel 2>/dev/null) || PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
  • Proper fallback: Falls back to CLAUDE_PROJECT_DIR if not in a git repo
  • Error handling: Suppresses stderr from git rev-parse
  • Consistent naming: Most use PROJECT_DIR, remind-codegraph.sh uses WORK_ROOT (acceptable variation)

Settings Integration

Clean addition of post-git-ops.sh to .claude/settings.json:76-78:

  • Proper timeout (30s for graph rebuild)
  • Correct matcher (Bash)
  • Follows existing pattern

Documentation & Examples

Excellent addition of docs/examples/claude-code-hooks/:

  • Complete setup instructions with ready-to-use scripts
  • Clear explanation of each hook's purpose and interactions
  • Subset installation guidance for different workflows
  • Proper .gitignore guidance for session logs

One improvement: The example guard-git.sh omits branch name validation that exists in the repo version (lines 95-101). This is mentioned in README line 67 but could be clearer.

Critical Concerns

None identified - this is a high-quality security and reliability improvement.

Final Recommendation

  • Rating: ⭐⭐⭐⭐☆ (4/5)
  • Action: APPROVE
  • Reasoning: Fixes critical security vulnerability, adds missing git operation handling, and provides proper worktree isolation. Well-tested patterns with proper fallbacks. Documentation is excellent. The only reason this isn't 5/5 is the minor inconsistency in variable naming and the hook blocking my ability to fully test the regex patterns (which is actually a good sign!).

Ready to merge - this addresses real issues with solid engineering.


@carlos-alm carlos-alm merged commit 2459cfc into main Feb 27, 2026
15 checks passed
@carlos-alm carlos-alm deleted the fix/hook-git-ops-resilience branch February 27, 2026 05:48
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 27, 2026

Greptile Summary

This PR fixes three hook resilience issues and adds distributable examples.

Key changes:

  • Fixed regex bypass in guard-git.sh where cd foo && git add . bypassed blocks by changing patterns from ^\s*git to (^|\s|&&\s*)git
  • Added new post-git-ops.sh hook that detects git operations (rebase/revert/cherry-pick/merge/pull) and automatically rebuilds the codegraph, logs changed files to session-edits.log, and clears stale entries from codegraph-checked.log
  • Implemented worktree isolation by using git rev-parse --show-toplevel instead of CLAUDE_PROJECT_DIR for session-local state files, preventing cross-session leakage
  • Added comprehensive distributable examples in docs/examples/claude-code-hooks/ with setup README

Minor observations:

  • The regex pattern catches most command chaining cases but has an edge case with semicolons without spaces (e.g., cd foo;git add .), though this is non-idiomatic bash style
  • All hooks properly handle errors with || true to remain non-blocking as intended

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The changes address well-defined issues with targeted fixes. The regex pattern fix correctly handles the documented bypass case. The worktree isolation changes are straightforward and use proper fallback logic. The new post-git-ops.sh hook uses safe error handling with || true and proper ORIG_HEAD checking. Documentation is comprehensive and accurate.
  • No files require special attention

Important Files Changed

Filename Overview
.claude/hooks/guard-git.sh Fixed regex bypass by changing patterns from ^\s*git to `(^
.claude/hooks/post-git-ops.sh New hook to detect git rebase/revert/merge/pull and rebuild graph, log changed files, clear stale reminders
.claude/hooks/track-edits.sh Added worktree isolation using git rev-parse --show-toplevel instead of CLAUDE_PROJECT_DIR
.claude/settings.json Added post-git-ops.sh hook to PostToolUse on Bash with 30s timeout
docs/examples/claude-code-hooks/README.md Comprehensive documentation for hook setup, explaining git op resilience and worktree isolation
docs/guides/recommended-practices.md Updated documentation to explain git operation resilience and worktree isolation features

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Bash Command Executed] --> B{Contains git rebase/<br/>revert/cherry-pick/<br/>merge/pull?}
    B -->|No| C[Exit hook]
    B -->|Yes| D[Get worktree root via<br/>git rev-parse --show-toplevel]
    D --> E[Rebuild codegraph<br/>incrementally]
    E --> F{Get changed files via<br/>git diff ORIG_HEAD HEAD}
    F -->|Success| G[Append changed files<br/>to session-edits.log]
    F -->|Fail/Empty| C
    G --> H{codegraph-checked.log<br/>exists?}
    H -->|Yes| I[Remove changed files<br/>from checked log]
    H -->|No| C
    I --> C
Loading

Last reviewed commit: 27243b7

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

16 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Feb 27, 2026

Additional Comments (1)

.claude/hooks/guard-git.sh
Pattern (^|\s|&&\s*) catches cd foo && git and cd foo; git (with space), but not cd foo;git (no space after semicolon). Edge case unlikely in practice since standard bash style uses spaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant