Splitting Branches
sdf split takes a large branch and decomposes it into a stack of smaller, focused PRs. Claude analyzes the diff and proposes a split plan — grouping files by theme, ordering layers by dependency, and handling shared files at the hunk level. The original branch is never modified.
When to use split
Use sdf split when you have an existing branch with a large diff that should have been a stack from the start. Common scenarios:
- A feature branch grew to 2,000+ lines and reviewers are struggling
- You prototyped something in a single branch and want to submit it as reviewable layers
- You inherited a branch from someone else and need to break it down
If you're starting fresh, use sdf new and sdf branch to build the stack incrementally. Split is for after-the-fact decomposition.
Prerequisites
- Claude CLI — required. Split uses Claude for analysis, plan generation, and hunk assignment. Install from claude.ai/code.
- Clean working tree — no uncommitted changes
- Source branch must not already be in a stack
- Source branch must have 2+ changed files relative to the base
Basic usage
sdf split --from feature/big-change --stack my-feature
Required flags:
--from <branch>— the source branch to split--stack <name>— the name for the new stack that will hold the split layers
Optional flags:
--base <branch>— base branch (default: auto-detected fromorigin/HEAD)--dry-run— show the plan without executing--yes,-y— skip the confirmation prompt--no-push— create branches locally without pushing or creating PRs
How it works
Phase 1: Analysis
Claude receives the full diff between the base branch and the source branch, including the list of changed files, commit log, and file tree. It groups the files into coherent layers — each representing a candidate PR — based on semantic themes.
For example, a feature branch touching database migrations, API endpoints, business logic, and tests might be split into:
Layer 1: Database schema (3 files, +120 -0)
Migration and model definitions
Layer 2: API endpoints (5 files, +340 -20)
HTTP handlers and route registration
Layer 3: Business logic (4 files, +280 -15)
Service layer and validation
Layer 4: Tests (6 files, +450 -0)
Unit and integration tests
Each file typically appears in exactly one layer. When a file's changes serve multiple concerns, it may appear in multiple layers — SDF handles this in the hunk assignment phase.
Phase 2: Dependency ordering
Claude determines the natural dependency order between layers. Types and schemas come before interfaces, APIs before business logic, business logic before UI. Tests travel with the code they test. The ordering ensures each layer compiles and passes tests independently.
Phase 3: Display and decision
After analysis, SDF displays the split plan showing each layer's name, description, file count, and line statistics. You then choose one of three actions:
- Execute — proceed with the split as proposed
- Refine — open an interactive Claude session to adjust the plan with natural language instructions (e.g., "move the validation files to layer 2" or "merge layers 3 and 4")
- Abort — cancel the split
Phase 4: Hunk-level splitting (if needed)
When the same file appears in multiple layers (shared files), SDF assigns individual diff hunks to the appropriate layer. Claude examines each hunk and assigns it based on its semantic content. SDF validates that every hunk is accounted for and no hunk appears in multiple layers.
If hunk assignment fails (Claude can't produce valid assignments), SDF falls back to keeping each shared file in its first layer only.
Phase 5: Execution
SDF creates the stack and branches:
- Initializes the stack with
sdf new - For each layer, creates a branch and applies the layer's changes
- Validates tree identity — confirms that the tip of the last branch is identical to the source branch (lossless split)
- Pushes all branches to origin
- Creates PRs for each branch with auto-generated titles
If validation fails (the split is not lossless), SDF rolls back — deletes the created branches and stack — and reports the error.
Phase 6: Session management
The Claude session ID is saved in .sdf/local.json so you can resume the analysis session later:
claude --resume <session-id>
The session ID is displayed at the end of the split output.
Worked example
# You have a large branch with 15 changed files
$ sdf split --from feature/user-management --stack users
Analyzing feature/user-management...
Split plan for users (base: main)
──────────────────────────────────────────────────
Layer 1: Database models (3 files, +145 -0)
User and role table migrations, model structs
Layer 2: Repository layer (4 files, +230 -12)
CRUD operations for users and roles
Layer 3: API handlers (5 files, +380 -25)
REST endpoints for user management
Layer 4: Integration tests (3 files, +290 -0)
End-to-end tests for all endpoints
Total: 15 files across 4 layers
? What would you like to do?
> Execute this split
Refine plan (opens Claude session)
Abort
After execution:
✓ Layer 1: users/database-models -- 3 files applied
✓ Layer 2: users/repository-layer -- 4 files applied
✓ Layer 3: users/api-handlers -- 5 files applied
✓ Layer 4: users/integration-tests -- 3 files applied
✓ Tree identity verified -- split is lossless
Pushing branches to origin...
✓ users/database-models
✓ users/repository-layer
✓ users/api-handlers
✓ users/integration-tests
Creating pull requests...
✓ PR #201: users/database-models → main
✓ PR #202: users/repository-layer → users/database-models
✓ PR #203: users/api-handlers → users/repository-layer
✓ PR #204: users/integration-tests → users/api-handlers
✓ Split complete -- 4 branches created in stack "users"
Refining the plan
If the initial plan isn't quite right, choose "Refine plan" to open an interactive Claude session. You can give natural language instructions:
- "Move
internal/validation.gofrom layer 3 to layer 2" - "Merge layers 2 and 3 into a single layer"
- "Split the tests into their own layer"
- "Rename layer 1 to 'Schema changes'"
After you exit the Claude session (/exit), SDF re-extracts the updated plan and handles any shared file reassignment automatically.
Dry run
Use --dry-run to see the plan without executing:
sdf split --from feature/big-change --stack my-feature --dry-run
This runs the full analysis phase and displays the plan, but does not create any branches, push, or create PRs.
Local-only split
Use --no-push to create branches locally without pushing or creating PRs:
sdf split --from feature/big-change --stack my-feature --no-push
You can then inspect the branches locally, push them manually, and create PRs with sdf pr from each branch.
What can go wrong
Analysis fails: If Claude can't produce a valid split plan, the command fails without modifying anything.
Validation fails (not lossless): If the final tree doesn't match the source branch exactly, SDF rolls back all created branches and the stack. This means a bug in the splitting logic — report it.
Hunk assignment fails: If shared files can't be split at the hunk level, SDF falls back to keeping each shared file in whichever layer it first appears. The split may still be valid, but some files might not land in their ideal layer.
Push fails: If pushing fails for some branches, SDF skips PR creation and tells you to push manually, then create PRs with sdf pr.