设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
打补丁
调试
外部系统
服务器管理
指南
管理
底层命令
-
2.49.0
2025-03-14
- 2.46.1 → 2.48.1 没有更改
-
2.46.0
2024-07-29
- 2.43.3 → 2.45.3 没有更改
-
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)。 此邮件列表的 存档 可以在浏览器中查看。
git-mentoring@googlegroups.com
此邮件列表的目标是新的贡献者,创建它是为了在一个不公开的主列表之外发布问题并接收答案。 尤其热衷于帮助指导新手的资深贡献者都在该列表上。 为了避免搜索索引器,需要组成员身份才能查看消息; 任何人都可以加入,无需批准。
#git-devel on Libera Chat
此 IRC 频道供 Git 贡献者之间进行对话。 如果有人当前在线并且知道你问题的答案,你可以实时获得帮助。 否则,你可以阅读 scrollback 以查看是否有人回答了你。 IRC 不允许离线私人消息,因此,如果你尝试向某人发送私人消息然后注销 IRC,他们将无法回复你。 最好在频道中提出你的问题,以便在你断开连接时可以得到解答,并使其他人可以从对话中学习。
入门
克隆 Git 仓库
Git 在许多位置都有镜像。 从其中一个克隆存储库; https://git-scm.cn/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, const char **argv, const char *prefix)
我们还需要添加 psuh 的声明; 打开 builtin.h
,找到 cmd_pull
的声明,并在其紧前面为 psuh
添加一行,以保持声明按字母顺序排序
int cmd_psuh(int argc, const char **argv, const char *prefix);
确保在你的 psuh.c
中 #include "builtin.h"
。 你还需要 #include "gettext.h"
才能使用与打印输出文本相关的函数。
继续,并将一些临时 printf 添加到 cmd_psuh
函数。 这是一个不错的起点,因为我们现在可以添加构建规则并注册命令。
注意
|
你的临时文本,以及你将在本教程过程中添加的大部分文本,都是面向用户的。 这意味着它需要本地化。 查看 po/README 下的 “Marking strings for translation”。 在整个教程中,我们将根据需要标记用于翻译的字符串; 你将来在编写面向用户的命令时也应该这样做。 |
int cmd_psuh(int argc, const char **argv, const char *prefix) { 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
中。我们可以通过将 cmd_struct
添加到 commands[]
数组来注册一个新命令。struct cmd_struct
接受一个包含命令名称的字符串、一个指向命令实现的函数指针和一个设置选项标志。现在,让我们继续模仿 push
。找到注册 cmd_push
的行,复制它,然后为 cmd_psuh
修改它,并将新行按字母顺序放置(紧接在 cmd_pull
之前)。
这些选项记录在 builtin.h
中,位于“Adding a new built-in.”下。由于我们希望稍后打印一些关于用户当前工作区上下文的数据,我们需要一个 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 列或更短的主题行开始提交,包括您正在处理的组件的名称,后跟一个空行(始终需要),然后是您的提交消息的正文,该正文应提供大部分上下文。请记住明确说明更改的“原因”,特别是如果从您的差异中不容易理解的话。编辑提交消息时,请不要删除 Signed-off-by
尾部,该尾部由上面的 -s
添加。
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
) 表示您同意开发者原创证书 1.1(请参阅 Documentation/SubmittingPatches
[[dco]] 标题)。
在本教程的剩余部分中,为了简洁起见,将仅列出主题行。但是,完整的示例提交消息可以在本文档顶部链接的参考实现中找到。
实现
至少做一些除了打印字符串之外的事情可能很有用。让我们首先看看我们得到了什么。
修改您的 cmd_psuh
实现以转储您传递的参数,并保留现有的 printf()
调用。
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
)。这没什么帮助。那么我们还能获得什么其他上下文?
在 #include "config.h"
中添加一行。然后,将以下代码添加到函数体中
const char *cfg_name; ... git_config(git_default_config, NULL); if (git_config_get_string_tmp("user.name", &cfg_name) > 0) printf(_("No name is found in config\n")); else printf(_("Your name: %s\n"), cfg_name);
git_config()
将从 Git 已知的配置文件中获取配置并应用标准优先级规则。git_config_get_string_tmp()
将查找特定的键 ("user.name") 并为您提供该值。有许多像这样的单键查找函数;您可以在 Documentation/technical/api-config.adoc
中查看它们全部(以及有关如何使用 git_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()
由 builtin/commit.c
中的 cmd_status()
调用。查看该实现,我们看到状态配置像这样填充
status_init_config(&s, git_status_config);
但是当我们深入研究时,我们可以发现 status_init_config()
包装了对 git_config()
的调用。让我们修改我们在上一次提交中编写的代码。
确保包含头文件,以便您可以使用 struct wt_status
#include "wt-status.h"
然后修改您的 cmd_psuh
实现以声明您的 struct wt_status
,准备它并打印其内容
struct wt_status status; ... wt_status_prepare(the_repository, &status); git_config(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,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
条目指向的位置将被更新。请务必用 parse_options()
的结果替换您的 argc
,否则如果您稍后尝试解析 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 来命名测试。但是,由于许多 family/subcmd 组合已满,最佳实践似乎是找到一个与你添加的命令足够接近的命令并共享其命名空间。
创建一个新文件 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
来了解你是否成功创建了新的测试脚本,这将检查测试编号的唯一性、可执行位等等。
准备分享:补丁系列剖析
你可能已经注意到,Git 项目通过电子邮件发送的补丁进行代码审查,这些补丁在准备就绪并获得社区批准后由维护者应用。Git 项目不接受来自拉取请求的贡献,并且通过电子邮件发送以供审查的补丁需要以特定的方式格式化。
在查看如何将你的提交转换为电子邮件发送的补丁之前,让我们分析一下最终结果,“补丁系列”的样子。这是一个 示例,展示了 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
打开一个拉取请求。前往 https://github.com/gitgitgadget/git 并使用“New pull request”按钮或可能与你新推送的分支的名称一起出现的方便的“Compare & pull request”按钮打开一个 PR。
查看 PR 的标题和描述,因为 GitGitGadget 分别将它们用作你的更改的封面信的主题和正文。有关如何命名你的提交以及在描述中包含哪些内容的建议,请参阅上面的 “封面信”。
注意
|
对于单补丁贡献,你的提交消息应该已经有意义并且从高层次解释了你的补丁的目的(正在发生什么以及为什么),因此你通常不需要任何其他上下文。在这种情况下,删除 GitHub 自动从你的提交消息生成的 PR 描述(你的 PR 描述应该是空的)。如果你确实需要提供更多的上下文,你可以在该空间中这样做,它将被附加到 GitGitGadget 将发送的电子邮件中,在三划线和 diffstat 之间(请参阅 奖励章节:单补丁更改 了解提交后的样子)。 |
当你满意时,提交你的拉取请求。
运行 CI 并准备发送
如果这是你第一次使用 GitGitGadget(很有可能,因为你正在使用本教程),那么需要有人授予你使用该工具的权限。正如 GitGitGadget 文档中所述,你只需要让已经使用它的人在你的 PR 上评论 /allow <username>
。即使没有授予权限,GitGitGadget 也会自动通过 CI 运行你的 PR,但在有人允许你使用该工具之前,你将无法 /submit
你的更改。
注意
|
你通常可以通过查看最近的拉取请求来找到可以 /allow 你的人,在这些拉取请求中,有人被授予了 /allow (搜索: is:pr is:open "/allow"),在这种情况下,作者和授予 /allow 的人都可以在现在 /allow 你,或者通过在 Libera Chat 上的 #git-devel IRC 频道上询问并链接你的拉取请求并要求某人 /allow 你。 |
如果 CI 失败,你可以使用 git rebase -i
更新你的更改并再次推送你的分支
$ git push -f remotename psuh
实际上,你应该持续以这种方式进行更改,直到你的补丁被接受到 next
分支。
根据评论更新
跳到 回复审查 了解如何回复你在邮件列表中收到的审查评论。
一旦你的分支根据所有审查意见恢复到你想要的状态,你可以再次提交。
$ git push -f remotename psuh
接下来,查看你在 GitGitGadget 上的 pull request;你应该看到 CI 已经再次启动。在 CI 运行的时候,你可以修改 pull request 线程顶部的描述;它将再次用作封面信。你应该使用这个空间来描述自上次版本以来发生了哪些变化,以便你的审查者了解他们正在查看的内容。当 CI 完成运行时,你可以再次评论 /submit
- GitGitGadget 将自动向你的更改添加 v2 标记。
使用 git send-email
发送补丁
如果你不想使用 GitGitGadget,你也可以使用 Git 本身来发送你的补丁。以这种方式使用 Git 的一些好处包括可以更精细地控制主题行(例如,能够在主题中使用标签 [RFC PATCH]),并且能够向自己发送“dry run”邮件,以确保在发送到列表之前一切看起来都很好。
先决条件:设置 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
为你创建一个封面信模板。在准备发送之前,你需要填写模板 - 但现在,该模板将与你的其他补丁位于同一位置。 -
-o psuh/
选项告诉format-patch
将补丁文件放入一个目录中。这很有用,因为git send-email
可以接受一个目录并从中发送所有补丁。 -
--base=auto
选项告诉命令记录“base commit”,接收者应该在该提交上应用补丁系列。auto
值将导致format-patch
自动计算基本提交,这是远程跟踪分支的 tip commit 和指定的修订范围的合并基础。 -
psuh@{u}..psuh
选项告诉format-patch
为你在psuh
分支上创建的提交生成补丁,自从它从其上游分支(如果你按照“设置你的工作区”部分中的示例,则为origin/master
)分叉以来。如果你已经在psuh
分支上,你可以只说@{u}
,这意味着“自当前分支从其上游分支分叉以来的提交”,这是同一件事。
该命令将为每个提交创建一个补丁文件。运行后,你可以使用你喜欢的文本编辑器查看每个补丁,并确保一切看起来正常;但是,不建议通过补丁文件进行代码修复。更好的方法是使用 git rebase -i
或通过添加新的提交来以通常的方式进行更改,而不是修改补丁。
注意
|
可选地,你还可以使用 --rfc 标志来将你的补丁主题加上“[RFC PATCH]”前缀,而不是“[PATCH]”。 RFC 代表“request for comments”,表示你的代码尚未完全准备好提交,但你希望开始代码审查过程。当你的补丁是一个提案,但不确定社区是否希望使用该方法解决问题时,也可以使用它 - 以进行某种设计审查。你还可能会在列表中看到标记为“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
生成的如下所示
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 ,了解一些你可能认为有价值的其他选项,例如更改 Reply-to 地址或添加更多 CC 和 BCC 行。 |
注意
|
如果你不确定要抄送给谁,运行 contrib/contacts/git-contacts 可以列出潜在的审查者。此外,你可以执行 git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch [1] 以自动将此电子邮件列表传递给 send-email 。 |
注意
|
当你发送真正的补丁时,它将发送到 git@vger.kernel.org - 但请不要将教程中的补丁集发送到真实的邮件列表!现在,你可以将其发送给自己,以确保你了解它的外观。 |
运行上面的命令后,你将看到一个交互式提示,提示即将发出的每个补丁。这使你有最后一次机会编辑或退出发送某些内容(但同样,不要以这种方式编辑代码)。一旦你在这些提示中按下 y
或 a
,你的电子邮件将被发送!恭喜!
太棒了,现在社区将放下一切并审查你的更改。(开玩笑 - 请耐心等待!)
发送 v2
本节将重点介绍如何发送补丁集的 v2 版本。要了解 v2 中应该包含什么,请跳到 回复审查,以获取有关如何处理审查者评论的信息。
我们将重用我们的 psuh
主题分支作为 v2。在进行任何更改之前,我们将标记 v1 分支的 tip,以便于参考
$ 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
之间的 range-diff (请参阅 git-range-diff[1])。这有助于告诉审查者你的 v1 和 v2 补丁之间的差异。
-v2
参数告诉 format-patch
将你的补丁输出为版本 “2”。例如,你可能会注意到你的 v2 补丁都像 v2-000n-my-commit-subject.patch
这样命名。 -v2
还会通过在补丁上加上“[PATCH v2]”而不是“[PATCH]”来格式化你的补丁,并且你的 range-diff 将以“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。
在查看电子邮件时,你还应该注意谁被抄送,因为在邮件列表中保持所有抄送在同一个线程上是一种常见的做法。你可以使用如下行将这些抄送行直接添加到你的封面信中(在 Subject 行之前)
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
我的补丁已通过电子邮件发送 - 现在怎么办?
请给审查者足够的时间来处理你的初始补丁,然后再发送更新版本。也就是说,抵制立即发送新版本的诱惑,因为其他人可能已经开始审查你的初始版本。
在等待审查意见期间,你可能会发现初始补丁中的错误,或者意识到实现补丁目标的不同且更好的方法。在这种情况下,你可以通过以下方式将你的发现传达给其他审查者
-
如果你发现的错误很小,请像审查者一样回复你的补丁,并提及你将在更新的版本中修复它们。
-
另一方面,如果你认为你想彻底改变方向,以至于对初始补丁的审查将浪费时间(对所有参与者而言),请立即撤回补丁,并回复类似“我正在研究一种更好的方法,所以请忽略此补丁并等待更新版本”。
现在,如果你在没有打磨的情况下过早地发送了你的初始补丁,以上是一个很好的做法。但更好的方法当然是首先避免过早地发送你的补丁。
请考虑到审查者审查每个新版本的补丁所需的时间。审查者与其现在看到初始版本(随后在 2 天内出现多个“哎呀,我更喜欢这个版本”的补丁),不如在 2 天后看到一个经过打磨的单个版本,并且该版本错误更少,是他们唯一需要审查的版本。
回复审查
几天后,你希望收到对你的补丁集的回复,其中包含一些评论。万岁!现在你可以继续工作了。
礼貌的做法是回复每条评论,通知审查者你已按照建议进行了更改,感觉原始版本更好,或者该评论启发你以一种优于原始版本和建议更改的新方式进行操作。这样,审查者无需检查你的 v2 来确定你是否实现了他们的评论。
审查者可能会询问你在补丁集中编写的内容,无论是在建议的提交日志消息中还是在更改本身中。你应该在回复消息中回答这些问题,但通常审查者提出这些问题来理解你打算写什么的原因是你的补丁集需要澄清才能被理解。
不要满足于仅在回复中回答他们的问题,并听到他们说他们现在理解你想说什么。更新你的补丁以澄清审查者遇到麻烦的点,并准备你的 v2;你用来解释你的 v1 以回答审查者问题的话语可能是有用的。你的目标是使你的 v2 足够清晰,以至于你无需向下一个阅读它的人给出相同的解释。
如果你要反驳评论,请礼貌地解释为什么你觉得你的原始版本更好;做好审查者仍然不同意你的准备,并且社区的其余成员可能会站在其中一边或另一边。与所有代码审查一样,重要的是对以不同于你最初计划的方式做事保持开放的心态;其他审查者对项目有不同的看法,并且可能正在考虑你没有想到的有效副作用。如果你不确定为什么提出更改建议或审查者要求你做什么,总是可以要求澄清。
确保你的电子邮件客户端具有纯文本电子邮件模式并且已启用;Git 列表拒绝 HTML 电子邮件。另请遵循 维护者说明中概述的邮件列表礼仪,这与围绕底部发帖和内联回复的大多数开源社区的礼仪规则相似。
当你更改代码时,最干净的做法 - 也就是说,生成的提交最容易查看 - 是使用 git rebase -i
(交互式变基)。请查看 O'Reilly 的这篇 概述。总体的想法是修改每个需要更改的提交;这样,与其拥有一个带有错误的补丁 A,一个在 v1 中很好并且不需要上游审查的补丁 B,以及一个为 v2 修复补丁 A 的补丁 C,不如只发布一个带有正确补丁 A 和正确补丁 B 的 v2。这是在更改历史记录,但由于它是你没有与任何人分享的本地历史记录,因此现在这样做是可以的!(稍后,这样做可能没有意义;请查看下面的部分以获取一些上下文。)
审查批准后
Git 项目有四个集成分支:seen
、next
、master
和 maint
。你的更改将在审查过程的早期被维护者放入 seen
;从那里,当它准备好进行更广泛的测试时,它将被合并到 next
中。许多早期测试人员使用 next
并且可能会报告问题。最终,next
中的更改将进入 master
,这通常被认为是稳定的。最后,当发布新版本时,maint
用于基于其进行错误修复。正如本文档开头所提到的,你可以阅读 Documents/SubmittingPatches
以获取有关使用各种集成分支的更多信息。
回到现在:你的代码受到了上游审查者的赞扬。它很完美。它已准备好被接受。你无需做任何其他事情;维护者会将你的主题分支合并到 next
,一切顺利。
但是,如果你在此之后发现它并不那么完美,你可能需要采取一些特殊步骤,具体取决于你所处的过程。
如果维护者在“What’s cooking in git.git”电子邮件中宣布你的主题已标记为 next
- 也就是说,他们计划将其合并到 next
但尚未这样做 - 你应该发送一封电子邮件,要求维护者等待更长时间:“我发送了我的 v4 系列,你将其标记为 next
,但我需要更改这个和那个 - 请在合并之前等待 v5。”
如果主题已经合并到 next
,而不是使用 git rebase -i
修改你的补丁,你应该增量地进行进一步的更改 - 也就是说,使用另一个提交,基于维护者的主题分支的顶部,如 https://github.com/gitster/git 中详细说明的那样。你的工作仍然在同一主题中,但现在是增量的,而不是主题分支的整体重写。
维护者的 GitHub 中的主题分支在 GitGitGadget 中镜像,因此如果你通过这种方式发送你的评论,你应该确保针对相应的 GitGitGadget/Git 分支打开你的 PR。
如果你使用 git send-email
,你可以像以前一样使用它,但你应该从 <topic>..<mybranch>
生成你的 diff,并将你的工作基于 <topic>
而不是 master
。