GitHubを使い始めると、かなり早い段階で「プルリクエスト」と「マージ」という言葉に出会う。
そして厄介なのが、この2つがセットで使われることだ。
「プルリクエストを出したら、もう変更されたの?」
「マージすると何が起きる?」
「プルリクエストとマージって、ほぼ同じ意味では?」
最初はこう思って当然だ。
しかし、プルリクエストとマージはまったく別の作業である。
簡単に言えば、
プルリクエスト=変更を取り込んでほしいという提案
マージ=その変更を実際に取り込むこと
だ。
この違いさえ分かれば、GitHubの操作はかなり理解しやすくなる。逆にここを曖昧なまま使うと、「変更したはずなのにmainに入っていない」という、GitHub初心者あるあるに突入する。
GitHub公式でも、プルリクエストはあるブランチから別のブランチへ変更をマージするための「提案」と説明されている。
プルリクエストとは?
「この変更を取り込んでください」という提案
プルリクエストは英語で「Pull Request」、略して「PR」と呼ばれる。
難しそうな名前だが、やっていることはかなり単純だ。
たとえばWebサイトを開発していて、現在の正式版が「main」というブランチにあるとする。
新しい機能を追加するとき、いきなりmainを書き換えるのは危険だ。
そこで、
main
│
└── feature-login
│
└── ログイン機能を開発
というように、別のブランチを作って作業する。
ログイン機能が完成した。
そこで、
feature-login の変更を
main に入れてください
と提案する。
これがプルリクエストだ。
GitHub公式でも、プルリクエストはコード変更をプロジェクトへマージするための提案であり、マージする前に変更について話し合ったりレビューしたりする場所として使われている。
つまり、
プルリクエストを作っただけでは、mainの中身はまだ変わらない。
ここはかなり重要だ。
プルリクエストでは変更内容を確認できる
プルリクエストを作ると、GitHub上で変更内容を確認できる。
たとえば、
- どのファイルを変更したか
- どのコードを追加したか
- どのコードを削除したか
- どんなコミットをしたか
- 自動テストに成功したか
- 他の人からどんなレビューを受けたか
などを確認できる。
GitHubでは「Conversation」「Commits」「Checks」「Files changed」などに情報が分けられている。
特に便利なのが「Files changed」だ。
変更前と変更後を比較できるので、
「関係ないコードまで消していないか?」
「本当にこの変更だけで大丈夫か?」
と確認してから正式版へ反映できる。
いきなり本番を書き換えるより、はるかに安全だ。
マージとは?
複数の変更を1つに統合すること
マージは英語の「merge」で、日本語では「統合する」「合体する」といった意味になる。
GitHubやGitでは、
あるブランチの変更を、別のブランチへ取り込むこと
をマージと呼ぶ。
先ほどの例なら、
変更前
main
│
└── feature-login
└── ログイン機能完成
プルリクエストを確認して問題がなければ、feature-loginをmainへマージする。
マージ後
feature-login
│
└─────┐
↓
main ───── ログイン機能追加
これで初めて、ログイン機能がmainへ入る。
つまり流れとしては、
コードを変更
↓
プルリクエスト
↓
内容を確認
↓
マージ
↓
mainに変更が入る
となる。
プルリクエストは確認するための入口であり、マージが実際の統合作業だ。
ここを分けて考えると分かりやすい。
プルリクエストとマージの違い
両者の違いを表にすると、かなり単純になる。
| 項目 | プルリクエスト | マージ |
|---|---|---|
| 英語 | Pull Request | Merge |
| 略称 | PR | 特になし |
| 意味 | 変更を取り込む提案 | 変更を実際に統合する |
| mainへの反映 | まだされない | 反映される |
| レビュー | できる | 基本的にはレビュー後に実行 |
| 目的 | 確認・相談・提案 | 変更を確定する |
たとえるなら、会社で書類を提出するときに近い。
プルリクエスト
=「この内容で進めていいですか?」
レビュー
=「内容を確認します」
マージ
=「OK。この内容を正式版にします」
こんなイメージだ。
プルリクエストを作っただけで仕事が終わったと思うと、永遠に正式版へ入らない。GitHubはそこまで人間の意図を察してはくれない。
プルリクエストからマージまでの流れ
1. ブランチを作る
まずmainとは別に、作業用のブランチを作る。
たとえばログイン機能なら、
feature-login
バグ修正なら、
fix-login-error
といった名前を付ける。
ブランチを分けることで、mainを壊さずに作業できる。
2. コードを変更してコミットする
作業用ブランチでコードを変更する。
変更内容をGitへ記録する作業が「コミット」だ。
たとえば、
ログイン画面を追加
という変更をコミットする。
必要なら複数回コミットしても構わない。
3. GitHubへPushする
ローカルPCだけにある変更をGitHubへ送る。
これがPushだ。
流れはこうなる。
PCで変更
↓
Commit
↓
Push
↓
GitHub
4. プルリクエストを作成する
GitHubへPushすると、変更したブランチからmainに対してプルリクエストを作れる。
ここで、
- 何を変更したのか
- なぜ変更したのか
- 確認してほしい部分
- テストした内容
などを書いておく。
自分一人で開発している場合でも、変更内容を後から確認しやすくなる。
GitHub公式でも、ブランチで変更し、コミットし、プルリクエストを開き、レビューしたあとにマージする流れが基本として紹介されている。
5. 内容をレビューする
プルリクエストを開いたら、変更したファイルを見る。
ここでミスを見つければ修正する。
チーム開発なら別の人が、
「この処理は大丈夫?」
「ここはもっと簡単にできる」
などとコメントすることもある。
自動テストを設定していれば、テスト結果も確認できる。
6. 問題なければマージする
レビューやテストで問題がなければマージする。
これで作業ブランチの変更がmainへ入る。
ブランチ作成
↓
作業
↓
Commit
↓
Push
↓
Pull Request
↓
レビュー・テスト
↓
Merge
↓
mainへ反映
この一連の流れを理解しておけば、GitHub上で今何をしているのか見失いにくい。
GitHubには3種類のマージ方法がある
実はGitHubのマージには主に3つの方法がある。
GitHub公式では「Merge commit」「Squash and merge」「Rebase and merge」が用意されている。
Merge commit
通常のマージだ。
作業ブランチで行ったコミットを残したままmainへ統合し、マージした記録も追加される。
main ────────●────
\ /
feature ●─●─●
変更の流れを細かく残したい場合に向いている。
一方で、細かいコミットが多いとGitの履歴が複雑になりやすい。
Squash and merge
個人的には、初心者にも理解しやすい方法だと思う。
「Squash」は押しつぶすという意味で、複数のコミットを1つにまとめてmainへ取り込む。
たとえば、
ログイン画面作成
↓
文字修正
↓
ボタン修正
↓
CSS修正
という4個のコミットがあったとする。
Squash and mergeなら、
ログイン機能追加
という1つのコミットとしてmainへ入れられる。
GitHub公式でも、Squash and mergeはプルリクエスト内の複数コミットを1つにまとめる方法と説明されている。
小さな修正コミットが多い場合にはかなり使いやすい。
Rebase and merge
Rebase and mergeでは、マージ用のコミットを作らず、作業ブランチのコミットをmainの続きとして並べる。
main ●─●─●
↓
●─●─●
履歴を一直線にしやすいのが特徴だ。
ただしRebaseはGit初心者には少し理解しにくい。
最初から無理に使う必要はない。
| マージ方法 | 特徴 | 向いているケース |
|---|---|---|
| Merge commit | 履歴をそのまま残す | 変更履歴を細かく残したい |
| Squash and merge | 複数コミットを1つにする | 履歴をシンプルにしたい |
| Rebase and merge | 履歴を一直線にする | Gitの履歴をきれいに管理したい |
個人開発で特別なルールがないなら、Squash and mergeはかなり扱いやすい選択肢だ。
プルリクエストを作ったのに反映されない理由
初心者が特に混乱しやすいのがここだ。
プルリクエストを作成しても、通常はmainへ変更されない。
なぜなら、
Pull Request
≠
Merge
だからだ。
プルリクエストはあくまで、
「この変更をmainへ入れたい」
という状態である。
GitHubの画面でプルリクエストが「Open」になっているなら、まだ変更を確認している途中だ。
問題がなく、必要なレビューやチェックを満たしたあとにマージすることで初めて変更が入る。リポジトリによっては、レビューやステータスチェックなどをマージの必須条件に設定することもできる。
CloseとMergeも間違えない
プルリクエストには「Close」という操作もある。
これも初心者には少し紛らわしい。
Mergeは、
変更を取り込んで
プルリクエストを終了
する。
一方、Closeは、
変更を取り込まず
プルリクエストを終了
する。
つまり、
| 操作 | 変更を取り込む? | プルリクエスト |
|---|---|---|
| Merge | ○ | 終了 |
| Close | × | 終了 |
となる。
「この変更はやっぱり不要だった」という場合はCloseする。
変更を正式に採用するならMergeだ。
マージコンフリクトとは?
マージするときに「Conflict」という言葉が出ることがある。
これがマージコンフリクトだ。
たとえばmainと作業ブランチの両方で、同じ場所を書き換えたとする。
mainでは、
価格:1000円
を、
価格:1200円
に変更した。
一方、作業ブランチでは、
価格:1000円
を、
価格:1500円
に変更した。
Gitからすると、
1200円?
1500円?
どちらを採用する?
となる。
Gitは人間の商売事情まで知らないので、自動では決められない。
そこで人間が正しい内容を選ぶ必要がある。
これがマージコンフリクトの解決だ。
一人で開発する場合もプルリクエストは必要?
「自分しかコードを触らないなら、プルリクエストなんて必要ないのでは?」
これはかなり自然な疑問だ。
実際、Gitではプルリクエストを使わず直接マージすることもできる。
ただ、私は個人開発でもプルリクエストを使う価値は高いと思う。
理由は単純で、
mainへ入れる前に変更を一覧で確認できるからだ。
特にAIを使ってコードを変更する場合は重要になる。
AIに、
「この機能を追加して」
と依頼すると、人間が想定していた以上のファイルを変更することもある。
そんなとき、
AIがコード変更
↓
Pull Request
↓
Files changedを確認
↓
問題なければMerge
という流れにしておけば、mainへ直接変更するより安全だ。
プルリクエストはチーム開発だけの機能ではない。
変更内容を確認するための安全装置としても使える。
初心者は「プルリクエスト→確認→マージ」で覚えればいい
GitやGitHubには、コミット、Push、Pull、Fetch、Rebase、Cherry-pickなど大量の用語が出てくる。
最初から全部理解しようとすると、かなり苦しい。
プルリクエストとマージについては、まず次だけ覚えておけば十分だ。
作業用ブランチで変更
↓
プルリクエスト
「この変更を入れていい?」
↓
内容を確認
↓
マージ
「OK。正式版に入れる」
↓
mainへ反映
この理解ができていれば、GitHub上で「今は提案段階なのか」「すでに正式版へ入ったのか」を判断できる。
GitHub公式のプルリクエスト解説も確認しておくと理解しやすい。
GitHub公式:プルリクエストについて
マージ方法についてはこちらが一次情報になる。
GitHub公式:pull request のマージ
まとめ
プルリクエストとマージはセットで登場するため、最初は同じような機能に見える。
しかし役割は明確に違う。
プルリクエストは変更を取り込むための「提案」、マージはその変更を実際に取り込む「確定処理」だ。
流れとして覚えるなら、
Branch
↓
Commit
↓
Push
↓
Pull Request
↓
Review
↓
Merge
↓
main
これでいい。
プルリクエストを作っただけではmainは変わらない。レビューして問題がなければマージし、そこで初めて変更が正式版へ入る。
私もGitHubを触り始めた段階では、この2つを別の操作として理解しただけで画面の意味がかなり分かりやすくなった。
特に覚えておきたいのは、たった一つだ。
「プルリクエスト=入れていい?」「マージ=入れた」
まずはこの理解で十分である。

コメント