簡體中文 ▾ 主題 ▾ 最新版本 ▾ gitworkflows 上次更新於 2.35.0

名稱

gitworkflows - Git 推薦工作流概述

概要

git *

描述

本文件試圖記錄並闡述 git.git 本身所使用的部分工作流元素。許多思想都適用於一般情況,儘管對於涉及人數較少的小型專案來說,完整的工作流很少需要。

我們制定了一套規則供快速參考,同時以文字的形式來解釋每一條規則的動機。不要總是字面理解它們;你應該更重視你行動的合理性,而不是像這樣的 manpages。

分開提交

總的來說,你應該嘗試將你的更改分解成小的邏輯步驟,並單獨提交它們。它們應該是連貫的,能夠獨立於任何後續提交而正常工作,並透過測試套件等。這使得審查過程更加容易,並且使歷史記錄在後續檢查和分析時更加有用,例如使用 git-blame[1]git-bisect[1]

為了實現這一點,儘量從一開始就將你的工作分解成小步驟。將幾個提交合並在一起總是比將一個大的提交分解成幾個更容易。不要害怕在過程中進行過小或不完美的步驟。你總可以在釋出它們之前使用 git rebase --interactive 去編輯這些提交。你可以使用 git stash push --keep-index 來獨立於其他未提交的更改執行測試套件;請參閱 git-stash[1] 的 EXAMPLES 部分。

管理分支

有兩種主要工具可以用來將一個分支的更改包含到另一個分支中:git-merge[1]git-cherry-pick[1]

合併有許多優點,所以我們儘量只用合併來解決問題。選擇性地應用提交(cherry-picking)仍然偶爾有用;請參見下面的“向上合併”示例。

最重要的是,合併是在分支級別工作的,而選擇性地應用提交是在提交級別工作的。這意味著一次合併可以輕鬆地將 1、10 或 1000 個提交的更改帶過來,反過來,這意味著工作流對於大量貢獻者(和貢獻)的擴充套件性更好。合併也更容易理解,因為合併提交是“承諾”,即其所有父提交的更改都已包含在內。

當然,也有一個權衡:合併需要更仔細的分支管理。以下子部分將討論重要問題。

升級

隨著一個給定的功能從實驗性發展到穩定,它也將在軟體的相應分支之間“升級”。git.git 使用以下整合分支

  • maint 跟蹤應該包含在下一個“維護版本”中的提交,即上一個已釋出穩定版本的更新;

  • master 跟蹤應該包含在下一個版本中的提交;

  • next 用於測試即將進入 master 的主題的穩定性。

還有一個第四個官方分支,其用法略有不同

  • seen(維護者已見的補丁)是一個整合分支,用於尚未準備好包含的內容(參見下面的“整合分支”)。

這四個分支中的每一個通常都是其上方分支的直接後代。

概念上,功能進入不穩定的分支(通常是nextseen),一旦被認為足夠穩定,就會“升級”到master以供下一個版本使用。

向上合併

上面討論的“向下升級”不能透過實際向下合併來完成,因為那樣會將不穩定分支上的所有更改合併到穩定分支中。因此,有以下規則

規則:向上合併

始終將你的修復提交到支援該修復的最舊分支。然後(定期)將整合分支向上合併到彼此。

這提供了一種非常受控的修復流程。如果你發現你在例如master上應用了一個修復,而該修復也需要應用在maint上,你將需要向下選擇性地應用它(使用 git-cherry-pick[1])。這會發生幾次,不用擔心,除非你這樣做非常頻繁。

主題分支

任何非平凡的功能都需要多個補丁來實現,並且在其生命週期中可能會有額外的錯誤修復或改進。

將所有內容直接提交到整合分支會導致許多問題:無法撤消的壞提交,因此必須逐一撤銷,這會產生混淆的歷史記錄,並且在你忘記撤銷一組更改的一部分時會產生進一步的錯誤。並行工作會混淆更改,導致進一步的混淆。

使用“主題分支”可以解決這些問題。這個名字很容易理解,但有一個來自上面“向上合併”規則的注意事項

規則:主題分支

為每個主題(功能、錯誤修復等)建立一個側分支。在你想最終將其合併到的最舊整合分支處分叉它。

