When working with stacked pull requests on GitHub, you often need to change the structure of your stack - reorder branches, combine them, or rename them. The GitHub CLI extension gh stack provides powerful tools to handle this easily.
Problem#
When developing features using stacked PRs, you commonly encounter situations like:
- Need to move a branch to a higher or lower position in the stack
- Want to combine two branches together
- Need to remove a branch from the stack while keeping the PR
- Want to insert a new branch between existing ones
- Need to rename a branch to better reflect its content
Instead of manually performing complex git rebase and force push operations, gh stack provides specialized commands.
Solution#
GitHub CLI offers two main approaches to restructure stacks:
1. Using gh stack modify (Recommended)#
This command opens an interactive terminal UI that lets you make structural changes and apply them all at once.
gh stack modifybashThe TUI interface supports the following keybindings:
| Key | Action | Description |
|---|---|---|
x | Drop | Remove branch and its commits from stack |
d | Fold down | Absorb branch into the one below (toward trunk) |
u | Fold up | Absorb branch into the one above (away from trunk) |
i | Insert below | Insert a new empty branch below (toward trunk) |
I | Insert above | Insert a new empty branch above (away from trunk) |
Shift+↓ | Move down | Reorder branch down (toward trunk) in the stack |
Shift+↑ | Move up | Reorder branch up (away from trunk) in the stack |
r | Rename | Rename the branch (opens inline prompt) |
z | Undo | Undo the last staged action |
Ctrl+S | Apply | Apply all changes |
2. Using gh stack unstack + gh stack init#
A more manual approach but flexible for complex changes:
# 1. Remove current stack
gh stack unstack
# 2. Make structural changes manually
git branch -m api-routes api-endpoints
git branch -d feature-removed
# 3. Re-create stack with new structure
gh stack init db-migrations api-endpoints frontendbashRestructuring Workflow#
Here’s the workflow for restructuring a stack:
flowchart TD
A[Current Stack] --> B{Method?}
B -->|Interactive| C[gh stack modify]
B -->|Manual| D[gh stack unstack]
C --> E[Open TUI]
E --> F[Select action]
F --> G[Stage changes]
G --> H{Done?}
H -->|No| F
H -->|Yes| I[Ctrl+S Apply]
D --> J[Manual changes]
J --> K[git branch -m/-d]
K --> L[gh stack init]
I --> M[Cascading rebase]
L --> M
M --> N[gh stack push]
N --> O[Restructured Stack]
Practical Examples#
Example 1: Moving a branch higher#
Suppose you have this stack from bottom to top:
graph TD
A[main] --> B[db-migrations]
B --> C[api-routes]
C --> D[frontend]
D --> E[testing]
You want to move testing above api-routes:
gh stack modify
# Use Shift+↑ to move testing up
# Ctrl+S to applybashResult:
graph TD
A[main] --> B[db-migrations]
B --> C[testing]
C --> D[api-routes]
D --> E[frontend]
Example 2: Combining two branches#
When you realize two branches should be combined:
graph TD
A[main] --> B[db-migrations]
B --> C[api-routes]
C --> D[api-validation]
D --> E[frontend]
Fold api-validation into api-routes:
gh stack modify
# Select api-validation, press d (fold down)
# Ctrl+S to applybashResult:
graph TD
A[main] --> B[db-migrations]
B --> C[api-routes + validation]
C --> D[frontend]
Example 3: Inserting a new branch#
When you need to add a layer between existing branches:
graph TD
A[main] --> B[db-migrations]
B --> C[api-routes]
C --> D[frontend]
Insert auth-middleware between api-routes and frontend:
gh stack modify
# Place cursor on api-routes
# Press I (insert above)
# Name the new branch
# Ctrl+S to applybashResult:
graph TD
A[main] --> B[db-migrations]
B --> C[api-routes]
C --> D[auth-middleware]
D --> E[frontend]
Cascading Rebase Process#
When you apply changes with gh stack modify, the following process occurs:
sequenceDiagram
participant User as You
participant CLI as gh stack modify
participant Git as Git
participant Remote as GitHub Remote
User->>CLI: gh stack modify
User->>CLI: Stage changes (move/fold/insert)
User->>CLI: Press Ctrl-S to Apply
CLI->>Git: Rename branches if needed
CLI->>Git: Insert new branches if needed
CLI->>Git: Cascading rebase
loop For each branch
CLI->>Git: Rebase current branch onto branch below
Git-->>CLI: Rebase complete
end
CLI->>User: Success notification
User->>CLI: gh stack push
CLI->>Remote: Force push with `\-\-force-with-lease`
Remote-->>CLI: Push successful
CLI-->>User: Stack updated on GitHub
Important Notes#
[!WARNING]
- Cannot modify branches from merged PRs
- Structural changes (drop, fold, insert, rename) cannot be mixed in the same session
- Always use
gh stack pushwith--force-with-leasefor safety- Backup important branches before major restructuring
Best Practices#
- Check current stack: Always run
gh stack viewbefore making changes - Use TUI:
gh stack modifyis safer because it previews changes before applying - Test locally: Ensure rebase succeeds before pushing
- Communicate: Notify your team about major stack structure changes
- Backup: Tag or branch backup for important stacks