blog.dopana

Back

GitHubでスタックされたプルリクエストを操作する際、スタックの構造を変更する必要がよくあります - ブランチの並べ替え、結合、名前変更など。GitHub CLI拡張機能のgh stackは、これを簡単に行うための強力なツールを提供します。

問題#

スタックされたPRを使用して機能を開発する際、以下のような状況によく遭遇します:

  • ブランチをスタック内の上位または下位の位置に移動する必要がある
  • 2つのブランチを結合したい
  • PRを保持したままブランチをスタックから削除する必要がある
  • 既存のブランチの間に新しいブランチを挿入したい
  • ブランチの名前を変更して内容をより正確に反映させたい

複雑なgit rebaseとforce push操作を手動で行う代わりに、gh stackは専用のコマンドを提供します。

解決策#

GitHub CLIは、スタックを再構築するための2つの主要なアプローチを提供します:

1. gh stack modifyを使用する(推奨)#

このコマンドは、構造的な変更を行い、すべてを一度に適用できる対話型ターミナルUIを開きます。

gh stack modify
bash

TUIインターフェースは以下のキーバインディングをサポートします:

キーアクション説明
xDropブランチとそのコミットをスタックから削除
dFold downブランチを下のブランチに吸収(trunk方向)
uFold upブランチを上のブランチに吸収(trunkから離れる方向)
iInsert below下に新しい空のブランチを挿入(trunk方向)
IInsert above上に新しい空のブランチを挿入(trunkから離れる方向)
Shift+↓Move downブランチを下に移動(trunk方向)
Shift+↑Move upブランチを上に移動(trunkから離れる方向)
rRenameブランチの名前を変更(インラインプロンプトを開く)
zUndo最後のステージされたアクションを取り消し
Ctrl+SApplyすべての変更を適用

2. gh stack unstack + gh stack initを使用する#

より手動なアプローチですが、複雑な変更には柔軟です:

# 1. 現在のスタックを削除
gh stack unstack

# 2. 構造的な変更を手動で行う
git branch -m api-routes api-endpoints
git branch -d feature-removed

# 3. 新しい構造でスタックを再作成
gh stack init db-migrations api-endpoints frontend
bash

再構築ワークフロー#

スタックを再構築するワークフローは以下の通りです:

flowchart TD
    A[現在のスタック] --> B{方法?}
    B -->|対話的| C[gh stack modify]
    B -->|手動| D[gh stack unstack]
    
    C --> E[TUIを開く]
    E --> F[アクションを選択]
    F --> G[変更をステージ]
    G --> H{完了?}
    H -->|いいえ| F
    H -->|はい| I[Ctrl+Sで適用]
    
    D --> J[手動変更]
    J --> K[git branch -m/-d]
    K --> L[gh stack init]
    
    I --> M[カスケーディングrebase]
    L --> M
    M --> N[gh stack push]
    N --> O[再構築されたスタック]

実用的な例#

例1:ブランチを上位に移動する#

下から上へのスタックがあるとします:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]
    D --> E[testing]

testingapi-routesの上に移動したい場合:

gh stack modify
# Shift+↑を使用してtestingを上に移動
# Ctrl+Sで適用
bash

結果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[testing]
    C --> D[api-routes]
    D --> E[frontend]

例2:2つのブランチを結合する#

2つのブランチを結合すべきだと気づいた場合:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[api-validation]
    D --> E[frontend]

api-validationapi-routesにfoldする:

gh stack modify
# api-validationを選択し、d(fold down)を押す
# Ctrl+Sで適用
bash

結果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes + validation]
    C --> D[frontend]

例3:新しいブランチを挿入する#

既存のブランチの間にレイヤーを追加する必要がある場合:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[frontend]

api-routesfrontendの間にauth-middlewareを挿入:

gh stack modify
# カーソルをapi-routesに置く
# I(insert above)を押す
# 新しいブランチに名前を付ける
# Ctrl+Sで適用
bash

結果:

graph TD
    A[main] --> B[db-migrations]
    B --> C[api-routes]
    C --> D[auth-middleware]
    D --> E[frontend]

カスケーディングrebaseプロセス#

gh stack modifyで変更を適用すると、以下のプロセスが発生します:

sequenceDiagram
    participant User as あなた
    participant CLI as gh stack modify
    participant Git as Git
    participant Remote as GitHub Remote

    User->>CLI: gh stack modify
    User->>CLI: 変更をステージ(移動/fold/挿入)
    User->>CLI: Ctrl-Sで適用
    
    CLI->>Git: 必要に応じてブランチ名を変更
    CLI->>Git: 必要に応じて新しいブランチを挿入
    CLI->>Git: カスケーディングrebase
    loop 各ブランチについて
        CLI->>Git: 現在のブランチを下のブランチにrebase
        Git-->>CLI: Rebase完了
    end
    
    CLI->>User: 成功通知
    User->>CLI: gh stack push
    CLI->>Remote: Force push with `\-\-force-with-lease`
    Remote-->>CLI: Push成功
    CLI-->>User: GitHubでスタックが更新されました

重要な注意点#

[!WARNING]

  • マージされたPRのブランチは変更できません
  • 構造的な変更(drop、fold、insert、rename)は同じセッションで混在できません
  • 安全のため常に--force-with-leasegh stack pushを使用してください
  • 大規模な再構築の前に重要なブランチをバックアップしてください

ベストプラクティス#

  • 現在のスタックを確認:変更前に常にgh stack viewを実行
  • TUIを使用:gh stack modifyは適用前に変更をプレビューできるため安全
  • ローカルでテスト:プッシュ前にrebaseが成功することを確認
  • コミュニケーション:主要なスタック構造変更についてチームに通知
  • バックアップ:重要なスタックのタグまたはブランチバックアップ

参考文献#