Commands
All commands are run from within a git repository. Most require the repository to have at least one stack registered (via sdf new or sdf fetch).
Stack management
sdf new [stack-name]
Create a new stack and its first branch
The stack name can be provided as a positional argument or via the --stack flag.
If --branch is omitted, the first branch is named after the stack. The base branch
is auto-detected from origin HEAD if not specified.
sdf new my-feature # positional stack name
sdf new --stack my-feature # explicit flag
sdf new my-feature --branch db-schema # custom first branch name
sdf new my-feature --base develop # custom base branch
sdf new my-feature --json # machine-readable output Flags:
| Flag | Default | Description |
|---|---|---|
--base | -- | base branch (default: auto-detected from origin HEAD) |
--branch | -- | name for the first branch (default: stack name) |
--json | -- | output machine-readable JSON |
--stack | -- | name for the stack (alternative to positional arg) |
--worktrees | -- | create each branch as a git worktree (worktree mode) |
sdf fetch
Discover and sync PR stacks from GitHub
Scans your open PRs, detects branch chains, and either registers
a new stack or reconciles an existing one.
sdf fetch # auto-detect base, scan all open PRs
sdf fetch --stack my-feature # name the stack explicitly
sdf fetch --base develop # specify base branch Flags:
| Flag | Default | Description |
|---|---|---|
--base | -- | base branch (default: auto-detected) |
--json | -- | output result as JSON |
--stack | -- | name for the stack (default: auto-generated from branches) |
sdf branch <name>
Add a new branch to the current stack
Flags:
| Flag | Default | Description |
|---|---|---|
--json | -- | output result as JSON |
--no-prefix | -- | create branch without applying the configured prefix |
--stack | -- | stack to add the branch to (default: auto-detect) |
sdf sync [stack-name]
Detect merged PRs and cascade-rebase downstream branches
Fetches from origin, queries GitHub for PR status, reconciles PR states,
cascade-rebases downstream branches, pushes, and updates PR navigation links.
By default, sync only rebases branches within the stack (e.g. after a PR is
merged or a parent branch is amended). If the base branch has advanced from
unrelated work, a hint is shown. To also rebase onto the latest base branch
tip (e.g. main), use --full.
When a rebase conflict occurs, an interactive menu offers Claude resolution,
manual resolution (pausing sync), skip, or abort.
sdf sync # sync within the stack only
sdf sync --full # also rebase onto latest base branch
sdf sync my-feature # sync a specific stack by name
sdf sync -y # skip confirmation prompt
sdf sync --continue # resume after manual conflict resolution
sdf sync --with-content # also update PR titles and descriptions Flags:
| Flag | Default | Description |
|---|---|---|
--continue | -- | resume after manual conflict resolution |
--full | -- | also rebase onto the latest base branch tip |
--json | -- | output result as JSON |
--stack | -- | stack to sync (default: auto-detect) |
--with-content | -- | update PR titles and descriptions |
-y, --yes | -- | skip confirmation prompt |
Steps performed:
- Fetch from origin and fast-forward the base branch
- Query GitHub for the status of each PR in the stack
- Reconcile PR states (mark merged nodes, fill in PR numbers)
- For each downstream node that needs rebasing: rebase onto new parent, push
- Update PR base branches on GitHub when a merged node is skipped
- Optionally update PR titles and descriptions (with
--with-contentor if configured) - Update stack navigation links in all PR descriptions
Merged nodes remain in the stack JSON and are displayed as completed. They are not removed. The ParentBranch() function skips merged nodes to find the effective parent for rebasing.
Conflict resolution: When a rebase conflict occurs, an interactive menu is presented with these options:
- Ask Claude to resolve (if
claudeCLI is available) - I'll fix it myself — pauses sync; resume later with
sdf sync --continue - Skip this branch — aborts the rebase for this branch, continues with the rest
- Abort sync — stops the entire sync
After choosing "I'll fix it myself", resolve the conflicts manually, stage the files with git add, then run sdf sync --continue.
sdf merge
Merge head PR and sync remaining branches
Merges the first open PR in the stack, retargets the next PR's base,
then triggers a sync to cascade-rebase remaining branches.
sdf merge # merge with squash (default)
sdf merge -y # skip confirmation
sdf merge --auto # enable GitHub auto-merge
sdf merge --method merge # use regular merge
sdf merge --stack my-feature # target a specific stack Flags:
| Flag | Default | Description |
|---|---|---|
--auto | -- | enable GitHub auto-merge if merge requirements are not yet met |
--json | -- | output result as JSON |
--method | squash | merge method: squash, merge, or rebase |
--stack | -- | stack to merge (default: auto-detect) |
-y, --yes | -- | skip confirmation prompt |
Merges the first open PR in the stack (the "head"), then runs sdf sync on the remaining branches. The safe pattern for draining a stack is to run sdf merge repeatedly — this keeps conflicts small by only crossing one squash boundary at a time. See the Sync Deep Dive for details.
sdf status [stack-name]
Show stack topology and sync state
Shows the topology, sync state, and PR status of a stack.
By default, only stack-internal sync state is shown. If the base branch has
advanced from unrelated work, an info hint is displayed. Use --full to include
base-branch drift in the sync state calculation.
sdf status # show stack status (stack-scoped)
sdf status --full # include base branch drift
sdf status my-feature # show a specific stack
sdf status --json # output as JSON
sdf status -v # show commit logs per branch Flags:
| Flag | Default | Description |
|---|---|---|
--full | -- | include base branch drift in sync state |
--json | -- | output result as JSON |
--stack | -- | stack to show (default: auto-detect) |
-v, --verbose | -- | show commit hashes and messages per branch |
Fetches from origin and fast-forwards the base branch to ensure sync state is accurate. Shows each branch with its PR number, status (open/merged/closed), and whether it needs syncing. Also performs lightweight reconciliation against GitHub PR states and warns about structural drift.
sdf pr
Create a GitHub PR for the current branch
Flags:
| Flag | Default | Description |
|---|---|---|
--branch | -- | target branch (default: current) |
--draft | -- | open the PR as a draft |
--json | -- | output result as JSON |
--ready | -- | mark the branch's draft PR as ready for review |
--title | -- | PR title (default: auto-generated from branch name) |
sdf move <commit>...
Move commits from current branch to parent
Cherry-picks listed commits onto the parent branch, strips them from the
current branch via rebase, and cascade-rebases downstream branches.
sdf move abc1234 # move one commit
sdf move abc1234 def5678 # move multiple commits Flags:
| Flag | Default | Description |
|---|---|---|
--json | -- | output result as JSON |
sdf split
Split a branch into a stack of smaller PRs
Uses an AI agent to analyze a branch and decompose it into a chain of
focused, reviewable PRs managed as an sdf stack.
Requires the Claude CLI to be installed. The original branch is never modified.
sdf split --from feature/big-change --stack my-feature
sdf split --from feature/big-change --stack my-feature --dry-run
sdf split --from feature/big-change --stack my-feature --base main -y Flags:
| Flag | Default | Description |
|---|---|---|
--base | -- | base branch (default: auto-detected) |
--dry-run | -- | show the split plan without executing |
--from | -- | source branch to split (required) |
--no-push | -- | create branches locally without pushing or creating PRs |
--stack | -- | name for the new stack (required) |
--worktrees | -- | create each split branch as a git worktree (worktree mode) |
-y, --yes | -- | skip confirmation prompt |
Uses Claude to analyze the source branch's full diff, identify semantic themes, and propose a split plan. The plan groups changed files into layers ordered by dependency (types/schema first, then APIs, then business logic, then UI). Each layer becomes a branch in the new stack.
Pipeline:
- Analysis — Claude groups changed files into layers by semantic theme. If a file spans multiple layers, a follow-up phase assigns individual hunks
- Plan — SDF displays the split plan showing layers, files, and estimated diffs
- Review — Interactive prompt to accept, refine (via Claude session), or abort
- Execute — Creates branches by extracting per-layer diffs and applying them as patches. Shared files are split at the hunk level
- Validate — Verifies
git diff original-branch stack/last-branchis empty (lossless split) - Ship — Pushes branches, creates PRs with stack navigation links
Plan refinement: Choosing "Refine plan" opens a Claude session where you can give natural language instructions to adjust the split (move files between layers, merge layers, rename layers). SDF re-extracts the updated plan automatically.
Safety: The original branch is never modified. If validation fails, the split is rolled back. Use --dry-run to preview the plan without executing.
Navigation
sdf switch [branch]
Switch to a branch and report its stack
Without arguments, lists all branches across all stacks.
With a branch name, checks it out and shows its stack position.
sdf switch db-schema # switch to a specific branch
sdf switch # list all branches from all stacks Flags:
| Flag | Default | Description |
|---|---|---|
--json | -- | output result as JSON |
--path-only | -- | print only the worktree path (worktree mode) |
Short alias: sdf <branch> (if no subcommand matches the name).
Configuration
sdf config
Manage sdf configuration
sdf config set <key> <value>
Set a configuration value
sdf config set branch_prefix.enabled true
sdf config set --global pr_title.conventional_commits true | Flag | Default | Description |
|---|---|---|
--global | -- | set value in global config (~/.config/sdf/config.json) |
--json | -- | output result as JSON |
sdf config show
Display effective merged configuration
| Flag | Default | Description |
|---|---|---|
--json | -- | output config as JSON only |
Deprecated commands
sdf register
Deprecated: use `sdf fetch` instead
Discover and sync PR stacks from GitHub
Utilities
sdf doctor
Check that dependencies are available
Reports the status of git (required), gh (needed for PR operations), and claude (needed for conflict resolution and PR descriptions).
sdf doctor Flags:
| Flag | Default | Description |
|---|---|---|
--json | -- | output result as JSON |
sdf version
Print version
sdf completion <bash|zsh|fish|powershell>
Generate or install shell completion scripts
Generate shell completion scripts for sdf.
To load completions manually:
Bash:
$ sdf completion bash > ~/.local/share/bash-completion/completions/sdf
Zsh:
$ sdf completion zsh > "${fpath[1]}/_sdf"
Fish:
$ sdf completion fish > ~/.config/fish/completions/sdf.fish
PowerShell:
PS> sdf completion powershell | Out-String | Invoke-Expression
Or use 'sdf completion install' to auto-detect your shell and install.
sdf completion install
Auto-detect shell and install completion scripts
Install shell completions for tab-completion of commands, stack names, branch names, and config keys:
sdf completion install # auto-detects your shell
sdf completion bash > ~/.local/share/bash-completion/completions/sdf
sdf completion zsh > ~/.zsh/completions/_sdf
sdf completion fish > ~/.config/fish/completions/sdf.fish
sdf ai intro
Teaches Claude about SDF by spawning a Claude session that introduces the tool's commands, workflows, and conventions. Claude creates a skill file for future sessions so it remembers SDF context.
sdf ai intro
Requires the Claude CLI.
sdf help
Show usage information and list all available commands.
sdf help