Git 全景課 / 第三部分 協作與正本控制 · M10

M10 協作流程:分支、PR 與審查

幾個人同時改同一份報告或同一個程式,靠的不是更多 Git 命令,而是一套大家都遵守的流程:各自開分支,透過 PR 提出改動,經審查後才進入正本。本單元走一次完整的 PR 循環,也比較幾種常見的團隊流程。
約 75 分鐘沙盒 6 個任務 · 小測 4 題先修:M9FAQ-002
學完本單元,你能夠:
  1. 完成一次 PR 循環:開分支、推送、開 PR、回應審查、合併、同步;
  2. 處理因合併次序而產生的 PR 衝突;
  3. 分辨 fork 和分支,以及 PR(GitHub)和 MR(GitLab);
  4. 比較 GitHub flow、trunk-based、Git flow,為團隊選擇合適的流程。

1為甚麼需要流程 Why a workflow

M9 學會了 push 和 pull,但如果每個人都直接推送到 main,就會出現三個問題:沒有人看過改動就進了正本;同時推送時要不斷處理被拒絕和衝突;出了問題也很難說清楚是哪一次、為甚麼改的。M0 說過,分散式的代價是需要約定單一正本。協作流程就是這個約定的具體做法。

2功能分支:每件事一條分支 Feature branches

最基本的規則:main 只放已完成、已審查的工作;每件新工作都在自己的分支上進行。分支名說明在做甚麼,例如 background、fix-sample-size。分支完成後經 PR 合併,然後刪除。

這也是 M7「一個 commit 一件事」的延伸:一條分支一件事,一個 PR 一件事,審查的人才看得懂。

3PR:提出改動,請人審查 Pull requests

PR(pull request)不是 Git 的功能,而是 GitHub、GitLab 等託管服務的功能。它的意思是:「請把我這條分支合併進 main」。一個 PR 包含:

PR 開出之後,在同一條分支上繼續推送 commit,PR 會自動更新,不用另開一個。審查的來回就是:審查者提意見 → 你修改並推送 → 再審查 → 批准 → 合併。

PR 與 MR GitHub 稱為 pull request(PR),GitLab 稱為 merge request(MR),概念完全相同。命令列上,GitHub 的官方工具是 gh(例如 gh pr create),GitLab 的是 glab(glab mr create)。

4沙盒:一次完整的 PR 循環 Sandbox: a full PR cycle

互動 GitHub、你和同學

左上是 GitHub 上的倉庫和 PR 列表;可以按 PR 上的按鈕,也可以在下面輸入 gh 命令(GitHub 官方命令列工具的真實寫法)。右上的按鈕模擬同學開 PR。

應用線:

GitHub:you/report

同學 A 的電腦

(同學 A 還沒有開 PR)

你的電腦:~/project

5合併次序與 PR 衝突 Merge order and conflicts

兩個 PR 各自都沒有問題,但先合併的那個會改變 main;後合併的那個,就要和「新的 main」比較。如果兩者改了同一處,後者就會顯示衝突,不能直接合併。解決方法和 M5 一樣,只是在 PR 的分支上進行:

gh pr checkout 2          # 取得 PR #2 的分支(等於 fetch+switch)
git merge origin/main     # 把最新的 main 合併進來,解決衝突
git add 檔案 && git commit
git push                  # PR #2 自動更新,衝突消失

也可以用 git rebase origin/main 代替 merge,但那是改寫歷史,只適合只有作者一個人在用的分支(M7 黃金規則),推送時要 --force-with-lease。

6fork:沒有寫入權時的做法 Forks

開源專案或大型課程倉庫,不會讓每個人都有寫入權。這時的流程是:

  1. 在 GitHub 上 fork:在你自己的帳號下複製一份倉庫(伺服器端的 clone);
  2. clone 你的 fork 到電腦;它是 origin。再把原倉庫加為第二個遠端,習慣叫 upstream:git remote add upstream <原倉庫網址>;
  3. 在分支上工作,push 到你的 fork(origin);
  4. 從你的 fork 對原倉庫開 PR;
  5. 原倉庫更新時,git fetch upstream,再把 upstream/main 合併或 rebase 進來。
分支fork
在哪裏同一個倉庫裏的一張標籤另一個倉庫(在你的帳號下)
需要原倉庫的寫入權嗎需要(才能推送分支)不需要
適合團隊成員外部貢獻者、學生交作業到課程倉庫

7三種常見的團隊流程 GitHub flow, trunk-based, Git flow

流程怎樣運作適合
GitHub flow只有一條長期分支 main;每件事開短期分支 → PR → 審查 → 合併 → 部署大部分小團隊、網站、文件和課程倉庫
trunk-based所有人頻繁(每天甚至每小時)把小改動合併進 main;分支壽命以小時計,未完成的功能用開關(feature flag)隱藏有完善自動測試、需要快速整合的團隊
Git flow長期分支 main(已發佈)和 develop(開發中),另有 feature/release/hotfix 分支,按規則互相合併有明確版本號、需要同時維護多個已發佈版本的產品

選擇的準則是:能滿足需要的最簡單流程。分支越多、壽命越長,合併時的衝突就越多。大部分團隊從 GitHub flow 開始就夠了;需要同時維護舊版本時,再加上發佈分支和 cherry-pick(M7)。

8審查:寫給人看的 PR Code review

開 PR 的人審查的人
一個 PR 一件事,越小越容易審先看說明,弄清楚目的再看 diff
標題說做了甚麼,說明寫為甚麼、怎樣驗證對事不對人;指出問題時附上理由或建議
開 PR 前自己先看一遍 diff,整理好 commit(M7)分清「必須改」和「可以考慮」
回應每一條意見:修改,或說明不改的理由改好了就批准,不要一直加新要求

知識工作同樣適用:一份報告的 PR,審查者看的是論點、數據來源和用詞,GitHub 會逐行顯示文字的改動(所以 M5 建議一句一行)。

9容易混淆的對照 Easily confused

常見誤解
  • 「PR 是 Git 的命令。」不是。Git 只有分支和合併;PR 是託管服務在其上加的討論和審查流程。
  • 「PR 開了就要等合併,不能再改。」可以繼續推送到同一條分支,PR 會自動更新。
  • 「PR 合併了,我的電腦就自動更新了。」不會。合併發生在 GitHub 上;你要 git pull 才拿到(M9)。
  • 「fork 等於分支。」fork 是另一個倉庫;只有沒有寫入權時才需要。

10命令速查 Cheat sheet

命令作用
git switch -c 名字 → git push -u origin 名字開功能分支並推送
gh pr create --title "…" --body "…"為目前分支開 PR
gh pr list / gh pr view 2列出 PR/查看某個 PR 的狀態
gh pr checkout 2把 PR #2 的分支取到本機
gh pr review 2 --approve / --request-changes -b "…"批准/要求修改
gh pr merge 2 --merge / --squash / --rebase以合併 commit/squash/rebase 合併
gh pr merge 2 --squash --delete-branch合併並刪除分支(遠端和本機)
git fetch --prune清理遠端已刪除的分支的 origin/* 記錄
git remote add upstream <網址>fork 流程:加入原倉庫為第二個遠端

11小測 Quiz

1. 審查者要求你修改 PR。你應該:
2. PR #1 剛合併。PR #2 原本沒有衝突,現在顯示有衝突。最可能的原因是:
3. 你想為一個沒有寫入權的開源專案改錯字。應該:
4. 一個三人小組寫課程報告,沒有版本號,也不用維護舊版本。最合適的流程是:

本單元重點 Summary

延伸閱讀