コードを書いているのはエディターとターミナルなのに、プルリクエストを出すときだけブラウザに移る。タブを探し、リポジトリのページを開き、「Compare & pull request」のボタンを押し、タイトルと説明を書き直し、レビューをお願いする相手を選ぶ。一つひとつは数十秒の作業でも、1日に何度も繰り返すと、そのたびに頭の中で組み立てていた続きが途切れてしまう。私が気になっていたのは、時間そのものより、この途切れのほうだった。
GitHub CLI、コマンド名で言えば gh は、GitHub が公式に配布しているコマンドラインの道具だ。git が手元のリポジトリと遠くのリポジトリのあいだで履歴をやり取りする道具だとすれば、gh はその外側にある GitHub 独自の仕組み、つまりプルリクエスト、イシュー、Actions の実行結果、リリースといったものをターミナルから扱うための道具になる。git の代わりではなく、git の隣に置いて使う。
この記事では、朝にブランチを切ってプルリクエストを出し、昼に CI の結果を待ち、午後にレビューをやり取りして、夕方にマージするまでの一日を、gh のコマンドだけでたどっていく。最後に、毎日使うための短縮の設定と、それでもブラウザを開いたほうが早い場面もまとめておく。
準備はインストールとログインの2つだけ

インストールは、Windows なら winget install --id GitHub.cli、macOS なら brew install gh の1行で終わる。Linux でも主要なディストリビューション向けのパッケージが用意されている。入れ終わったら gh --version で版を確かめておく。gh は数週間おきに新しい版が出るので、手順の説明と手元の動きが違うと感じたら、まず版を新しくするのが近道だと思う。
次にログインする。gh auth login を実行すると、どの GitHub につなぐか、git の通信に HTTPS と SSH のどちらを使うかを順に聞かれる。認証の方法は、ブラウザでの承認を選ぶのが手軽だ。ターミナルに8文字の確認コードが表示され、ブラウザで GitHub の承認画面を開いてそのコードを入れると、ログインが完了する。ブラウザを使うのはこの一度だけで、受け取った認証情報は OS の資格情報の保管場所にしまわれる。
ログインできたかどうかは gh auth status で確かめられる。どのアカウントで、どこに認証情報が置かれているかが表示される。あわせて gh auth setup-git を一度実行しておくと、git の push や pull でも gh の認証情報が使われるようになり、パスワードやトークンを毎回聞かれることがなくなる。サーバーや自動化の仕組みの中で使うときは、ログインの代わりに環境変数 GH_TOKEN にトークンを入れておけば、gh はそれを読んで動く。
朝、ブランチを切ってgh pr createを打つ
一日の始まりは、いつもの git の操作からだ。既定のブランチを最新にしてから、作業用のブランチを切る。
git switch main
git pull
git switch -c fix/login-timeout
コードを直してコミットしたら、ここで初めて gh を使う。
gh pr create --fill
--fill は、コミットの情報からプルリクエストのタイトルと本文を自動で埋める指定だ。コミットが1つならそのメッセージの1行目がタイトルに、残りが本文になる。コミットが複数あるときは、ブランチ名がタイトルになり、本文にはコミットの一覧が並ぶ。複数のコミットがあっても最初のコミットの内容を使いたいなら --fill-first、すべてのコミットのメッセージと本文をまとめて説明に入れたいなら --fill-verbose を選ぶ。--fill と一緒に --title や --body を渡した場合は、そちらが優先される。
ブランチをまだ push していなくても困らない。gh はブランチが遠くのリポジトリに届いていないことに気づくと、どこへ push するかを聞いてきて、そのまま push してからプルリクエストを作る。成功すると、作られたプルリクエストの URL が1行表示される。何も指定せずに gh pr create とだけ打てば、タイトル、本文、追加の設定を順に対話形式で聞いてくれるので、最初のうちはこちらから始めるのもよい。
よく一緒に使う指定は次のようなものだ。
gh pr create --fill --draft --reviewer tanaka,myorg/backend --assignee @me --label bug
--draft は下書きのプルリクエストとして作る指定で、まだレビューしてほしくない段階で CI だけ先に回したいときに便利だ。--reviewer にはレビューをお願いする人やチームをカンマ区切りで並べ、--assignee @me で自分を担当者にし、--label でラベルを付ける。マージ先のブランチは --base で変えられ、指定しなければリポジトリの既定のブランチになる。本文に Fixes #123 と書いておけば、マージしたときに123番のイシューが自動で閉じられる。
本文を長めに書きたいときは、--body-file でファイルから読み込むか、--editor でいつものエディターを開いて書く。エディターでは1行目がタイトル、残りが本文として扱われる。作る前に中身を確かめたいなら --dry-run を付けると、プルリクエストを作らずに内容だけを表示してくれる。ただし、ブランチの push は行われることがあるので、そこだけは注意しておきたい。
昼、CIの結果をgh pr checksで待つ

