Stacked Diffs with Atomic
Stacked diffs (also called "stacked changes" or "patch stacks") are a powerful workflow pattern where you build multiple logical changes on top of each other, each representing a reviewable unit of work.
What are Stacked Diffs?
A stacked diff is a series of changes where each change builds on the previous one, creating a dependency chain. Instead of one massive change with 50 files, you create 5 focused changes with 10 files each.
Example Stack
Feature Implementation Stack:
┌─────────────────────────────────┐
│ Change 5: Integration tests │ ← Top of stack
├─────────────────────────────────┤
│ Change 4: API routes │
├─────────────────────────────────┤
│ Change 3: Business logic │
├─────────────────────────────────┤
│ Change 2: Database schema │
├─────────────────────────────────┤
│ Change 1: Type definitions │ ← Base
└─────────────────────────────────┘
Why Use Stacked Diffs?
1. Better Code Review
- Focused Reviews: Each change is small and reviewable in minutes
- Clear Context: Reviewers understand the progression
- Faster Approval: Small changes get approved quickly
- Better Feedback: Easier to spot issues in focused changes
2. Parallel Development
- Don't Wait: Continue building while earlier changes are under review
- Stay Productive: Keep moving forward without blocking
- Easy Iteration: Update individual changes without rebuilding everything
3. Easier Debugging
- Bisect Changes: Find which change introduced a bug
- Selective Testing: Test each layer independently
- Rollback Precision: Remove problematic changes without affecting others
Atomic vs Git: Key Differences
Git's Problem
In Git, stacked changes require rebasing when the base changes:
# Git stacked branches
git checkout -b feature-1
git commit -m "Step 1"
git checkout -b feature-2
git commit -m "Step 2"
# If feature-1 gets updated after review:
git checkout feature-1
git commit --amend # Change the commit
git checkout feature-2
git rebase feature-1 # REQUIRED: Rebase to get updates
# Conflict potential! Commit hashes change!
Problems:
- Rebase required for every update to base changes
- Commit hashes change (breaks references, discussions)
- Conflicts happen during rebase
- Linear history assumption breaks parallel work
Atomic's Solution
Atomic's change identity and commutative merges eliminate rebasing:
# Atomic stacked changes
atomic stack new feature-work
atomic record src/types.rs -m "Step 1" # Change ABC
atomic record src/logic.rs -m "Step 2" # Change DEF
# DEF depends on ABC automatically
# If ABC gets updated after review:
atomic unrecord ABC # Remove old version
atomic record src/types.rs -m "Step 1 (updated)" # Change ABC' (new hash)
# Step 2 still works! No rebase needed!
atomic apply DEF # Atomic handles dependency automatically
Benefits:
- No rebasing required
- Changes maintain identity even when base changes
- Conflicts detected at application time (more flexible)
- True parallel development
Building Your First Stack
Step 1: Create a Stack
# Create a new stack for your feature
atomic stack new feature/user-auth
atomic stack switch feature/user-auth
Step 2: Build Changes Incrementally
# Change 1: Add types
vi src/types/user.rs
atomic record src/types/user.rs -m "Add User type definition"
# Output: Change ABC123 recorded
# Change 2: Add database schema (depends on types)
vi migrations/001_users.sql
atomic record migrations/001_users.sql -m "Add users table schema"
# Output: Change DEF456 recorded (depends on ABC123)
# Change 3: Add authentication logic
vi src/auth/login.rs
atomic record src/auth/login.rs -m "Implement login logic"
# Output: Change GHI789 recorded (depends on DEF456)
# Change 4: Add API routes
vi src/api/auth.rs
atomic record src/api/auth.rs -m "Add auth API endpoints"
# Output: Change JKL012 recorded (depends on GHI789)
Step 3: View Your Stack
# See the dependency chain
atomic log --deps
# Output:
# JKL012 - Add auth API endpoints
# └─ GHI789 - Implement login logic
# └─ DEF456 - Add users table schema
# └─ ABC123 - Add User type definition
Step 4: Push for Review
# Push entire stack to remote
atomic push --stack feature/user-auth
# Or push individual changes
atomic push ABC123 DEF456 # Just types and schema
Working with Stack Changes
Updating a Change in the Middle
Unlike Git, updating changes is straightforward:
# Current stack: ABC → DEF → GHI → JKL
atomic log --graph
# Update the middle change (DEF)
atomic unrecord DEF
vi migrations/001_users.sql # Make improvements
atomic record migrations/001_users.sql -m "Add users table (v2)"
# New change: DEF' (different hash)
# Dependent changes (GHI, JKL) still work!
atomic apply GHI # Automatically uses DEF'
atomic apply JKL # Still applies correctly
Reordering Changes
If changes are independent, reorder freely:
# Current: ABC → DEF → GHI
# Want: ABC → GHI → DEF
atomic unrecord DEF GHI # Remove both
atomic apply GHI # Apply in new order
atomic apply DEF
Splitting a Large Change
# You have a large change XYZ
atomic show XYZ
# Output: 20 files modified
# Split into logical pieces
atomic split-change XYZ \
--files src/types/*.rs \
-m "Part 1: Type definitions"
atomic split-change XYZ \
--files src/logic/*.rs \
-m "Part 2: Business logic"
# Now you have XYZ-1 and XYZ-2 that reviewers can handle separately
Squashing Changes
# Combine two related changes
atomic squash ABC DEF -m "Combined type and schema changes"
# Output: New change with combined hunks
Review Workflow
Push Changes Individually
# Push just the base change for initial review
atomic push ABC
# Continue working on dependent changes locally
atomic record more-work.rs -m "Building on ABC"
# When ABC is approved, push next layer
atomic push DEF
Update After Review Feedback
# Reviewer comments on ABC
atomic show ABC # Review the change
# Update it
atomic unrecord ABC
vi src/types/user.rs # Address feedback
atomic record src/types/user.rs -m "Add User type (v2)"
# Push updated version
atomic push ABC
# Dependent changes still work without modification!
Advanced Patterns
Parallel Stacks from Same Base
# Create two independent stacks from main
atomic stack new feature/frontend
atomic stack new feature/backend
# Both can pull the same base changes
atomic stack switch feature/frontend
atomic pull ABC DEF # Pull backend types
atomic stack switch feature/backend
atomic pull ABC DEF # Same changes, same hashes!
Cascading Updates
When a base change is updated, all stacks using it can pull the update:
# Stack A updates shared change ABC
atomic unrecord ABC
atomic record src/shared.rs -m "Shared types (v2)"
atomic push ABC
# Stack B can pull the update
atomic stack switch feature-b
atomic pull ABC # Gets the updated version
# Atomic handles dependency updates automatically
Cherry-Picking Changes
Pull specific changes from other stacks without the full history:
# You want just change DEF from another stack
atomic pull DEF
# Atomic automatically pulls dependencies (ABC) if needed
# But NOT unrelated changes (GHI, JKL)
Best Practices
1. Keep Changes Focused
Each change should:
- ✅ Do one logical thing
- ✅ Be independently reviewable
- ✅ Pass tests on its own (if possible)
- ❌ Mix unrelated concerns
2. Write Clear Messages
# Good messages
atomic record -m "Add User authentication type"
atomic record -m "Implement JWT token validation"
atomic record -m "Add /login API endpoint"
# Bad messages
atomic record -m "Updates"
atomic record -m "Fix stuff"
atomic record -m "Work in progress"
3. Test Each Layer
# After each change, verify it works
atomic record src/feature.rs -m "Add feature"
cargo test # Make sure tests pass
atomic record src/api.rs -m "Add API"
cargo test # Verify again
4. Push Early, Push Often
# Don't wait to push entire stack
atomic record types.rs -m "Add types"
atomic push # Push immediately for early feedback
# Continue building while under review
atomic record logic.rs -m "Add logic"
5. Use Descriptive Stack Names
# Good stack names
atomic stack new feature/user-authentication
atomic stack new bugfix/memory-leak-in-parser
atomic stack new refactor/extract-database-layer
# Bad stack names
atomic stack new my-work
atomic stack new temp
atomic stack new asdf
Common Workflows
Building a Complex Feature
# Day 1: Foundation
atomic stack new feature/payment-system
atomic record types.rs -m "Payment types"
atomic record schema.sql -m "Payment tables"
atomic push
# Day 2: Core logic (while Day 1 under review)
atomic record processor.rs -m "Payment processor"
atomic record validation.rs -m "Payment validation"
atomic push
# Day 3: Integration
atomic record api.rs -m "Payment API endpoints"
atomic record webhooks.rs -m "Payment webhooks"
atomic push
# Day 4: Address review feedback on Day 1
atomic unrecord <types-hash>
vi types.rs # Fix issues
atomic record types.rs -m "Payment types (v2)"
atomic push
# Days 2-3 changes still work! No rebase needed!
Experimental Branch Pattern
# Start experiment on separate stack
atomic stack new experiment/new-algorithm
atomic record algorithm.rs -m "Try new approach"
# If successful, merge back
atomic stack switch main
atomic pull <algorithm-hash>
# If failed, just delete stack
atomic stack delete experiment/new-algorithm
# Change stays in global store, can recover if needed
Comparison with Git Workflows
| Workflow | Git | Atomic |
|---|---|---|
| Create stack | git checkout -b | atomic stack new |
| Add change | git commit | atomic record |
| Update base | git rebase (required) | Automatic |
| Reorder changes | git rebase -i | atomic unrecord + atomic apply |
| Split change | Manual history rewrite | atomic split-change |
| Push for review | git push | atomic push |
| Handle conflicts | During rebase | During apply (more flexible) |
| Change identity | Hash changes on rebase | Hash stays same |
Troubleshooting
Change Won't Apply
# If a change conflicts:
atomic apply ABC
# Error: Conflict in src/file.rs
# Option 1: Fix conflicts and amend
atomic apply ABC --interactive
# Resolve conflicts, then:
atomic record src/file.rs -m "Resolved version"
# Option 2: Skip the change
atomic unrecord ABC
# Continue without it
Dependency Issues
# If dependencies are wrong:
atomic show ABC --deps
# See what ABC depends on
# If you need to change dependencies:
atomic unrecord ABC
atomic apply <new-deps>
atomic record files -m "ABC with updated deps"
Stack Got Messy
# View current stack state
atomic log --graph
# Option 1: Reorder cleanly
atomic unrecord --all # Remove all from stack
atomic apply ABC DEF GHI # Reapply in order
# Option 2: Create fresh stack
atomic stack new feature-clean
atomic pull ABC DEF GHI # Pull changes to new stack
atomic stack switch feature-clean
Next Steps
- Read AI Agent Workflows for agent-based stacked changes
- See Stacks Command Reference for all stack operations
- Learn about Change Identity for deeper understanding
Summary
Stacked diffs in Atomic provide:
- ✅ Better reviews: Small, focused changes
- ✅ Parallel work: Build while reviewing
- ✅ No rebasing: Changes maintain identity
- ✅ Flexible iteration: Update any layer easily
- ✅ True independence: Commutative merge semantics
Unlike Git's branch-based stacks that require constant rebasing, Atomic's change-based model makes stacked workflows natural and friction-free.