Git入門:バージョン管理のきほん

プルリクエストを出す

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

このレッスンで分かること

  • プルリクエストが「変更を取り込んでほしい」という依頼であること
  • ブラウザと gh pr create の両方で作る手順
  • レビューされやすい粒度と説明文の書き方、Draft の使いどころ

プルリクエストは変更の取り込み依頼

前のレッスンまでで、ローカルのブランチを GitHub 上のリモートリポジトリに push できるようになりました。リモートリポジトリとは、GitHub 側に置かれたリポジトリの実体のことです。

ただし push しただけでは、その変更は本流のブランチに入りません。main は多くのチームで直接触らないよう保護されていて、変更を入れるには「このブランチの変更を main に取り込んでください」と申請する必要があります。この申請がプルリクエスト(Pull Request、略して PR)です。

プルリクエストは Git の機能ではなく GitHub の機能です。ローカルの Git だけを使っている限り出てきません。役割は次の 3 つです。

役割何が起きるか
差分の提示取り込み先との差分がファイル単位で並ぶ
議論の場行ごとにコメントを付けて相談できる
実行の入口承認後にボタン 1 つでマージできる

つまりプルリクエストは、マージという操作の前に「見せて、話して、決める」時間を挟むための仕組みです。

プルリクエストを作る

作り方は 2 通りあります。ブラウザから作る方法と、ターミナルから gh コマンドで作る方法です。できあがるものは同じなので、好きなほうを使ってください。その前に、まずブランチを push しておきます。

まずブランチを push する

プルリクエストを作るには、先に作業ブランチをリモートへ送っておきます。ここでは feature/login-form というブランチで作業していたとします。

ターミナル

$ git switch -c feature/login-form $ git add . $ git commit -m "ログインフォームの見た目を追加" $ git push -u origin feature/login-form

origin は、clone したときに自動で付くリモートリポジトリの名前です。-u は「このローカルブランチは origin の同名ブランチと対応します」と覚えさせるオプションで、次からは git push だけで送れます。

push が成功すると、ターミナルに次のような案内が出ます。

プレーンテキスト

remote: Create a pull request for 'feature/login-form' on GitHub by visiting: remote: https://github.com/your-name/your-repo/pull/new/feature/login-form

この URL をそのまま開けば、プルリクエストの作成画面に飛べます。

push する前に git status で、意図しないファイルが混ざっていないか確認してください。設定ファイルや個人用のメモが一緒に入ってしまうと、レビューする側は本題の差分を見つけられなくなります。

ブラウザから作る

GitHub のリポジトリページを開くと、最近 push したブランチについて Compare & pull request という緑のボタンが上部に出ます。これを押すと作成画面が開きます。

ボタンが見当たらないときは、リポジトリの Pull requests タブから New pull request を押し、比較するブランチを自分で選びます。画面の上部に取り込み先と取り込み元の 2 つが並ぶので、左が main、右が feature/login-form になっているか必ず確認してください。この 2 つは逆向きにも作れてしまいます。

その下に差分が表示されます。ここで自分の変更をひととおり読み返します。他人にレビューを頼む前の自己レビューで、書きかけのコードや消し忘れたデバッグ用の出力はたいてい見つかります。

タイトルと説明を書いて Create pull request を押せば完成です。

gh pr create で作る

ターミナルから離れずに作りたいときは GitHub CLI(gh コマンド)を使います。ブラウザで作るのと結果は同じです。

インストールは Mac なら Homebrew、Windows なら winget が手軽です。

ターミナル

# Mac $ brew install gh # Windows (PowerShell) > winget install --id GitHub.cli

初回だけログインします。

ターミナル

$ gh auth login

あとは作業ブランチにいる状態で次を実行します。

ターミナル

$ gh pr create --base main --title "ログインフォームを追加" --body "ログイン画面の入力フォームを追加しました。バリデーションは次のPRで対応します。"

--base が取り込み先のブランチです。省略するとリポジトリの既定ブランチが使われます。オプションを付けずに gh pr create だけを打つと、対話形式でタイトルと本文を順に聞かれます。

作成後によく使うコマンドをまとめます。

コマンド何をするか
gh pr createプルリクエストを作る
gh pr view --web作った PR をブラウザで開く
gh pr status自分に関係する PR の状態を一覧する
gh pr checksCI の実行結果を見る
gh pr readyDraft を通常の PR に切り替える

レビュアーを指名する

PR を作っただけでは、誰も気づかないことがあります。右側のサイドバーにある Reviewers から、見てほしい人を指名してください。指名するとその人に通知が届きます。

CLI からも指定できます。

ターミナル

$ gh pr create --reviewer taro,hanako --assignee @me

--assignee は担当者、つまりこの PR を進める責任がある人です。自分を指す @me を入れておくと、あとから一覧で自分の PR を探しやすくなります。

Labels でラベルを付けておくのも役に立ちます。bugdocumentation のような分類のほか、WIP(作業中)や needs-discussion(相談したい)を用意しているチームもあります。

指名は 1〜2 人に絞ってください。5 人に頼むと、全員が「他の誰かが見るだろう」と思って誰も見ません。責任の所在をはっきりさせたほうが早く返ってきます。

粒度は「1 つの PR で 1 つの目的」

プルリクエストで最も差が出るのは、コマンドではなく大きさです。

レビューできる差分の量には限界があります。数百行を超えたあたりから、読む側は 1 行ずつ追うのをやめて雰囲気で承認しはじめます。そうなった PR はレビューを通ったように見えて、実際には誰も検証していません。

