GitHub Stacks CLI(gh stack)がとにかく便利

数珠繋ぎでPRを細かく作成する私にとって、GitHub CLI の拡張 gh stack を実務で試したところ、これがとにかく便利だったので使い方を残しておきます。依存し合う変更を小さなPRに保ちたいのに、Git運用の面倒さが先に立つ。その面倒を根性ではなく仕組みに寄せてくれる道具です。

いままでの数珠繋ぎのPRのデメリット

「基盤の整備」の上に「UI変更」を重ねる、といった依存する変更を私は数珠繋ぎのPRで出してきました。レビューしやすい単位に分ける、という目的自体は正しいのですが、運用には毎回同じつらさがありました。

  • どのブランチがどのbaseブランチから派生しているかがわかりづらい
  • baseブランチを取り込む際に rebase + force push 地獄になる

数珠が3本、4本と伸びると、PR一覧を眺めても依存の順番が読み取れません。基盤側にレビュー指摘が入れば、上に乗る全ブランチを順番に rebase して force push して、PRのbaseがずれていないか確かめて。ここを毎回手作業でやるのが、いちばんのストレスでした。

gh stack を使うとどうなるのか

gh stack は、main から線形に積み上がったブランチの列を stack(依存し合うブランチの束)としてまとめて扱う GitHub CLI 拡張です。導入は拡張を1つ入れるだけ。

gh extension install github/gh-stack

基盤ブランチで stack を始め、その上にUIブランチを重ねて、最後に submit します。

gh stack init --base main feature/a-foundation
# 基盤を実装して git commit
gh stack add feature/b-depends-on-a
# UIを実装して git commit
gh stack submit --auto

これで層ごとのPRがまとめて作られます。基盤PRのbaseはmain、UI側PRのbaseは基盤ブランチ。レビュアには各PRにその層の差分だけが見えるので、「基盤→UI」の順で物語のように読めます。リポジトリ側の設定によっては、GitHub 上でも Stack としてリンク表示されるとのこと。

代表的なコマンド

init / add / submit のほかに、よく使うコマンドはこちら。

gh stack view

stack の状態確認です。今いる stack にどのブランチがどの順で積まれているか、base はどれか、各層の PR リンクと最新コミット、を並べて見せてくれます。「このブランチ、どこから派生したんだっけ」と git log --graph を睨む時間がなくなりました。非対話で使うなら --json、ブランチ名だけ欲しければ --short

別の stack に乗り換えたいときは gh stack checkout です。引数なしで実行すると、ローカルと GitHub 上の stack が一覧で出て、選ぶだけで checkout できる模様。stack 番号や PR 番号を渡して直接切り替えることもできます。

gh stack sync

main が進んだときの全体同期です。fetch して、trunk を最新にし、stack の全ブランチを下から順に積み直し、push して、PR の状態まで揃える。ここまでを1コマンドで済ませます。「他の人の修正が main に入ったから、#A を main に rebase、#B を新しい #A に rebase、それぞれ force push」という一連の作業が丸ごと消えます。

gh stack rebase —upstack

下の層を直した直後に、その上の層だけを新しい土台に載せ直すコマンドです。基盤PRにレビュー指摘対応のコミットを足したら、これで上の層に取り込みます。

sync との使い分けは「何が動いたか」で決めます。

  • main が動いた → gh stack sync(trunk 込みで全体を揃える)
  • 自分が下の層にコミットを足した → gh stack rebase --upstackgh stack push(上だけ載せ直す)

下層のコミット追加だけなら rebase --upstack の方が意図が明確で、余計な fetch や PR 同期も走りません。

push は必ず gh stack push で

stack しているブランチに対して、いつもの癖で git push してしまわないよう注意が要ります。rebase --upstack のあとは上の層の tip も動いているのに、git push が押すのは今 checkout している1ブランチだけ。上の層はリモートに反映されないまま取り残され、PR の差分や base がずれた状態になります。

gh stack push なら stack 内の全ブランチを --force-with-lease 付きでまとめて押してくれるので、rebase --upstack とセットで覚えてしまうのが安全です。

gh stack rebase --upstack   # 上の層を載せ直す
gh stack push               # 上の層まで含めて一括 push(git push は使わない)

私は stack で作業中は git push を封印して、push は常に gh stack push にしています。

ちなみにコミットは普通の git add / git commit です。gh stack commit のようなコマンドはなく、gh stack が引き受けるのは層の移動・一括push・PR作成・rebaseといった「stackならではの面倒」だけ。覚えることが少なくて、これは助かります。

下の層だけ直したいとき

上の rebase --upstack を実際の流れに置くとこうなります。「基盤PRにレビュー指摘が来た。修正をUI側にも取り込みたい」という、数珠繋ぎでいちばん面倒だった場面です。

gh stack bottom             # いちばん下の層へ移動
git commit -am "fix: レビュー指摘対応"
gh stack rebase --upstack   # 上の層を新しい土台に載せ直す
gh stack push               # stack一式をまとめてpush

手動なら force-push まみれになる作業が、この4行で終わります。

私は普段からコミット履歴を rebase 中心できれいに保ちたい派です。その「きれいさ」を維持するコストを人間の注意力ではなくコマンドに寄せられるのが、この道具の本質だと考えています。

ちなみに worktree を層ごとに分ける必要はなく、1つの作業ディレクトリで gh stack up / down と層を行き来すれば足ります。

引っかかりやすい点は3つほど。リポジトリ側で Stacked PRs の設定が有効になっていないと submit が stack を組めない場合があります。CI やエージェントから使うときは --auto--json を付けて対話プロンプトを避ける。マージは個別の gh pr merge ではなく、下の層から gh stack merge で進めるのが想定経路です。

AI エージェントにも同じ手順を覚えさせる

gh stack はエージェント向けの skill も同じリポジトリで配っています。GitHub CLI の gh skill コマンド(プレビュー機能)で入れられます。

gh skill install github/gh-stack

これで、Claude Code や Codex、Cursor などのコーディングエージェントが「stack をどう切るか」「submit には --autoview には --json を付けて対話プロンプトを避ける」といった作法を知った状態で gh stack を扱えるようになります。置き場所は --agent(claude-code / codex / cursor など)と --scope(project / user)で選べる模様。

私は Claude Code に実装を任せることが増えているので、こういう「人間が覚える運用ルールを、そのままエージェントにも配れる」形はありがたいです。自分で SKILL を書くまでもなく、公式が README とセットで面倒を見てくれるぶん、運用ルールが古びにくい。

数珠繋ぎのPRを普通のフローにする

依存の順番が見えづらい、baseを取り込むたびに rebase + force push。数珠繋ぎのPRにつきものだったこの2つの面倒は、gh stack を試してみて「依存するブランチ列を手で管理していたから」だったと感じています。そこを仕組みに寄せてしまえば、小さなPRの積み上げは普通の開発フローになる。

依存する変更が生まれた次の機能開発で、まず2層だけの stack から試してみてください。

出典