首页
/ Bitcoin Core 贡献者指南:从提交补丁到 Peer Review 的完整工作流

Bitcoin Core 贡献者指南:从提交补丁到 Peer Review 的完整工作流

2026-09-06 21:11:04作者:韦蓉瑛

本文以 Bitcoin Core 仓库根目录的 CONTRIBUTING.md 为主体,完整梳理该项目"开放贡献者模型"下的协作规范:如何提交原子化的 commit、如何撰写符合规范的 Pull Request(PR)标题与正文、squash 与 rebase 的实操命令、Peer Review 的术语体系(Concept (N)ACK / Approach (N)ACK / ACK BRANCH_COMMIT),以及合并判定、共识级补丁的额外要求和 backport 元数据格式。读完本文,你可以按项目维护者的标准独立完成一个可被合并的 PR,并理解其背后的 git 历史卫生原则。

一、开放贡献者模型:没有特权开发者

Bitcoin Core 采用开放贡献者模型(open contributor model):任何人都可以通过同行评审(peer review)、测试和补丁三种形式参与开发。项目并不存在"特权开发者"的概念——开源社区通常是靠贡献者随时间赢得信任而自然形成的 meritocracy(贤者政治)。

但从实践管理角度,仍需要一定的层级结构:仓库维护者(repository maintainers)负责合并 pull request、执行发布周期(release cycle,见 发布流程)和社区管理。这意味着:

  • 贡献入口对所有开发者平等;
  • 但代码进入 master 的"最后一公里"由维护者把关,评审与测试正是普通贡献者影响这个把关过程的主要渠道。

1.1 新贡献者的最佳切入点

文档明确指出:深入的评审和测试是整个项目的瓶颈,也是任何人开始贡献时最有效的方式。相比直接开 PR,先做评审和测试能让你对代码和流程学到更多,还可能帮助你发现相关问题和后续可以贡献代码的跟进点。

开始贡献前,建议先熟悉 Bitcoin Core 的构建系统和测试体系。当前仓库中对应的资料与代码位置:

