blog.dopana

Back

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:

This command opens an interactive terminal UI that lets you make structural changes and apply them all at once.

gh stack modify
bash

The TUI interface supports the following keybindings:

KeyActionDescription
xDropRemove branch and its commits from stack
dFold downAbsorb branch into the one below (toward trunk)
uFold upAbsorb branch into the one above (away from trunk)
iInsert belowInsert a new empty branch below (toward trunk)
IInsert aboveInsert a new empty branch above (away from trunk)
Shift+↓Move downReorder branch down (toward trunk) in the stack
Shift+↑Move upReorder branch up (away from trunk) in the stack
rRenameRename the branch (opens inline prompt)
zUndoUndo the last staged action
Ctrl+SApplyApply 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 frontend
bash

Restructuring 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 apply
bash

Result:

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 apply
bash

Result:

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 apply
bash

Result:

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 push with --force-with-lease for safety
  • Backup important branches before major restructuring

Best Practices#

  • Check current stack: Always run gh stack view before making changes
  • Use TUI: gh stack modify is 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

References#