贡献指南

Go 项目欢迎所有贡献者。

本文档旨在指导您完成向 Go 项目贡献代码的过程,该过程与其他开源项目的贡献过程略有不同。我们假设您对 Git 和 Go 有基本的了解。

除了此处的信息外,Go 社区还维护了一个 CodeReview Wiki 页面。在您了解代码审查流程时,欢迎您为 Wiki 做出贡献。

请注意,gccgo 前端位于其他地方;请参阅 参与 gccgo 贡献

成为贡献者

概述

第一步是注册为 Go 贡献者并配置您的环境。以下是需要遵循的步骤清单

如果您愿意,可以使用一个自动工具来完成这些步骤。只需运行

$ go install golang.org/x/tools/cmd/go-contrib-init@latest
$ cd /code/to/edit
$ go-contrib-init

本章的其余部分详细介绍了这些说明。如果您已完成上述步骤(手动或通过工具),请跳至 贡献代码前

步骤 0:选择 Google 帐户

对 Go 的贡献是通过具有特定电子邮件地址的 Google 帐户进行的。确保在整个过程中以及在您后续的所有贡献中都使用相同的帐户。您可能需要决定是使用个人地址还是公司地址。选择将取决于谁将拥有您将编写和提交的代码的版权。在决定使用哪个帐户之前,您可能需要与您的雇主讨论此主题。

Google 帐户可以是 Gmail 电子邮件帐户、G Suite 组织帐户或与外部电子邮件地址关联的帐户。例如,如果您需要使用未通过 G Suite 管理的现有公司电子邮件,则可以创建一个与 您的现有电子邮件地址关联的帐户

您还需要确保您的 Git 工具配置为使用您选择的电子邮件地址创建提交。您可以全局配置 Git(作为所有项目的默认设置),也可以本地配置 Git(针对单个特定项目)。您可以使用以下命令检查当前配置

$ git config --global user.email  # check current global config
$ git config user.email           # check current local config

更改配置的地址

$ git config --global user.email [email protected]   # change global config
$ git config user.email [email protected]            # change local config

步骤 1:贡献者许可协议

在将您的第一个更改发送到 Go 项目之前,您必须已完成以下两个 CLA 之一。您应该签署哪个 CLA 取决于谁拥有您工作的版权。

您可以在 Google 开发者贡献者许可协议 网站上检查您当前签署的协议并签署新的协议。如果您的贡献的版权持有人已在与另一个 Google 开源项目相关的连接中完成了协议,则无需再次完成。

如果提交代码的版权持有人发生变化,例如,如果您开始代表新公司贡献代码,请发送邮件至 golang-dev 邮件列表。这将让我们了解情况,以便我们可以确保完成适当的协议。

步骤 2:配置 git 身份验证

主要 Go 仓库位于 go.googlesource.com,这是一个由 Google 托管的 Git 服务器。Web 服务器上的身份验证是通过您的 Google 帐户进行的,但您还需要在计算机上配置 git 以访问它。请按照以下步骤操作

  1. 访问 go.googlesource.com,然后点击页面右上角菜单栏中的“生成密码”。您将被重定向到 accounts.google.com 进行登录。
  2. 登录后,您将进入一个标题为“配置 Git”的页面。此页面包含一个个性化的脚本,当在本地运行时,该脚本将配置 Git 以保存您唯一的身份验证密钥。此密钥与在服务器上生成并存储的一个密钥配对,类似于 SSH 密钥的工作方式。
  3. 复制此脚本并在本地终端中运行它,以将您的秘密身份验证令牌存储在 .gitcookies 文件中。如果您使用的是 Windows 计算机并运行 cmd,则应改为按照黄色框中的说明运行命令;否则运行常规脚本。

步骤 3:创建 Gerrit 帐户

Gerrit 是 Go 维护人员用来讨论和审查代码提交的开源工具。

要注册您的帐户,请访问 go-review.googlesource.com/login/,然后使用上面使用的相同 Google 帐户登录一次。

步骤 4:安装 git-codereview 命令

对 Go 的更改必须在被接受之前进行审查,无论是谁进行更改。一个名为 git-codereview 的自定义 git 命令简化了将更改发送到 Gerrit 的过程。

通过运行以下命令安装 git-codereview 命令:

$ go install golang.org/x/review/git-codereview@latest