プルリクエストを出すと、リポジトリに設定されたテストやビルドが動き出す。昼食から戻ってきたころには終わっているはずだが、結果を見るためだけにブラウザを開く必要はない。gh pr checks を打てば、いまのブランチに結びついたプルリクエストの CI の一覧が、成功、失敗、実行中に分けて表示される。番号を指定しなくても、今いるブランチから対象のプルリクエストを見つけてくれるのが gh の便利なところだ。
終わるまで待ちたいなら --watch を付ける。10秒ごとに表示が更新され、すべての CI が終わった時点でコマンドも終わる。更新の間隔は --interval で秒単位に変えられる。一つでも失敗したらすぐに知りたいときは --fail-fast を足すと、最初の失敗の時点で待つのをやめてくれる。必須の CI だけを見たいなら --required で絞り込める。
このコマンドは終わり方で結果を返すので、ほかのコマンドとつなげるのにも向いている。すべて成功すれば終了コードは0、失敗があれば1、まだ実行中のものが残っていれば8になる。たとえば gh pr checks --watch && gh pr ready と書いておけば、CI が全部通った時点で下書きを「レビュー待ち」に切り替える、という段取りが1行で組める。
失敗していた場合は、どの手順で落ちたかを確かめる。gh run list で最近の実行の一覧を出し、該当する実行の番号を gh run view に渡す。--log-failed を付けると、失敗した手順のログだけが表示される。長い成功ログの中から赤い行を探す手間が省けるので、私はここがいちばん助かっている。直してコミットし、もう一度 push すれば、CI はまた最初から走り出す。
自分に関係するプルリクエストをまとめて眺めたいときは gh pr status が便利だ。今のブランチのプルリクエスト、自分が作ったもの、自分にレビューが求められているものが分かれて表示され、それぞれの CI とレビューの状況も一緒に見える。朝いちばんと昼休み明けにこれを打つのが、一日の区切りになっている。
午後、レビューをもらい、レビューを返す

