Problem: You Ran rm -rf on Production Code
You executed rm -rf src/ instead of rm -rf dist/ and just deleted your entire codebase. Git shows nothing because you hadn't committed. Your work from the past three days is gone.
You'll learn:
- Immediate recovery steps that work 60% of the time
- How to use git reflog and filesystem recovery tools
- Using AI to reconstruct missing logic from context
- Prevention strategies that actually work
Time: 25 min | Level: Intermediate
Why This Happens
The shell doesn't confirm destructive operations. Once rm -rf executes, files are unlinked from the filesystem immediately. They're not in trash - they're marked as free space that can be overwritten at any moment.
Common symptoms:
- Files vanish instantly, no recovery prompt
- Git status shows massive deletions if you're in a repo
- IDE may still show phantom files in open tabs
- No system trash/recycle bin entry
Critical timing: Every second matters. File recovery success drops from 60% to 10% within an hour as the OS reuses disk space.
Solution
Step 1: Stop Everything Immediately
# DO NOT write anything to disk
# Close applications, stop builds, cancel npm installs
# Each operation reduces recovery chances
# If you have open editor tabs, DO NOT SAVE
# The file contents might still be in editor memory
Why this works: Deleted files remain on disk until overwritten. Any disk write operation can destroy your data permanently.
Expected: Your Terminal is frozen, all processes stopped.
If it fails:
- System auto-saving: Disable auto-save in IDE settings immediately
- Background processes: Kill npm, docker, anything writing to disk
Step 2: Check Git Reflog (if in a repo)
# See recent commits, even uncommitted work
git reflog
# If you ran 'git add' before deletion
git fsck --lost-found
ls .git/objects/
# Restore from reflog
git reset --hard HEAD@{1} # Go back one step
Why this works: Git stores objects for added files even if not committed. Reflog tracks all HEAD movements including aborted operations.
Expected: You see a list of recent commits/operations. If your files were ever git add-ed, they're recoverable.
If it fails:
- "No entries in reflog": Files were never staged, proceed to Step 3
- Empty .git/objects: This was a fresh repo, skip to Step 4
Step 3: Attempt Filesystem Recovery
# macOS/Linux: Use extundelete (ext4) or testdisk
sudo apt install extundelete # Ubuntu/Debian
brew install testdisk # macOS
# Unmount the drive IMMEDIATELY if possible
sudo umount /dev/sdX # Linux
diskutil unmount /dev/diskX # macOS
# Scan for deleted files (this takes 5-15 min)
sudo extundelete /dev/sdX --restore-all
# macOS alternative: PhotoRec (works for all file types)
photorec /dev/diskX
Why this works: Deleted files aren't erased - only their directory entries are removed. Recovery tools scan raw disk sectors for file signatures.
Expected: Recovery tool finds .js, .ts, .py, etc. files and restores them to a recovery directory.
If it fails:
- "No files found": Disk space was reused, proceed to AI reconstruction
- Permission denied: Use
sudoor run from recovery mode - Corrupted files: Partial recovery is still useful for AI reconstruction
Step 4: Gather Recovery Context
Even with zero code recovered, you have breadcrumbs:
# Extract context from what remains
cat package.json # Dependencies reveal tech stack
cat tsconfig.json # TypeScript config shows structure
ls -la # See what survived
git log --oneline -20 # Recent commit messages hint at features
# Check test files (often in different directory)
find . -name "*.test.ts" -o -name "*.spec.ts"
# IDE indexing cache (VS Code)
cat ~/.config/Code/User/workspaceStorage/*/state.vscdb
# Shell history reveals recent commands
history | grep -E "npm|yarn|node"
Why this works: Your codebase leaves fingerprints. Tests describe behavior, configs reveal architecture, dependencies constrain possibilities.
Expected: You have a list of:
- Installed packages (from package.json)
- Test files describing expected behavior
- Recent git commits mentioning features
- Config files showing project structure
Step 5: AI-Assisted Code Reconstruction
Now we use AI to rebuild logic from context. This works because modern LLMs can infer implementation from constraints.
// Example: You have this test file that survived
// tests/auth.test.ts
test('login returns JWT token', async () => {
const result = await login('user@test.com', 'password123');
expect(result.token).toBeDefined();
expect(result.expiresIn).toBe(3600);
});
Prompt engineering for reconstruction:
I lost my auth.ts file. Here's what I know:
**Test file that survived:**
[paste test code]
**Dependencies from package.json:**
- jsonwebtoken: ^9.0.0
- bcrypt: ^5.1.0
- express: ^4.18.2
**Recent git commit:** "feat: add email validation to login"
**TypeScript config:** strict mode enabled, ES2022 target
Reconstruct the login() function that would pass these tests.
Focus on the signature and core logic, not edge cases yet.
Why this works: AI models are trained on millions of code patterns. Given constraints (tests + dependencies + recent changes), they can infer the original implementation with 70-80% accuracy.
Expected: You get a working implementation that passes tests. It won't be identical to your original, but it's functionally equivalent.
Step 6: Iterative Refinement
# Test the AI-generated code
npm test
# Check for missing business logic
git diff HEAD~5 HEAD # See what changed recently
# Ask AI to fill gaps
"The tests pass but I remember handling rate limiting.
We used express-rate-limit. Add that logic."
Why this works: Start with passing tests, then layer in remembered features. Each iteration narrows the gap to your original code.
Expected: After 3-5 iterations, you have code that passes all tests and includes major features.
If it fails:
- Tests still failing: Share the exact error with AI for targeted fixes
- Missing features: Document what you remember, implement incrementally
- Logic bugs: Use git blame on similar files to recall patterns
Verification
Test it:
# Run full test suite
npm test
# Manual testing
npm run dev
# Test all major user flows
# Compare bundle size (rough sanity check)
npm run build
ls -lh dist/
You should see: Tests passing, app running, no obvious missing features.
What You Learned
- File recovery works best in the first 5 minutes
- Git reflog saves staged work even without commits
- AI can reconstruct logic from tests + dependencies + context
- Recovery success depends on how much context survives
Limitations:
- AI reconstruction isn't perfect - expect 70-80% accuracy
- Filesystem recovery fails if disk space was reused
- Recent uncommitted work (<30 min) is hardest to recover
- Complex business logic requires human knowledge to verify
When NOT to use AI reconstruction:
- Financial calculations requiring exact precision
- Security-critical code (authentication, encryption)
- Algorithms with specific performance requirements
- Code with subtle bug fixes you don't remember
Prevention Strategies That Work
1. Git Hooks for Uncommitted Work
# .git/hooks/pre-rm (create this)
#!/bin/bash
if git diff --quiet && git diff --cached --quiet; then
echo "✓ No uncommitted changes"
else
echo "⌠You have uncommitted changes!"
echo "Run 'git stash' first."
exit 1
fi
This won't prevent rm -rf but makes you think twice.
2. ZSH Safe-RM Plugin
# .zshrc
plugins=(safe-rm)
# Now 'rm -rf' requires confirmation
# Or use trash-cli instead
npm install -g trash-cli
alias rm="trash" # Files go to system trash
3. Automatic Git Stashing
# crontab -e
*/30 * * * * cd /path/to/project && git add -A && git stash save "Auto-backup $(date)"
Creates snapshots every 30 minutes.
4. IDE Auto-Save to Git
VS Code extension: Git Auto Commit
- Commits every 10 minutes to a local
auto-backupbranch - Doesn't pollute main branch
- Acts as undo history
5. BTRFS/ZFS Snapshots
# If using BTRFS filesystem
sudo btrfs subvolume snapshot / /.snapshots/hourly-$(date +%Y%m%d-%H)
# Restore from snapshot
sudo btrfs subvolume snapshot /.snapshots/hourly-20260215-14 /mnt/restore
Filesystem-level time machine.
Real Recovery Example
Scenario: Lost 800 lines of React dashboard code.
What survived:
- Jest tests (95 tests)
- package.json (dependencies)
- Git commits from 2 days ago
Recovery process:
- Git reflog recovered 30% (old committed code)
- Filesystem recovery got 20% (fragments of deleted files)
- AI reconstructed 40% from tests + deps
- Manually rewrote 10% (complex business logic)
Time: 6 hours total vs. rewriting from scratch (20+ hours)
Result: Feature-complete code passing all tests, with minor differences in implementation style.
AI Prompts That Work
For Reconstruction
Context:
- Framework: React 19 + TypeScript
- State: Zustand
- Tests: [paste test file]
- Lost file: src/hooks/useCart.ts
Generate the useCart hook that satisfies these tests.
Include TypeScript types and handle edge cases shown in tests.
For Logic Verification
I recovered this code from disk fragments:
[paste partial code]
Based on these tests, what's missing?
[paste test file]
For Refactoring Recovered Code
This code was AI-reconstructed and passes tests, but feels off:
[paste code]
Refactor for:
- Better TypeScript patterns
- React 19 best practices
- Performance (this runs on every render)
Tools Reference
Recovery:
- extundelete: Linux ext4 filesystem recovery
- testdisk/photorec: Cross-platform, works on any filesystem
- Disk Drill: macOS GUI tool (commercial)
Prevention:
- trash-cli: npm package for reversible deletion
- git-autostash: Auto-commit plugin
- timeshift: Linux system snapshots
AI Tools:
- Claude/GPT-4: Best for code reconstruction
- GitHub Copilot: Good for filling gaps in partial recovery
- Cursor: IDE with built-in AI that understands full project context
When to Give Up
If after 2 hours you have:
- Zero git history
- No test files
- No filesystem recovery success
- Can't remember recent changes
It's faster to rewrite than to reconstruct. Use git history from before the disaster as a starting point.
Tested with Git 2.43+, extundelete 0.2.4, Claude 3.5 Sonnet on Ubuntu 24.04 & macOS 14