确保 git-codereview 已安装在您的 shell 路径中,以便 git 命令可以找到它。检查是否

$ git codereview help

打印帮助文本,而不是错误。如果打印错误,请确保 $GOPATH/bin 位于您的 $PATH 中。

在 Windows 上,当使用 git-bash 时,您必须确保 git-codereview.exe 位于您的 git exec-path 中。运行 git --exec-path 以查找正确的路径,然后创建符号链接或仅将可执行文件从 $GOPATH/bin 复制到此目录。

贡献代码前

项目欢迎代码补丁,但为了确保事情得到良好的协调,您应该在开始工作之前讨论任何重大更改。建议您在问题跟踪器中表明您的贡献意图,可以通过 提交新问题 或认领 现有问题 来实现。

贡献地点

Go 项目由主要的 go 仓库组成,其中包含 Go 语言的源代码,以及许多 golang.org/x/... 仓库。这些包含支持 Go 的各种工具和基础设施。例如,golang.org/x/pkgsite 用于 pkg.go.devgolang.org/x/playground 用于 Go 游乐场,golang.org/x/tools 包含各种 Go 工具,包括 Go 语言服务器 gopls。您可以在 go.googlesource.com 上查看所有 golang.org/x/... 仓库的列表。

检查问题跟踪器

无论您是否已经知道要做出什么贡献,或者您正在寻找想法,问题跟踪器 始终是首选之地。问题会被分类以对其进行分类和管理工作流程。

大多数 golang.org/x/... 仓库也使用主要的 Go 问题跟踪器。但是,其中一些仓库单独管理其问题,因此请确保检查您要为其贡献代码的仓库的正确跟踪器。

大多数问题将被标记以下工作流标签之一

您可以使用 GitHub 的搜索功能查找需要帮助的问题。例如

为任何新问题打开一个问题

除了非常简单的更改之外,所有贡献都应与现有问题相关联。请随时打开一个问题并讨论您的计划。此过程使每个人都有机会验证设计,有助于防止工作重复,并确保该想法符合语言和工具的目标。它还检查设计在编写代码之前是否合理;代码审查工具不是进行高级讨论的地方。

在计划工作时,请注意 Go 项目遵循 六个月的开发周期,用于主要的 Go 代码库。每个周期的后半部分为为期三个月的功能冻结期,在此期间仅接受错误修复和文档更新。新的贡献可以在功能冻结期间提交,但它们不会在冻结结束前合并。冻结适用于整个主代码库,以及构建版本中包含的二进制文件所需的 golang.org/x/... 代码库中的代码。请参阅已引入 标准库go 命令 的软件包列表。

对语言、库或工具的重大更改(包括主代码库和所有 golang.org/x 代码库中的 API 更改,以及 go 命令的命令行更改)必须先通过 更改提案流程 才能被接受。

敏感的安全相关问题(仅限!)应报告给 [email protected]

通过 GitHub 提交更改

鼓励已经熟悉 GitHub 流程 的首次贡献者使用相同的流程进行 Go 贡献。即使 Go 维护者使用 Gerrit 进行代码审查,也创建了一个名为 Gopherbot 的机器人来将 GitHub 拉取请求同步到 Gerrit。

像往常一样打开一个 GitHub 拉取请求。Gopherbot 将创建一个相应的 Gerrit 更改列表(“CL”)并在您的 GitHub 拉取请求中发布指向它的链接;拉取请求的更新也将反映在 Gerrit CL 中。当有人在 CL 上发表评论时,他们的评论也将发布到您的拉取请求中,因此您将收到通知。

一些需要注意的事项

通过 Gerrit 提交更改

至少目前无法完全同步 Gerrit 和 GitHub,因此我们建议您学习 Gerrit。它不同但功能强大,熟悉它将有助于您了解流程。

概述

这是整个流程的概述

本节的其余部分将更详细地描述这些步骤。

步骤 1:克隆源代码

除了最近的 Go 安装之外,您还需要从正确的代码库中检出一个源代码的本地副本。您可以将 Go 源代码库检出到您想要的任何本地文件系统上,只要它在您的 GOPATH 之外即可(默认为您主目录中的 go 目录)。从 go.googlesource.com(而不是 GitHub)克隆

主 Go 代码库

$ git clone https://go.googlesource.com/go
$ cd go

golang.org/x/... 代码库

