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

名稱

gitworkflows - Git 推薦工作流概述

概要

git *

描述

本文件試圖闡述並說明 git.git 本身使用的一些工作流元素。許多理念具有普遍適用性,儘管對於涉及人數較少的較小專案,通常不需要完整的工作流。

我們制定了一套*規則*以供快速參考,同時散文部分試圖說明每條規則的動機。請勿總是拘泥於字面意思;您應該更重視行動的充分理由,而非像本文件這樣的手冊頁。

分離更改

作為一般規則,您應該嘗試將更改拆分為小的邏輯步驟,並提交每個步驟。它們應該保持一致,獨立於任何後續提交而工作,透過測試套件等。這使得審查過程更容易,並且歷史記錄對於後續的檢查和分析更有用,例如使用 git-blame[1]git-bisect[1]

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

管理分支

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

合併具有許多優點,因此我們嘗試僅透過合併來解決儘可能多的問題。揀選(cherry-picking)偶爾仍然有用;請參閱下面的“向上合併”以獲取示例。

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

當然,這也有一個權衡:合併需要更仔細的分支管理。以下小節討論了要點。

畢業

當一個給定功能從實驗性走向穩定時,它也在軟體的相應分支之間“畢業”。git.git 使用以下*整合分支*

  • *maint* 跟蹤應該進入下一個“維護版本”的提交,即上次釋出的穩定版本的更新;

  • *master* 跟蹤應該進入下一個發行版的提交;

  • *next* 旨在作為測試分支,用於測試主題在 master 中的穩定性。

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

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

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

從概念上講,功能從不穩定分支(通常是 *next* 或 *seen*)進入,一旦被認為足夠穩定,便“畢業”到 *master* 以供下一個發行版使用。

向上合併

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

規則:向上合併

始終將您的修復提交到需要它們的最舊受支援分支。然後(定期地)將整合分支向上合併到彼此中。

這提供了非常受控的修復流。如果您發現您已將修復應用於例如 *master* 分支,而 *maint* 分支也需要此修復,則需要向下揀選(使用 git-cherry-pick[1])。這種情況會發生幾次,除非您非常頻繁地這樣做,否則無需擔心。

主題分支

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

直接在整合分支上提交所有內容會導致許多問題:不良提交無法撤銷,因此必須逐一恢復,這會建立混亂的歷史記錄,並且當您忘記恢復一部分更改組時,還會產生進一步的錯誤潛力。並行工作會混淆更改,造成進一步的混亂。

使用“主題分支”解決了這些問題。這個名稱非常不言自明,但有一個注意事項,它來自上面的“向上合併”規則

規則:主題分支

為每個主題(功能、錯誤修復等)建立一個側分支。從您最終想要合併到的最舊的整合分支中分叉出來。

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

  • 要將功能/錯誤修復合併到整合分支中,只需合併即可。如果主題在此期間進一步發展,請再次合併。(請注意,您不一定非要先將其合併到最舊的整合分支。例如,您可以先將錯誤修復合併到 *next*,給它一些測試時間,然後在您確定它穩定時合併到 *maint*。)

  • 如果您發現需要從 *other* 分支獲取新功能以繼續處理您的主題,請將 *other* 合併到 *topic* 中。(但是,請勿“習慣性地”這樣做,見下文。)

  • 如果您發現自己從錯誤的分支分叉,並想將其“時光倒流”,請使用 git-rebase[1]

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

我們應該指出,“習慣性地”(沒有任何真正理由地定期)將整合分支合併到您的主題中——以及由此引申開來,定期地將任何上游內容合併到任何下游內容中——是不被贊成的

規則:只在明確定義的點合併到下游

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

否則,被合併的主題將突然包含不止一個(良好分離的)更改。由此產生的許多小型合併將極大地混淆歷史記錄。任何日後調查檔案歷史的人都必須查明該合併是否影響了開發中的主題。上游甚至可能無意中合併到“更穩定”的分支中。諸如此類。