目安として、次の状態を目指します。

  • 変更が 1 つの目的に絞られている
  • 差分が 400 行を大きく超えない
  • タイトルを「〜と〜をやりました」と書かずに済む

タイトルに「と」が 2 回出てきたら、PR を分ける合図です。

よくある失敗

ここで実際にありがちな失敗を 1 つ挙げます。ログインフォームを作っている途中で、既存コードのインデントがそろっていないのが気になり、ついでにフォーマッタを全ファイルにかけてしまうケースです。

その結果、差分は 2,000 行になります。本題であるログインフォームの 80 行は、書式だけの変更 1,900 行に埋もれて誰にも読まれません。

こうなったときは、いったん機能側だけを取り出します。

ターミナル

$ git switch main $ git switch -c feature/login-form-only $ git cherry-pick a1b2c3d

cherry-pick は特定のコミットだけを別のブランチに移す操作です。詳しくは 必要なコミットだけ取り込む(cherry-pick) で扱っています。書式だけの変更は別 PR に切り出し、「これは自動整形のみで挙動の変更なし」と説明を添えれば、レビューは一瞬で終わります。

混ぜないための一番の対策は、作業を始める前にブランチを分けることです。整形したくなったら、その場でやらずにメモしておき、あとで別ブランチを切ります。

説明文に何を書くか

説明文の目的は、レビュアーが差分を読む前に文脈をそろえることです。コードを見れば分かることは書かず、コードを見ても分からないことを書きます。

書くべき項目は次の 4 つです。

  1. 何のための変更か — 対応する Issue 番号やチケットへのリンク
  2. 何を変えたか — 主要な変更点を 2〜4 行の箇条書きで
  3. どう確認したか — 動かした手順、確認した画面、通したテスト
  4. レビューで見てほしい点 — 迷った設計判断、意見が欲しい箇所

逆に書かなくていいのは、変更したファイル名の羅列です。それは GitHub が勝手に表示します。

実際の例を挙げます。

プレーンテキスト

## 目的 Issue #142 のログイン画面を実装する ## 変更点 - LoginForm コンポーネントを追加 - メールアドレスとパスワードの入力欄、送信ボタンを配置 - 送信処理はまだ未接続(次のPRで対応) ## 確認したこと - ローカルで /login を開き、入力と送信ボタンの活性状態を確認 - 既存のテストが全て通ることを確認 ## 見てほしい点 - フォームの状態管理を useState でやっていますが、 他画面と合わせるなら別の方法のほうがよいでしょうか

チームによっては、この形をテンプレートとして .github/pull_request_template.md に置いています。そのファイルがあると、新規 PR の説明欄に自動で内容が入ります。

Draft はいつ使うか

Draft pull request は「作業途中なのでまだレビューしないでください」という状態の PR です。作成画面の Create pull request ボタンの横にある下向き矢印から Create draft pull request を選ぶと作れます。CLI なら --draft を付けます。

ターミナル

$ gh pr create --draft --title "検索機能の下書き"

Draft には次の性質があります。

  • マージボタンが押せない(誤マージを防げる)
  • レビュアーへの通知が飛ばない
  • CI は通常どおり動く

使いどころは主に 3 つです。1 つ目は、方向性が合っているか早めに相談したいとき。骨組みだけ作って Draft で出し、「この設計で進めていいですか」と聞けば、完成後に全部書き直す事故を防げます。

2 つ目は、CI を回したいだけのとき。手元では通るのに CI では落ちる、という状況を調べたいときに便利です。

3 つ目は、大きな作業の進捗を見えるようにしておきたいときです。

準備ができたら Ready for review ボタン、または gh pr ready で通常の PR に切り替えます。

作業が終わっているのに Draft のまま放置すると、誰も気づかないまま止まります。Draft は「今は見なくていい」という意思表示なので、終わったら必ず切り替えてください。

マージの 3 つの方式

レビューが通ると、Merge pull request ボタンが押せるようになります。このボタンには下向き矢印が付いていて、3 つの方式から選べます。履歴の残り方が変わるので、違いを押さえておきます。

方式履歴への入り方
Create a merge commitブランチのコミットがそのまま入り、マージコミットが 1 つ足される
Squash and mergeブランチのコミットが 1 つにまとめられて入る
Rebase and mergeブランチのコミットが main の先端に並べ直されて入る

多くのチームが Squash and merge を既定にしています。作業中の「typo 修正」「レビュー指摘対応」といった細かいコミットが main の履歴に残らず、PR 1 つが 1 コミットとして並ぶからです。あとから履歴を追うとき、PR 単位で読めるのは大きな利点です。

逆に、1 つの PR の中でコミットを意味のある単位に分けて作ってあるなら、Create a merge commit でそのまま残す価値があります。マージの仕組みそのものは マージの仕組み(fast-forward と マージコミット) で扱いました。

マージが終わったら、画面に出る Delete branch ボタンでリモートのブランチを消します。役目を終えたブランチを残しておくと、ブランチ一覧が読めなくなります。手元のブランチも掃除しておきます。

ターミナル

$ git switch main $ git pull $ git branch -d feature/login-form

-d はマージ済みのブランチだけを消すオプションです。まだマージされていないブランチを指定すると、Git が警告して止めてくれます。

この章のポイント
  • プルリクエストは GitHub の機能で、ブランチの変更を取り込んでもらうための依頼
  • ブラウザでも gh pr create でも作れる。取り込み先と取り込み元の向きだけは必ず確認する
  • 1 つの PR に 1 つの目的だけを入れる。書式の一括変更は必ず別 PR にする
  • 説明文には目的・変更点・確認方法・見てほしい点を書く。相談したい段階なら Draft で出す