(本例中为 golang.org/x/tools
$ git clone https://go.googlesource.com/tools
$ cd tools

步骤 2:在新分支中准备更改

每个 Go 更改都必须在从 master 分支创建的单独分支中进行。您可以使用普通的 git 命令创建分支并将更改添加到暂存区

$ git checkout -b mybranch
$ [edit files...]
$ git add [files...]

要提交更改,请使用 git codereview change 而不是 git commit

$ git codereview change
(open $EDITOR)

您可以在您喜欢的编辑器中像往常一样编辑提交描述。git codereview change 命令会自动在底部附近添加一个唯一的 Change-Id 行。Gerrit 使用该行来匹配同一更改的后续上传。请勿编辑或删除它。Change-Id 如下所示

Change-Id: I2fbdbffb3aab626c4b6f56348861b7909e3e8990

该工具还会检查您是否已对源代码运行 go fmt,以及提交消息是否遵循 建议的格式

如果您需要再次编辑文件,您可以暂存新的更改并重新运行 git codereview change:每次后续运行都将修改现有提交,同时保留 Change-Id。

确保您始终在每个分支中保留一个提交。如果您错误地添加了更多提交,则可以使用 git rebase 将它们 压缩在一起,成为一个提交。

步骤 3:测试您的更改

您已 编写并测试了您的代码,但在将代码发送出去进行审查之前,请运行整个树的所有测试以确保更改不会破坏其他包或程序。

在主 Go 代码库中

这可以通过运行 all.bash 来完成

$ cd go/src
$ ./all.bash

(要在 Windows 下构建,请使用 all.bat

运行一段时间并打印大量测试输出后,命令应以打印以下内容结束,

ALL TESTS PASSED

您可以使用 make.bash 而不是 all.bash 仅构建编译器和标准库,而不运行测试套件。构建 go 工具后,它将安装在您克隆 Go 代码库的目录下的 bin/go 中,您可以直接从那里运行它。另请参阅有关如何 快速测试您的更改 的部分。

在 golang.org/x/... 代码库中

运行整个代码库的测试(例如 golang.org/x/tools

$ cd tools
$ go test ./...

如果您担心构建状态,您可以查看 构建仪表板。测试失败也可能在代码审查中的 TryBots 中被捕获。

某些代码库,如 golang.org/x/vscode-go 将具有不同的测试基础设施,因此始终检查您正在工作的代码库的文档。代码库根目录中的 README 文件通常包含此信息。

步骤 4:发送更改以供审查

更改准备就绪并在整个树上进行测试后,将其发送以供审查。这是使用 mail 子命令完成的,尽管它的名称如此,但它不会直接发送任何邮件;它只是将更改发送到 Gerrit

$ git codereview mail

Gerrit 为您的更改分配一个编号和 URL,git codereview mail 将打印类似以下内容

remote: New Changes:
remote:   https://go-review.googlesource.com/99999 math: improved Sin, Cos and Tan precision for very large arguments

如果您收到错误,请查看 故障排除邮件错误 部分。

如果您的更改与一个开放的 GitHub 问题相关,并且您已遵循 建议的提交消息格式,则该问题将在几分钟内由机器人更新,在评论中将您的 Gerrit 更改链接到它。

步骤 5:审查后修改更改

Go 维护者将在 Gerrit 上审查您的代码,您将通过电子邮件收到通知。您可以在 Gerrit 上查看审查并在那里发表评论。如果您愿意,也可以 使用电子邮件回复

如果您需要在审查后修改更改,请在之前创建的同一分支中编辑文件,将它们添加到 Git 暂存区,然后使用 git codereview change 修改提交

$ git codereview change     # amend current commit
(open $EDITOR)
$ git codereview mail       # send new changes to Gerrit

如果您不需要更改提交描述,只需保存并退出编辑器即可。请记住不要触碰特殊的 Change-Id 行。

同样,请确保您始终在每个分支中保留一个提交。如果您错误地添加了更多提交,则可以使用 git rebase 将它们 压缩在一起,成为一个提交。

良好的提交消息

Go 中的提交消息遵循一组特定的约定,我们将在本节中讨论。

以下是一个好的示例

math: improve Sin, Cos and Tan precision for very large arguments

The existing implementation has poor numerical properties for
large arguments, so use the McGillicutty algorithm to improve
accuracy above 1e10.

The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm

Fixes #159

第一行

更改描述的第一行通常是更改的简短单行摘要,以主要受影响的包作为前缀。

一个经验法则是,它应该写成完成“此更改修改 Go 以 ______”这句话。这意味着它不以大写字母开头,不是完整的句子,并且实际上总结了更改的结果。

在第一行后跟一个空行。

主要内容

其余描述进行详细说明,并应为更改提供上下文并解释其作用。用正确的标点符号写完整的句子,就像在 Go 中编写注释一样。不要使用 HTML、Markdown 或任何其他标记语言。

添加任何相关信息,例如,如果更改影响性能,则添加基准数据。通常使用 benchstat 工具来格式化更改描述的基准数据。

引用问题

特殊符号“Fixes #12345”将更改与 Go 问题跟踪器 中的问题 12345 关联起来。当此更改最终应用时,问题跟踪器将自动将问题标记为已修复。

如果更改是解决问题的部分步骤,则改为写“Updates #12345”。这将在问题中留下一个评论,链接回 Gerrit 中的更改,但当更改应用时,它不会关闭该问题。

如果您针对 golang.org/x/... 代码库发送更改,则必须使用 GitHub 支持的完全限定语法,以确保更改链接到主代码库中的问题,而不是 x/ 代码库。大多数问题都在主代码库的问题跟踪器中跟踪。正确的形式是“Fixes golang/go#159”。

审查流程

本节详细解释了审查流程以及在邮件发送更改后如何处理审查。

常见的初学者错误

当更改发送到 Gerrit 时,通常会在几天内进行分类。维护者会查看并提供一些初步审查,对于首次贡献者来说,通常会关注基本的美观性和常见错误。这些包括以下内容:

Trybots

维护者在初步阅读您的更改后,将触发 trybots,这是一个服务器集群,将在多个不同的架构上运行完整的测试套件。大多数 trybots 在几分钟内完成,届时会在 Gerrit 中发布一个链接,您可以在其中查看结果。

如果 trybot 运行失败,请点击链接并检查测试失败的平台的完整日志。尝试理解哪里出了问题,更新您的补丁以修复它,然后重新上传。维护者将触发新的 trybot 运行以查看问题是否已解决。

有时,代码库在某些平台上可能会中断几个小时;如果 trybot 报告的失败似乎与您的补丁无关,请访问构建仪表盘并检查相同平台上的其他最近提交中是否出现相同的失败。在这种情况下,请随时在 Gerrit 中写评论,说明该失败与您的更改无关,以帮助维护者了解情况。

审查

Go 社区非常重视彻底的审查。将每个审查评论视为一张工单:您需要通过某种方式“关闭”它,方法是对其进行操作,例如实施建议或说服审查者。

更新更改后,请查看审查评论并确保回复每一个评论。您可以点击“完成”按钮回复,表示您已实施审查者的建议;否则,请点击“回复”并解释您为什么没有实施,或者您做了什么替代操作。

更改经过多轮审查是完全正常的,每次可能有一位或多位审查者提出新的评论,然后等待更新后的更改后再进行审查。即使对于经验丰富的贡献者,此循环也会发生,因此不要因此而气馁。

投票约定

在接近做出决定时,审查者将对您的更改应用“代码审查”投票。有两个可能的投票

要提交更改,必须获得维护者的代码审查 +2 票。

维护者还可以对更改应用保留 +1 票,以标记现在不应提交的更改(例如,因为更改中新 API 的提案审查尚未完成)。

要提交更改,不得有任何维护者的保留 +1 票。

最后,要提交更改,必须有两位 Google 员工参与,无论是作为更改的上载者还是作为至少投票代码审查 +1 的审查者。此要求出于合规性和供应链安全原因。

提交已批准的更改

当更改准备就绪时,维护者将提交更改,将其作为提交添加到 Gerrit 代码库中。

这两个步骤(批准和提交)是分开的,因为在某些情况下,维护者可能希望批准但不想立即提交(例如,代码库可能暂时冻结)。

提交更改会将其检入代码库。更改说明将包含指向代码审查的链接,该链接将更新为指向代码库中更改的链接。由于用于集成更改的方法是 Git 的“Cherry Pick”,因此代码库中的提交哈希将因提交操作而更改。

如果您的更改已获批准几天但尚未提交,请随时在 Gerrit 中写评论请求提交。

更多信息

除了此处的的信息外,Go 社区还维护了一个代码审查维基页面。随着您对审查流程了解的深入,请随时为该页面做出贡献。

其他主题

本节收集了一些不在问题/编辑/代码审查/提交流程本身范围内的其他评论。

Gopls

在处理主 Go 代码库并使用 gopls 与您的编辑器时,gopls 调用的 go 命令必须与您正在处理的源代码版本相对应。可以使用 make.bash 构建 go 命令,并且应该将 bin 目录添加到您的 PATH 中。有关更多详细信息,请参阅 Gopls:高级主题

Go 代码库中的文件不列出作者姓名,既是为了避免杂乱,也是为了避免必须保持列表的最新状态。相反,您的姓名将显示在更改日志中。

您贡献的新文件应使用标准版权声明

// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

代码库中的文件版权为添加年份。不要更新您更改的文件的版权年份。

解决邮件错误

git codereview mail 命令失败的最常见原因是提交中的电子邮件地址与您在注册过程中使用的电子邮件地址不匹配。
如果您看到类似以下内容...

remote: Processing changes: refs: 1, done
remote:
remote: ERROR:  In commit ab13517fa29487dcf8b0d48916c51639426c5ee9
remote: ERROR:  author email address XXXXXXXXXXXXXXXXXXX
remote: ERROR:  does not match your user account.

您需要配置 Git 以使此代码库使用您注册的电子邮件地址。要更改电子邮件地址以确保此情况不再发生,请运行

$ git config user.email [email protected]

然后使用以下命令更改提交以使用此备用电子邮件地址

$ git commit --amend --author="Author Name <[email protected]>"

然后通过运行以下命令重试

$ git codereview mail

快速测试您的更改

对代码树的每次更改都运行 all.bash 都是很繁琐的。尽管强烈建议在发送更改之前运行它,但在正常的开发周期中,您可能只想编译和测试您正在开发的包。

指定审查者/抄送其他人

除非另有明确说明(例如,在导致发送更改的讨论中),否则最好不要指定审查者。所有更改都会自动抄送至[email protected] 邮件列表。如果这是您的第一次更改,则在邮件列表中显示之前可能会有审核延迟,以防止垃圾邮件。

您可以使用 -r-cc 选项指定审查者或抄送感兴趣的各方。两者都接受以逗号分隔的电子邮件地址列表

$ git codereview mail -r [email protected] -cc [email protected],[email protected]

同步您的客户端

在您工作期间,其他人可能已将更改提交到代码库。要更新您的本地分支,请运行

$ git codereview sync

(在幕后,这将运行 git pull -r。)

审查他人的代码

作为审查流程的一部分,审查者可以直接提出更改(在 GitHub 工作流中,这将是其他人将提交附加到拉取请求)。Gerrit 提供对命令的访问权限,这些命令将帮助您导入其他开发人员提出的更改,以便您可以在本地对其进行审查/测试。从您要导入的 CL 的 Gerrit 页面中,打开“⋮”菜单,点击“下载补丁”链接。根据您首选的 git 工作流,选择相应的命令。选项将如下所示

$ git fetch https://go.googlesource.com/review refs/changes/21/13245/1 && git checkout FETCH_HEAD

要还原,请更改回您正在使用的分支。

设置 git 别名

可以通过键入以下内容直接从 shell 运行 git-codereview 命令,例如,

$ git codereview sync

但为 git-codereview 自己的子命令设置别名会更方便,因此上述操作将变为:

$ git sync

git-codereview 子命令已选择与 Git 自身的子命令不同,因此定义这些别名是安全的。要安装它们,请将此文本复制到您的 Git 配置文件(通常是您主目录中的 .gitconfig)中

[alias]
	change = codereview change
	gofmt = codereview gofmt
	mail = codereview mail
	pending = codereview pending
	submit = codereview submit
	sync = codereview sync

发送多个依赖更改

高级用户可能希望将相关的提交堆叠在一个分支中。Gerrit 允许更改相互依赖,从而形成这样的依赖链。每个更改都需要单独批准和提交,但审阅者可以看到依赖关系。

要发送一组依赖更改,请将每个更改作为同一分支下的不同提交,然后运行

$ git codereview mail HEAD

确保显式指定HEAD,在发送单个更改时通常不需要此操作。更多详细信息可以在git-codereview 文档中找到。