设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
修补
调试
邮件
外部系统
服务器管理员
指南
管理
底层命令
- 2.46.1 → 2.47.0 无变化
- 2.46.0 07/29/24
- 2.43.3 → 2.45.2 无变化
- 2.43.2 02/13/24
- 2.43.1 02/09/24
- 2.43.0 11/20/23
- 2.42.1 → 2.42.3 无变化
- 2.42.0 08/21/23
- 2.41.1 → 2.41.2 无变化
- 2.41.0 06/01/23
- 2.39.1 → 2.40.3 无变化
- 2.39.0 12/12/22
- 2.38.1 → 2.38.5 无变化
- 2.38.0 10/02/22
- 2.37.1 → 2.37.7 无变化
- 2.37.0 06/27/22
- 2.35.1 → 2.36.6 无变化
- 2.35.0 01/24/22
- 2.34.1 → 2.34.8 无变化
- 2.34.0 11/15/21
- 2.33.1 → 2.33.8 无变化
- 2.33.0 08/16/21
- 2.31.1 → 2.32.7 无变化
- 2.31.0 03/15/21
- 2.30.1 → 2.30.9 无变化
- 2.30.0 12/27/20
- 2.29.1 → 2.29.3 无变化
- 2.29.0 10/19/20
- 2.28.1 无变化
- 2.28.0 07/27/20
- 2.26.1 → 2.27.1 无变化
- 2.26.0 03/22/20
- 2.25.1 → 2.25.5 无变化
- 2.25.0 01/13/20
- 2.24.1 → 2.24.4 无变化
- 2.24.0 11/04/19
- 2.23.1 → 2.23.4 无变化
- 2.23.0 08/16/19
摘要
本教程演示了创建对 Git 树的更改、将其发送以供审查以及根据评论进行更改的端到端工作流程。
相关阅读
本教程旨在总结以下文档,但读者可能会发现有用的其他上下文
-
Documentation/SubmittingPatches
-
Documentation/howto/new-command.txt
获取帮助
如果您遇到困难,可以在以下地方寻求帮助。
[email protected]
这是主要的 Git 项目邮件列表,其中进行代码审查、版本公告、设计讨论等。有兴趣贡献的人员欢迎在此处发布问题。Git 列表要求使用纯文本邮件,并在回复邮件时首选内联和底部回复;您将被抄送您收到的所有回复。或者,您可以通过向 <[email protected]> 发送电子邮件订阅列表(有关详细信息,请参阅 https://subspace.kernel.org/subscribing.html)。此邮件列表的 存档 可供在浏览器中查看。
[email protected]
此邮件列表面向新贡献者,旨在作为在主要列表的公众视野之外发布问题和接收答案的地方。特别感兴趣帮助指导新手的资深贡献者也在列表中。为了避免搜索索引器,需要群组成员身份才能查看消息;任何人都可以加入,无需批准。
#git-devel 在 Libera Chat 上
此 IRC 频道用于 Git 贡献者之间的对话。如果有人当前在线并且知道您问题的答案,您可以实时获得帮助。否则,您可以阅读 回滚 以查看是否有人回答了您。IRC 不允许脱机私人消息,因此,如果您尝试向某人发送私人消息然后注销 IRC,他们将无法回复您。最好在频道中提出您的问题,以便在您断开连接时可以得到答复,并且其他人可以从对话中学习。
开始
克隆 Git 仓库
Git 在许多位置进行了镜像。从其中一个位置克隆仓库;https://git.js.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"
以使用与打印输出文本相关的函数。
继续在 cmd_psuh
函数中添加一些一次性 printf。这是一个不错的起点,因为我们现在可以添加构建规则并注册命令。
注意
|
您的临时文本以及您在本教程过程中将添加的大部分文本都是面向用户的。这意味着它需要本地化。查看 po/README 下的“标记要翻译的字符串”。在整个教程中,我们将根据需要标记要翻译的字符串;将来在编写面向用户的命令时,您也应该这样做。 |
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
中。我们可以通过向 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 个字符的主题行开头,其中包括您正在处理的组件名称,后跟一个空行(始终需要),然后是提交信息的正文,正文应提供大部分上下文。请记住要明确说明更改的“原因”,尤其是在更改原因无法从差异中轻易理解的情况下。编辑提交信息时,请勿删除由上述-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 <[email protected]>
继续使用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.txt
中查看所有这些函数(以及有关如何使用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-*.txt
。这些是 Git 了解的子命令的手册页。您可以打开这些文件并查看以熟悉格式,然后创建一个新的文件Documentation/git-psuh.txt
。与 Git 项目中的大多数文档一样,帮助页面使用 AsciiDoc 编写(请参阅 CodingGuidelines,“编写文档”部分)。使用以下模板填写您自己的手册页。
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,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.txt
。这是一个方便的工具,用于提取您需要处理的选项,它需要一个使用说明字符串。
为了使用它,我们需要准备一个以 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
面向用户,或称瓷器 - 所以我们将标记为“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
中的“编写测试”和“源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项目不接受来自拉取请求的贡献,并且用于审查的电子邮件补丁需要以特定的方式格式化。
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”的位置上标记为“PATCH v2”、“PATCH v3”等。例如,“[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
来显示你已经添加的远程。从你新fork在GitHub上的页面,你可以点击“克隆或下载”来获取URL;然后你需要运行以下命令来添加,将你自己的URL和远程名称替换为提供的示例
$ git remote add remotename [email protected]: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,并使用“新建拉取请求”按钮或可能显示在你新推送的分支名称旁边的便捷“比较和拉取请求”按钮打开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上的拉取请求;你应该会看到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
为你创建一个附信模板。你需要在准备发送之前填写模板 - 但目前,模板将与你的其他补丁放在一起。 -
-o psuh/
选项告诉format-patch
将补丁文件放置到一个目录中。这很有用,因为git send-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
生成的如下所示
Documentation/git-psuh.txt | 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.txt create mode 100644 builtin/psuh.c create mode 100755 t/t9999-psuh-tutorial.sh
最后,信中将包含用于生成补丁的 Git 版本。你可以保留该字符串。
发送电子邮件
此时,你应该有一个 psuh/
目录,其中包含你的补丁和附信。是时候发送它了!你可以像这样发送它
$ git send-email [email protected] psuh/*.patch
注意
|
检查 git help send-email 以获取一些你可能觉得有价值的其他选项,例如更改回复地址或添加更多抄送和密送行。 |
注意
|
如果你不确定要抄送给谁,运行 contrib/contacts/git-contacts 可以列出潜在的审阅者。此外,你可以执行 git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch [1] 将此电子邮件列表自动传递给 send-email 。 |
注意
|
当你发送真正的补丁时,它将发送到 [email protected] - 但请不要将教程中的补丁集发送到真正的邮件列表!目前,你可以将其发送给自己,以确保你了解它会是什么样子。 |
运行上面的命令后,你将收到一个交互式提示,用于即将发送的每个补丁。这为你提供最后一次机会来编辑或退出发送某些内容(但同样,不要以这种方式编辑代码)。一旦你在这些提示符处按下 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 补丁放在一起。使用单个目录可以轻松地参考旧的 v1 补丁,同时校对 v2 补丁,但你需要注意只发送 v2 补丁。我们将使用类似 psuh/v2-*.patch
的模式(而不是 psuh/*.patch
,这将匹配 v1 和 v2 补丁)。
再次编辑你的附信。现在是时候提及你上次版本和现在的区别,如果它有什么重大变化。你的第二个附信不需要完全相同的正文;重点向审阅者解释你所做的可能不太明显的更改。
你还需要找到你之前附信的 Message-ID。你可以在发送第一个序列时从 git send-email
的输出中记下它,或者可以在 邮件列表 上查找它。在档案中找到你的附信,点击它,然后点击“永久链接”或“原始”以显示 Message-ID 标头。它应该与以下内容匹配
Message-ID: <[email protected]>
你的 Message-ID 是 <[email protected]>
。下面的示例也将使用此示例;确保将其替换为你 **之前的附信** 的正确 Message-ID - 也就是说,如果你正在发送 v2,请使用 v1 的 Message-ID;如果你正在发送 v3,请使用 v2 的 Message-ID。
当你查看电子邮件时,你还应该注意谁被抄送了,因为在邮件列表中保持所有抄送给线程的做法很常见。你可以使用以下标头中的行将这些抄送行直接添加到你的附信中(在主题行之前)
CC: [email protected], Othe R <[email protected]>
现在再次发送电子邮件,密切注意你传递给命令的消息。
$ git send-email [email protected] --in-reply-to="<[email protected]>" psuh/v2-*.patch
加分章节:单补丁更改
在某些情况下,你的非常小的更改可能只包含一个补丁。当发生这种情况时,你只需要发送一封电子邮件即可。你的提交消息应该已经很有意义,并且在高级别上解释补丁的目的(正在发生什么以及为什么),但如果你需要提供更多上下文,你可以在补丁中的 ---
下方执行此操作。请看下面的示例,它是使用 git format-patch
在单个提交上生成的,然后编辑以在 ---
和 diffstat 之间添加内容。
From 1345bbb3f7ac74abde040c12e737204689a72723 Mon Sep 17 00:00:00 2001 From: A U Thor <[email protected]> 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 <[email protected]> --- 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
(交互式变基),则结果最干净,即生成的提交最容易查看。请查看 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
中,生活很美好。
但是,如果您在此之后发现它并不完美,您可能需要根据您所处的流程阶段采取一些特殊步骤。
如果维护者在“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>
生成差异,并将您的工作基于<topic>
而不是master
。