内容 仓库位置
开发者编码规范(C++ 风格、测试结构、加锁约定等) doc/developer-notes.md
单元测试(Boost.Test) src/test/(约 300 个 .cpp 文件)
功能测试(Python 集成测试) test/functional/(300+ 测试脚本,规范见 test/functional/README.md
Fuzz 测试文档(libFuzzer / AFL++ / Honggfuzz) doc/fuzzing.md
CI 测试脚本(容器化测试矩阵) ci/test/ci/README.md
Lint 检查(rust-based linter 等) ci/lint/test/lint/
PR 评审俱乐部 官方组织的 PR Review Club(Bitcoin Core 社区活动)

1.2 AI 工具使用政策

如果贡献过程中使用了 AI 工具,必须阅读并遵守 AI 政策。核心要求包括:

  • 禁止用 AI 生成与维护者/其他贡献者交流的评论,评论必须由人撰写,疑似 AI 生成的评论可能被 moderation;
  • 提交 PR 的前提是:你了解代码所用语言、你自己有能力写出这段代码、理解周边既有代码和所提议变更的影响;
  • 必须能用自己的话解释 PR 的变更,包括 PR 正文和对 reviewer 提问的回复,不得复制 AI 的回答去回复 reviewer 的提问
  • 项目要求有"人在环"(human author in the loop):PR 不应由自主 Agent 打开或驱动,commit 中也不要把 agent 列为作者或共同作者;违反此条的 PR 可能被无预警关闭。

二、沟通渠道

围绕 Bitcoin Core 开发的沟通主要通过以下渠道进行:

  • IRC:Libera Chat 的 #bitcoin-core-dev 频道是开发讨论的主要场所,有 web 客户端可直接参与,也有第三方聊天历史存档可查;
  • GitHub issues 与 pull requests:代码库改进的讨论在此进行;
  • bitcoindev 邮件列表:复杂的或有争议的共识规则(consensus)或 P2P 协议变更,在动手写补丁之前应先在此列表上讨论(列表有公开存档)。

渠道选择的实践含义是:普通的 bugfix、重构走 GitHub 即可;一旦你的改动触碰共识规则,未先在邮件列表充分讨论的补丁很难通过评审(详见第六节的决策流程)。

三、贡献者工作流:fork → 分支 → 提交 → PR

代码库采用"contributor workflow"维护:所有人无一例外都通过 pull request 提交补丁提案。这种方式便于社会化协作、测试和同行评审。

3.1 基本流程

  1. Fork 仓库(仅在第一次贡献时);
  2. 创建主题分支(topic branch);
  3. 提交补丁(committing patches,见 3.3 节);
  4. 将变更推送到你的 fork;
  5. 创建 pull request(见 3.4 节)。

对 PR 作者有三条硬性要求(来自文档原文的归纳):

  • 必须完全且有把握地理解自己的变更,并且已经测试过
  • 应说明哪些测试覆盖了本次变更,或列出你用于确认变更的手动步骤;
  • 应准备好清晰地说明并解释变更的动机;若评审者有疑虑,PR 可能被直接关闭。

3.2 monotree:GUI 与 Node 仓库的划分

当前 Bitcoin Core 采用"monotree"(单树多仓库)组织:GUI 相关的问题或 PR 使用 bitcoin-core/gui 仓库,其余所有问题和 PR 使用 bitcoin/bitcoin(node)仓库,两个仓库的 master 分支内容完全一致。

默认判据:只修改 src/qt 的改动属于 GUI-only PR。但有以下三个例外:

  • 全局重构或其他横向(transversal)改动 → 走 node 仓库;
  • GUI 相关的构建系统改动 → 走 node 仓库,因为这类变更需要构建系统 reviewer 的评审(对应本仓库中的 CMakeLists.txtcmake/ 等文件);
  • 修改 src/interfaces 的变更 → 走 node 仓库,因为这些接口可能影响钱包等其他组件(对应本仓库的 src/interfaces/src/common/interfaces.cpp)。

对于同时包含构建系统与接口改动的大型 GUI 变更,推荐的分步策略是:先在 GUI 仓库开 PR 达成方向共识,再把构建系统与接口的变更提交到 node 仓库。

项目编码规范必须遵循 developer notes

3.3 提交补丁(Committing Patches)

原子性与可读性。commit 应当是原子的(atomic commit convention),diff 应当易读。因此:

  • 不要把格式修复、代码移动与真正的代码改动混在同一个 commit 里;
  • 每个单独的 commit 必须是"卫生的"(hygienic):能独立构建成功,无警告、无错误、无回归、无测试失败。

commit 结构中的测试归属:文档引用 developer notes 的 "Commit Structure for Tests" 一节,其具体规则是:

  • 若已有测试覆盖了被修改的行为,应在同一 commit 中更新这些测试(diff 同时记录新旧期望值);
  • 简单的功能或 bugfix 没有既有覆盖时,变更与测试通常可以在同一个 commit;
  • 非平凡的 refactor,若相关不变量还没有自动化测试,先在单独的测试 commit 中加入覆盖,refactor commit 本身就不需要改动测试期望;
  • 对既有行为的非平凡修改若无覆盖,考虑加一个前置的 characterization test commit,并用 TODO 注释标记那些期望值会随行为改变而变化的断言。

commit message 规范(默认应详尽):

  • 短标题行(最长 50 字符)+ 空行 + 详细的解释性段落;
  • 例外:仅当标题本身就自解释时(如 "Correct typo in init.cpp"),单行标题即可;
  • 消息要面向未来读代码的人,解释你做各项决策的理由;
  • 若某个 commit 关联其他 issue,请加上引用,例如 refs #1234fixes #4321。使用 fixescloses 关键字会在 PR 合并时自动关闭对应 issue;
  • commit message 中永远不要出现 @ 提及(@username)。

PR 之外的两个实操技巧(来自 生产力笔记,与 squash 工作流直接相关):

# 在 "dummy rebase" 上用 autosquash 收纳 fixup commit,
# 而不必在更新的 master 上 rebase(避免引入无关冲突):
git rebase -i --autosquash "$(git merge-base master HEAD)"

# 对自 diverge 点以来每个 commit 自动跑构建与单测:
git rebase -i --exec "cmake --build build && ctest --test-dir build" "$(git merge-base master HEAD)"

3.4 创建 Pull Request

标题前缀必须标明 PR 影响的组件或区域。合法的 area 前缀完整列表如下:

前缀 适用范围
consensus 共识关键(consensus critical)代码变更
doc 文档变更
qtgui bitcoin-qt 变更
log 日志消息变更
mining 挖矿代码变更
netp2p P2P 网络代码变更
refactor 不改变行为的重构
rpcrestzmq RPC、REST 或 ZMQ API 变更
contribcli 脚本和工具变更
testqaci 单元测试、QA 测试或 CI 代码变更
utillib 工具库(utils)或库变更
wallet 钱包代码变更
build CMake 变更
guix Guix 可复现构建变更

官方给出的标题示例:

consensus: Add new opcode for BIP-XXXX OP_CHECKAWESOMESIG
net: Automatically create onion service, listen on Tor
qt: Add feed bump button
log: Fix typo in log message

正文要求

  • 必须充分描述补丁做了什么,更要为什么,并给出理由与论证;
  • 应引用相关讨论(其他 issue 或邮件列表讨论);
  • 新建 PR 的正文中不得包含任何 @ 提及。原因:PR 描述在合并时会并入 merge commit 的 commit message,每个 fork 该 commit 时,被提及的用户都会被反复通知。用户名提及应放在 PR 的后续评论中。

翻译变更:翻译不应以 PR 形式提交。流程见 翻译流程:翻译通过 Transifex 管理,src/qt/locale/ 下的源文件由自动化脚本更新(如用 cmake --preset dev-mode 构建后 --target translate 重新生成 bitcoin_en.ts),普通 PR 不应包含翻译源文件的更新,以避免合并冲突并在发布前留出翻译时间。

WIP 与 RFC 标记:若 PR 暂不考虑合并,标题前加 [WIP],或在正文中使用 GitHub 的 Tasks Lists 标记待办任务。

3.5 处理评审反馈

PR 提交后应预期收到其他贡献者的评论与评审。你可以本地新增 commit 并推送到 fork,从而给 PR 追加 commit。

  • 在 PR 被合并前,你被期望回复所有评审评论
  • 你可以修改代码,也可以不同意反馈而拒绝,但必须在回复中明确表达;
  • 若存在悬而未决的反馈而你未在处理,PR 可能被关闭。

3.6 Squash Commits

若 PR 中含有 fixup commit(反复修改同一行代码的 commit)或粒度过细的 commit,可能在你获得评审之前就被要求先 squash。官方给出的基本工作流:

git checkout your_branch_name
git rebase -i HEAD~n
# n 通常是 PR 中 commit 的数量。
# 将第一行之外的 commit 从 'pick' 改为 'squash',保存并退出。
# 在下一个屏幕上编辑/润色 commit message。
# 保存并退出。
git push -f # (force push 到 GitHub)

Squash 后如需更新 commit message,应使其读起来像一条连贯的消息——大多数情况下意味着不是简单罗列中间 commit。

注意:若分支中含 merge commit,上述工作流可能不生效,需要先移除 merge commit(见下一节的 rebase)。

另外两条纪律:

  • 不要为同一变更开多个 PR;用已打开(或更早创建)的 PR 来修正变更,这保留了针对该变更集的既有讨论与评审;
  • Peer review 所需时间不可预测,因 PR 而异。

3.7 Rebase Changes

当 PR 与目标分支冲突时,可能被告知其 rebase 到当前目标分支顶部:

git fetch https://github.com/bitcoin/bitcoin  # Fetch the latest upstream commit
git rebase FETCH_HEAD  # Rebuild commits on top of the new base

生产力笔记 提供了单 PR 的更精细做法(不必拉全量数据):

# 单独 fetch 某个 PR
git fetch upstream pull/<number>/head
# fetch 并切到本地分支
git fetch upstream pull/<number>/head:pr-<number> && git switch pr-<number>

Rebase 后,评审者被鼓励对 force push 进行 sign-off(复核)。生产力笔记 中介绍的 git range-diff 工具(Git >= 2.19)用于"diff of diffs":当贡献者 rebase 或修改非头部的 commit 后 force push,reviewer 无法仅凭 commit hash 判断之前的评审是否仍然有效,git range-diff master previously-reviewed-head new-head 可以直接对比新旧两个 commit 范围的 patch 差异,从而高效完成复核。为避免无谓的评审损耗(review churn),维护者通常会优先合并那些获得最多评审关注的 PR。

3.8 干净的 git 历史与签名验证

项目追求干净的 git 历史:代码变更只出现在非 merge commit 中。这简化了可审计性——merge commit 可以假定不携带任意代码变更;merge commit 必须签名,且其产生的 git tree hash 必须是确定且可复现的。

仓库中 contrib/verify-commits/ 的脚本负责检查这一点。其 README 说明了配套机制:

  • verify-commits.py 是一个 Python 3 脚本,对照 trusted-keys(受信 PGP 指纹列表)验证 commit 签名;
  • 配置文件包括 trusted-git-root(信任根:第一个未签名 commit 的哈希)、trusted-sha512-root-committrusted-keysallow-revsig-commits(因签名密钥过期/吊销而需豁免的 commit 列表);
  • 使用前需先用 gpg 导入受信密钥;
  • 一个重要安全细节:不能用不受信的脚本来验证自身——先 checkout 代码再对 HEADverify-commits.py 是不安全的(脚本本身可能已被植入后门)。正确的顺序是先 fetch,用受信版本的 verify-commits.py 验证 origin/master,再 checkout,例如:
git fetch origin && \
./contrib/verify-commits/verify-commits.py origin/master && \
git checkout origin/master

除非指定 --clean-merge 0verify-commits.py 还会验证每个 merge commit 是否干净应用(要求至少 git v2.38.0)。

四、PR 哲学:聚焦,避免"超大 PR"

补丁集(patchset)应当始终聚焦:一个 PR 可以加功能、修 bug、或做重构,但不能三者混杂。同时要避免"super pull requests"——试图做太多、过大或过于复杂的 PR,因为其评审难度极高。

4.1 新功能

增加新功能必须考虑其长期技术债与维护成本。提议一个需要维护的新功能前,先考虑你是否愿意维护它(包括修 bug)。如果未来某个功能成为"孤儿"(无人维护),它可能被仓库维护者移除。

4.2 重构

重构是项目演进不可避免的一部分,规范将其分为三类:

  1. 代码移动(code-only moves);
  2. 代码风格修复(code style fixes);
  3. 代码重构(code refactoring)。

三条铁律:

  • 重构 PR 不应混合这三类活动,以便评审容易且无争议;
  • 任何情况下,重构 PR 都不得改变代码行为(bug 必须原样保留,"bugs must be preserved as is");
  • 维护者追求对重构 PR 的快速周转,因此尽量短、不复杂、易验证;
  • 新贡献者不应提交重构类 PR——判断代码"该放在哪"并理解全部影响(包括对其他打开 PR 的 rebase 代价)需要一定经验;
  • 明显琐碎、或没有清晰收益的重构 PR,维护者可能直接关闭以减轻评审负担。

五、Peer Review:术语体系与评审深度

任何人可以参与 peer review,评审以 PR 评论表达。reviewer 通常检查明显的错误、实际跑一遍补丁集、并对技术价值发表意见。维护者在判断是否达到合并共识时会综合考虑 peer review(注意:讨论可能分散在 GitHub、邮件列表和 IRC 三处)。

5.1 评审成本的经济学

代码评审是繁重但重要的一环,因此某类 PR 会被直接拒绝:一般地,如果改进的收益不足以抵消所需的评审成本,PR 被拒绝的概率很高。PR 作者有责任说服 reviewer 变更值得这份评审成本;若 reviewer 在"概念上 NACK"你的 PR,作者可能需要摆出论据、甚至做研究来支撑自己的提议。

此外,若有合理理由怀疑 PR 作者不完全理解自己提交的变更,或明显自己都没做过基本测试,PR 可能被立即关闭。

5.2 概念评审(Conceptual Review)

两种表达:

  • Concept (N)ACK:"我(不)同意这个 PR 的总体目标";
  • Approach (N)ACKConcept ACK 但"我(不)同意这个变更的实现路径"。

NACK 必须附带理由,解释为什么该变更不值得做;没有理由的 NACK 可被忽视

5.3 代码评审(Code Review)

在概念达成一致后,才开始代码评审。评审以 ACK BRANCH_COMMIT 开始,其中 BRANCH_COMMIT 是 PR 分支的顶部 commit,随后附评审者说明自己如何完成的评审。PR 评论中的惯用语:

  • "I have tested the code":除了跑单元/功能/fuzz 测试外,还做了变更相关的手动测试;若手动测试方式不明显,应描述出来;
  • "I have not tested the code, but I have reviewed it and it looks OK, I agree it can be merged":只做了代码审读而未实际运行测试;
  • "nit":琐碎的、通常非阻塞的问题。

评审权重规则:

  • 维护者保留用常识判断权衡各评审意见的权利,也可以基于 merit(贡献深度)加权;
  • 随时间展现出更深的投入与理解、或有明确领域专长的 reviewer,其意见自然更重——这是所有行业的常态;
  • 触碰共识关键代码(包括对共识关键代码的重构)的补丁集,讨论与 peer review 门槛会大幅提高,因为错误对更广泛社区的代价可能极高;
  • 提议改变 Bitcoin 共识的补丁集,必须:已在邮件列表和 IRC 充分讨论、有被广泛讨论的编号 BIP、并且维护者判断社区对"这是一个有价值的变更"形成了普遍的技术共识。

5.4 找不到 reviewer 怎么办

多数 reviewer 本身也是有自己项目的开发者,评审过程可能相当漫长,需要耐心。若 PR 数月无人问津,文档给出五种排查思路:

  1. 可能正值 feature freeze(临近发布的特性冻结期):期间只考虑 bug fix,新功能 PR 不会优先处理——等发布结束即可;
  2. 变更本身可能不受欢迎:与其"沉默如雷"(thundering silence)相对,nit 和批评反而说明有人在认真对待你的贡献。沉默是对变更的普遍(轻度)不喜欢的良好信号。不要个人化,而是重新审视自己的提议是否:改动太多、太宽泛、不符合 developer notes、危险或不安全、写得凌乱。找出并解决这些问题后,可以在 IRC 上请人评价"概念本身";
  3. 代码可能太复杂以至于只有少数人懂,而他们甚至不知道这个 PR 存在:用 GitHub 的 Git Blame 功能查最后修改你正在改的代码的人,找到并礼貌地"轻推"(nudge)他们——但不要不停刷屏;
  4. 最后兜底:直接在 IRC 或别处请求有人看一眼你的 PR。若你认为等待了不合理的时长(比如超过一个月)且没有特别原因(如只改了几行代码),这么做完全没问题。同时,当别人请求反馈你的代码时记得"还人情",社区会自我平衡;
  5. 等待期间最好的事是去给别人做评审

六、决策流程("Decision Making" Process)

以下规则适用于 Bitcoin Core 项目(以及相关项目如 libsecp256k1)的代码变更,不要将其与比特币网络层面的协议共识变更混淆。PR 是否合并由项目 merge 维护者决定,他们综合考虑:补丁是否符合项目总体原则、是否达到入库的最低标准、以及贡献者群体的普遍共识。

所有 PR 必须满足

  • 有清晰的使用场景,修复可复现的 bug,或服务项目整体利益(例如面向模块化的重构);
  • 经过良好的 peer review;
  • 在适用处具备单元测试、功能测试和 fuzz 测试(对应本仓库的 src/test/test/functional/ 与 fuzz 目标,fuzz 构建与运行见 doc/fuzzing.md);
  • 遵循代码风格规范(C++ 风格见 developer notes,功能测试风格见 test/functional/README.md);
  • 不破坏既有测试套件;
  • 修复 bug 时,在可能处应有展示该 bug 的单元测试证明修复有效,以防止回归;
  • 行为变化时同步更新相关注释与文档。

共识规则变更远比普通补丁复杂,因为它影响整个生态系统:必须先经过邮件列表的大量讨论并配有编号 BIP;每种情况都不同,但应当预期付出比其他方式更多的时间与精力(评审与共识构建要求都更高)。

七、Backport:回移植的元数据规范

安全修复与 bug fix 可以从 master 回移植(backport)到 release 分支。维护者会批量执行回移植,并在需要时使用正确的 Needs backport (...) 标签(原作者无需操心)。

backport commit 的正文必须包含以下元数据:

Github-Pull: #<PR number>
Rebased-From: <commit hash of the original commit>

此外,官方还提到:可参考历史 backport PR 实例,以及 bitcoin-maintainer-tools 仓库中的 backport.py 脚本(位于项目外部的 maintainer 工具仓库,本文不展开)。

八、版权与许可证

向本仓库贡献即表示同意:除非 contrib/debian/copyright 或文件顶部另有说明,否则你的作品以 MIT 许可证授权(对应仓库根的 COPYING 文件)。凡由你贡献但并非原创的作品,必须包含其许可证头,注明原作者与来源。这与全仓库源码文件头部普遍出现的 Distributed under the MIT software license, see the accompanying file COPYING 注释保持一致。

九、快速核对清单(Pre-Submission Checklist)

把以上规范压缩成提交前的自检清单:

  1. 改动是否单一聚焦?格式化/移动与行为变更是否拆开了?每个 commit 独立可构建、无警告、无测试失败?
  2. commit 标题 ≤50 字符、正文解释了"为什么"、无 @ 提及?测试按 developer notes 的 commit 结构规则放对了位置?
  3. PR 标题带了正确的 area 前缀(对照第三节的 14 类前缀表)?正文说明了 what + why + 测试依据,且无 @ 提及?
  4. 只改 src/qt 之外还碰了构建系统或 src/interfaces?→ 确认应走 node 仓库。
  5. 若等待 rebase:git fetch + git rebase FETCH_HEAD,force push 后用 range-diff 帮助 reviewer 复核;若需 squash,按 git rebase -i HEAD~n 工作流合并并改写连贯的 commit message。
  6. 涉及共识关键代码或共识规则?→ 先确认已有邮件列表讨论与 BIP,评审门槛相应提高。
  7. 若使用了 AI 工具:确认符合 AI_POLICY.md,所有对外沟通均为人工撰写,commit 作者中无 agent。

以上流程与仓库中的实际工程设施(CMake 构建体系、ci/test/ 的多平台测试矩阵、contrib/verify-commits/ 的签名验证、doc/productivity.md 的评审效率工具)共同构成了 Bitcoin Core 高质量协作的完整闭环:贡献者按原子 commit 与聚焦 PR 提交,社区按 Concept/Approach/Code 三层评审过滤,维护者按可复现的签名历史合并,最终形成一条"每个 merge commit 都可审计"的 master 分支。

登录后查看全文
热门项目推荐
相关项目推荐