Recover from rm -rf Disasters: AI-Assisted Code Restoration

Lost code to rm -rf? Learn immediate recovery steps and how AI can reconstruct logic from git history, tests, and dependencies.

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 sudo or 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-backup branch
  • 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:

  1. Git reflog recovered 30% (old committed code)
  2. Filesystem recovery got 20% (fragments of deleted files)
  3. AI reconstructed 40% from tests + deps
  4. 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