然後許多事情可以很自然地完成

  • 要將功能/錯誤修復合併到整合分支,只需合併它。如果主題在此期間發生了進一步的演變,請再次合併。(請注意,你不一定必須先將其合併到最舊的整合分支。例如,你可以先將一個錯誤修復合併到next,給它一些測試時間,然後在你知道它穩定時將其合併到maint。)

  • 如果你發現你需要來自其他分支的新功能來繼續你的主題工作,將其他分支合併到topic。(然而,不要“習慣性地”這樣做,見下文。)

  • 如果你發現你分叉錯了分支,並且想將其“移回時間”,請使用 git-rebase[1]

請注意,最後一點與其他兩點衝突:已經合併到其他地方的主題不應被 rebase。請參閱 git-rebase[1] 中 RECOVERING FROM UPSTREAM REBASE 部分。

我們應該指出,“習慣性地”(定期無故)將整合分支合併到你的主題中 — — 進而,定期將任何上游內容合併到任何下游內容 — — 是不被提倡的

規則:僅在明確的點合併到下游

除非有充分的理由,否則不要合併到下游:上游 API 更改影響了你的分支;你的分支不再能幹淨地合併到上游;等等。

否則,合併到的主題突然包含了比單個(已分開的)更改更多的內容。由此產生的許多小合併將嚴重混亂歷史記錄。任何後來調查檔案歷史記錄的人都必須弄清楚這次合併是否影響了正在開發的主題。上游甚至可能意外地被合併到一個“更穩定”的分支。等等。

一次性整合

如果你遵循了上一段,你現在將有很多小的分支,並且偶爾會想知道它們是如何互動的。也許將它們合併的結果甚至不起作用?但另一方面,我們希望避免將它們合併到任何“穩定”的地方,因為這種合併不容易撤銷。

當然,解決方案是進行一次可以撤銷的合併:合併到一個一次性分支。

規則:一次性整合分支

要測試多個主題的互動,將它們合併到一個一次性分支。你絕對不能基於這樣的分支進行任何工作!

如果你(非常)清楚地表明該分支將在測試後立即刪除,你甚至可以釋出該分支,例如讓測試人員有機會使用它,或者讓其他開發人員有機會檢視他們正在進行的工作是否相容。git.git 有一個名為seen的官方一次性整合分支。

釋出的分支管理

假設你使用了上面討論的合併方法,當你要釋出專案時,你需要做一些額外的分支管理工作。

功能釋出是從master分支建立的,因為master跟蹤應該包含在下一個功能釋出中的提交。

master分支應該是maint的超集。如果這個條件不成立,那麼maint就包含了一些未包含在master中的提交。因此,這些提交所代表的修復將不會包含在你的功能釋出中。

要驗證master確實是maint的超集,請使用 git log

配方:驗證mastermaint的超集

git log master..maint

此命令不應列出任何提交。否則,請檢出master並將其合併到maint中。

現在你可以繼續建立功能釋出了。給master的最新提交打上標籤,表示釋出版本

配方:釋出標籤

git tag -s -m "Git X.Y.Z" vX.Y.Z master

你需要將新標籤推送到公共 Git 伺服器(參見下面的“分散式工作流”)。這將使其他人能夠跟蹤你的專案。推送還可以觸發一個 post-update hook 來執行與釋出相關的專案,例如構建釋出 tarball 和預格式化的文件頁面。

同樣,對於維護版本,maint跟蹤要釋出的提交。因此,在上面的步驟中,只需標記並推送maint而不是master

功能釋出後的維護分支管理

在功能釋出之後,你需要管理你的維護分支。

首先,如果你希望繼續為最近之前的那個功能釋出維護修復,那麼你必須建立另一個分支來跟蹤那個先前版本的提交。

為此,當前維護分支將被複制到另一個名為先前版本號的分支(例如,maint-X.Y.(Z-1),其中 X.Y.Z 是當前釋出版本)。

配方:複製 maint

git branch maint-X.Y.(Z-1) maint

maint分支現在應該被快進到新發布的程式碼,以便可以跟蹤當前版本的維護修復。

配方:更新 maint 到新版本
  • git checkout maint

  • git merge --ff-only master

如果由於不是快進合併而導致合併失敗,那麼可能是maint上的某些修復在功能釋出中被遺漏了。如果分支的內容如前一節所述得到驗證,這種情況就不會發生。

功能釋出後的 next 和 seen 分支管理

在功能釋出之後,next整合分支可以根據需要使用next上剩餘的主題從master的頂端回退和重建

配方:回退並重建 next
  • git switch -C next master

  • git merge ai/topic_in_next1

  • git merge ai/topic_in_next2

  • …​​

