What are Stacked Branches?
Instead of one massive PR with 50 files, stacked branches let you split work into small, reviewable pieces that build on each other:
○ bugfix/auth-validation-edge-case 1↑
○ feature/auth-validation 1↑
◉ feature/auth-login 1↑ ← you are here
○ feature/auth 1↑ 1↓ ⟳
│ ○ bugfix/payments-retries 1↑ 1↓ ⟳
│ ○ feature/payments-api 2↑
│ ○ feature/payments 1↑ 1↓ ⟳
│ │ ○ feature/profile-edit 1↑
│ │ ○ ☁ feature/profile 1↑ PR #42
○─┴─┘ ☁ main
Each branch is a focused PR. Reviewers see small diffs. You ship faster.
Why stax?
- Fast - Native Rust binary, runs in ~21ms (17x faster than alternatives)
- Interactive TUI - Full terminal UI with diff viewer, reorder mode, and keyboard shortcuts
- Visual - Beautiful tree rendering showing your entire stack at a glance
- Smart - Tracks what needs rebasing, shows PR status, handles conflicts gracefully
- Compatible - Uses same metadata format as freephite (migrate instantly)
Install
# Homebrew (macOS/Linux)
&&
# Or with cargo binstall
Quick Start
# 1. Authenticate with GitHub
# 2. Create stacked branches
# 3. View your stack
# ◉ auth-ui 1↑ ← you are here
# ○ auth-api 1↑
# ○ main
# 4. Submit PRs for the whole stack
# Creating PR for auth-api... ✓ #12 (targets main)
# Creating PR for auth-ui... ✓ #13 (targets auth-api)
# 5. After reviews, sync and rebase
Interactive TUI
Run stax with no arguments to launch the interactive terminal UI:
TUI Features:
- Visual stack tree with PR status, sync indicators, and commit counts
- Full diff viewer for each branch
- Keyboard-driven: checkout, restack, submit PRs, create/rename/delete branches
- Reorder mode: Rearrange branches in your stack with
othenShift+↑/↓
| Key | Action |
|---|---|
↑/↓ |
Navigate branches |
Enter |
Checkout branch |
r |
Restack selected branch |
s |
Submit stack |
o |
Enter reorder mode (reparent branches) |
n |
Create new branch |
d |
Delete branch |
? |
Show all keybindings |
Reorder Mode
Rearrange branches within your stack without manually running reparent commands:
- Select a branch and press
oto enter reorder mode - Use
Shift+↑/↓to move the branch up or down in the stack - Preview shows which reparent operations will happen
- Press
Enterto apply changes and automatically restack
Core Commands
| Command | What it does |
|---|---|
stax |
Launch interactive TUI |
stax ls |
Show your stack with PR status and what needs rebasing |
stax create <name> |
Create a new branch stacked on current |
stax ss |
Submit stack - push all branches and create/update PRs |
stax rs |
Repo sync - pull trunk, clean up merged branches |
stax rs --restack |
Sync and rebase all branches onto updated trunk |
stax co |
Interactive branch checkout with fuzzy search |
stax u / stax d |
Move up/down the stack |
stax m |
Modify - stage all changes and amend current commit |
stax pr |
Open current branch's PR in browser |
stax undo |
Undo last operation (restack, submit, etc.) |
Safe History Rewriting with Undo
Stax makes rebasing and force-pushing safe with automatic backups and one-command recovery:
# Make a mistake while restacking? No problem.
# ✗ conflict in feature/auth
# Your repo is recoverable via: stax undo
# Instantly restore to before the restack
# ✓ Undone! Restored 3 branch(es).
How It Works
Every potentially-destructive operation (restack, submit, sync --restack, TUI reorder) is transactional:
- Snapshot - Before touching anything, stax records the current commit SHA of each affected branch
- Backup refs - Creates Git refs at
refs/stax/backups/<op-id>/<branch>pointing to original commits - Execute - Performs the operation (rebase, force-push, etc.)
- Receipt - Saves an operation receipt to
.git/stax/ops/<op-id>.json
If anything goes wrong, stax undo reads the receipt and restores all branches to their exact prior state.
Undo & Redo Commands
| Command | Description |
|---|---|
stax undo |
Undo the last operation |
stax undo <op-id> |
Undo a specific operation |
stax redo |
Redo (re-apply) the last undone operation |
Flags:
--yes- Auto-approve prompts (useful for scripts)--no-push- Only restore local branches, don't touch remote
Remote Recovery
If the undone operation had force-pushed branches, stax will prompt:
# ✓ Restored 2 local branch(es)
# This operation force-pushed 2 branch(es) to remote.
# Force-push to restore remote branches too? [y/N]
Use --yes to auto-approve or --no-push to skip remote restoration.
Real-World Example
You're building a payments feature. Instead of one 2000-line PR:
# Start the foundation
# ... write database models, commit ...
# Stack the API layer on top
# ... write API endpoints, commit ...
# Stack the UI on top of that
# ... write React components, commit ...
# View your stack
# ◉ payments-ui 1↑ ← you are here
# ○ payments-api 1↑
# ○ payments-models 1↑
# ○ main
# Submit all 3 as separate PRs (each targeting its parent)
# Creating PR for payments-models... ✓ #101 (targets main)
# Creating PR for payments-api... ✓ #102 (targets payments-models)
# Creating PR for payments-ui... ✓ #103 (targets payments-api)
Reviewers can now review 3 small PRs instead of one giant one. When payments-models is approved and merged:
# ✓ Pulled latest main
# ✓ Cleaned up payments-models (merged)
# ✓ Rebased payments-api onto main
# ✓ Rebased payments-ui onto payments-api
# ✓ Updated PR #102 to target main
Working with Multiple Stacks
You can have multiple independent stacks at once:
# You're working on auth...
# Teammate needs urgent bugfix reviewed - start a new stack
# View everything
# ○ auth-validation 1↑
# ○ auth-login 1↑
# ○ auth 1↑
# │ ◉ hotfix-payment 1↑ ← you are here
# ○─┘ main
Navigation
| Command | What it does |
|---|---|
stax u |
Move up to child branch |
stax d |
Move down to parent branch |
stax u 3 |
Move up 3 branches |
stax top |
Jump to tip of current stack |
stax bottom |
Jump to base of stack (first branch above trunk) |
stax t |
Jump to trunk (main/master) |
stax co |
Interactive picker with fuzzy search |
Reading the Stack View
○ feature/validation 1↑
◉ feature/auth 2↑ 1↓ ⟳
│ ○ ☁ feature/payments PR #42
○─┘ ☁ main
| Symbol | Meaning |
|---|---|
◉ |
Current branch |
○ |
Other branch |
☁ |
Has remote tracking |
1↑ |
1 commit ahead of parent |
1↓ |
1 commit behind parent |
⟳ |
Needs restacking (parent changed) |
PR #42 |
Has open PR |
Configuration
Config at ~/.config/stax/config.toml:
[]
= "cesar/" # Auto-prefix branches: "auth" → "cesar/auth"
[]
= "origin"
= "github" # github, gitlab, gitea
GitHub Authentication
# Option 1: Environment variable (recommended)
# Option 2: Interactive setup
Freephite/Graphite Compatibility
stax uses the same metadata format as freephite and supports similar commands:
| freephite | stax | graphite | stax |
|---|---|---|---|
fp ss |
stax ss |
gt submit |
stax submit |
fp rs |
stax rs |
gt sync |
stax sync |
fp bc |
stax bc |
gt create |
stax create |
fp bco |
stax bco |
gt checkout |
stax co |
fp bu |
stax bu |
gt up |
stax u |
fp bd |
stax bd |
gt down |
stax d |
fp ls |
stax ls |
gt log |
stax log |
Migration is instant - just install stax and your existing stacks work.
All Commands
Stack Operations
| Command | Alias | Description |
|---|---|---|
stax status |
s, ls |
Show stack (simple view) |
stax log |
l |
Show stack with commits and PR info |
stax submit |
ss |
Push and create/update PRs |
stax sync |
rs |
Pull trunk, delete merged branches |
stax restack |
Rebase current branch onto parent | |
stax diff |
Show diffs for each branch vs parent | |
stax range-diff |
Show range-diff for branches needing restack |
Branch Management
| Command | Alias | Description |
|---|---|---|
stax create <name> |
c, bc |
Create stacked branch |
stax checkout |
co, bco |
Interactive branch picker |
stax modify |
m |
Stage all + amend current commit |
stax rename |
b r |
Rename branch and optionally edit commit message |
stax branch track |
Track an existing branch | |
stax branch reparent |
Change parent of a branch | |
stax branch delete |
Delete a branch | |
stax branch fold |
Fold branch into parent | |
stax branch squash |
Squash commits on branch |
Navigation
| Command | Alias | Description |
|---|---|---|
stax up [n] |
u, bu |
Move up n branches |
stax down [n] |
d, bd |
Move down n branches |
stax top |
Move to stack tip | |
stax bottom |
Move to stack base | |
stax trunk |
t |
Switch to trunk |
Interactive
| Command | Description |
|---|---|
stax |
Launch interactive TUI |
Recovery
| Command | Description |
|---|---|
stax undo |
Undo last operation (restack, submit, etc.) |
stax undo <op-id> |
Undo a specific operation by ID |
stax redo |
Re-apply the last undone operation |
Utilities
| Command | Description |
|---|---|
stax auth |
Set GitHub token |
stax config |
Show configuration |
stax doctor |
Check repo health |
stax continue |
Continue after resolving conflicts |
stax pr |
Open PR in browser |
Common Flags
stax create -m "msg"- Create branch with commit messagestax create -a- Stage all changesstax create -am "msg"- Stage all and commitstax rename new-name- Rename current branchstax rename -e- Rename and edit commit messagestax submit --draft- Create PRs as draftsstax submit --yes- Auto-approve promptsstax submit --no-prompt- Use defaults, skip interactive promptsstax submit --reviewers alice,bob- Add reviewersstax submit --labels bug,urgent- Add labelsstax submit --assignees alice- Assign usersstax sync --restack- Sync and rebase all branchesstax status --json- Output as JSONstax undo --yes- Undo without promptsstax undo --no-push- Undo locally only, skip remote
CI/Automation example:
Benchmarks
| Command | stax | freephite | graphite |
|---|---|---|---|
ls (10-branch stack) |
22.8ms | 369.5ms | 209.1ms |
Raw hyperfine results:
➜ hyperfine 'stax ls' 'fp ls' 'gt ls' --warmup 3
Benchmark 1: stax ls
Time (mean ± σ): 22.8 ms ± 1.0 ms [User: 9.0 ms, System: 11.3 ms]
Range (min … max): 21.1 ms … 26.9 ms 112 runs
Benchmark 2: fp ls
Time (mean ± σ): 369.5 ms ± 7.0 ms [User: 268.8 ms, System: 184.2 ms]
Range (min … max): 360.7 ms … 380.4 ms 10 runs
Benchmark 3: gt ls
Time (mean ± σ): 209.1 ms ± 2.8 ms [User: 152.5 ms, System: 52.6 ms]
Range (min … max): 205.9 ms … 215.7 ms 13 runs
Summary
stax ls ran
9.18 ± 0.43 times faster than gt ls
16.23 ± 0.79 times faster than fp ls
License
MIT