hannahanna (hn)
note 2025-11-12: wip; currently just vibe coded. building some stuff to see if it works
A worktree manager that enables true parallel development with isolated environments.
What is hannahanna?
hannahanna (command: hn) is a tool that makes it easy to work on multiple Git branches simultaneously. Each worktree gets its own complete, isolated development environment while intelligently sharing resources when safe.
Why hannahanna?
- Work on multiple features in parallel without stashing or context switching
- Create isolated environments for code reviews, experiments, or hotfixes
- Automatically share dependencies like
node_moduleswhen compatible - Track parent/child relationships between worktrees for nested workflows
- Execute hooks on worktree creation/deletion for automated setup
Installation
Or build from source:
Quick Setup (Recommended)
After installation, run the automated setup:
This command will:
- Install shell completions for your shell (bash/zsh/fish)
- Provide instructions for shell integration setup
- Create example templates (
.hn-templates/) - Validate your environment (git, docker)
The setup command auto-detects your shell, or you can specify:
Manual Shell Integration
Alternatively, for the hn switch command to work (changes directory), add this to your ~/.bashrc or ~/.zshrc:
Quick Start
# Create worktrees for multiple features
# List all worktrees
# Switch between worktrees
# Show detailed info
# Remove when done
Commands
hn add <name> [options]
Create a new worktree.
# Create from current branch
# Create from specific branch
# Create without new branch (checkout existing)
Options:
--from <branch>- Base branch (default: current branch)--no-branch- Checkout existing branch instead of creating new one--sparse <path>- Sparse checkout paths (repeatable, v0.2+)--no-hooks- Skip hook execution (for untrusted repositories)
Sparse Checkout (v0.2+):
# Monorepo: only checkout specific paths
# Configure default sparse paths in .hannahanna.yml
hn list [options]
List all worktrees.
# Simple list
# Tree view showing parent/child relationships
Output shows:
- Worktree name
- Branch name
- Current commit (short hash)
*marker for current worktree
hn switch <name>
Switch to a worktree (requires shell integration).
Supports fuzzy matching:
hn return [options]
Return to parent worktree with optional merge (requires shell integration).
# Switch back to parent worktree
# Merge current branch into parent before returning
# Merge, return, and delete current worktree
# Force merge commit (no fast-forward)
Perfect for nested workflows:
# ... fix bug, commit ...
# ... continue feature work
Options:
--merge- Merge current branch into parent before returning--delete- Delete current worktree after merging (requires--merge)--no-ff- Force merge commit (no fast-forward)
hn each <command> [options]
Execute a command in all worktrees.
# Run tests in all worktrees
# Run command in parallel
# Only run on feature worktrees
# Stop on first failure
# Only run on worktrees with Docker running
Options:
--parallel- Execute commands concurrently across all worktrees--stop-on-error- Stop on first command failure (default: continue)--filter=<pattern>- Filter worktrees by name using regex--docker-running- Only run on worktrees with active Docker containers
Perfect for:
- Running tests across all features simultaneously
- Updating dependencies in all worktrees
- Checking git status or running git commands everywhere
- Batch operations on filtered subsets of worktrees
hn integrate <source> [options]
Merge a source worktree or branch into a target worktree.
# Merge a worktree into current worktree
# Merge a worktree into a specific target
# Merge a branch (not a worktree) into current worktree
# Force merge commit (no fast-forward)
# Squash commits before merging
# Use specific merge strategy
Options:
--into=<target>- Target worktree name (defaults to current worktree)--no-ff- Force merge commit (no fast-forward)--squash- Squash commits before merging--strategy=<strategy>- Git merge strategy (e.g., 'recursive', 'ours', 'theirs')
Examples:
# Work on a feature, then merge it into main worktree
# ... make changes, commit ...
# Integrate changes from main into current feature branch
Note: Target worktree must have no uncommitted changes. Supports fuzzy matching for worktree names.
hn sync [source-branch] [options]
Sync current worktree with another branch (typically main).
# Sync with main branch (default)
# Sync with specific branch
# Use rebase instead of merge
# Automatically stash/unstash uncommitted changes
# Merge without auto-committing
Options:
source-branch- Branch to sync with (defaults to 'main')--strategy=<merge|rebase>- Sync strategy (defaults to 'merge')--autostash- Automatically stash uncommitted changes before sync--no-commit- Don't automatically commit after merge
Examples:
# Keep feature branch up to date with main
# ... work on feature ...
# Use rebase for cleaner history
# Sync with uncommitted changes
Perfect for:
- Keeping feature branches up to date with main
- Pulling in latest changes from develop branch
- Resolving conflicts with upstream changes
hn info [name]
Show detailed information about a worktree.
# Info for current worktree
# Info for specific worktree
Displays:
- Path, branch, commit
- Parent/child worktrees
- Git status summary
- Shared resources (symlinks/copies)
hn remove <name> [options]
Remove a worktree.
# Remove worktree
# Force removal (ignore uncommitted changes)
Options:
--force/-f- Force removal even if there are uncommitted changes--no-hooks- Skip hook execution (for untrusted repositories)
Safety checks:
- Warns about uncommitted changes (unless
--force) - Runs
pre_removehook if configured (unless--no-hooks) - Cleans up state directories
hn prune
Clean up orphaned state directories from deleted worktrees.
hn setup [options] (v0.4)
Automate hannahanna installation and shell integration.
# Auto-detect shell and run setup
# Specify shell explicitly
What it does:
- Shell Completions: Installs completions to the appropriate location for your shell
- Shell Integration: Provides instructions for adding the cd wrapper to your shell config
- Example Templates: Creates
.hn-templates/with microservice and frontend examples - Environment Validation: Checks for git and docker installation
After running setup:
- Reload your shell:
source ~/.bashrc(or~/.zshrc) - Try tab completion:
hn <TAB> - Explore templates:
ls .hn-templates/
Options:
--shell <bash|zsh|fish>- Specify shell type (auto-detects if omitted)
This is the recommended way to set up hannahanna after installation.
hn completions <shell> (v0.4)
Generate shell completions for auto-completion (manual alternative to hn setup).
# Bash
# Zsh
# Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath)
# Fish
# Fish auto-loads completions
After setup, enjoy tab completion:
hn config <subcommand>
Manage configuration files.
# Create a new configuration file with template
# Validate configuration syntax
# Show current configuration
# Edit configuration in $EDITOR
Subcommands:
init- Create.hannahanna.ymlwith comprehensive templatevalidate- Check configuration syntax and show summaryshow- Display current configuration as YAMLedit- Open config in$EDITORand validate after saving
hn docker <subcommand>
Manage Docker containers for worktrees (requires Docker configuration).
# Show container status for all worktrees
# Start containers for a worktree
# Stop containers for a worktree
# Restart containers for a worktree
# View logs from containers
# Clean up orphaned containers
Subcommands:
ps- Show container status for all worktreesstart <name>- Start Docker containers for a worktreestop <name>- Stop Docker containers for a worktreerestart <name>- Restart Docker containers for a worktreelogs <name> [service]- View logs (optionally for specific service)prune- Remove containers for deleted worktrees
Features:
- Automatic port allocation to avoid conflicts
- Isolated Docker Compose projects per worktree
- Health check monitoring
- Works with both
docker composeand legacydocker-compose
hn ports <subcommand>
Manage Docker port allocations.
# List all port allocations
# Show ports for a specific worktree
# Release ports for a worktree
Subcommands:
list- Show all port allocations across worktreesshow <name>- Show port allocations for a specific worktreerelease <name>- Manually release port allocationsreassign <name>- Reassign ports to resolve conflicts (v0.3+)
hn state <subcommand> (v0.3)
Manage worktree state directories.
# List all state directories with sizes
# Check disk usage for specific worktree
# Clean orphaned state directories
Subcommands:
list- View all state dirs with sizessize [name]- Check disk usage for a specific worktree or all worktreesclean- Remove orphaned state directoriescache stats- View registry cache statistics (v0.4)cache clear- Clear registry cache (v0.4)
Command Aliases (v0.3)
Define custom command aliases in .hannahanna.yml:
aliases:
sw: switch
ls: list
lt: list --tree
s: sw # Chained aliases supported
Features:
- Cycle detection prevents infinite loops
- Chained aliases supported (s → sw → switch)
- Aliases work with arguments:
hn sw feature-x - Cannot override built-in commands
Usage:
# Define in .hannahanna.yml
# Use them
Configuration
Create a .hannahanna.yml file in your repository root:
# Shared resources (symlinked from main repo)
shared_resources:
- source: node_modules
target: node_modules
compatibility: package-lock.json
- source: vendor
target: vendor
compatibility: composer.lock
# File copying (for templates/config files)
shared:
copy:
- .env.template -> .env
- config/local.yml.example -> config/local.yml
# Lifecycle hooks
hooks:
post_create: |
echo "Setting up worktree..."
npm install
make setup
pre_remove: |
echo "Cleaning up..."
make cleanup
Shared Resources
Symlinks with Compatibility Checking:
shared_resources:
- source: node_modules
target: node_modules
compatibility: package-lock.json
When compatibility is specified, hannahanna compares the lockfile between the main repo and worktree:
- Compatible (identical lockfiles) → Create symlink to save disk space
- Incompatible (different lockfiles) → Skip symlink, worktree gets isolated copy
File Copying:
shared:
copy:
- .env.template -> .env
- config/database.yml.example -> config/database.yml
Files are copied once during worktree creation, perfect for:
- Environment config files (
.env) - Local configuration templates
- Files that should exist but not be symlinked
Hooks
Execute commands at specific lifecycle events:
hooks:
post_create: "npm install && npm run setup"
pre_remove: "npm run cleanup"
timeout_seconds: 300 # 5 minutes (default)
⚠️ SECURITY WARNING: Hooks execute arbitrary shell commands from your .hannahanna.yml configuration file. Only use hannahanna in repositories you trust. Never clone and run hn add in untrusted repositories without first reviewing the .hannahanna.yml file for malicious hooks.
Security Feature: Use the --no-hooks flag to disable hook execution when working with untrusted repositories:
Available hooks:
pre_create- Runs before worktree creation (v0.3+)post_create- Runs after worktree creationpost_switch- Runs after switching to a worktree (v0.3+)pre_remove- Runs before worktree deletionpost_remove- Runs after worktree deletion (v0.3+)pre_integrate- Runs before merging (v0.3+)post_integrate- Runs after merging (v0.3+)
All hooks support conditional execution via branch patterns (v0.3+)
Environment variables available in hooks:
$HNHN_NAME- Worktree name$HNHN_PATH- Worktree path$HNHN_BRANCH- Branch name$HNHN_COMMIT- Commit hash$HNHN_STATE_DIR- State directory path
Hook Timeout: Hooks automatically timeout after 5 minutes (300 seconds) by default to prevent hanging processes. You can customize this in your config:
hooks:
timeout_seconds: 600 # 10 minutes
If a hook times out, the operation will fail with a clear error message. Use --no-hooks to skip hooks entirely.
Use Cases
Multiple Features in Parallel
# Work on auth
# Make changes, commit
# Quick switch to billing
# Make changes, commit
# All worktrees running simultaneously with isolated node_modules (if incompatible)
Hotfix During Feature Work
# Deep in feature work
# Urgent bug reported!
# Fix bug in hotfix worktree
# Fix, test, commit
# Merge to main
# Clean up
# Back to feature work
Nested Worktrees
# Working on big feature
# Discover bug while implementing
# Fix bug
# Fix, commit
# Merge back to parent
# View hierarchy
# main
# └── feature-payment
# └── fix-validation-bug
Code Review
# Review a pull request
# Test locally
# Browse to localhost:3000
# Done reviewing
Advanced Features
Helpful Error Messages
hannahanna provides context-aware error messages with actionable suggestions:
Error suggestions cover common scenarios:
- Worktree already exists → Remove, rename, or switch options
- Worktree not found → List all, check spelling, create new
- Uncommitted changes → Commit, stash, or force remove
- No parent → Explains parent tracking, suggests alternatives
- Port conflicts → Port management commands
- Docker issues → Installation and permission fixes
Fuzzy Matching
Most commands support fuzzy name matching:
Matching rules:
- Exact match (case-sensitive) - highest priority
- Exact match (case-insensitive)
- Substring match (case-insensitive)
- Error if ambiguous (multiple matches)
Parent/Child Tracking
When you create a worktree from within another worktree, it's automatically tracked as a child:
# Shows parent/child relationships
State Management
Each worktree gets a state directory (.hn-state/<name>/) for:
- Worktree-specific metadata
- Logs and temporary files
- Future: isolated databases, caches
State directories are automatically cleaned up when you remove a worktree. Orphaned states can be cleaned with:
Graphite Compatibility
hannahanna works seamlessly with Graphite!
Graphite is a tool for managing stacked diffs and PRs. Since Graphite is built on top of standard Git operations, hannahanna's worktree management integrates perfectly with Graphite workflows.
Using hannahanna with Graphite:
# Create separate worktrees for different stacks
# Work on your stack in isolation
# Each worktree can have its own Graphite stack
# Switch between different stacks easily
# Sync stacks with main
Benefits of using hannahanna with Graphite:
- Isolated stacks: Each worktree can have its own Graphite stack without interference
- Parallel development: Work on multiple stacks simultaneously
- Easy context switching: Switch between stacks without stashing or committing
- Resource isolation: Different dependency versions for different stacks
Example workflow:
# Stack 1: Authentication overhaul
# Stack 2: Billing features (in parallel)
# Work on both stacks independently
# Make changes to JWT...
# Make changes to billing...
Since Graphite uses standard Git branches and commits under the hood, all hannahanna commands (integrate, sync, return) work perfectly with Graphite-managed branches.
Project Structure
When you use hannahanna, your repository layout looks like:
my-project/ # Main repository
├── .hannahanna.yml # Configuration
├── .hn-state/ # State directories (gitignored)
│ ├── feature-x/
│ └── feature-y/
├── node_modules/ # Shared when compatible
├── src/
└── package.json
../feature-x/ # Worktree 1 (sibling directory)
├── node_modules -> ../my-project/node_modules # Symlink
├── .env # Copied from .env.template
└── src/
../feature-y/ # Worktree 2 (sibling directory)
├── node_modules/ # Isolated (incompatible lockfile)
├── .env # Copied from .env.template
└── src/
Development Status
Current Version: v0.4.0
Implemented:
- ✅ Git worktree management (add, list, remove, switch, info, prune)
- ✅ Parent/child tracking with nested workflow support
- ✅
returncommand for merging back to parent - ✅
integratecommand for merging worktrees/branches - ✅
synccommand for keeping branches up to date - ✅
eachcommand for batch operations - ✅ Fuzzy name matching
- ✅ Shared resource symlinks with compatibility checking
- ✅ File copying for templates
- ✅ Extended lifecycle hooks (7 total) - v0.3
- pre_create, post_create, post_switch
- pre_remove, post_remove
- pre_integrate, post_integrate
- Conditional execution via branch patterns
- ✅ State management with file locking
- ✅ State commands (list/size/clean) - v0.3
- ✅ Docker integration
- Port allocation system
- Port reassign command - v0.3
- Container lifecycle management (exec/restart/prune)
- Docker Compose override generation
- ✅ Config management commands (init/validate/show/edit)
- ✅ Command aliases with cycle detection - v0.3
- ✅ Helpful error messages with actionable suggestions
- ✅ Graphite compatibility - Works seamlessly with Graphite stacks
Test Coverage: 273 tests passing (87 lib + 186 integration), zero warnings
Multi-VCS Support (v0.3 Complete):
- ✅ VCS abstraction layer with trait-based design
- ✅ Auto-detection (Jujutsu → Git → Mercurial priority)
- ✅ Full Mercurial backend (
hg shareworkspaces) - ✅ Sparse checkout for Mercurial - v0.3
- ✅ Full Jujutsu backend (
jj workspacesupport) - ✅ Clear error messages for unsupported VCS operations
v0.2 Features (Complete):
- ✅ Sparse checkout for Git and Jujutsu (monorepo support)
- ✅ Configuration hierarchy (user/repo/worktree)
v0.3 Features (Complete):
- ✅ Command aliases with cycle detection
- ✅ Extended hooks (7 types with conditional execution)
- ✅ State management commands
- ✅ Port reassign command
- ✅ Docker enhancements (exec/restart/prune)
v0.4 Features (Complete):
- ✅ Registry caching system - 50%+ faster worktree listings
- Intelligent TTL-based caching (30s default)
- Auto-invalidation on add/remove operations
- Cache management:
hn state cache stats/clear
- ✅ Performance benchmark suite - Criterion-based benchmarks
- Established performance targets for key operations
- Run with
cargo bench - Documentation in
BENCHMARKS.md
- ✅ Shell completions - Auto-completion for bash/zsh/fish
- Generate with
hn completions <shell> - Full command and option completion
- Generate with
- ✅ Enhanced
hn infooutput - Rich, actionable information- Status with emojis (✓/⚠)
- Age, disk usage, VCS type
- Parent/children relationships
- Docker memory & CPU stats
- Suggested actions section
- ✅ Mercurial sparse checkout
See: spec/plan.md and spec/spec.md for detailed roadmap
Troubleshooting
Shell Integration Not Working
If hn switch or hn return don't change your directory, check these common issues:
1. Shell Integration Not Loaded
Symptom: hn switch outputs a path but doesn't change directory
Diagnosis:
# Check if shell wrapper is defined
Expected output:
hn is a function
hn ()
{
# ... function code ...
}
If it shows hn is /path/to/hn: Shell integration is not loaded.
Fix:
# Add to ~/.bashrc or ~/.zshrc
# Then reload your shell
2. Wrong Shell Configuration File
Symptom: Works in new terminals but not current one
Common Issues:
- Added to
~/.bash_profileinstead of~/.bashrc(Linux) - Added to
~/.zshrcbut running bash - Added to
~/.bashrcbut running zsh
Fix:
# Check your shell
# Add eval "$(hn init-shell)" to the correct file:
# - Bash on Linux: ~/.bashrc
# - Bash on macOS: ~/.bash_profile or ~/.bashrc
# - Zsh: ~/.zshrc
# - Fish: ~/.config/fish/config.fish (not yet supported)
# Then reload
3. Shell Integration Conflicts
Symptom: Shell wrapper seems loaded but doesn't work correctly
Possible Causes:
- Multiple
eval "$(hn init-shell)"lines in shell config - Conflicting aliases or functions named
hn - PATH issues causing wrong
hnbinary to be called
Diagnosis:
# Check for duplicates
# Check for conflicts
Fix:
# Remove duplicate eval lines, keep only one
# Remove conflicting aliases
# Reload shell
4. Non-Interactive Shell
Symptom: Works in terminal but not in scripts
Explanation: Shell integration only works in interactive shells. Scripts should use cd with the output of hn switch:
# In scripts, don't rely on shell wrapper
# Or better, use full path operations
WORKTREE_PATH=
Permission Errors
Symptom: Permission denied errors when creating worktrees
Common Causes:
- Repository is in read-only location
- Insufficient permissions for parent directory
- SELinux or filesystem restrictions
Fix:
# Check permissions
# Ensure writable
# Check filesystem
Docker Port Conflicts
Symptom: Port allocation fails or containers won't start
Diagnosis:
# Check port allocations
# Check what's using a port
|
Fix:
# Release ports for a worktree
# Or manually edit port registry
# Change base port in config
# Set docker.ports.base to different range
Hook Failures
Symptom: hn add fails with hook errors
Diagnosis:
# Validate config
# Check what hooks would run
Fix:
# Skip hooks for untrusted repos
# Debug hook script
# Hooks run in worktree directory with these variables:
# - $HNHN_NAME, $HNHN_PATH, $HNHN_BRANCH, $HNHN_COMMIT, $HNHN_STATE_DIR
# Test hook manually
# ... then run hook commands
Worktree in Inconsistent State
Symptom: Worktree shows in hn list but directory doesn't exist
Fix:
# Remove git worktree reference
# Clean up hannahanna state
# Remove manually if needed
Performance Issues
Symptom: hn add is slow, especially with large node_modules
Solutions:
# Use shared resources instead of copying
# In .hannahanna.yml:
# Or use Docker isolation
Getting More Help
If you're still stuck:
- Check verbose output: Most commands support
-vor--verbose(planned feature) - Review logs: Check
.hn-state/for any state files - Validate git state: Run
git worktree listto see git's view - File an issue: GitHub Issues
When reporting issues, include:
- Output of
hn --version - Your shell:
echo $SHELL - Output of
type hn - Output of
git worktree list - Relevant error messages
Contributing
Contributions welcome! Please follow these guidelines:
Development Setup
-
Fork and clone the repository
-
Install git hooks to ensure code quality:
This installs a pre-commit hook that runs
rustfmtandclippyautomatically. -
Make your changes
-
Run tests:
-
Submit a pull request
Code Quality Standards
- All code must pass
rustfmtformatting - All code must pass
clippywith-D warnings(no warnings allowed) - All tests must pass
- New features should include tests
License
MIT License - see LICENSE for details
Name Origin
Hannahanna (Ḫannaḫanna) is the Hittite mother goddess, associated with creation and nurturing - fitting for a tool that creates and manages development environments.