這樣做的優點是next的歷史記錄將是乾淨的。例如,合併到next的一些主題最初可能看起來很有希望,但後來被發現是不可取的或過早的。在這種情況下,該主題被從next中撤銷,但歷史上仍然保留了它曾經被合併和撤銷的事實。透過重新建立next,你為這些主題的下一次迭代提供了一個乾淨的開始,而功能釋出是做到這一點的歷史好時機。

如果你這樣做,你應該公開宣佈next已被回退和重建。

同樣的過程也可以用於seen。由於seen是一個一次性分支,如上所述,因此不需要公開宣佈。

分散式工作流

在上一節之後,你應該知道如何管理主題。總的來說,你不會是專案中唯一工作的人,所以你將不得不分享你的工作。

粗略地說,有兩種重要的工作流:合併和補丁。重要的區別在於,合併工作流可以傳播完整的歷史記錄,包括合併,而補丁則不能。這兩種工作流可以並行使用:在git.git中,只有子系統維護者使用合併工作流,而其他人則傳送補丁。

請注意,維護者可能會施加限制,例如“已簽名的-by”要求,所有提交/補丁都必須遵守才能包含。有關更多資訊,請參閱你專案的文件。

合併工作流

合併工作流透過在上下游之間複製分支來工作。上游可以將貢獻合併到官方歷史中;下游以官方歷史為基礎進行工作。

有三種主要工具可用於此

  • git-push[1] 將你的分支複製到遠端倉庫,通常是所有相關方都可以讀取的倉庫;

  • git-fetch[1] 將遠端分支複製到你的倉庫;以及

  • git-pull[1] 一次性完成 fetch 和 merge。

注意最後一點。除非你確實想合併遠端分支,否則不要使用git pull

釋出更改很容易

配方:推送/拉取:釋出分支/主題

git push <remote> <branch> 並告訴大家可以從哪裡獲取。

你仍然需要透過其他方式告知人們,例如郵件。(Git 提供了 git-request-pull[1] 來向上遊維護者傳送預格式化的 pull 請求,以簡化此任務。)

如果你只想獲取整合分支的最新副本,保持更新也很容易

配方:推送/拉取:保持更新

使用 git fetch <remote>git remote update 來保持更新。

然後,只需按照前面所述,從穩定的遠端分支分叉你的主題分支。

如果你是維護者,並且想將其他人的主題分支合併到整合分支,他們通常會透過郵件傳送請求。這樣的請求看起來像

Please pull from
    <URL> <branch>

在這種情況下,git pull 可以一次性完成 fetch 和 merge,如下所示。

配方:推送/拉取:合併遠端主題

git pull <URL> <branch>

偶爾,維護者在嘗試從下游拉取更改時可能會遇到合併衝突。在這種情況下,他們可以要求下游進行合併並自行解決衝突(也許他們對如何解決衝突有更好的瞭解)。這是下游應該從上游合併的少數情況之一。

補丁工作流

如果你是一個以電子郵件形式向上遊傳送更改的貢獻者,你應該像往常一樣使用主題分支(見上文)。然後使用 git-format-patch[1] 來生成相應的電子郵件(強烈推薦手動格式化,因為它使維護者的工作更輕鬆)。

配方:format-patch/am:釋出分支/主題
  • git format-patch -M upstream..topic 將它們轉換為預格式化的補丁檔案

  • git send-email --to=<recipient> <patches>

有關更多用法說明,請參閱 git-format-patch[1]git-send-email[1] 的 manpages。

如果維護者告訴你你的補丁不再適用於當前上游,你將不得不 rebase 你的主題(你不能使用合併,因為你不能格式化補丁的合併)。

配方:format-patch/am:保持主題更新

git pull --rebase <URL> <branch>

然後你可以在 rebase 過程中修復衝突。據推測,你除了透過郵件之外沒有釋出你的主題,所以 rebase 它不是問題。

如果你收到這樣的補丁系列(作為維護者,或者也許是郵件列表的讀者),請將郵件儲存到檔案,建立一個新的主題分支,然後使用git am來匯入提交。

配方:format-patch/am:匯入補丁

git am < patch

一個值得指出的功能是三向合併,它可以在你遇到衝突時提供幫助:git am -3 將使用補丁中包含的索引資訊來確定合併基礎。有關其他選項,請參閱 git-am[1]

GIT

Git[1] 套件的一部分