Skip to content

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回だけ チームに加わるたびに何度も使う
  1. チームの Organization のページから、練習用リポジトリを開きます
  2. リポジトリ画面の緑の Code ボタンを押し、HTTPS の URL をコピーします
  3. VS Code でコマンドパレット(Ctrl + Shift + P)を開き、「Git: クローン」を選んで URL を貼ります
  4. 保存先フォルダを選び、「開く」を選びます
  5. 左下のブランチ名が main になっていることを確認します

clone は複製です。 .git ごと落ちてくるので、その瞬間から全履歴が自分の PC にあります。 GitHub が落ちても手元に履歴は残ります。 Git が分散型と呼ばれるのは、この性質のためです。

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

① から ⑦ を一周したら、また ① に戻ります。 ① を飛ばして古い状態から枝を作ると、あとでぶつかります。

main にいることを確認し、「変更の同期」を押します。 作業を始める前に pull する、を習慣にしてください。

左下のブランチ名から「新しいブランチの作成」を選び、add-<ローマ字の自分の名前> という名前を付けます。

members/<自分の名前>.md を新規作成し、自己紹介を書きます。 そのうえで members.md に自分の行を1行追記します。

ステージしてコミットします。メッセージは <名前>の自己紹介を追加 とします。

「Branch の発行」を押します。 押した後、VS Code に「PR を作成しますか」という通知が出ることがあります。

  1. GitHub のリポジトリ画面に出る Compare & pull request を押します
  2. タイトルに何をしたかを書きます(<名前>の自己紹介を追加)
  3. 本文に、何を変えたか、なぜ変えたか、確認してほしい点を書きます
  4. Create pull request を押します

本文には次の雛形を使ってください。 書くことが決まっていれば、入力で手が止まりません。

## 何をしたか
## なぜ
## 確認してほしいこと

5-3 で行います。

5-3 やってみよう:レビューしてマージする

Section titled “5-3 やってみよう:レビューしてマージする”

チーム内で、1人1つ以上、他の人の PR にコメントを付けます。

  1. PR の Files changed タブを開きます

  2. コメントしたい行にカーソルを合わせると、行の左に + が出ます。これを押します

    PR の Files changed タブ。追加行に開いたコメント入力欄と Start a review ボタン、右上の Submit review に番号を振ったもの
  3. コメントを書き、Start a review を押します

  4. 右上の Submit review で送信します。3種類から選びます

    • Comment は意見を述べるだけ
    • Approve は承認
    • Request changes は修正の要求
  1. Merge pull request を押し、Confirm merge を押します
  2. マージ後に出る Delete branch を押してかまいません(コミットは main に残ります)
  3. 全員が自分の手元で「変更の同期」を押します。他の人の自己紹介が降りてきます

レビューで何を指摘するか、どう伝えるかは、チームの文化の話なのでここでは扱いません。 この節で覚えるのは、どこを押せばコメントが付き、どこを押せばマージされるかです。

1つだけ添えておきます。 「ここが分からないので教えてください」も立派なレビューです。 指摘できることがなければコメントしてはいけない、と思うと誰も何も書かなくなります。

この節が終わると、members.md にチーム全員の名前が並びます。

5-4 やってみよう:コンフリクトを体験する

Section titled “5-4 やってみよう:コンフリクトを体験する”

同じ場所を2人が別々に変更すると、Git は自動で合流できません。 この状態をコンフリクトと呼びます。 起きてはいけない事故ではなく、日常的に起きて手で直せばよいだけのものだと分かることが、この節の目的です。

わざと発生させる(2人1組で実施)

Section titled “わざと発生させる(2人1組で実施)”
  1. A さんと B さんが、両方とも最新の main からブランチを作ります

  2. 二人とも members.md の同じ行を編集します(並び順を変える、同じ行にコメントを足す、など)

  3. 両方とも push して PR を作ります

  4. A さんが先にマージします。ここは成功します

  5. B さんの PR を見ると、This branch has conflicts that must be resolved と表示されています

    PR 画面の下部に出た警告。This branch has conflicts that must be resolved という文と Resolve conflicts ボタン、競合したファイル members.md が赤枠で囲まれている
  1. B さんは手元で main に切り替え、pull します(A さんの変更が入ります)

  2. 自分のブランチに切り替え、コマンドパレットから「Git: ブランチをマージ」を選び、main を選びます

  3. コンフリクトが起きます。VS Code がファイルに ! マークを付けます

  4. ファイルを開くと、次のような記号が挿入されています

    members.md(コンフリクトが起きた状態)
    <<<<<<< HEAD
    自分の変更
    =======
    相手の変更
    >>>>>>> main
  5. これは Git が書き込んだ「どちらにしますか」というメモです

  6. 「マージエディターで解決」ボタンを押します。画面が3つのペインに分かれます

    VS Code のマージエディター。左上のペインが受信中、右上が現在のマシン、下が結果で、それぞれに競合した行が表示されている
    • 左の「受信中」は、取り込もうとしている側です(いまの場合は main)
    • 右の「現在のマシン」は、いま自分がいるブランチです(B さんが手順1で作ったブランチ)
    • 下の「結果」が、実際に保存される内容です
  7. 各ペインの上に出る「受信中 を適用する」「現在のマシン を適用する」「組み合わせを受け入れる」から選びます。「結果」を直接書き直してもかまいません。むしろこれが本来の姿です

  8. 右上の「テキスト エディター」に切り替えて、記号ごと自分で書き直すこともできます。その場合は <<<<<<< と ======= と >>>>>>> をすべて消します

  9. 残りの競合がなくなったら、右下の「マージの完了」を押します

  10. ステージしてコミットし、push します

  11. PR を見ると conflicts の表示が消えていて、マージできる状態になっています

コンフリクトは、Git が「私にはどちらが正しいか判断できません」と言っているだけの状態です。 人間が読んで、正しい形に直せばそれで終わります。

もっと知りたい人へ:コンフリクトを減らすには

起きる回数は、段取りで減らせます。

  • こまめに pull して、手元と共有リポジトリの差を小さく保つ
  • 1つの PR を小さくして、レビューとマージを早く回す
  • 同じファイルを同時に触らないように、担当を決めてから作業する

それでもゼロにはなりません。 減らす工夫と、起きたときに直せることの両方が必要です。

症状 原因 対処
push できない(rejected) リモートが自分より進んでいる 先に pull(「変更の同期」)する
Compare & pull request が出ない 再読み込みしていない、または push できていない 再読み込みする。Pull requests タブから New pull request でも作れる
PR の変更内容に他人の変更まで入っている 古いブランチから枝を作った main を最新にしてから、ブランチを作り直す
マージボタンが押せない コンフリクト、または権限がない 5-4 を実施する。権限を確認する
マージ後も手元に他人の変更がない pull していない 「変更の同期」を押す
操作 コマンド
リポジトリを手元に複製する 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