一次性整合

如果您遵循了上一段,您現在將有許多小型主題分支,並且偶爾會想知道它們如何互動。也許合併它們的結果甚至無法工作?但另一方面,我們希望避免將它們合併到任何“穩定”的地方,因為此類合併不易撤銷。

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

規則:一次性整合分支

為了測試幾個主題的互動,將它們合併到一個一次性分支中。您絕不能在此類分支上進行任何工作!

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

釋出版的分支管理

假設您正在使用上面討論的合併方法,那麼在釋出專案時,您需要進行一些額外的分支管理工作。

特性發布版是從 *master* 分支建立的,因為 *master* 跟蹤應進入下一個特性發布版的提交。

*master* 分支應該是 *maint* 的超集。如果此條件不成立,則 *maint* 包含一些未包含在 *master* 中的提交。因此,這些提交所代表的修復將不會包含在您的特性發布版中。

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

方法:驗證 *master* 是 *maint* 的超集

git log master..maint

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

現在您可以繼續建立特性發布版。在 *master* 的頂端應用一個標籤來指示釋出版本

方法:釋出版打標籤

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

您需要將新標籤推送到公共 Git 伺服器(請參閱下面的“分散式工作流”)。這使得標籤可供跟蹤您專案的其他人使用。推送還可以觸發 post-update 鉤子,以執行釋出相關專案,例如構建釋出 tar 包和預格式化的文件頁面。

同樣,對於維護髮布版,*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* 可以選擇性地回溯並從 *master* 的頂端重建,使用 *next* 上現存的主題。

方法:回溯並重建 next
  • git switch -C next master

  • git merge ai/topic_in_next1

  • git merge ai/topic_in_next2

  • ……

這樣做的好處是 *next* 的歷史記錄將是乾淨的。例如,一些合併到 *next* 中的主題最初可能看起來很有前景,但後來被發現是不受歡迎的或不成熟的。在這種情況下,該主題會從 *next* 中恢復(revert),但歷史記錄中仍保留著它曾經被合併和恢復的事實。透過重新建立 *next*,您為這些主題的另一次嘗試提供了乾淨的起點,而特性發布版是執行此操作的一個良好歷史點。

如果您這樣做,那麼您應該釋出一份公開宣告,表明 *next* 已被回溯並重建。

*seen* 也可以遵循相同的回溯和重建過程。由於 *seen* 是一個一次性分支,如上所述,因此不需要公開宣告。

分散式工作流

看完上一節後,您應該知道如何管理主題。一般來說,您不會是專案上唯一工作的人,因此您必須分享您的工作。

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

請注意,維護者可能會施加限制,例如“Signed-off-by”要求,所有提交/補丁必須符合這些要求才能被包含。有關更多資訊,請查閱您專案的文件。

合併工作流

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

有三種主要工具可用於此目的

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

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

  • git-pull[1],它一次性完成抓取和合並。

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

釋出更改很容易

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

git push <遠端> <分支> 並告訴所有人從何處抓取。

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

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

方法:推送/拉取:保持最新

使用 git fetch <遠端>git remote update 來保持最新。

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

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

Please pull from
    <URL> <branch>

在這種情況下,*git pull* 可以一次性完成抓取和合並,如下所示。

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

git pull <URL> <分支>

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

補丁工作流

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

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

  • git send-email --to=<收件人> <補丁>

有關更多使用說明,請參閱 git-format-patch[1]git-send-email[1] 的手冊頁。

如果維護者告訴您您的補丁不再適用於當前上游,您將不得不變基您的主題(您不能使用合併,因為您無法對合並進行 format-patch 操作)

方法:format-patch/am:保持主題最新

git pull --rebase <URL> <分支>

然後您可以在變基期間解決衝突。據推測,您除了透過郵件之外沒有釋出過您的主題,因此對其進行變基不是問題。

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

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

git am < patch

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

GIT

Git[1] 套件的一部分

scroll-to-top