anthropics / anthropics/claude-code
[BUG] Critical: git stash pop + reset --hard destroyed ~600 lines of new code and unrelated stash in worktree session
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
### What's Wrong?
## What happened
- Session A (N4-4328) had uncommitted work: review.mjs (~260 lines), review.spec.mjs (~308 lines), edits to 4 files
- Session B (N4-3927) had an uncommitted stash with ~86 files under packages/workspace/src/
- Both sessions shared the same git repository (monorepo)
- In Session A, bare `git stash pop` was issued twice, followed by `git reset --hard HEAD`
- Result: Session A's N4-4328 work was destroyed, and Session B's N4-3927 stash was also destroyed
## Impact
- Primary loss: ~570 lines of new code (review.mjs, review.spec.mjs) + modifications to validate-key.mjs, validate-key.spec.mjs, key-vocabulary.json, package.json
- Secondary loss: ~86 uncommitted files under packages/workspace/src/ belonging to N4-3927 branch
- Recovery: 1161 unreachable commits exist in object database but are unrecoverable without manual hash identification
- Cost: Significant token spend to faithfully re-implement from documented spec
## Root causes
1. Bare `git stash pop` issued despite environment forbidding it — enforcement message came too late (post-pop)
2. `git reset --hard HEAD` was not blocked or confirmed when uncommitted changes were present
3. No cross-session stash isolation — one session's mistakes destroyed another session's work
4. Reflog was reset, eliminating recovery trail
## Environment
- Tool: Claude Code CLI
- Session type: git worktree
- Isolation: enabled (--worktree-path set)
- Monorepo: shared git database across multiple concurrent worktrees/sessions
### What Should Happen?
1. **Block bare `git stash pop` in worktree sessions before execution** — not after it fails with a warning. Environment currently forbids it but enforcement arrives too late to prevent the pop.
2. **Require explicit confirmation for `git reset --hard` when uncommitted changes exist**, with a warning about stash stack safety and cross-session risks.
3. **Tag stash entries by session ID** so one session's stash pop cannot silently destroy another session's uncommitted work.
4. **Preserve reflog even after reset** so `git reflog` can show what was discarded.
### Error Messages/Logs
```shell
```
### Steps to Reproduce
1. Start a Claude Code session in a git worktree with uncommitted changes
2. Issue `git stash push -u -m "my-work"` to stash changes from another session
3. Push a second stash: `git stash push -u -m "other-session-work"` (simulates concurrent session)
4. Issue bare `git stash pop` (without flags) — this pops the most recent stash
5. If unaware of stash depth, issue `git stash pop` again without verifying the first pop succeeded
6. Run `git reset --hard HEAD` to discard any remaining working-tree changes
7. Run `git stash list` — observe: both stashes and all uncommitted work are gone
8. Run `git fsck --unreachable` — observe: orphaned commits still exist in object database
### Claude Model
Sonnet (default)
### Is this a regression?
Yes, this worked in a previous version
### Last Working Version
_No response_
### Claude Code Version
2.1.276 (Claude Code)
### Platform
Anthropic API
### Operating System
macOS
### Terminal/Shell
VS Code integrated terminal
### Additional Information
_No response_
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the Claude Code CLI handling of git worktree sessions and the command paths for bare git stash pop and git reset --hard. Reproduce the two-session sequence in the issue, then trace when warnings or confirmations are applied. Done should prevent the reported cross-session loss and preserve a verifiable recovery path, with tests covering concurrent stashes and destructive resets.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100