5. Pull Request で共同作業する
チームで1つのリポジトリを共有し、他の人の変更と自分の変更を合流させます。 ここまでの章は、この章のための準備でした。
チームの Organization の中に、練習用リポジトリ git-practice が用意されています。
members/ フォルダと members.md の雛形が入っていて、Organization のメンバーであればアクセスできます。
- 本番と同じ環境で操作を覚えるため、練習も自分たちの Organization 上で行います
- コンフリクトの体験(5-4)は、チーム内の2人1組で行います
5-0 やってみよう:チームのリポジトリを手元に持ってくる
Section titled “5-0 やってみよう:チームのリポジトリを手元に持ってくる”実際のチーム開発で最も多い入り口は、git init ではなく clone です。
2-2 でやったゼロからの作成は、プロジェクトにつき最初の1回だけしか起きません。
すでにあるリポジトリに途中から加わるほうが、これから何度も繰り返す作業です。
| init:ゼロから作る | clone:すでにあるものを複製する |
|---|---|
| 空のフォルダから始める | GitHub 上のリポジトリから始める |
| 「リポジトリを初期化する」を押す | 「Git: クローン」を実行する |
| 履歴が空の状態ができる | 履歴ごと丸ごと手元に来る |
| プロジェクトにつき最初の1回だけ | チームに加わるたびに何度も使う |
- チームの Organization のページから、練習用リポジトリを開きます
- リポジトリ画面の緑の
Codeボタンを押し、HTTPS の URL をコピーします - VS Code でコマンドパレット(
Ctrl+Shift+P)を開き、「Git: クローン」を選んで URL を貼ります - 保存先フォルダを選び、「開く」を選びます
- 左下のブランチ名が
mainになっていることを確認します
clone は複製です。
.git ごと落ちてくるので、その瞬間から全履歴が自分の PC にあります。
GitHub が落ちても手元に履歴は残ります。
Git が分散型と呼ばれるのは、この性質のためです。
5-1 Pull Request とは何か
Section titled “5-1 Pull Request とは何か”Pull Request は、この変更を取り込んでいいですかという提案であり、取り込む前に話し合うための場所です。
flowchart TD
subgraph mypc["自分の PC"]
mybranch("自分のブランチ")
end
subgraph gh["GitHub"]
ghbranch("GitHub 上のブランチ")
pr["Pull Request<br/>「この変更を入れていいですか」"]
ghmain("GitHub の main")
end
subgraph team["チーム全員の PC"]
localmain("それぞれの手元の main")
end
rv1(["レビュアー A"])
rv2(["レビュアー B"])
mybranch -- "push" --> ghbranch
ghbranch --> pr
rv1 -. "コメント" .-> pr
rv2 -. "コメント" .-> pr
pr -- "マージ" --> ghmain
ghmain -- "pull" --> localmain
classDef local fill:#dbeafe,stroke:#3b82f6,color:#1e3a8a
classDef remote fill:#ede9fe,stroke:#8b5cf6,color:#4c1d95
classDef person fill:#fff7ed,stroke:#fb923c,color:#7c2d12
classDef alert fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#78350f
class mybranch,localmain local
class ghbranch,ghmain remote
class pr alert
class rv1,rv2 person
style mypc fill:none,stroke:#3b82f6,stroke-dasharray: 4 4
style team fill:none,stroke:#3b82f6,stroke-dasharray: 4 4
style gh fill:none,stroke:#8b5cf6,stroke-dasharray: 4 4
自分の手元から出た変更は、GitHub 上でいったん Pull Request という形で止まります。
そこにチームの誰かがコメントを付け、合意できたらマージされて main に入ります。
全員がそれを pull して、ようやく他のメンバーの手元にも届きます。
4-5 でやったローカルでのマージと比べると、違いは場所と記録です。
| ローカルでマージ | Pull Request | |
|---|---|---|
| どこで | 自分の PC | GitHub 上 |
| 誰が見るか | 自分だけ | チーム全員 |
| 議論 | できない | コメントで議論できる |
| 残るもの | コミットだけ | なぜこの変更をしたかも残る |
Pull Request の値打ちは、マージの手段であることよりも、記録と議論が残ることにあります。 半年後に「なぜこんな実装になっているのか」と思ったとき、Pull Request を読めば経緯が分かります。
名前は紛らわしいところがあります。 自分が pull するのではなく、相手に pull してもらうようお願いする、という意味です。 GitLab では Merge Request と呼ばれていて、そちらのほうが意味は素直です。 以下では Pull Request を PR と略します。
5-2 やってみよう:共同作業の一周
Section titled “5-2 やってみよう:共同作業の一周”この7ステップが、これ以降ずっと繰り返す作業の型になります。
flowchart LR s1["① pull<br/>最新にする"] --> s2["② ブランチを作る"] --> s3["③ 編集する"] --> s4["④ コミット"] s4 --> s5["⑤ push"] --> s6["⑥ PR を作る"] --> s7["⑦ レビューとマージ"] s7 -- "①へ戻る" --> s1 classDef local fill:#dbeafe,stroke:#3b82f6,color:#1e3a8a classDef remote fill:#ede9fe,stroke:#8b5cf6,color:#4c1d95 classDef work fill:#f1f5f9,stroke:#94a3b8,color:#334155 classDef safe fill:#dcfce7,stroke:#22c55e,color:#14532d classDef alert fill:#fef3c7,stroke:#f59e0b,color:#78350f class s1 alert class s2,s3,s4 local class s5,s6,s7 remote
① から ⑦ を一周したら、また ① に戻ります。 ① を飛ばして古い状態から枝を作ると、あとでぶつかります。
① pull
Section titled “① pull”main にいることを確認し、「変更の同期」を押します。
作業を始める前に pull する、を習慣にしてください。
② ブランチを作る
Section titled “② ブランチを作る”左下のブランチ名から「新しいブランチの作成」を選び、add-<ローマ字の自分の名前> という名前を付けます。
③ 編集する
Section titled “③ 編集する”members/<自分の名前>.md を新規作成し、自己紹介を書きます。
そのうえで members.md に自分の行を1行追記します。
④ コミット
Section titled “④ コミット”ステージしてコミットします。メッセージは <名前>の自己紹介を追加 とします。
⑤ push
Section titled “⑤ push”「Branch の発行」を押します。 押した後、VS Code に「PR を作成しますか」という通知が出ることがあります。
⑥ PR を作る
Section titled “⑥ PR を作る”- GitHub のリポジトリ画面に出る
Compare & pull requestを押します - タイトルに何をしたかを書きます(
<名前>の自己紹介を追加) - 本文に、何を変えたか、なぜ変えたか、確認してほしい点を書きます
Create pull requestを押します
本文には次の雛形を使ってください。 書くことが決まっていれば、入力で手が止まりません。
## 何をしたか
## なぜ
## 確認してほしいこと⑦ レビューとマージ
Section titled “⑦ レビューとマージ”5-3 で行います。
5-3 やってみよう:レビューしてマージする
Section titled “5-3 やってみよう:レビューしてマージする”チーム内で、1人1つ以上、他の人の PR にコメントを付けます。
行にコメントを付ける
Section titled “行にコメントを付ける”-
PR の
Files changedタブを開きます -
コメントしたい行にカーソルを合わせると、行の左に
+が出ます。これを押します
-
コメントを書き、
Start a reviewを押します -
右上の
Submit reviewで送信します。3種類から選びますCommentは意見を述べるだけApproveは承認Request changesは修正の要求
Merge pull requestを押し、Confirm mergeを押します- マージ後に出る
Delete branchを押してかまいません(コミットはmainに残ります) - 全員が自分の手元で「変更の同期」を押します。他の人の自己紹介が降りてきます
レビューで何を指摘するか、どう伝えるかは、チームの文化の話なのでここでは扱いません。 この節で覚えるのは、どこを押せばコメントが付き、どこを押せばマージされるかです。
1つだけ添えておきます。 「ここが分からないので教えてください」も立派なレビューです。 指摘できることがなければコメントしてはいけない、と思うと誰も何も書かなくなります。
この節が終わると、members.md にチーム全員の名前が並びます。
5-4 やってみよう:コンフリクトを体験する
Section titled “5-4 やってみよう:コンフリクトを体験する”同じ場所を2人が別々に変更すると、Git は自動で合流できません。 この状態をコンフリクトと呼びます。 起きてはいけない事故ではなく、日常的に起きて手で直せばよいだけのものだと分かることが、この節の目的です。
わざと発生させる(2人1組で実施)
Section titled “わざと発生させる(2人1組で実施)”-
A さんと B さんが、両方とも最新の
mainからブランチを作ります -
二人とも
members.mdの同じ行を編集します(並び順を変える、同じ行にコメントを足す、など) -
両方とも push して PR を作ります
-
A さんが先にマージします。ここは成功します
-
B さんの PR を見ると、
This branch has conflicts that must be resolvedと表示されています
-
B さんは手元で
mainに切り替え、pull します(A さんの変更が入ります) -
自分のブランチに切り替え、コマンドパレットから「Git: ブランチをマージ」を選び、
mainを選びます -
コンフリクトが起きます。VS Code がファイルに
!マークを付けます -
ファイルを開くと、次のような記号が挿入されています
members.md(コンフリクトが起きた状態) <<<<<<< HEAD自分の変更=======相手の変更>>>>>>> main -
これは Git が書き込んだ「どちらにしますか」というメモです
-
「マージエディターで解決」ボタンを押します。画面が3つのペインに分かれます
- 左の「受信中」は、取り込もうとしている側です(いまの場合は
main) - 右の「現在のマシン」は、いま自分がいるブランチです(B さんが手順1で作ったブランチ)
- 下の「結果」が、実際に保存される内容です
- 左の「受信中」は、取り込もうとしている側です(いまの場合は
-
各ペインの上に出る「受信中 を適用する」「現在のマシン を適用する」「組み合わせを受け入れる」から選びます。「結果」を直接書き直してもかまいません。むしろこれが本来の姿です
-
右上の「テキスト エディター」に切り替えて、記号ごと自分で書き直すこともできます。その場合は
<<<<<<<と=======と>>>>>>>をすべて消します -
残りの競合がなくなったら、右下の「マージの完了」を押します
-
ステージしてコミットし、push します
-
PR を見ると conflicts の表示が消えていて、マージできる状態になっています
コンフリクトは、Git が「私にはどちらが正しいか判断できません」と言っているだけの状態です。 人間が読んで、正しい形に直せばそれで終わります。
もっと知りたい人へ:コンフリクトを減らすには
起きる回数は、段取りで減らせます。
- こまめに pull して、手元と共有リポジトリの差を小さく保つ
- 1つの PR を小さくして、レビューとマージを早く回す
- 同じファイルを同時に触らないように、担当を決めてから作業する
それでもゼロにはなりません。 減らす工夫と、起きたときに直せることの両方が必要です。
5-5 つまずきポイント
Section titled “5-5 つまずきポイント”| 症状 | 原因 | 対処 |
|---|---|---|
| push できない(rejected) | リモートが自分より進んでいる | 先に pull(「変更の同期」)する |
Compare & pull request が出ない |
再読み込みしていない、または push できていない | 再読み込みする。Pull requests タブから New pull request でも作れる |
| PR の変更内容に他人の変更まで入っている | 古いブランチから枝を作った | main を最新にしてから、ブランチを作り直す |
| マージボタンが押せない | コンフリクト、または権限がない | 5-4 を実施する。権限を確認する |
| マージ後も手元に他人の変更がない | pull していない | 「変更の同期」を押す |
5-6 GUI と CLI の対応表
Section titled “5-6 GUI と CLI の対応表”| 操作 | コマンド |
|---|---|
| リポジトリを手元に複製する | git clone <URL> |
| 作業前に最新化する | git switch main と git pull |
| ブランチを作る | git switch -c add-yourname |
| 初回の push | git push -u origin add-yourname |
| PR を作る | GitHub の Web 画面(GitHub CLI なら gh pr create) |
| コンフリクト解消後 | git add <ファイル> と git commit |