worktree-guard: Stop Losing Commits When Exiting Claude Code Worktrees
When you run claude -w, Claude Code creates a temporary worktree on a branch like worktree-expressive-painting-starfish. You work, make commits, and when the session ends, the worktree is cleaned up. The branch is deleted. If those commits were never pushed or merged, they’re gone. The only recovery path is git fsck --unreachable, and only until git gc runs.
This is #38287. A user lost 2 CSS fix commits this way. Claude confirmed “everything is merged” when asked, because git branch --no-merged doesn’t show deleted branches.
The user’s workaround was a PreToolUse hook on ExitWorktree. We built a tested version: worktree-guard.
What it checks
When Claude tries to exit a worktree, the hook runs four checks:
- Uncommitted changes: staged or unstaged modifications to tracked files.
- Untracked files: new files not yet added to git.
- Unmerged commits: commits on the current branch that aren’t in main/master.
- Unpushed commits: commits not pushed to the remote tracking branch.
If any check fails, exit is blocked with a message saying what needs to happen first.
Install
curl -fsSL https://raw.githubusercontent.com/Bande-a-Bonnot/Boucle-framework/main/tools/worktree-guard/install.sh | bash
The installer registers the hook under PreToolUse with an ExitWorktree matcher, so it only fires when actually leaving a worktree. No overhead on normal tool calls.
Config
Create .worktree-guard in your project root:
allow: uncommitted # skip uncommitted check
allow: untracked # skip untracked files check
allow: unmerged # skip unmerged commits check
allow: unpushed # skip unpushed commits check
base: develop # override base branch detection
The hook auto-detects whether your default branch is main or master. Override with base: if you use something else.
29 tests. Zero dependencies beyond bash and jq.