レビューの返事が届いたら、gh pr view --comments で読む。プルリクエストのタイトル、本文、状態に続いて、付いたコメントが時間順に表示される。指摘に合わせて直したら、そのブランチにコミットして push するだけで、プルリクエストの中身も新しくなる。レビューをお願いする相手を増やしたいときは gh pr edit --add-reviewer suzuki、ラベルを足すなら gh pr edit --add-label urgent のように、作ったあとのプルリクエストも gh から書き換えられる。返事を書くときは gh pr comment --body "修正しました" で一言残せる。
下書きで出していたなら、準備が整った時点で gh pr ready を打つと、レビュー待ちの状態に切り替わる。逆に、もう少し手を入れたくなったら gh pr ready --undo で下書きに戻せる。
今度は自分がほかの人のプルリクエストを見る番だ。gh pr list で開いているプルリクエストの一覧を出し、気になる番号を gh pr diff 128 に渡すと、差分がターミナルに表示される。変更が大きいときは、先に gh pr diff 128 --name-only で変わったファイルの名前だけを確かめておくと、どこから読むかの見当がつく。
差分を読むだけでなく手元で動かしたいときは、gh pr checkout 128 を使う。そのプルリクエストのブランチが手元に取り込まれて、そこへ切り替わる。ほかの人が自分のフォークから出したプルリクエストでも、遠くのリポジトリを自分で追加する必要はない。今の作業を中断したくないなら --worktree に別のフォルダーを指定すると、作業フォルダーを分けて取り込める。
読み終えたら gh pr review で結果を返す。問題がなければ gh pr review 128 --approve、直してほしい点があれば gh pr review 128 --request-changes --body "エラー時の戻り値を確認してください"、どちらとも決めずに意見だけ残すなら --comment を使う。なお、GitHub では自分が出したプルリクエストを自分で承認することはできないので、一人で運用しているリポジトリでは承認の手順を飛ばしてマージすることになる。
夕方、gh pr mergeで取り込んで片付ける
レビューの承認がそろい、CI もすべて通ったら、マージする。
gh pr merge --squash --delete-branch
取り込み方は3つから選ぶ。--merge はコミットをそのまま残してマージコミットを作り、--squash はプルリクエストのコミットを1つにまとめてから取り込み、--rebase はコミットを既定のブランチの上に並べ直す。指定しなければ対話形式で聞かれる。小さな修正を細かくコミットしていくやり方なら、--squash にしておくと既定のブランチの履歴が読みやすくなると思う。
--delete-branch を付けると、マージのあとで手元と遠くのリポジトリの両方から作業用のブランチが消え、手元は既定のブランチに切り替わる。ブランチの消し忘れは、溜まってくると一覧が読めなくなるので、私は毎回この指定を付けている。切り替わったあとは念のため git pull を打ち、手元の既定のブランチを最新にしてから次の作業に移る。
CI がまだ走っている途中なら、--auto を付けておく手もある。必要な条件がそろった時点で自動的にマージされるので、結果を待たずに帰り支度を始められる。ただし、この機能はリポジトリの設定で自動マージが許可されている必要がある。マージキューを使っているブランチでは取り込み方の指定は要らず、条件を満たした時点でキューに並ぶ。管理者の権限で条件を無視してマージする --admin もあるが、これはよほどの事情があるときだけにしておきたい。
毎日使うなら、エイリアスとエディターを決めておく
同じ指定を毎日打つなら、短い名前を付けておくと楽になる。gh にはエイリアスの仕組みがあり、たとえば次のように登録できる。
gh alias set prc 'pr create --fill --assignee @me'
gh alias set mine 'pr list --author @me'
これで gh prc と打てばプルリクエストが作られ、gh mine で自分のプルリクエストの一覧が出る。$1 のように引数を受け取る書き方もでき、パイプでほかのコマンドにつなぎたいときは --shell を付けて登録する。
本文やコメントを書くときに開くエディターは gh config set editor "code --wait" のように決めておく。--wait を付けておかないと、VS Code が開いた瞬間に gh が「書き終わった」と判断してしまうので注意したい。表示が長いときにページ送りをさせたいなら、gh config set pager less でページャーも指定できる。
最初からすべてを覚える必要はないと思う。gh pr create --fill、gh pr checks --watch、gh pr merge --squash --delete-branch の3つだけで、一日の流れのほとんどはブラウザなしで回る。残りは、必要になったときに gh pr --help で一覧を見れば足りる。
ブラウザを開いたほうが早い場面もある
ここまでターミナルだけで回す話をしてきたが、ブラウザを完全に閉じる必要はない。gh のレビューのコマンドが受け付けるのはプルリクエスト全体へのコメントで、特定の行を指して意見を書くやり方には向いていない。行ごとに細かく指摘したいときや、数十のファイルにまたがる大きな差分を見比べたいときは、ブラウザの画面のほうが速く正確に読める。画像やデザインの変更も、ターミナルでは確かめようがない。
そういう場面のために、gh の多くのコマンドには --web という指定がある。gh pr view --web を打てば、そのプルリクエストのページがブラウザで直接開く。リポジトリのページを開いて一覧から探す手間がないので、ブラウザに移るときも寄り道をせずに済む。
ターミナルで済ませるか、ブラウザに移るか。その線引きは人それぞれだと思うが、私は「定型の操作はターミナル、目で比べる作業はブラウザ」と分けている。毎日同じ順番で繰り返すことは gh に任せ、考えながら読む必要があるものだけをブラウザに残す。そうしておくと、ブラウザを開く回数そのものが、その日に頭を使った回数の目安になるのが面白いところだ。
関連記事
- GitHub Actionsの最初の1本は、pushで動かすか時刻で動かすかを決めるところから(プルリクエストで走るCIを自分で書くとき)
- git worktreeで作業フォルダをブランチの数だけ持つ、stashと切り替えをやめるための備忘録(gh pr checkoutの–worktreeと組み合わせるとき)
- VS CodeのDev ContainersでPCを汚さない開発環境を作る、devcontainer.jsonは4行から
- Pythonの仮想環境、venvとuvの違いは「箱」と「記録」の分担にある
- GitHub Pages で技術・理論記事を読む
- Amebaブログ版はこちら
- 今夜はウイスキー・カルチャーの記事やジャズ・映画のエッセイも公開予定です → note はこちら