n8n:gh-stack について
依存関係のあるブランチとプルリクエストを管理する GitHub CLI 拡張 `gh stack` の利用を支援するスキルです。非対話型の操作を重視し、スタックの構成、移動、送信、同期、マージを案内します。
主な機能
- 01依存関係に沿ってブランチ層を計画
- 02ブランチスタックの作成と移動
- 03スタック型プルリクエストの送信と同期
- 04外部ツール管理のブランチをリンク
- 05範囲と方式を指定してスタックをマージ
- 06対話型コマンドとプロンプトを回避
活用シーン
- 01大きな変更をレビュー可能なプルリクエストに分割
- 02下位ブランチの変更後に依存ブランチをリベース
- 03スタック型プルリクエストの状態を確認
- 04関連するプルリクエスト群をマージ
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ n8n-io/ n8n --skill n8n:gh-stackインストール後、Claude Code で/n8n:gh-stackを入力して読み込まれたか確認します。
詳細
gh-stack
gh stack は、スタック化されたブランチとプルリクエストを管理するための GitHub CLI 拡張機能です。スタックとは、各ブランチがその下のブランチを土台として構築される、順序付けられたブランチの一覧で、トランクブランチ(通常はリポジトリのデフォルトブランチ)を起点とします。各ブランチは、その一つ下のブランチをベースとする 1 つの PR に対応するため、レビュアーにはその階層の差分だけが表示されます。
main (trunk)
└── auth-layer → PR #1 (base: main) - bottom (closest to trunk)
└── api-endpoints → PR #2 (base: auth-layer)
└── frontend → PR #3 (base: api-endpoints) - top (furthest from trunk)
スタックの下はトランクに最も近いブランチで、上はトランクから最も遠いブランチです。各ブランチは、その一つ下のブランチを継承します。ナビゲーションコマンド(up、down、top、bottom)はこのモデルに従います。up はトランクから遠ざかり、down はトランクに近づきます。
このスキルを使う場面
ユーザーが次のことを希望している場合に、このスキルを使用してください。
- 大規模な変更を、レビューしやすい小さな PR の連鎖に分割する
- 依存関係のあるブランチのスタックを作成、リベース、プッシュ、または同期する
- ブランチスタック内の階層間を移動する
- スタック化された PR のステータスを確認する
- ブランチの削除、並べ替え、または名前変更のためにスタックを解体して再構築する
前提条件
GitHub CLI(gh)v2.0 以降がインストールされ、認証済みである必要があります。次のコマンドで拡張機能をインストールします。
gh extension install github/gh-stack
gh stack を使用する前に、対話型のプロンプトが表示されないように git を設定します。
git config rerere.enabled true # remember conflict resolutions (skips prompt on init)
git config remote.pushDefault origin # if multiple remotes exist (skips remote picker)
エージェントのルール
すべての gh stack コマンドは非対話形式で実行する必要があります。 各コマンドの呼び出しには、プロンプト、TUI、対話型メニューを回避するために必要なフラグと位置引数をすべて指定してください。コマンドが入力を求める状態になると、無期限に停止します。
init、add、checkoutには、ブランチ名を必ず位置引数として渡してください。 これらのコマンドを引数なしで実行すると、対話型プロンプトが表示されます。ブランチ名は指定どおりに使用され、接頭辞の追加や変換は行われません。そのため、gh stack add refactor/fooを実行すると、refactor/fooという名前のブランチが作成されます。gh stack submitでは必ず--autoを使用し、PR のタイトルを自動生成してください。--autoを指定しない場合、submitは新しい PR ごとにタイトルの入力を求めます。gh stack viewでは必ず--jsonを使用してください。--jsonを指定しない場合、エージェントが操作できない対話型 TUI が起動します。ほかに適切なフラグはありません。必ず--jsonを渡してください。- 複数のリモートがある場合は適切に対処してください。 設定済みのリモートが複数ある場合は、事前に
git config remote.pushDefault originを設定するか、--remote <name>を受け付けるコマンド(push、submit、sync、rebase、link)に渡してください。checkout、modify、trunkはリモートを解決しますが、--remoteフラグはありません。これらのコマンドはremote.pushDefaultに依存します。複数のリモートがあり、デフォルトが設定されていない状態で非対話モードで実行すると、エラーで終了します。 - 複数のスタックで共有されているブランチは避けてください。 ブランチが複数のスタックに属している場合、コマンドはコード 6 で終了します。まず、共有されていないブランチにチェックアウトしてください。
- コードを書く前に、依存関係の順序に沿ってスタックのレイヤーを計画してください。 基盤となる変更(モデル、API、共有ユーティリティ)は下位ブランチに、依存する変更(UI、利用側)は上位ブランチに配置します。
gh stack initを実行する前に、依存関係の連鎖をよく検討してください。 - ステージングとコミットには、標準の
git addとgit commitを使用してください。 これにより、各ブランチに含める変更を細かく制御できます。-Amのショートカットも使用できますが、デフォルトの方法にはしないでください。スタック型 PR は、各ブランチに意図の明確な論理的まとまりの変更が含まれている場合に最も効果を発揮します。 - 下位レイヤーを変更する必要がある場合は、スタックを下に移動してください。 フロントエンドのブランチで作業中に API の変更が必要だとわかった場合、現在のレイヤーで回避しようとしないでください。適切なブランチ(
gh stack down、gh stack checkout、またはgh stack bottom)に移動し、そこで変更してコミットした後、gh stack rebase --upstackを実行してから、上位に戻って作業を続けてください。 - 外部ツールのワークフローでは
gh stack linkを使用してください。 ブランチを外部ツール(jj、Sapling など)で管理している場合は、gh stack link branch-a branch-bを使用してください。linkはローカルのトラッキング状態に依存せず、API を介した PR とスタックの管理を目的としています。スタックを作成または更新するには、ブランチまたは PR を 2 つ以上指定してください。既存スタックの最上位に追加するには、スタック番号の後に追加するブランチまたは PR を指定します(例:gh stack link 7 branch-c)。 - スタック型 PR のマージには
gh stack merge --yesを使用してください。gh pr mergeはスタック型 PR では機能しません。非対話型ターミナルでは、gh stack mergeはプロンプトなしで実行され、スタック全体を下から上へアトミックにマージします。明示するには--yesを渡してください。プルリクエスト番号(gh stack merge 42 --yesは PR #42 までをすべてマージします)またはスタック番号(ローカルでチェックアウトする必要のないgh stack merge 7 --yes)を渡して、マージの対象を指定します。--squash、--rebase、--merge、または--merge-method <method>でマージ方法を選択してください。いずれも指定しない場合は、最後に使用した方法が使われます。マージはすべて成功するか、すべて失敗するかのどちらかです。いずれかの PR をマージできない場合は、どれもマージされず、失敗理由が報告されます。マージ前に確認されるプルリクエストの状態は基本的なもの(オープンで、ドラフトではないか)のみです。スタックでは、マージ要件の回避はサポートされていません。ベースブランチでマージキューが使われている場合、スタックは直接マージされずにキューに追加されます。マージ方法はキューによって選択されます(指定した方法は警告とともに無視されます)。プルリクエストはまとめてキューに追加されますが、キューの処理に合わせてマージされるため、一度にすべてではなく、別々のグループとして取り込まれる場合があります。 次の操作は絶対に行わないでください。いずれも対話型プロンプトまたは TUI が起動し、処理が停止します:
- ❌
gh stack viewまたはgh stack view --short— 必ずgh stack view --jsonを使用してください - ❌
--autoを付けずにgh stack submitを実行する — 必ずgh stack submit --autoを使用してください - ❌ ブランチ引数を付けずに
gh stack initを実行する — 必ずブランチ名を指定してください - ❌ ブランチ名を付けずに
gh stack addを実行する — 必ずブランチ名を指定してください - ❌ 引数を付けずに
gh stack checkoutを実行する — 必ず PR 番号またはブランチ名を指定してください - ❌ 該当するブランチに別のローカルスタックがすでに存在する状態で
gh stack checkout <pr-number>を実行する — 回避できない競合解決プロンプトが表示されます。まずgh stack unstack --localを使用してローカルの追跡状態を削除してください(GitHub 上のスタックはそのまま維持されます)。その後、チェックアウトを再試行してください
スタック構造について
スタック内の各ブランチは、独立してレビューできる明確で論理的な作業単位を表す必要があります。ブランチ内の変更には一貫性があり、まとまりとして扱うのが自然で、単一の PR として意味が通るようにしてください。
依存関係の連鎖
スタックされたブランチは依存関係の連鎖を形成し、各ブランチはそのひとつ下のブランチを基盤として構築されます。そのため、基盤となる変更は下位(先行)のブランチに配置し、それに依存するコードは上位(後続)のブランチに配置してください。
コードを書く前に、レイヤーを計画してください。 たとえば、フルスタック機能は次のような構成にできます(この汎用的な例ではなく、実際のタスクに適したブランチ名を使用してください)。
main (trunk)
└── data-models ← shared types, database schema
└── api-endpoints ← API routes that use the models
└── frontend-ui ← UI components that call the APIs
└── integration ← tests that exercise the full stack
これは説明用の例です。作業内容に合わせてブランチ名とレイヤーの境界を選んでください。重要な原則は、あるレイヤーのコードが別のレイヤーのコードに依存する場合、その依存先は同じブランチか、より下位のブランチに含める必要があるということです。
ブランチの命名
各レイヤーの対象を反映する、明確で具体的なブランチ名を選んでください(例:auth、api-routes、frontend)。ブランチ名は init と add に指定したとおりに使われ、何も追加されたり変換されたりしません。スラッシュも使用でき、名前の一部として扱われます(例:gh stack add refactor/foo は refactor/foo という名前のブランチを作成します)。
変更の意図的なステージング
git add と git commit を直接使う主な理由は、どの変更をどのブランチに含めるかを制御することです。作業ツリーに複数のファイルがある場合は、現在のブランチ向けの一部をステージングしてコミットし、その後、新しいブランチを作成して残りをステージングできます。
# You're on data-models with several new files in your working tree.
# Stage only the model files for this branch:
git add internal/models/user.go internal/models/session.go
git commit -m "Add user and session models"
git add db/migrations/001_create_users.sql
git commit -m "Add user table migration"
# Now create a new branch for the API layer and stage the API files there:
gh stack add api-routes # created & switched to the api-routes branch
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
これにより、各ブランチの対象をひとつの懸念事項に絞れます。ブランチごとに複数のコミットがあっても問題ありません。重要なのは、ブランチ内のすべてのコミットが同じ論理的な懸念事項に関係し、別の懸念事項に属する変更は別のブランチに配置されることです。
新しいブランチを作成するタイミング
これまでに構築したものに依存する別の懸念事項に取り組み始めるときは、新しいブランチ(gh stack add)を作成してください。新しいブランチを作成するタイミングの目安は次のとおりです。
- バックエンドの作業からフロントエンドの作業に切り替える
- コアロジックからテストやドキュメントに移る
- 次の変更群のレビュー担当者が異なる
- 現在のブランチの PR がすでにレビューに十分な大きさになっている
1つのスタックで、1つのストーリーを
レビュアーの視点からスタックを考えてみましょう。PR のスタックは、機能やプロジェクトについて一貫したストーリーを伝える必要があります。レビュアーが PR を順番に読んで変更の流れを理解できるようにし、それぞれの PR が全体を構成する小さく論理的な要素になるようにします。
1つのスタックを使う場合: すべてのブランチが同じ機能、プロジェクト、または密接に関連する取り組みの一部である場合です。作業が複数の領域(モデル、API、フロントエンド)にまたがっていても、すべてが同じ目標に向かっているなら問題ありません。
別のスタックを作成する場合: 作業が現在のスタックと無関係な場合です。別の機能、無関係な領域のバグ修正、独立したリファクタリングなどが該当します。複数の作業に取り組んでいるというだけで、無関係な作業を1つのスタックに混在させないでください。取り組みごとに gh stack init で新しいスタックを開始するか、gh stack checkout で既存のスタックに切り替えてください。
気づいた誤字の修正など、小規模で付随的な修正は、些細なものであれば現在のスタックに含めてもかまいません。ただし、変更が独立したプロジェクトに発展した場合は、専用のスタックを作成してください。
クイックリファレンス
| タスク | コマンド |
|---|---|
| スタックを作成する | gh stack init auth |
| 複数のブランチでスタックを作成する | gh stack init auth api frontend |
| 既存のブランチを取り込む | gh stack init existing-branch-a existing-branch-b |
| カスタムのトランクを設定する | gh stack init --base develop branch-a |
| スタックにブランチを追加する | gh stack add api-routes |
| ブランチを追加し、すべてをステージしてコミットする | gh stack add -Am "message" api-routes |
| ブランチをリモートにプッシュする | gh stack push |
| 特定のリモートにプッシュする | gh stack push --remote origin |
| ブランチをプッシュしてドラフト PR を作成する | gh stack submit --auto |
| レビュー可能な状態で PR を作成する | gh stack submit --auto --open |
| 同期する(フェッチ、リベース、プッシュ) | gh stack sync |
| 特定のリモートと同期する | gh stack sync --remote origin |
| 同期してマージ済みブランチを整理する | gh stack sync --prune |
| スタック全体をリベースする | gh stack rebase |
| 上位のスタックのみをリベースする | gh stack rebase --upstack |
| トランクを含めずにリベースする | gh stack rebase --no-trunk |
| コンフリクト後に続行する | gh stack rebase --continue |
| リベースを中止する | gh stack rebase --abort |
| スタックの詳細を表示する(JSON) | gh stack view --json |
| スタック内の上下のブランチに切り替える | gh stack up [n] / gh stack down [n] |
| 最上位/最下位のブランチに切り替える | gh stack top / gh stack bottom |
| スタック番号でチェックアウトする | gh stack checkout 7 |
| PR でチェックアウトする | gh stack checkout 42 |
| ブランチでチェックアウトする(ローカルのみ) | gh stack checkout feature-auth |
| 現在のスタックを解体して再構成する | gh stack unstack |
| 番号を指定して特定のスタックを解体する | gh stack unstack 7 |
| 現在のスタック全体をマージする | gh stack merge --yes |
| 番号を指定してスタックをマージする | gh stack merge 7 --yes |
| 特定の PR までをマージする | gh stack merge 42 --yes |
| 特定の方法でマージする | gh stack merge --yes --squash |
ワークフロー
最初からスタックを作成する:エンドツーエンド
# 1. Initialize a stack with the first branch
gh stack init auth
# → creates auth and checks it out
# 2. Write code for the first layer (auth)
cat > auth.go << 'EOF'
package auth
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// verify token
next.ServeHTTP(w, r)
})
}
EOF
# 3. Stage and commit using standard git commands
git add auth.go
git commit -m "Add auth middleware"
# You can make multiple commits on the same branch
cat > auth_test.go << 'EOF'
package auth
func TestMiddleware(t *testing.T) {
// test auth middleware
}
EOF
git add auth_test.go
git commit -m "Add auth middleware tests"
# 4. When you're ready for a new concern, add the next branch
gh stack add api-routes
# → creates api-routes
# 5. Write code for the API layer
cat > api.go << 'EOF'
package api
func RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("/users", handleUsers)
}
EOF
git add api.go
git commit -m "Add API routes"
# 6. Add a third layer for frontend
gh stack add frontend
# → creates frontend
cat > frontend.go << 'EOF'
package frontend
func RenderDashboard(w http.ResponseWriter) {
// calls the API endpoints from the layer below
}
EOF
git add frontend.go
git commit -m "Add frontend dashboard"
# ── Stack complete: auth → api-routes → frontend ──
# 7. Push everything and create PRs (drafts by default)
gh stack submit --auto
# 8. Verify the stack
gh stack view --json
ショートカット: より速い手順にしたい場合は、
gh stack add -Am "message" branch-nameを使うと、ステージ、コミット、ブランチ作成を1つのコマンドで実行できます。1つのコミットで構成するレイヤーには便利ですが、意図的にステージする手順は省略されます。
スタック途中で変更する
これはエージェントにとって重要なワークフローです。上位レイヤーで作業中に、下位レイヤーで変更が必要だと気づいた場合(たとえば、フロントエンドのコンポーネントを作成中に API エンドポイントを追加する必要が生じた場合)は、適切なブランチに移動してそこで変更し、リベースしてください。
# You're on frontend but need to add an API endpoint
# 1. Navigate to the API branch
gh stack down
# or: gh stack checkout api-routes
# 2. Make the change where it belongs
cat > users_api.go << 'EOF'
package api
func handleGetUser(w http.ResponseWriter, r *http.Request) {
// new endpoint the frontend needs
}
EOF
git add users_api.go
git commit -m "Add get-user endpoint"
# 3. Rebase everything above to pick up the change
gh stack rebase --upstack
# 4. Navigate back to where you were working
gh stack top
# or: gh stack checkout frontend
# 5. Continue working — the API changes are now available
重要な理由: フロントエンドのブランチで API を変更すると、その変更は誤った PR に含まれてしまいます。API の PR には変更が含まれず、フロントエンドの PR には無関係な API の差分が混在します。変更は必ず、論理的に属するブランチに加えてください。
中間ブランチを変更して同期する
ブランチの作成後に見直しが必要な場合(例:レビューのフィードバックへの対応):
# 1. Navigate to the branch that needs changes
gh stack bottom
# or: gh stack checkout auth
# or: gh stack checkout 42 (by PR number)
# 2. Make changes and commit
cat > auth.go << 'EOF'
package auth
// updated implementation
EOF
git add auth.go
git commit -m "Fix auth token validation"
# 3. Rebase everything above this branch
gh stack rebase --upstack
# 4. Push the updated stack
gh stack push
マージ後の定期的な同期
# Single command: fetch, rebase, push, sync PR and stack state
gh stack sync
# Sync and automatically clean up local branches for merged PRs
gh stack sync --prune
エージェント向けの注意: 非対話型環境では、プルーニングの確認プロンプトは表示されません。マージ済み PR のローカルブランチを削除するには、
--pruneを明示的に指定してください。
エージェント向けの注意:
syncは GitHub 上のスタックもローカルにミラーリングします。github.com で PR がスタックに追加されている場合、そのブランチはローカルに取得され、自動的にローカルスタックに追加されます。ローカルとリモートのスタックが分岐している場合(ローカルスタックとリモートスタックがそれぞれ異なる変更を受けた場合)、同期を解決するよう促すことができるのは対話型ターミナルのみです。非対話型環境では同期を中止し(何もプッシュまたは更新されません)、ℹ Sync abortedを表示して正常終了します。分岐を解決するには、スタックを解除して再作成してください。
スカッシュマージからの復旧
GitHub で PR がスカッシュマージされると、元のブランチのコミットはトランクの履歴に残らなくなります。gh stack はこれを自動的に検出し、git rebase --onto を使用して残りのコミットを正しく再適用します。
# After PR #1 (auth) is squash-merged on GitHub:
gh stack sync
# → fetches latest, detects the merge, fast-forwards trunk
# → rebases api-routes onto updated trunk (skips merged branch)
# → rebases frontend onto api-routes
# → pushes updated branches
# → reports: "Merged: #1"
# Verify the result
gh stack view --json
# → auth shows "isMerged": true, "state": "MERGED"
# → api-routes and frontend show updated heads
この処理中に sync で競合が発生した場合、すべてのブランチがリベース前の状態に復元され、終了コード 3 で終了します。解決手順については、リベースの競合を処理する(エージェントのワークフロー)を参照してください。
リベースの競合を処理する(エージェントのワークフロー)
# 1. Start the rebase
gh stack rebase
# 2. If exit code 3 (conflict):
# - Parse stderr for conflicted file paths
# - Read those files to find <<<<<<< / ======= / >>>>>>> markers
# - Edit files to resolve conflicts
# - Stage resolved files:
git add path/to/resolved-file.go
# 3. Continue the rebase
gh stack rebase --continue
# 4. If another conflict occurs, repeat steps 2-3
# 5. If unable to resolve, abort to restore everything
gh stack rebase --abort
--json 出力を解析する
# Get stack state as JSON
output=$(gh stack view --json)
# Check if any branch needs a rebase, and rebase if so
needs_rebase=$(echo "$output" | jq '[.branches[] | select(.needsRebase == true)] | length')
if [ "$needs_rebase" -gt 0 ]; then
echo "Branches need rebase, rebasing stack..."
gh stack rebase
fi
# Get all open PR URLs
echo "$output" | jq -r '.branches[] | select(.pr.state == "OPEN") | .pr.url'
# Find merged branches
echo "$output" | jq -r '.branches[] | select(.isMerged == true) | .name'
# Get the current branch
echo "$output" | jq -r '.currentBranch'
# Check if the stack is fully merged (all branches merged)
echo "$output" | jq '[.branches[] | .isMerged] | all'
スタックを再構成する(ブランチの削除、並べ替え、名前の変更)
unstack を使用してスタックを解除し、構造を変更してから再初期化します。
# 1. Remove the local tracking and the GitHub stack grouping (PRs are NOT deleted)
gh stack unstack
# 2. Make structural changes — e.g. delete a branch, reorder, rename
git branch -m old-branch-1 new-branch-1
# 3. Re-create the stack with the new structure
gh stack init --base main new-branch-1 new-branch-2 new-branch-3
コマンド
スタックを初期化する — gh stack init
新しいスタックを作成します。位置引数としてブランチ名を少なくとも 1 つ必ず指定してください。ブランチ引数を指定せずに実行すると、エージェントが使用できない対話型プロンプトが表示されます。
gh stack init [flags] <branches...>
# Create a stack with a new branch
gh stack init auth
# → creates auth and checks it out
# Create a stack with new branches
gh stack init branch-a branch-b branch-c
# Use a different trunk branch
gh stack init --base develop branch-a branch-b
# Adopt existing branches into a stack (handled automatically if the branches exist)
gh stack init branch-a branch-b branch-c
| フラグ | 説明 |
|---|---|
-b, --base <branch> | トランクブランチ(デフォルトはリポジトリのデフォルトブランチ) |
動作:
- ブランチ名は指定どおりに作成されます(スラッシュは使用でき、そのまま維持されます)
- まだ存在しないブランチを作成します(トランクブランチから分岐)
- 既存のブランチは自動的に採用され、不足しているブランチはトランクから作成されます
- リストの最後のブランチをチェックアウトします
git rerereを有効にして、リベース中の競合解決を記録します。リポジトリでの初回実行時に確認プロンプトが表示される場合があります。プロンプトを回避するには、事前にgit config rerere.enabled trueを設定してください
ブランチを追加 — gh stack add
現在のスタックの上に新しいブランチを追加します。最上位のブランチ上(または、スタックにまだブランチがない場合は trunk 上)で実行する必要があります。必ずブランチ名を指定してください。指定せずに実行すると、対話形式のプロンプトが表示されます。
gh stack add [flags] <branch>
推奨ワークフロー — ブランチを作成してから、標準の git を使用します:
# Create a new branch and switch to it
gh stack add api-routes
# Write code, stage deliberately, and commit
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
# Make more commits on the same branch as needed
git add internal/api/middleware.go
git commit -m "Add rate limiting middleware"
ショートカット — ステージング、コミット、ブランチ作成を 1 つのコマンドで実行します:
# Create a new branch, stage all changes, and commit
gh stack add -Am "Add API routes" api-routes
# Create a new branch, stage tracked files only, and commit
gh stack add -um "Fix auth bug" auth-fix
| フラグ | 説明 |
|---|---|
-m, --message <string> | このメッセージでコミットを作成します |
-A, --all | 未追跡ファイルを含むすべての変更をステージングします(-m が必要です) |
-u, --update | 追跡対象のファイルのみをステージングします(-m が必要です) |
動作に関する注意事項:
-Aと-uは同時に指定できません。- 現在のブランチにコミットがない場合(例:
initの直後)、add -Amは新しいブランチを作成せず、現在のブランチに直接コミットします。 - ブランチ名はそのまま使用されます。
gh stack add refactor/fooはrefactor/fooという名前のブランチを作成します。名前にプレフィックスが付加されたり、変換されたりすることはありません。ブランチ名を指定せずに-mを指定した場合、コミットメッセージから日付+スラッグ形式の名前が自動生成されます(例:03-24-add_api_routes)。 - スタックの最上位ではないブランチから実行すると、終了コード 5 で
"can only add branches on top of the stack"が表示されます。まずgh stack topを使用して切り替えてください。 - 未コミットの変更:
-Amを指定せずにgh stack add branch-nameを実行すると、作業ツリー内の未コミットの変更(ステージング済みまたは未ステージング)は新しいブランチに引き継がれます。これは標準的な git の動作で、作業ツリーには変更を加えません。新しいブランチでクリーンな状態から始めたい場合は、addの実行前に現在のブランチで変更をコミットするか、スタッシュしてください。
ブランチをリモートにプッシュ — gh stack push
アクティブなスタックのブランチをリモートにプッシュします。
gh stack push [flags]
# Push all branches
gh stack push
# Push to specific remote
gh stack push --remote upstream
| フラグ | 説明 |
|---|---|
--remote <name> | プッシュ先のリモート(複数のリモートがある場合に使用します) |
動作:
- アクティブ(マージ済みでもキュー登録済みでもない)なすべてのブランチを、ブランチごとに明示的な
--force-with-leaseチェックを行う、非アトミックな複数 ref のプッシュでプッシュします - あるブランチが拒否されても、別のブランチは更新される場合があります。拒否されたブランチを修正して、コマンドを再実行してください
- プルリクエストの作成や更新は行いません。その場合は
gh stack submitを使用してください
出力(stderr):
Pushed N branchesの概要
ブランチを送信して PR を作成する — gh stack submit
スタック内のすべてのブランチをプッシュし、GitHub に PR を作成します。必ず --auto を指定してください。指定しない場合、submit は新しいブランチごとに PR のタイトルを求めます。
# Submit and auto-title new PRs (required for non-interactive use)
gh stack submit --auto
# Submit and create PRs as ready for review (not drafts)
gh stack submit --auto --open
| フラグ | 説明 |
|---|---|
--auto | プロンプトを表示せずに PR タイトルを自動生成します(非対話型での使用では必須) |
--open | 新規および既存の PR をレビュー可能な状態にします |
--remote <name> | プッシュ先のリモート(複数のリモートがある場合に使用) |
動作:
- アクティブな(マージされておらず、キューにも入っていない)各ブランチを、ブランチごとに明示的な
--force-with-leaseチェックを行いながら順番にプッシュします。submit 全体はアトミックではありません - 後続のブランチのプッシュが拒否された場合、それより前のブランチのプッシュと PR の更新は残ります。拒否の原因を修正し、同じコマンドを再実行してください
- PR がまだない各ブランチに新しい PR を作成します(ベースには、マージされていない祖先ブランチのうち最も近いものを設定します)
- PR の作成後、GitHub 上でそれらを Stack として相互にリンクします(リポジトリでスタックが有効になっている必要があります)
- スタック内のすべての PR がすでにマージされている場合、スタックは完了しており、拡張できません。
submitは未マージのブランチを自動的にフォークして、トランクを起点とする新しいスタックを作成し、GitHub に登録します。マージ済みのスタックには変更を加えません - スタックを利用できない場合(終了コード 9)、そのリポジトリではスタック型 PR が有効になっていません。対話型モードでは、
submitは代わりに通常の(スタック化されていない)PR を作成するかどうかを確認します。非対話型モードでは、終了コード 9 で終了します - すでに PR があるブランチの PR メタデータを同期します
PR タイトルの自動生成(--auto):
- ブランチ上のコミットが 1 つの場合 → コミットの件名を PR タイトルに、コミット本文を PR 本文に使用します
- ブランチ上のコミットが複数の場合 → ブランチ名を読みやすく整形し(ハイフン/アンダースコアをスペースに変換)、タイトルにします
出力(stderr):
- 新しく作成した PR ごとに
Created PR #N for <branch> - 既存の PR ごとに
PR #N for <branch> is up to date Pushed and synced N branchesの概要
ブランチをスタックとしてリンクする(ローカルトラッキングなし)— gh stack link
ローカルのトラッキング状態を作成せずに、GitHub 上で PR をスタックにリンクします。他のツール(jj、Sapling、git-town)でスタックブランチを管理しており、API 経由で GitHub のスタック PR を作成するだけでよい場合に、この方法をおすすめします。
gh stack link [flags] <stack-number | branch-or-pr> <branch-or-pr> [...]
# Link branches into a stack (pushes, creates PRs, creates stack)
gh stack link branch-a branch-b branch-c
# Use a different base branch and mark PRs as ready for review
gh stack link --base develop --open branch-a branch-b branch-c
# Link existing PRs by number
gh stack link 10 20 30
# Add branches to an existing stack of PRs
gh stack link 42 43 feature-auth feature-ui
# Append to the top of an existing stack by its stack number
# (7 is a stack number; only the new PRs/branches are listed)
gh stack link 7 48 feature-auth
最初の引数がスタック番号の場合、残りの引数はそのスタックの最上位に追加されるため、現在の PR を再度列挙する必要はありません。すでにスタックに含まれている引数はスキップされ、別のスタックにある引数は拒否されます。最初の引数が数値の場合、既存のスタックと一致する場合にのみスタックとして扱われます。一致しない場合は、PR またはブランチとして扱われます。
| フラグ | 説明 |
|---|---|
--base <branch> | スタック最下位のベースブランチ(デフォルトはリポジトリのデフォルトブランチ) |
--open | 新規および既存の PR をレビュー可能な状態にする |
--remote <name> | プッシュ先のリモート(複数のリモートがある場合に使用) |
動作:
- 引数はスタックの順序(下から上)で指定します
- 各引数にはブランチ名または PR 番号を指定できます。数値の引数はまず PR 番号として扱われ、その番号の PR が見つからない場合はブランチ名として扱われます
- ブランチの引数はリモートに自動的にプッシュされます(非強制、アトミック)
- オープンな PR がないブランチには、自動生成されたタイトルと適切なベースブランチの連鎖を設定して新しい PR が作成されます(最初のブランチでは
--baseを使用し、以降のブランチでは直前のブランチを使用します) - ベースブランチが想定される連鎖と一致しない既存の PR は、自動的に修正されます
- PR がまだスタックに含まれていない場合は、新しいスタックが作成されます。一部の PR がすでにスタックに含まれている場合は、スタックが更新されます(追加のみ。既存の PR が削除されることはありません)
- ローカル状態の作成や変更は行いません
出力(stderr):
Pushing N branches to <remote>...- 既存の PR があるブランチには
Found PR #N for branch <name> - 新しく作成された PR には
Created PR #N for <branch> (base: <base>) - ベースブランチが修正された場合は
Updated base branch for PR #N to <base> Created stack with N PRsまたはUpdated stack to N PRs
スタックを同期する — gh stack sync
フェッチ、リベース、プッシュ、PR の状態同期を、1 つのコマンドで実行します。日常的な同期に推奨されるコマンドです。
gh stack sync [flags]
| フラグ | 説明 |
|---|---|
--remote <name> | フェッチ元およびプッシュ先のリモート(複数のリモートがある場合に使用) |
--prune | マージ済み PR のローカルブランチを削除します |
実行内容(順番):
- リモートから最新の変更をフェッチします
- リモートスタックを調整します — GitHub 上のスタックをローカルに反映します。GitHub 上でスタックに PR が追加されている場合、そのブランチを取得し、ローカルスタックの末尾に追加します。ローカルとリモートのスタックが分岐している場合、非対話型ターミナルでは同期を中止します。対話型ターミナルでは、分岐を解決するための選択肢(ローカルスタックをリモート版に置き換える、GitHub 上のスタックを削除して再作成できるようにする、またはキャンセルする)を提示します。
- トランクをファストフォワードしてリモートに合わせます(すでに最新の場合はスキップし、分岐している場合は警告します)
- すべてのスタックブランチを更新後の親ブランチにカスケードリベースします(トランクが移動した場合のみ)。マージ済み PR は自動的に処理されます。競合が検出されると、すべてのブランチがリベース前の状態に復元され、コマンドはコード 3 で終了します — 解決手順についてはリベースの競合を処理するを参照してください
- アクティブなブランチをすべてアトミックにプッシュします
- GitHub から PR の状態を同期し、各 PR のステータスを報告します
- スタックオブジェクトを同期します — GitHub 上で、開いている PR をスタックにリンクします。PR がまだスタックに含まれていない場合は新しいスタックを作成し、すでにスタックに含まれている PR がある場合は更新します(追加のみ)。PR が 2 件以上ある場合にのみ実行されます。同期によって PR が作成されることはありません — PR の作成には
gh stack submitを使用してください - プルーン — 対話型ターミナルでは、マージ済み PR のローカルブランチを削除するかどうかを確認します。確認を省略するには
--pruneを使用してください。非対話型環境では、--pruneが明示的に渡された場合のみプルーンが実行されます
出力(stderr):
✓ Fetched latest changes from originPulling N new branches from the remote stack ...の後に✓ Pulled N new branches into the stack from the remote(リモートスタックが先行している場合)⚠ Your local stack has diverged from the stack on GitHub(スタックが分岐している場合。Local:/Remote:のチェーンを含む)ℹ Sync aborted — no changes were made(同期がキャンセルされた場合)✓ Trunk main fast-forwarded to <sha>または✓ Trunk main is already up to date✓ Rebased <branch> onto <base>(ベースが移動した場合、ブランチごと)✓ Pushed N branches✓ PR #N (<branch>) — Open(ブランチごと)Merged: #N, #M(マージ済みブランチ)✓ Stack created on GitHub with N PRs/✓ Stack updated on GitHub with N PRs/✓ Linked to the existing stack on GitHub(PR が 2 件以上ある場合)✓ Pruned <branch> (merged)(プルーンが実行された場合、削除したブランチごと)- GitHub 上のスタックオブジェクトがローカルに合わせて作成または更新された場合は
✓ Stack synced、ブランチのみが同期された場合(PR が 2 件未満、またはスタック型 PR が利用できない場合)は✓ Branches synced
スタックをリベースする — gh stack rebase
リモートからプルし、スタックのブランチを順にリベースします。sync で競合が報告された場合や、より細かく制御したい場合(例:スタックの一部だけをリベースする場合)に使用します。
gh stack rebase [flags] [branch]
# Rebase the entire stack
gh stack rebase
# Rebase only branches from trunk to current branch
gh stack rebase --downstack
# Rebase only branches from current branch to top
gh stack rebase --upstack
# Rebase stack branches without pulling from or rebasing with trunk
gh stack rebase --no-trunk
# After resolving a conflict: stage files with `git add`, then:
gh stack rebase --continue
# Abort and restore all branches to pre-rebase state
gh stack rebase --abort
| フラグ | 説明 |
|---|---|
--downstack | trunk から現在のブランチまでのブランチのみをリベースします |
--upstack | 現在のブランチから最上位までのブランチのみをリベースします |
--no-trunk | trunk をスキップし、スタックのブランチ同士のみをリベースします(フェッチも trunk のリベースもしません) |
--continue | 競合を解決した後に続行します |
--abort | 中止して、すべてのブランチを元に戻します |
--remote <name> | フェッチ元のリモート(複数のリモートがある場合に使用します) |
| 引数 | 説明 |
|---|---|
[branch] | 対象ブランチ(デフォルトは現在のブランチです) |
競合の処理: 解決ワークフローの全体については、ワークフローセクションのリベースの競合を処理するを参照してください。
マージ済み PR の検出: ブランチの PR が GitHub でマージされている場合、リベースは --onto モードを使用して自動的に処理し、マージ先の上にコミットを正しく再適用します。
Rerere(競合の記憶): init によって git rerere が有効になるため、以前に解決した競合は今後のリベースで自動的に解決されます。
trunk を使わないモード: --no-trunk を使うと、リモートからのフェッチと trunk ブランチへのリベースをスキップできます。ブランチ間のリベースのみが実行されます(ブランチ 2 をブランチ 1 に、ブランチ 3 をブランチ 2 にリベースするなど)。アップストリームの変更を取り込まずに、スタックのブランチ同士を揃えたい場合に便利です。
スタックを表示する — gh stack view
現在のスタックのブランチ、PR の状態、最近のコミットを表示します。必ず --json を指定してください。指定しない場合、このコマンドはエージェントが操作できない対話型 TUI を起動します。
# Always use --json
gh stack view --json
| フラグ | 説明 |
|---|---|
--json | スタックのデータを JSON として標準出力に出力します(対話なしで使用する場合は必須です) |
--json の出力形式:
{
"trunk": "main",
"currentBranch": "api-routes",
"branches": [
{
"name": "auth",
"head": "abc1234...",
"base": "def5678...",
"isCurrent": false,
"isMerged": true,
"isQueued": false,
"needsRebase": false,
"pr": {
"number": 42,
"url": "https://github.com/owner/repo/pull/42",
"state": "MERGED"
}
},
{
"name": "api-routes",
"head": "789abcd...",
"base": "abc1234...",
"isCurrent": true,
"isMerged": false,
"isQueued": false,
"needsRebase": false,
"pr": {
"number": 43,
"url": "https://github.com/owner/repo/pull/43",
"state": "OPEN"
}
}
]
}
ブランチごとのフィールド:
name— ブランチ名head— 現在の HEAD SHAbase— 最後に同期した時点での親ブランチの HEAD SHAisCurrent— このブランチがチェックアウトされているかどうかisMerged— PR がマージされているかどうかisQueued— PR がマージ待ちキューに入っているかどうかneedsRebase— ベースブランチが祖先ではないかどうか(非線形の履歴)pr— PR のメタデータ(PR がない場合は省略)。stateは"OPEN"、"MERGED"、または"QUEUED"です。
スタックを移動する
ブランチ名を覚えずにブランチ間を移動します。これらのコマンドは完全に非対話型です。
gh stack up # Move up one branch (further from trunk)
gh stack up 3 # Move up three branches
gh stack down # Move down one branch (closer to trunk)
gh stack down 2 # Move down two branches
gh stack top # Jump to the top of the stack (furthest from trunk)
gh stack bottom # Jump to the bottom (first non-merged branch above trunk)
gh stack trunk # Jump to the trunk branch (e.g. main)
移動範囲はスタックの両端で制限されます。アクティブなブランチから移動する場合、マージ済みのブランチはスキップされます。
スタックをチェックアウトする — gh stack checkout
スタック番号、プルリクエスト番号、PR の URL、またはブランチ名を指定してスタックをチェックアウトします。必ず引数を指定してください。引数なしで gh stack checkout を実行すると、対話型の選択メニューが表示されます。
gh stack checkout <stack-number | pr-number | pr-url | branch>
# By stack number (the identifier shown in the GitHub stack UI)
gh stack checkout 7
# By PR number (pulls from GitHub)
gh stack checkout 42
# By PR URL
gh stack checkout https://github.com/owner/repo/pull/42
# By branch name (local only)
gh stack checkout feature-auth
数字のみを指定した場合は、まずスタック番号(GitHub のスタック UI に表示される識別子)として解決されます。その番号のスタックがない場合は、PR 番号、次にブランチ名として試されます。スタック番号、PR 番号、または PR の URL を指定すると、このコマンドは GitHub 上のスタックをフェッチし、ブランチをプルして、ローカルにスタックを設定します。スタックがすでにローカルに存在し、一致する場合は、そのブランチに切り替えます。
⚠️ エージェントへの警告: ローカルのスタックとリモートのスタックでブランチ構成が異なる場合、このコマンドはフラグで回避できない対話型の競合解決プロンプトを表示します。これを避けるには、まず
gh stack unstack --localを実行して、競合するローカルの追跡状態を削除してください(GitHub 上のスタックはそのまま保持されます)。その後、gh stack checkout <pr-number>を再実行します。
ブランチ名を指定した場合、このコマンドはローカルで追跡されているスタックのみを対象に解決します。対話なしで安全に使用できます。
スタックを解除する — gh stack unstack
スタックを解体して、ブランチの削除や並べ替え、名前の変更、その他の大きな変更を行えるようにします。スタックを解除した後、gh stack init を使って、希望する構成でスタックを再作成します。
スタックの解除で削除されるのはスタックのグループ化のみです(GitHub 上および/またはローカル)。プルリクエストやブランチそのものが削除されることはありません。
引数を指定しない場合、このコマンドはアクティブなスタック(現在チェックアウトしているブランチを含むスタック)を対象とし、GitHub 上でスタックを解除して、ローカルの追跡情報を削除します。
スタック番号を指定すると、GitHub 上の特定のスタックを解除します。リポジトリ内のどこからでも実行でき、スタックがローカルでチェックアウトされているかどうかは問いません。番号を使って GitHub API 経由で直接スタックを解除します(gh stack link と同様に、ローカルの追跡情報は不要です)。スタックがローカルでも追跡されている場合は、ローカルの追跡情報も削除されます。
gh stack unstack [<stack-number>] [flags]
# Tear down the current stack — removes local tracking and the GitHub grouping (PRs are NOT deleted), then rebuild
gh stack unstack
gh stack init --base main branch-2 branch-1 branch-3 # reordered
# Unstack a specific stack by its number, from anywhere in the repo
gh stack unstack 7
# Only remove local tracking (keep the stack on GitHub)
gh stack unstack --local
| フラグ | 説明 |
|---|---|
--local | ローカルでのみスタックを削除します(GitHub 上には残します)。GitHub には接続しません |
エージェント向けの注意:
gh stack unstack <number>はリモートを優先する API ラッパーです。ローカルで追跡されているかどうかにかかわらず、リポジトリ内のどこからでも番号を指定して GitHub 上のスタックを解除でき、非対話型で安全に使用できます。--localは GitHub に接続しません。--localと、ローカルで追跡されていない番号を組み合わせるとエラーになります。不明なスタック番号を指定すると、「GitHub 上に見つかりません」というエラーが返されます(終了コード 2)。
出力規約
- ステータスメッセージは絵文字の接頭辞付きで stderr に出力されます:
✓(成功)、✗(エラー)、⚠(警告)、ℹ(情報)。 - データ出力(例:
view --json)は stdout に出力されます。 - 出力をパイプで渡すとき、データ出力のみが必要であれば
2>/dev/nullを使ってステータスメッセージを抑制してください。
終了コードとエラーからの復旧
| コード | 意味 | エージェントの対応 |
|---|---|---|
| 0 | 成功 | 通常どおり続行します |
| 1 | 一般的なエラー | 詳細について stderr を確認します。コミットまたはプッシュの失敗を示している可能性があります |
| 2 | スタックに属していません | まず gh stack init を実行してスタックを作成します |
| 3 | リベースの競合 | stderr から競合しているファイルパスを解析し、競合を解決して gh stack rebase --continue を実行します |
| 4 | GitHub API の失敗 | gh auth status を確認し、コマンドを再試行します |
| 5 | 無効な引数 | コマンドの呼び出し方を修正します(フラグと引数を確認してください) |
| 6 | 曖昧さの解消が必要 | ブランチが複数のスタックに属しています。まず gh stack checkout <specific-branch> を実行して、共有されていないブランチに切り替えます |
| 7 | リベースがすでに進行中です | 競合を解決した後に gh stack rebase --continue を実行するか、最初からやり直すには gh stack rebase --abort を実行します |
| 8 | スタックがロックされています | 別の gh stack プロセスがスタックファイルを書き込み中です。ロックは 5 秒後にタイムアウトするため、待ってから再試行してください |
| 9 | スタックされた PR を利用できません | このリポジトリではスタックされた PR が有効になっていません。まずリポジトリでスタックを有効にする必要があることをユーザーに伝えてください |
| 10 | Modify からの復旧が必要です | gh stack modify セッションが中断されました。このスキルでは modify を使用しないため、エージェントがこの状態を発生させてはいけません。リポジトリがこの状態になった場合は、gh stack modify --abort を実行して変更前の状態に戻します |
既知の制限事項
- スタックは厳密に線形です。 分岐するスタック(単一の親に複数の子)はサポートされていません。各ブランチは親をちょうど1つ、子を最大1つ持ちます。並行して作業を進める必要がある場合は、別々のスタックを使用してください。
- スタックの曖昧さの解消は回避できません。 現在のブランチが複数のスタックのトランクである場合、コマンドはコード 6 でエラーになります。先に共有されていないブランチにチェックアウトしてください。
- 複数のリモートでは
--remoteまたは設定が必要です。 複数のリモートが設定されている場合は、git 設定でremote.pushDefaultを設定するか、それを受け付けるコマンド(push、submit、sync、rebase、link)に--remote <name>を渡してください。checkout、modify、trunkには--remoteフラグがなく、remote.pushDefaultに依存します。 - リモートスタックのチェックアウトにはスタック番号または PR 番号が必要です。 ブランチ名を指定した
checkoutは、ローカルで追跡されているスタックでのみ機能します。GitHub からスタックを取得するには、スタック番号または PR 番号を使用してください(例:gh stack checkout 7またはgh stack checkout 123)。 - PR のタイトルと本文は自動生成されます。
submit時にカスタムの PR タイトルや本文を設定するフラグはありません。タイトルと本文はコミットメッセージとフッターから生成されます。作成後に PR のタイトルと本文を変更するにはgh pr editを使用してください。