設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
-
2.52.0
2025-11-17
- 2.51.2 無變更
-
2.51.1
2025-10-15
- 2.50.1 → 2.51.0 無變更
-
2.50.0
2025-06-16
- 2.49.1 無更改
-
2.49.0
2025-03-14
- 2.46.1 → 2.48.2 無更改
-
2.46.0
2024-07-29
- 2.43.3 → 2.45.4 無更改
-
2.43.2
2024-02-13
-
2.43.1
2024-02-09
-
2.43.0
2023-11-20
- 2.42.1 → 2.42.4 無更改
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 無更改
-
2.41.0
2023-06-01
- 2.39.1 → 2.40.4 無更改
-
2.39.0
2022-12-12
- 2.38.1 → 2.38.5 無更改
-
2.38.0
2022-10-02
- 2.37.1 → 2.37.7 無更改
-
2.37.0
2022-06-27
- 2.35.1 → 2.36.6 無更改
-
2.35.0
2022-01-24
- 2.34.1 → 2.34.8 無更改
-
2.34.0
2021-11-15
- 2.33.1 → 2.33.8 無更改
-
2.33.0
2021-08-16
- 2.31.1 → 2.32.7 無更改
-
2.31.0
2021-03-15
- 2.30.1 → 2.30.9 無更改
-
2.30.0
2020-12-27
- 2.29.1 → 2.29.3 無更改
-
2.29.0
2020-10-19
- 2.28.1 無更改
-
2.28.0
2020-07-27
- 2.26.1 → 2.27.1 無更改
-
2.26.0
2020-03-22
- 2.25.1 → 2.25.5 無更改
-
2.25.0
2020-01-13
- 2.24.1 → 2.24.4 無更改
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 無更改
-
2.23.0
2019-08-16
此資訊專用於 Git 專案
請注意,如果您打算為 Git 專案本身做貢獻,此資訊才與您相關。它絕不是普通 Git 使用者的必讀內容。
摘要
這是一個教程,演示了建立 Git 提交、傳送以供審查以及根據反饋進行修改的端到端工作流程。
相關閱讀
本教程旨在總結以下文件,但讀者可能會發現其他有用的附加背景資訊
-
Documentation/SubmittingPatches -
Documentation/howto/new-command.adoc
獲取幫助
如果您遇到困難,可以在以下地方尋求幫助。
git@vger.kernel.org
這是主要的 Git 專案郵件列表,程式碼審查、版本公告、設計討論等都在這裡進行。有興趣貢獻的人歡迎在此處釋出問題。Git 郵件列表要求純文字郵件,回覆郵件時偏好內聯和底部回覆;您將在所有回覆中被抄送。可選地,您可以透過傳送電子郵件至 <git+subscribe@vger.kernel.org> 訂閱該列表(有關詳細資訊,請參閱 https://subspace.kernel.org/subscribing.html)。該郵件列表的 存檔 可在瀏覽器中檢視。
Libera Chat 上的 #git-devel
此 IRC 頻道用於 Git 貢獻者之間的交流。如果有人線上並且知道您問題的答案,您可以即時獲得幫助。否則,您可以閱讀 scrollback,看看是否有人回覆了您。IRC 不允許離線私信,因此如果您嘗試私信某人然後退出 IRC,他們無法回覆您。最好在頻道中提問,這樣即使您斷開連線也能得到答覆,並且其他人也可以從對話中學習。
Discord 上的 #discord
這是一個非官方的 Git Discord 伺服器,面向所有人,從剛開始使用 Git 的使用者到開發 Git 的人員。這是一個提問、分享技巧以及即時與更廣泛的 Git 社群聯絡的好地方。
該伺服器設有用於一般討論的頻道,以及專門為 Git 使用者和 Git 開發人員準備的頻道。伺服器的搜尋功能還可以幫助您查詢之前的對話和常見問題的答案。
入門
克隆 Git 倉庫
Git 在多個位置進行了映象。從其中一個位置克隆倉庫;https://git-scm.tw/downloads 建議從 GitHub 上的映象克隆是最佳選擇之一。
$ git clone https://github.com/git/git git $ cd git
安裝依賴項
要從原始碼構建 Git,您需要在系統上安裝一些依賴項。有關所需內容的提示,您可以檢視 INSTALL 檔案,並特別注意關於 Git 對外部程式和庫的依賴項的部分。該文件提到了一個方法,可以在不安裝的情況下“試用”我們剛構建好的 Git;本教程將使用此方法。
確保您的環境擁有您所需的一切,方法是構建上面步驟中您剛剛克隆的 Git
$ make
|
注意
|
Git 的構建是並行化的。上面未包含 -j#,但您可以根據自己的喜好在此處及其他地方使用它。 |
編寫程式碼!
|
注意
|
可以在 https://github.com/nasamuffin/git/tree/psuh 找到參考實現。 |
新增新命令
許多子命令都寫成內建命令,這意味著它們是用 C 實現的,並編譯到主 git 可執行檔案中。將非常簡單的 psuh 命令實現為內建命令將演示程式碼庫的結構、內部 API,以及作為貢獻者與審查者和維護者合作將此更改整合到系統中的過程。
內建子命令通常實現為一個名為“cmd_”後跟子命令名的函式,位於以子命令命名的原始檔(位於 builtin/ 目錄下)中。因此,將您的命令實現到 builtin/psuh.c 檔案中是合理的。建立該檔案,並在其中,按照樣式和簽名編寫命令的入口點函式:
int cmd_psuh(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED, struct repository *repo UNUSED)
有幾點需要注意:
-
子命令實現接收其命令列引數,如同
main() 函式一樣,透過int argc+const char **argv。 -
它還接受兩個額外的引數,
prefix和repo。它們的確切含義將在稍後討論。 -
由於第一個示例不會使用任何引數,編譯器將給出關於未使用引數的警告。由於新增新內建命令的 API 要求必須有這四個引數,因此您不能省略它們。相反,您可以在每個引數前新增
UNUSED,以告知編譯器您 **知道** 您(還)沒有使用它。
我們還需要新增 psuh 的宣告;開啟 builtin.h 檔案,找到 cmd_pull 的宣告,並在它前面新增一行用於 psuh 的宣告,以保持宣告按字母順序排序。
int cmd_psuh(int argc, const char **argv, const char *prefix, struct repository *repo);
確保在您的 psuh.c 中包含 "builtin.h"。您還需要包含 "gettext.h" 來使用與列印輸出文字相關的函式。
繼續在 cmd_psuh 函式中新增一些臨時的 printf。這是一個不錯的起點,因為現在我們可以新增構建規則並註冊該命令。
|
注意
|
您的臨時文字,以及在本教程過程中您將新增的許多文字,都是面向使用者的。這意味著它需要是可本地化的。檢視 po/README 檔案中“標記需要翻譯的字串”部分。在本教程中,我們將根據需要標記字串以供翻譯;將來在編寫使用者可見的命令時,您也應該這樣做。 |
int cmd_psuh(int argc UNUSED, const char **argv UNUSED,
const char *prefix UNUSED, struct repository *repo UNUSED)
{
printf(_("Pony saying hello goes here.\n"));
return 0;
}
讓我們嘗試構建它。開啟 Makefile 檔案,找到 builtin/pull.o 被新增到 BUILTIN_OBJS 的位置,並以相同的方式在它旁邊按字母順序新增 builtin/psuh.o。完成後,移至頂層目錄,僅使用 make 進行構建。另外,新增 DEVELOPER=1 變數以啟用一些額外的警告:
$ echo DEVELOPER=1 >config.mak $ make
|
注意
|
當您開發 Git 專案時,首選使用 DEVELOPER 標誌;如果您因為某些原因無法使用它,可以關閉它,但最好將問題告知郵件列表。 |
太好了,現在您的新命令可以獨立構建了。但沒人呼叫它。讓我們來改變這一點。
命令列表位於 git.c 檔案中。我們可以透過向 commands[] 陣列新增一個 cmd_struct 來註冊一個新命令。 struct cmd_struct 包含一個命令名稱字串、一個指向命令實現的函式指標以及一個設定選項標誌。目前,讓我們繼續模仿 push。找到註冊 cmd_push 的行,複製它,併為 cmd_psuh 修改它,將新行放置在字母順序上(緊隨 cmd_pull 之前)。
選項記錄在 builtin.h 的“新增新內建命令”部分。由於我們希望稍後列印有關使用者當前工作區上下文的資料,因此我們需要 Git 目錄,所以選擇 RUN_SETUP 作為我們唯一的選項。
再次進行構建。您應該會看到一個乾淨的構建,所以讓我們來試用一下,看看它是否有效。在 bin-wrappers 目錄中有一個可以用於測試的二進位制檔案。
$ ./bin-wrappers/git psuh
看!您有了一個命令!幹得好!讓我們提交這個。
git status 顯示了修改過的 Makefile、builtin.h 和 git.c,以及未跟蹤的 builtin/psuh.c 和 git-psuh。首先,讓我們處理二進位制檔案,它應該被忽略。在編輯器中開啟 .gitignore 檔案,找到 /git-pull,並在其中按字母順序新增您新命令的條目。
... /git-prune-packed /git-psuh /git-pull /git-push /git-quiltimport /git-range-diff ...
再次檢查 git status 應該顯示 git-psuh 已從未跟蹤列表中移除,並且 .gitignore 已新增到修改列表。現在我們可以暫存並提交:
$ git add Makefile builtin.h builtin/psuh.c git.c .gitignore $ git commit -s
您將看到編輯器彈出,以便您編寫提交訊息。提交應以 50 列或更短的標題行開始,包括您正在處理的元件的名稱,然後是一個空行(始終必需),接著是提交訊息的主體,該主體應提供大部分上下文。請記住要明確並提供您更改的“原因”,尤其是當從 diff 中不易理解時。編輯提交訊息時,請勿刪除上面使用 -s 新增的 Signed-off-by 標記。
psuh: add a built-in by popular demand Internal metrics indicate this is a command many users expect to be present. So here's an implementation to help drive customer satisfaction and engagement: a pony which doubtfully greets the user, or, a Pony Saying "Um, Hello" (PSUH). This commit message is intentionally formatted to 72 columns per line, starts with a single line as "commit message subject" that is written as if to command the codebase to do something (add this, teach a command that). The body of the message is designed to add information about the commit that is not readily deduced from reading the associated diff, such as answering the question "why?". Signed-off-by: A U Thor <author@example.com>
繼續使用 git show 檢查您的新提交。“psuh:”表明您主要修改了 psuh 命令。標題行讓讀者瞭解您所做的更改。簽名行(-s)表示您同意《開發者證書》(Developer’s Certificate of Origin 1.1)(請參閱 Documentation/SubmittingPatches [[dco]] 部分)。
在教程的其餘部分,為了簡潔起見,僅列出標題行。然而,完整的示例提交訊息可在本文件頂部連結的參考實現中找到。
實現
除了列印字串之外,至少做些其他事情可能很有用。讓我們先看看我們得到的所有內容。
修改您的 cmd_psuh 實現,以轉儲您收到的引數,保留現有的 printf() 呼叫;由於引數現在已被使用,請從它們中刪除 UNUSED 宏:
int i;
...
printf(Q_("Your args (there is %d):\n",
"Your args (there are %d):\n",
argc),
argc);
for (i = 0; i < argc; i++)
printf("%d: %s\n", i, argv[i]);
printf(_("Your current working directory:\n<top-level>%s%s\n"),
prefix ? "/" : "", prefix ? prefix : "");
構建並嘗試執行。正如您所料,基本上只有我們在命令列上傳遞的任何內容,包括我們的命令名稱。(如果您的 prefix 為空,請嘗試 cd Documentation/ && ../bin-wrappers/git psuh)。這沒什麼用。那麼我們還能獲得什麼其他上下文呢?
新增一行以包含 "config.h" 和 "repository.h"。然後,在函式體中新增以下內容:函式體
const char *cfg_name;
...
repo_config(repo, git_default_config, NULL);
if (repo_config_get_string_tmp(repo, "user.name", &cfg_name))
printf(_("No name is found in config\n"));
else
printf(_("Your name: %s\n"), cfg_name);
repo_config() 將從 Git 已知的配置檔案中獲取配置,並應用標準的優先順序規則。 repo_config_get_string_tmp() 將查詢特定鍵(“user.name”)並返回其值。存在許多類似的單鍵查詢函式;您可以在 Documentation/technical/api-config.adoc 中檢視所有這些函式(以及有關如何使用 repo_config() 的更多資訊)。
您應該看到列印的名稱與您執行以下命令時看到的名稱匹配:
$ git config --get user.name
太好了!現在我們知道如何檢查 Git 配置中的值了。讓我們也提交這個,以免丟失我們的進度。
$ git add builtin/psuh.c $ git commit -sm "psuh: show parameters & config opts"
|
注意
|
同樣,以上是為了在本教程中簡潔起見。在實際更改中,您不應使用 -m,而應使用編輯器編寫有意義的訊息。 |
然而,瞭解使用者的上下文是什麼樣的還是挺好的。讓我們看看是否能打印出使用者當前分支的名稱。我們可以模仿 git status 的實現;列印程式位於 wt-status.c 檔案中,我們可以看到分支儲存在一個 struct wt_status 中。
wt_status_print() 由 cmd_status() 在 builtin/commit.c 中呼叫。檢視該實現,我們看到狀態配置如下填充:
status_init_config(&s, git_status_config);
但當我們深入研究時,可以發現 status_init_config() 封裝了對 repo_config() 的呼叫。讓我們修改我們在上一個提交中所寫的程式碼。
確保包含該標頭檔案,以便您可以使用 struct wt_status。
#include "wt-status.h"
然後,修改您的 cmd_psuh 實現,以宣告您的 struct wt_status,準備它,並列印其內容:
struct wt_status status;
...
wt_status_prepare(repo, &status);
repo_config(repo, git_default_config, &status);
...
printf(_("Your current branch: %s\n"), status.branch);
再次執行它。看看——這是您當前分支的(詳細)名稱!
讓我們也提交這個。
$ git add builtin/psuh.c $ git commit -sm "psuh: print the current branch"
現在讓我們看看是否能獲取有關特定提交的一些資訊。
幸運的是,這裡有一些輔助函式。 commit.h 有一個名為 lookup_commit_reference_by_name 的函式,我們可以簡單地提供一個硬編碼的字串; pretty.h 有一個非常方便的 pp_commit_easy() 呼叫,它不需要傳遞完整的格式物件。
新增以下包含項:
#include "commit.h" #include "pretty.h"
然後,在您的 cmd_psuh() 實現的宣告和邏輯附近分別新增以下行:
struct commit *c = NULL;
struct strbuf commitline = STRBUF_INIT;
...
c = lookup_commit_reference_by_name("origin/master");
if (c != NULL) {
pp_commit_easy(CMIT_FMT_ONELINE, c, &commitline);
printf(_("Current commit: %s\n"), commitline.buf);
}
struct strbuf 為基本的 char* 提供了一些安全措施,其中之一是長度成員,以防止緩衝區溢位。它需要使用 STRBUF_INIT 進行良好初始化。當您需要傳遞 char* 時,請記住這一點。
lookup_commit_reference_by_name 會解析您傳遞給它的名稱,因此您可以嘗試更改那裡使用的值,看看您能發現什麼。
pp_commit_easy 是 pretty.h 中的一個方便的包裝函式,它接受一個單獨的格式列舉簡寫,而不是一個完整的格式結構。然後它會根據該簡寫格式化列印提交。這些類似於許多 Git 命令中 --pretty=FOO 可用的格式。
構建並執行它,如果您使用的名稱與示例中的相同,您應該會看到您所知的 origin/master 中最近一次提交的主題行。不錯!讓我們也提交這個。
$ git add builtin/psuh.c $ git commit -sm "psuh: display the top of origin/master"
新增文件
太棒了!您有了一個很棒的新命令,可以分享給社群了。但是等等——這不是很使用者友好。執行以下命令:
$ ./bin-wrappers/git help psuh
您的新命令沒有文件!讓我們來修復它。
檢視 Documentation/git-*.adoc 檔案。這些是 Git 已知子命令的手冊頁。您可以開啟它們檢視格式,然後建立一個新檔案 Documentation/git-psuh.adoc。與 Git 專案中的大多數文件一樣,幫助頁面使用 AsciiDoc 編寫(請參閱 CodingGuidelines,“Writing Documentation”部分)。使用以下模板填寫您自己的手冊頁:
git-psuh(1) =========== NAME ---- git-psuh - Delight users' typo with a shy horse SYNOPSIS -------- [verse] 'git-psuh [<arg>...]' DESCRIPTION ----------- ... OPTIONS[[OPTIONS]] ------------------ ... OUTPUT ------ ... GIT --- Part of the git[1] suite
關於此內容最重要的一點是檔案頭,用 = 劃線;NAME 部分;以及 SYNOPSIS,其中通常包含您的命令接收引數時的語法。嘗試使用成熟的手冊頁標題,以使您的文件與其他 Git 和 UNIX 手冊頁保持一致;這可以為您的使用者節省時間,因為他們可以直接跳到包含所需資訊的章節。
|
注意
|
在嘗試構建文件之前,請確保已安裝 asciidoc 包。 |
現在您已經編寫了手冊頁,您需要顯式地構建它。我們像這樣將 AsciiDoc 轉換為 troff,後者是人類可讀的格式:
$ make all doc $ man Documentation/git-psuh.1
或
$ make -C Documentation/ git-psuh.1 $ man Documentation/git-psuh.1
雖然這不像執行 git help 那樣令人滿意,但至少您可以檢查您的幫助頁面是否看起來正確。
您還可以透過在頂層目錄執行 make check-docs 來檢查文件覆蓋率是否良好(即,專案是否已識別您的命令已實現並已記錄)。
繼續提交您的新文件更改。
新增用法文字
嘗試執行 ./bin-wrappers/git psuh -h。您的命令在結束時應該會崩潰。這是因為 -h 是一個特殊情況,您的命令應該透過列印用法來處理它。
請檢視 Documentation/technical/api-parse-options.adoc。這是一個方便的工具,用於提取您需要處理的選項,它接受一個用法字串。
為了使用它,我們需要準備一個 NULL 結尾的用法字串陣列和一個 builtin_psuh_options 陣列。
向 #include "parse-options.h" 新增一行。
在全域性作用域,新增您的用法字串陣列:
static const char * const psuh_usage[] = {
N_("git psuh [<arg>...]"),
NULL,
};
然後,在您的 cmd_psuh() 實現中,我們可以宣告並填充我們的 option 結構。我們的非常簡單,但如果您想更詳細地探索 parse_options(),可以新增更多內容:
struct option options[] = {
OPT_END()
};
最後,在列印您的引數和字首之前,新增對 parse-options() 的呼叫:
argc = parse_options(argc, argv, prefix, options, psuh_usage, 0);
此呼叫將修改您的 argv 引數。它將從 argv 中刪除您在 options 中指定的選項,並更新 options 條目指向的位置。請務必將您的 argc 替換為 parse_options() 的結果,否則如果您以後嘗試解析 argv,您將感到困惑。
值得注意的是特殊引數 --。正如您可能知道的,許多 Unix 命令使用 -- 來表示“命名引數結束”—— -- 之後的所有引數僅被解釋為位置引數。(如果您想將一個通常被解釋為標誌的引數傳遞給某個東西,這會很有用。) parse_options() 將在遇到 -- 時停止解析,並將剩餘的選項原樣返回。
現在您有了用法提示,您可以教 Git 如何在 git help git 或 git help -a 顯示的通用命令列表中顯示它,該列表是從 command-list.txt 生成的。找到 git-pull 行,以便您可以在其上方按字母順序新增 git-psuh 行。現在,我們可以新增一些關於命令的屬性,這些屬性會影響它在上述幫助命令中的顯示位置。 command-list.txt 的頂部共享有關每個屬性含義的資訊;在這些幫助頁面中,命令是根據這些屬性排序的。 git psuh 是面向使用者的(porcelain),所以我們將它標記為“mainporcelain”。對於“mainporcelain”命令,command-list.txt 頂部的註釋表明我們還可以選擇性地新增另一個列表中的屬性;由於 git psuh 顯示了一些關於使用者工作區的資訊,但並不修改任何內容,因此我們將其標記為“info”。確保保持您的屬性與 command-list.txt 中的其餘內容風格一致,使用空格對齊和分隔它們。
git-prune-packed plumbingmanipulators git-psuh mainporcelain info git-pull mainporcelain remote git-push mainporcelain remote
再次構建。現在,當您使用 -h 執行時,您應該會看到您的用法被打印出來,並且您的命令在任何其他有趣的事情發生之前終止。太棒了!
繼續提交這個。
測試
測試程式碼非常重要——即使是一個像這樣的小玩具命令也是如此。此外,沒有測試,您的補丁將不會被接受到 Git 樹中。您的測試應該:
-
說明當前功能的行為
-
證明當前行為符合預期行為
-
確保外部可見的行為在後續更改中不會被破壞
所以讓我們寫一些測試。
相關閱讀:t/README
編寫您的測試
由於這是一個玩具命令,讓我們將其命名為 t9999。然而,由於許多系列/子命令組合已經滿了,最好的做法似乎是找到一個與您新增的命令足夠接近的命令,並共享其名稱空間。
建立一個新檔案 t/t9999-psuh-tutorial.sh。使用以下頭部開始(請參閱 t/README 中的“編寫測試”和“Source test-lib.sh”):
#!/bin/sh test_description='git-psuh test This test runs git-psuh and makes sure it does not crash.' . ./test-lib.sh
測試被封裝在 test_expect_success 中,以輸出 TAP 格式的結果。讓我們確保 git psuh 不會糟糕地退出,並且確實提到了正確的動物:
test_expect_success 'runs correctly with no args and good output' ' git psuh >actual && grep Pony actual '
透過在指令碼底部新增以下內容來指示您已執行完所有想執行的內容:
test_done
確保將您的測試指令碼標記為可執行檔案:
$ chmod +x t/t9999-psuh-tutorial.sh
您可以透過執行 make -C t test-lint 來了解您是否成功建立了新的測試指令碼,該命令會檢查諸如測試編號唯一性、可執行位等內容。
準備分享:補丁系列(Patch Series)的構成
您可能已經注意到,Git 專案透過電子郵件補丁進行程式碼審查,當補丁準備好並獲得社群批准後,維護者會將其應用。Git 專案不接受來自 pull requests 的貢獻,並且傳送用於審查的補丁需要以特定的方式格式化。
在檢視如何將您的提交轉換為電子郵件補丁之前,讓我們分析一下最終結果“補丁系列”的樣子。以下是在 Git 郵件列表存檔 的 Web 介面上補丁系列的摘要檢視的 示例。
2022-02-18 18:40 [PATCH 0/3] libify reflog John Cai via GitGitGadget 2022-02-18 18:40 ` [PATCH 1/3] reflog: libify delete reflog function and helpers John Cai via GitGitGadget 2022-02-18 19:10 ` Ævar Arnfjörð Bjarmason [this message] 2022-02-18 19:39 ` Taylor Blau 2022-02-18 19:48 ` Ævar Arnfjörð Bjarmason 2022-02-18 19:35 ` Taylor Blau 2022-02-21 1:43 ` John Cai 2022-02-21 1:50 ` Taylor Blau 2022-02-23 19:50 ` John Cai 2022-02-18 20:00 ` // other replies elided 2022-02-18 18:40 ` [PATCH 2/3] reflog: call reflog_delete from reflog.c John Cai via GitGitGadget 2022-02-18 19:15 ` Ævar Arnfjörð Bjarmason 2022-02-18 20:26 ` Junio C Hamano 2022-02-18 18:40 ` [PATCH 3/3] stash: call reflog_delete from reflog.c John Cai via GitGitGadget 2022-02-18 19:20 ` Ævar Arnfjörð Bjarmason 2022-02-19 0:21 ` Taylor Blau 2022-02-22 2:36 ` John Cai 2022-02-22 10:51 ` Ævar Arnfjörð Bjarmason 2022-02-18 19:29 ` [PATCH 0/3] libify reflog Ævar Arnfjörð Bjarmason 2022-02-22 18:30 ` [PATCH v2 0/3] libify reflog John Cai via GitGitGadget 2022-02-22 18:30 ` [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior John Cai via GitGitGadget 2022-02-23 8:54 ` Ævar Arnfjörð Bjarmason 2022-02-23 21:27 ` Junio C Hamano // continued
我們可以注意幾點:
-
每個提交都作為單獨的電子郵件傳送,以提交訊息標題作為主題,前面加上“[PATCH i/n]”,表示一個 n 個提交的系列中的第 i 個提交。
-
每個補丁都作為對系列介紹性電子郵件(稱為封面信)的回覆傳送,前面加上“[PATCH 0/n]”。
-
補丁系列的後續迭代將用“PATCH v2”、“PATCH v3”等替換“PATCH”。例如,“[PATCH v2 1/3]”將是第二個迭代中三個補丁中的第一個。每次迭代都附帶一封新的封面信(如上面的“[PATCH v2 0/3]”),它本身是前一次迭代封面信的回覆(稍後會詳細介紹)。
|
注意
|
單個補丁主題的傳送格式為“[PATCH]”、“[PATCH v2]”等,不帶 i/n 編號(在上方的執行緒概覽中,沒有顯示單個補丁主題)。 |
封面信
除了每份補丁一個電子郵件外,Git 社群還希望您的補丁附帶一封封面信。這是提交更改的重要組成部分,因為它能從高層次向社群解釋您試圖做什麼,以及為什麼這樣做,其清晰度遠超僅僅檢視補丁本身。
您的封面信標題應簡潔地概括您整個主題分支的目的。通常使用祈使語氣,就像我們的提交訊息標題一樣。以下是我們為補丁系列命名的規則:
新增 psuh 命令 ---
封面信正文用於為審閱者提供額外背景資訊。務必解釋您的補丁本身未能闡明的任何內容,但請記住,由於封面信不會記錄在提交歷史中,任何對儲存庫歷史的未來讀者有用的資訊都應包含在您的提交訊息中。
這是 psuh 的示例正文
Our internal metrics indicate widespread interest in the command git-psuh - that is, many users are trying to use it, but finding it is unavailable, using some unknown workaround instead. The following handful of patches add the psuh command and implement some handy features on top of it. This patchset is part of the MyFirstContribution tutorial and should not be merged.
此時,教程將分岔,以演示兩種不同的格式化補丁集和獲取審閱的方法。
要介紹的第一種方法是 GitGitGadget,它對於熟悉 GitHub 通用拉取請求工作流程的人很有用。此方法需要 GitHub 帳戶。
要介紹的第二種方法是 git send-email,它可以提供更精細地控制要傳送的電子郵件。此方法需要一些設定,具體取決於您的系統,並且在本教程中不涵蓋。
無論您選擇哪種方法,您與審閱者的互動方式都是相同的;審閱過程將在 GitGitGadget 和 git send-email 部分之後介紹。
透過 GitGitGadget 傳送補丁
傳送補丁的一種選擇是遵循典型的拉取請求工作流程,並透過 GitGitGadget 傳送您的補丁。GitGitGadget 是 Johannes Schindelin 建立的一個工具,旨在讓習慣於 GitHub PR 工作流程的 Git 貢獻者生活更輕鬆。它允許貢獻者針對 Git 專案的映象開啟拉取請求,並做一些魔法操作,將 PR 轉換為一組電子郵件併為您傳送出去。它還會為您執行 Git 持續整合套件。其文件位於 https://gitgitgadget.github.io/。
在 GitHub 上 Fork git/git
在您可以使用 GitGitGadget 傳送補丁進行審閱之前,您需要 Fork Git 專案並上傳您的更改。首先,請確保您擁有一個 GitHub 帳戶。
前往 GitHub 映象 並找到 Fork 按鈕。將您的 Fork 放在您認為合適的位置並建立它。
上傳到您自己的 Fork
要將您的分支上傳到您自己的 Fork,您需要將新的 Fork 新增為遠端。您可以使用 git remote -v 來顯示您已新增的遠端。從 GitHub 上的新 Fork 頁面,您可以按“Clone or download”來獲取 URL;然後您需要執行以下命令來新增,將您自己的 URL 和遠端名稱替換為提供的示例。
$ git remote add remotename git@github.com:remotename/git.git
或使用 HTTPS URL
$ git remote add remotename https://github.com/remotename/git/.git
再次執行 git remote -v,您應該會看到新的遠端顯示出來。執行 git fetch remotename(替換為您遠端的實際名稱)以準備推送。
接下來,透過執行 git branch 再次仔細檢查您是否一直在新的分支上進行開發。如果您沒有,現在是時候將您的新提交移到自己的分支上了。
正如本文件開頭簡要提到的,我們的工作基於 master,所以請繼續並按如下所示更新,或使用您首選的工作流程。
$ git checkout master $ git pull -r $ git rebase master psuh
最後,您已準備好推送新的主題分支!(由於我們分支和命令的命名選擇,請謹慎輸入以下命令。)
$ git push remotename psuh
現在您應該可以在 GitHub 上檢視新建立的分支了。
透過 GitGitGadget 傳送 PR
為了讓程式碼得到測試和格式化以便審閱,您需要先針對 gitgitgadget/git 或 git/git 開啟一個拉取請求。前往 https://gitgitgadget.github.io/ 或 https://github.com/git/git,然後使用“New pull request”按鈕或可能出現的、帶有您新推送分支名稱的“Compare & pull request”按鈕來開啟 PR。
使用 gitgitgadget/git 和 git/git 作為基礎之間的區別可以在 [此處](https://gitgitgadget.github.io/#should-i-use-gitgitgadget-on-gitgitgadgets-git-fork-or-on-gits-github-mirror) 找到。
審閱 PR 的標題和描述,因為 GitGitGadget 分別將它們用作您更改的封面信的主題和正文。有關如何為您的提交命名以及在描述中包含哪些內容,請參閱上面的 “封面信”。
|
注意
|
對於單補丁貢獻,您的提交訊息應已具有意義,並從高層次解釋補丁的目的(正在發生什麼以及為什麼),因此通常不需要額外上下文。在這種情況下,請刪除 GitHub 自動從您的提交訊息中生成的 PR 描述(您的 PR 描述應為空)。如果您確實需要提供更多上下文,可以在該空間中進行,它將被附加到 GitGitGadget 將要傳送的電子郵件中,位於三虛線行和 diffstat 之間(有關提交後外觀,請參閱 附錄:單補丁更改)。 |
當您滿意後,提交您的拉取請求。
執行 CI 並準備傳送
如果您是第一次使用 GitGitGadget(很可能,因為您正在使用此教程),那麼需要有人授予您使用該工具的許可權。正如 GitGitGadget 文件中所述,您只需要讓一個已經在使用它的人在您的 PR 上評論 /allow <username>。GitGitGadget 會在沒有獲得許可權的情況下自動執行您的 PR 透過 CI,但直到有人允許您使用該工具,您才能 /submit 您的更改。
|
注意
|
您通常可以在 GitGitGadget 上找到可以 /allow 您的人,方法是檢視最近有人獲得 /allow 的拉取請求(搜尋:is:pr is:open "/allow"),在這種情況下,作者和授予 /allow 的人都可以 /allow 您,或者透過在 #git-devel IRC 頻道上詢問 Libera Chat,連結您的拉取請求並請求某人 /allow 您。 |
如果 CI 失敗,您可以使用 git rebase -i 更新您的更改並再次推送您的分支。
$ git push -f remotename psuh
事實上,您應該一直以這種方式進行更改,直到您的補丁被接受到 next 為止。
傳送您的補丁
現在您的 CI 已透過,並且有人已授予您使用 GitGitGadget 的許可權(透過 /allow 命令),傳送審閱就像在您的 PR 上評論 /submit 一樣簡單。
使用評論更新
跳到 響應審閱部分,瞭解如何回覆您在郵件列表中收到的審閱評論。
一旦您的分支按照所有審閱評論進行了修改,您就可以再次提交。
$ git push -f remotename psuh
接下來,檢視您針對 GitGitGadget 的拉取請求;您應該會看到 CI 已重新啟動。現在,當 CI 執行時,是時候修改拉取請求執行緒頂部的描述了;它將再次用作封面信。您應該利用此空間描述自上一版本以來所做的更改,以便審閱者對他們正在檢視的內容有所瞭解。CI 執行完成後,您可以再次評論 /submit - GitGitGadget 將自動為您的更改新增 v2 標記。
使用 git send-email 傳送補丁
如果您不想使用 GitGitGadget,您也可以使用 Git 本身來郵寄您的補丁。以這種方式使用 Git 的一些好處包括對主題行的更精細控制(例如,能夠在主題中使用 [RFC PATCH] 標籤)以及能夠傳送“試執行”郵件給自己,以確保在傳送到列表之前一切看起來都很好。
前提條件:設定 git send-email
send-email 的配置可能因您的作業系統和電子郵件提供商而異,因此本教程不予涵蓋,僅說明在許多 Linux 發行版中,git-send-email 未與典型的 git 安裝一起打包。您可能需要安裝此附加包;網上有很多資源可以幫助您做到這一點。您還需要確定配置它以使用您的 SMTP 伺服器的正確方法;同樣,由於此配置可能因您的系統和電子郵件設定而有很大差異,因此超出了本教程的範圍。
準備初始補丁集
使用 Git 傳送電子郵件是一個兩部分的過程;在準備電子郵件本身之前,您需要準備補丁。幸運的是,這很簡單。
$ git format-patch --cover-letter -o psuh/ --base=auto psuh@{u}..psuh
-
--cover-letter選項告訴format-patch為您建立封面信模板。在準備傳送之前,您需要填寫該模板 - 但現在,該模板將與您的其他補丁放在一起。 -
-opsuh/選項告訴format-patch將補丁檔案放入一個目錄中。這很有用,因為gitsend-email可以接受一個目錄並從中傳送所有補丁。 -
--base=auto選項告訴命令記錄“基本提交”,收件人應在此提交上應用補丁系列。auto 值將導致format-patch自動計算基本提交,這是遠端跟蹤分支的尖端提交與指定的修訂範圍的合併基。 -
psuh@{u}..psuh選項告訴format-patch為您在psuh分支上建立的提交生成補丁,自從它從其上游分支(如果您遵循了“設定您的工作區”部分中的示例,則為origin/master)分叉以來。如果您已經在psuh分支上,您可以只說@{u},它的意思是“自當前分支與上游分支分叉以來的提交”,這與前者相同。
該命令將為每個提交建立一個補丁檔案。執行後,您可以用您喜歡的文字編輯器檢視每個補丁,並確保一切看起來都正常;但是,不建議透過補丁檔案進行程式碼修復。最好使用 git rebase -i 以正常方式進行更改,或者新增一個新提交,而不是修改補丁。
|
注意
|
可選地,您還可以使用 --rfc 標誌將補丁主題字首設定為“[RFC PATCH]”而不是“[PATCH]”。RFC 代表“請求評論”,表示雖然您的程式碼尚未準備好提交,但您希望開始程式碼審閱過程。當您的補丁是某個提議,但您不確定社群是否要採用該方法來解決問題時,也可以使用此標誌 - 進行一種設計評審。您可能還會在列表中看到標記為“WIP”(進行中)的補丁 - 這意味著它們不完整,但希望審閱者檢視到目前為止的內容。您可以使用 --subject-prefix=WIP 新增此標誌。 |
檢查並確保您的補丁和封面信模板存在於您指定的目錄中 - 您已基本準備好傳送審閱!
準備電子郵件
由於您使用 --cover-letter 呼叫了 format-patch,您已經準備了一個封面信模板。用您喜歡的編輯器開啟它。
您應該會看到一些已經存在的標題。檢查您的 From: 標題是否正確。然後修改您的 Subject:(有關如何為您的補丁系列選擇好的標題,請參閱上面的 “封面信”)
Subject: [PATCH 0/7] Add the 'psuh' command
請務必保留“[PATCH 0/X]”部分;這表明 Git 社群這封電子郵件是一個補丁系列的開始,許多審閱者會根據此標誌過濾他們的電子郵件。
當您呼叫 git send-email 來新增封面信時,您需要新增一些額外的引數。
接下來,您需要填寫封面信的正文。同樣,有關要包含的內容,請參閱上面的 “封面信”。
由 git format-patch --cover-letter 建立的模板包含一個 diffstat。這為審閱者提供了一個關於他們的審閱主題的摘要。從示例實現生成的 psuh 的 diffstat 如下所示。
Documentation/git-psuh.adoc | 40 +++++++++++++++++++++ Makefile | 1 + builtin.h | 1 + builtin/psuh.c | 73 ++++++++++++++++++++++++++++++++++++++ git.c | 1 + t/t9999-psuh-tutorial.sh | 12 +++++++ 6 files changed, 128 insertions(+) create mode 100644 Documentation/git-psuh.adoc create mode 100644 builtin/psuh.c create mode 100755 t/t9999-psuh-tutorial.sh
最後,信件將包含用於生成補丁的 Git 版本。您可以保留該字串不變。
傳送電子郵件
此時,您應該有一個名為 psuh/ 的目錄,其中填充了您的補丁和封面信。是時候郵寄出去了!您可以像這樣傳送:
$ git send-email --to=target@example.com psuh/*.patch
|
注意
|
檢視 git help send-email 以瞭解您可能覺得有用的其他選項,例如更改回復地址或新增更多 CC 和 BCC 行。 |
|
注意
|
如果您不確定要 CC 誰,執行 contrib/contacts/git-contacts 可以列出潛在的審閱者。此外,您可以執行 git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch[1] 來自動將此電子郵件列表傳遞給 send-email。 |
|
注意
|
當您傳送真實補丁時,它將傳送到 git@vger.kernel.org - 但請不要將本教程的補丁集傳送到真實的郵件列表!目前,您可以將其傳送給自己,以確保您瞭解其外觀。 |
|
注意
|
傳送補丁後,您可以訪問 https://lore.kernel.org/git/ 來確認它們是否已送達郵件列表。使用搜索欄查詢您的姓名或補丁的主題。如果出現,則表示您的電子郵件已成功送達。 |
執行上述命令後,您將看到每個即將傳送的補丁的互動式提示。這為您提供了最後一次編輯或退出傳送的機會(但請再次注意,不要在此處編輯程式碼)。一旦您在這些提示符處按下 y 或 a,您的電子郵件就會被髮送!恭喜!
太棒了,現在社群將放下一切來審閱您的更改。(開玩笑的 - 請耐心等待!)
傳送 v2
本節將重點介紹如何傳送補丁集的 v2 版本。要了解 v2 版本應包含哪些內容,請跳至 響應審閱 部分,瞭解如何處理審閱者的評論。
我們將重用我們的 psuh 主題分支用於 v2。在進行任何更改之前,我們將標記 v1 分支的尖端以便於引用。
$ git checkout psuh $ git branch psuh-v1
使用 git rebase -i 根據審閱者的評論調整提交,從而最佳化您的補丁系列。一旦補丁系列準備好提交,請再次生成您的補丁,但使用一些新標誌。
$ git format-patch -v2 --cover-letter -o psuh/ --range-diff master..psuh-v1 master..
--range-diff master..psuh-v1 引數告訴 format-patch 在 psuh-v1 和 psuh 之間包含一個範圍差異,並將其包含在封面信中(請參閱 git-range-diff[1])。這有助於告知審閱者 v1 和 v2 補丁之間的區別。
-v2 引數告訴 format-patch 將您的補丁輸出為版本“2”。例如,您可能會注意到您的 v2 補丁都命名為 v2-000n-my-commit-subject.patch。 -v2 還會透過在補丁前面加上“[PATCH v2]”而不是“[PATCH]”來格式化您的補丁,並且您的範圍差異將以“Range-diff against v1”為字首。
執行此命令後,format-patch 將把補丁輸出到 psuh/ 目錄,與 v1 補丁並列。使用單個目錄可以方便地在校對 v2 補丁時引用舊的 v1 補丁,但您需要小心只發送 v2 補丁。我們將使用像 psuh/v2-*.patch 這樣的模式(而不是 psuh/*.patch,後者將匹配 v1 和 v2 補丁)。
再次編輯您的封面信。現在是提及您上次版本和現在版本之間差異的好時機,如果這是非常重要的內容。您不必在第二封封面信中使用完全相同的正文;重點是向審閱者解釋您所做的可能不那麼顯眼的更改。
您還需要找到前一封封面信的 Message-ID。您可以從 git send-email 的輸出中傳送第一個系列時記下它,或者可以在 郵件列表 上查詢它。在存檔中找到您的封面信,點選它,然後點選“permalink”或“raw”以顯示 Message-ID 標題。它應該匹配
Message-ID: <foo.12345.author@example.com>
您的 Message-ID 是 <foo.12345.author@example.com>。此示例將在下面使用;請務必將其替換為您**上一個封面信**的正確 Message-ID - 也就是說,如果您傳送 v2,請使用 v1 的 Message-ID;如果您傳送 v3,請使用 v2 的 Message-ID。
在檢視電子郵件時,您還應該注意誰被 CC 了,因為在郵件列表中,保持執行緒中的所有 CC 是常見做法。您可以直接在您的封面信中新增這些 CC 行,在主題行之前,使用如下一行:
CC: author@example.com, Othe R <other@example.com>
現在再次傳送電子郵件,密切注意您傳遞給命令的訊息。
$ git send-email --to=target@example.com --in-reply-to="<foo.12345.author@example.com>" psuh/v2-*.patch
附錄:單補丁更改
在某些情況下,您非常小的更改可能只包含一個補丁。當這種情況發生時,您只需要傳送一封電子郵件。您的提交訊息應該已經具有意義,並從高層次解釋您補丁的目的(發生了什麼以及為什麼),但如果您需要提供更多上下文,可以在補丁中的 --- 下方進行。看下面的例子,它是在單個提交上使用 git format-patch 生成的,然後編輯以新增 --- 和 diffstat 之間的內容。
From 1345bbb3f7ac74abde040c12e737204689a72723 Mon Sep 17 00:00:00 2001 From: A U Thor <author@example.com> Date: Thu, 18 Apr 2019 15:11:02 -0700 Subject: [PATCH] README: change the grammar I think it looks better this way. This part of the commit message will end up in the commit-log. Signed-off-by: A U Thor <author@example.com> --- Let's have a wild discussion about grammar on the mailing list. This part of my email will never end up in the commit log. Here is where I can add additional context to the mailing list about my intent, outside of the context of the commit log. This section was added after `git format-patch` was run, by editing the patch file in a text editor. README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88f126184c..38da593a60 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Git - fast, scalable, distributed revision control system ========================================================= -Git is a fast, scalable, distributed revision control system with an +Git is a fast, scalable, and distributed revision control system with an unusually rich command set that provides both high-level operations and full access to internals. -- 2.21.0.392.gf8f6787159e-goog
我的補丁已傳送電子郵件 - 現在怎麼辦?
在傳送更新版本之前,請給審閱者足夠的時間來處理您的初始補丁。也就是說,請剋制立即傳送新版本的衝動,因為其他人可能已經開始審閱您的初始版本了。
在等待審閱評論時,您可能會在初始補丁中發現錯誤,或者可能意識到另一種更好的方法來實現補丁的目標。在這種情況下,您可以透過以下方式將您的發現傳達給其他審閱者。
-
如果您發現的錯誤很小,請回復您的補丁,就像您是審閱者一樣,並提到您將在更新版本中修復它們。
-
另一方面,如果您認為您想要改變方向的幅度如此之大,以至於對初始補丁的審閱將是浪費時間(對所有相關人員而言),請立即回覆“我正在研究一種更好的方法,請忽略此補丁並等待更新版本。”來撤回該補丁。
好了,以上是如果您過早地傳送了未經打磨的初始補丁,一種不錯的做法。但當然,更好的方法是首先避免過早傳送補丁。
請體諒審閱者檢查您補丁每個新版本所需的時間。審閱者寧願看到兩天後出現一個經過打磨的、錯誤較少的版本,而不是現在看到初始版本(隨後兩天內出現多個“哎呀,我更喜歡這個版本而不是上一個版本”的補丁)。
響應審閱
幾天後,您很可能會收到對您補丁集的回覆,並附帶一些評論。太棒了!現在您可以回去工作了。
禮貌的做法是回覆每一條評論,通知審閱者您已做出建議的更改,認為原方案更好,或者該評論啟發您以一種新的、優於原始方案和建議更改的方式來完成。這樣,審閱者就不必檢查您的 v2 來弄清楚您是否實現了他們的評論。
審閱者可能會詢問您在補丁集中寫的內容,無論是提議的提交日誌訊息還是程式碼本身。您應該在您的回覆訊息中回答這些問題,但審閱者之所以提出這些問題以理解您想寫的內容,通常是因為您的補丁集需要澄清才能被理解。
不要僅僅滿足於回答他們的問題並聽他們說他們現在理解您想說什麼。更新您的補丁以澄清審閱者遇到困難的要點,並準備您的 v2;您用來解釋 v1 以回答審閱者問題的措辭可能會很有用。您的目標是使您的 v2 清晰到無需向下一個閱讀它的人給出相同的解釋。
如果您要反駁某個評論,請禮貌地說明您認為原方案更好的原因;請做好準備,審閱者仍可能不同意您的觀點,而社群的其他人也可能在其中一方或另一方發表意見。與所有程式碼審閱一樣,重要的是保持開放的心態,嘗試以一種不同於您最初計劃的方式行事;其他審閱者對專案的看法與您不同,他們可能正在考慮一個您沒有想到的有效副作用。如果您不確定為什麼會提出某項更改,或者審閱者要求您做什麼,隨時可以尋求澄清。
請確保您的電子郵件客戶端具有純文字電子郵件模式並已啟用;Git 列表拒絕 HTML 電子郵件。請同時遵循 維護者說明 中概述的郵件列表禮儀,這類似於大多數開源社群中關於底部發帖和內聯回覆的禮儀規則。
當您對程式碼進行更改時,最乾淨(即,結果提交最容易檢視)的方式是使用 git rebase -i(互動式 rebase)。看一下 O’Reilly 的這個 概述。總體的想法是修改每個需要更改的提交;這樣,您就可以提交一個 v2,其中包含一個正確的補丁 A 和一個正確的補丁 B,而不是一個帶有錯誤的補丁 A,一個在 v1 中沒問題且無需上游審閱的補丁 B,以及一個修復補丁 A 的補丁 C。這改變了歷史,但由於這是您尚未與任何人共享的本地歷史,所以現在沒問題!(稍後,這樣做可能沒有意義;看看它下面的部分以獲取一些上下文。)
批准審閱後
Git 專案有四個整合分支:seen、next、master 和 maint。您的更改將在審閱過程的早期由維護者放入 seen,然後,當它準備好進行更廣泛的測試時,它將合併到 next。許多早期測試者使用 next,並可能會報告問題。最終,next 中的更改將進入 master,通常被認為是穩定的。最後,當一個新版本釋出時,maint 用於基於 bug 修復。如本文件開頭所述,您可以閱讀 Documents/SubmittingPatches 以獲取有關各種整合分支使用的更多資訊。
現在回到當前:您的程式碼已獲得上游審閱者的讚賞。它是完美的。它已準備好被接受。您無需做任何其他事情;維護者將把您的主題分支合併到 next,一切順利。
但是,如果您在此之後發現它並不那麼完美,您可能需要根據您在過程中的位置採取一些特殊步驟。
如果維護者在“git.git 中有什麼新內容”電子郵件中宣佈您的主題已標記為 next - 即,他們計劃將其合併到 next 但尚未合併 - 您應該傳送一封電子郵件請求維護者再等一會兒:“我傳送了我的系列的 v4,您已將其標記為 next,但我需要更改這個和那個 - 請等待 v5 再合併。”
如果該主題已合併到 next,則不要使用 git rebase -i 修改您的補丁,而應增量地進行進一步更改 - 也就是說,新增另一個提交,基於維護者在 https://github.com/gitster/git 中詳細介紹的主題分支。您的工作仍在同一主題中,但現在是增量的,而不是對主題分支進行 wholesale 重寫。
維護者 GitHub 中的主題分支在 GitGitGadget 中有映象,因此如果您透過這種方式傳送審閱,您應該確保將 PR 開啟到適當的 GitGitGadget/Git 分支。
如果您使用 git send-email,您可以像以前一樣使用它,但您應該生成從 <topic>..<mybranch> 開始的 diffs,並將您的工作基於 <topic> 而不是 master。