Chapter 10

开源协作:与海外 maintainer 打交道

开源是无报酬的工作——所以你和 maintainer 沟通时,"姿态" 比技术更先被看到。

10.1 开源协作的特殊性

给海外开源项目贡献,与公司内 PR 协作有几个根本不同:

  1. 你是请求者,maintainer 没义务回应你。 Maintainer 多数是无偿志愿者,PR 入队列后什么时候被看是他们的安排。
  2. 沟通门槛比合并门槛低。 任何人都能开 issue 评论,但合不合代码是 maintainer 决定。
  3. 跨文化敏感度极高。 大型项目有来自全球的贡献者,对礼貌、性别代词、CoC(Code of Conduct)的标准远高于公司内部。
  4. 留痕永久公开。 你 5 年前的傲慢评论会被新的雇主搜到。

所以开源沟通的英语不是"标准协作英语" + 一点礼貌——它是另一个语体,需要更软、更耐心、更明显地承认对方的工作。

10.2 第一次提 PR 的礼貌话术

第 0 步:先看 CONTRIBUTING.md

大部分项目根目录有 CONTRIBUTING.md.github/CONTRIBUTING.md,规定了贡献流程、commit 规范、CI 要求。读完再开 PR 是基本礼仪。如果你跳过:

# Maintainer 会发的回复(典型)
"Thanks for the PR! Could you read CONTRIBUTING.md first?
We require <X> before we can review."

开篇礼貌话术

提交前,特别是较大改动,先开个 issue 沟通:"Is this approach acceptable?" 比直接甩 PR 礼貌得多。

# 试探性 issue
"Hey @maintainer, I noticed <problem> and I'd like to take a stab
at fixing it. Before I start, would you be open to an approach
that does <A>? Or do you have a different direction in mind?

Happy to discuss before I write any code."

# 直接 PR 时的开篇
"Hi! First-time contributor here. This PR addresses #1234.
I tried to follow the existing patterns in <related-file> — let
me know if I missed any conventions. Looking forward to your
feedback!"

说明限制

# 提前告知缺口
"This is a draft. The implementation is complete but the test
coverage is only ~70% — I wanted to get directional feedback
before adding more tests."

"I haven't been able to test on Windows. If you can run the CI
on a Windows runner, that would catch any platform issues."

"This is my first time touching this part of the codebase, so
please be brutal in review."

请求 review

# Tag 时礼貌
"Whenever you have a chance, would love a review on this. No rush
— I know the team is heads-down on the v3 release."

"@maintainer would you be the right person to look at this, or
should I tag someone else?"

"Hi @maintainers — bumping this gently. Happy to make any
adjustments needed. If now's not a good time, just let me know
and I'll come back later."

10.3 被 reject 时的回应

被 reject 是开源协作的常态。你的代码 50% 概率不会被合——即使写得很好。Maintainer 拒绝可能是因为:

被 reject 时要做的不是争论,而是:

  1. 感谢 maintainer 花时间看。
  2. 表达理解。
  3. 询问是否有不同的方向可以贡献。
  4. 不要把 PR 留在那里 "万一改主意"。

拒绝接受模板

# 完全接受
"Thanks for the explanation — totally makes sense. I appreciate
you taking the time to look at this. I'll close the PR. If a
different approach would help, let me know."

# 接受但保留意见
"Understood, and I appreciate the explanation. I do think <X>
might still be valuable, but I respect that it's not aligned
with where the project is going. Closing this for now."

# 不完全理解,请求澄清
"Thanks for looking at this. Could you help me understand the
concern with <X>? I want to make sure I take the right lesson
from this for future contributions."

# 提议 follow-up
"Got it. Out of curiosity, would a smaller PR that just <Y> have
a better chance? Happy to scope down."
// trap

不要因为一次 reject 就在 issue 里抱怨 / 在 Twitter / 微博上吐槽 maintainer。开源圈是小圈子,一次抱怨可能让你以后所有 PR 都被打上"难合作"的标签。

10.4 报告 bug:MRE / MCVE

MRE = Minimal Reproducible Example
MCVE = Minimal, Complete, Verifiable Example

开源 maintainer 收到的 90% bug 报告都缺少 MRE。能写出 MRE 的报告自动跳到处理队列前列。

MRE 三原则

  1. Minimal:删掉所有不影响 bug 的代码。一个公司项目的 1000 行复现脚本不是 minimal。
  2. Complete:从 npm installgit clone 开始的人能跑起来。不要省略 import / setup / config。
  3. Verifiable:你自己跑过这份代码确认 bug 能复现。

MRE 模板

### Bug summary
<一句话>
"Calling foo({ x: undefined }) in v2.4 throws, but worked in v2.3."

### Steps to reproduce

```bash
git clone https://github.com/me/repro
cd repro
npm install
npm test
```

The repro repo contains:
- package.json (pinning the affected version)
- index.js (5 lines, the failing call)
- test.js (one test that asserts the failure)

### Expected behavior
foo({ x: undefined }) should return null.

### Actual behavior
TypeError: Cannot read properties of undefined.
Full stack trace at <link to gist>.

### Environment
- <package> version: 2.4.1
- node: 20.11.0
- OS: macOS 14.3 (also reproduces on Ubuntu 22.04 in CI)

### Bisect
git bisect identifies commit abc123 ("refactor: ...") as the
first bad commit. Reverting that commit fixes the issue.

"Bisect" 这一段是黄金加分项——你已经替 maintainer 缩小了搜索空间到一个具体 commit。

10.5 Mailing list 的语体

Linux kernel、Postgres、Python、GCC、LLVM 等"老派"项目仍以 mailing list 为主要协作媒介。Mailing list 的英文比 GitHub Issue 更正式

开篇 / 称呼

# 正式
"Hi all,"
"Hi $maintainer,"
"Dear $maintainer,"

# 较随意但仍合适
"Hello,"
"Greetings,"

主体段落

# 描述更完整,少缩写
(GitHub)"AFAICT this breaks BC."
(mailing) "As far as I can tell, this change breaks backwards
            compatibility because ..."

# 引用上文用 > 标记(plain text email 传统)
On Mon, Apr 8, 2024 at 10:23 PM Alice <alice@example.com> wrote:
> I think we should add a flag for this.
>
> The flag would default to off.

I'd push back on adding a new flag here. We've been trying to
reduce config surface area in 2.x ...

结尾署名

# 最常见
Best,
Your Name

# Linux 风
Thanks,
--
Your Name

# 完整签名(含组织 / 角色)
Best regards,

Your Name
Senior Engineer, Some Company
your@email.com

Subject line 的传统

# Linux kernel 风格 (含子系统标签)
[PATCH v2 3/5] mm: vmscan: don't watermark boost on swap-full

# Postgres 风格
[PATCH] Fix double-free in transam during recovery

# Python 风格
PEP 729: Typing governance process

# 回复用 Re:
Re: [PATCH v2 3/5] mm: vmscan: don't watermark boost ...

10.6 Code of Conduct (CoC) 术语

大部分知名项目都采纳了 Contributor Covenant 或类似 CoC。常见术语:

术语含义
Code of Conduct (CoC)行为准则
contributor贡献者
maintainer维护者
community社区
harassment骚扰
doxxing人肉搜索
trolling故意挑衅
bad faith恶意
good faith善意
marginalized groups边缘化群体
inclusive language包容性语言
warning / strike警告
temporary ban临时封禁
permanent ban永久封禁

需要避免的语言

以下用词在现代开源圈被认为不合适,主流项目已系统替换:

避免替代
master / slavemain / primary, replica / secondary
blacklist / whitelistdenylist / allowlist, blocklist / safelist
guys (指代群体)everyone, folks, team, all
he / him 默认假设they / them
man-hoursperson-hours, engineer-hours
sanity checkquick check, smoke test
dummy variableplaceholder, stub
crazy / insanewild, surprising
// note

这些不是"政治正确"——是项目维护成本。Inclusive language 让更多人愿意贡献,对项目长期健康有实际收益。GitHub、Linux kernel、Python 等都已经做了批量重命名(master → main 等)。

10.7 跨时区异步沟通

时区话术

# 告知你的时区
"I'm in UTC+8 / China time, so my replies during your evening
will be slow. I'll get back to you within 12-18 hours."

"For context: I'm based in Shanghai. The fastest sync would be
your morning / my evening."

# 安排会议
"Could we find a time that works across <regions>? I have a
fairly flexible schedule between 0:00–10:00 UTC."

"Suggested slots (in UTC):
  Tue 14:00 / Wed 14:00 / Thu 23:00
What works for you?"

常用异步术语

# 时间相关
EOD (end of day) - 当天结束前
EOW (end of week) - 周末前
COB (close of business) - 下班前
SOD (start of day) - 当天上班后
ETA - estimated time of arrival
RSVP - 请回复(参会)

# 状态
afk (away from keyboard) - 暂离
ooo (out of office) - 不在
on-call - 值班
heads down - 专注工作中

# 沟通
ping - 找一下
nudge / bump - 轻轻提醒
loop in - 拉某人进对话
cc - 抄送
fwiw - for what it's worth, 仅供参考

异步消息模板

# 提问 + 默认动作
Hi @maintainer,

I'm working on issue #4321. Two implementation paths I'm considering:

  A. <描述>
  B. <描述>

If I don't hear back by Friday EOD UTC, I'll go with option A
(simpler, but slightly less flexible).

Thanks!

# 状态更新
Quick update on #5678:

- Implementation: 80% done
- Tests: 50% done
- ETA: PR by next Tuesday

Will ping again when it's ready for review.

# 请求帮助 + 优雅退路
Stuck on this part — looking for hints, not a solution. If
nobody has time this week, no worries; I'll keep digging.

10.8 真实开源贡献流程

下面是从 0 到 PR 合并的标准流程:

Step 1: 找一个 "good first issue" 标签的 issue
   ↓
Step 2: 评论占坑
   "I'd like to take this on, if no one else is working on it."
   ↓
Step 3: Fork + clone
   $ gh repo fork owner/repo --clone
   ↓
Step 4: 读 CONTRIBUTING.md
   ↓
Step 5: 写代码 + 测试
   ↓
Step 6: 跑 lint / test / format
   $ make lint test fmt
   ↓
Step 7: Commit (Conventional Commits)
   $ git commit -m "fix(parser): handle UTF-16 BOM"
   ↓
Step 8: Push + 开 PR
   ↓
Step 9: 等 CI + 等 review
   ↓
Step 10: 回应 review 评论
   ↓
Step 11: 被合并 / 被关闭 / 收到 nudge
   ↓
Step 12: 致谢 maintainer,并继续找下一个 issue

10.9 与 maintainer 建立长期关系

偶尔贡献一两个 PR 收益小;持续给一个项目贡献 6-12 个月,回报巨大(job referral、行业声誉、技术深度)。

建立关系的 7 个动作

  1. 持续在同一个项目贡献。Maintainer 会逐渐记住你的名字。
  2. 积极在 issue 区帮其他人。回答其他用户的问题,maintainer 会感激。
  3. 主动 review 别人的 PR。Maintainer 时间紧,外部 reviewer 是宝贵的。
  4. 写好 release notes / changelog 条目。这是 maintainer 经常忘记的脏活。
  5. 修文档 typo。看起来微小,但显示你"在用心"。
  6. 不催 review。每周一次 nudge 是上限。
  7. 合并后致谢。"Thanks for the thorough review!" 让 maintainer 觉得有被看见。
// rule

"开源不是慈善,是声誉投资。" 持续贡献 6-12 个月,你的 GitHub profile 比简历更有说服力。

10.10 真实场景模板库

1. 第一次 issue

Hi! Loving the project. Bumped into <issue> with v2.4.1.

<描述 + MRE>

Happy to work on a fix if you'd accept a PR for this.

2. 主动接 issue

I'd like to take a stab at this if no one's actively working on it.
Plan: <3 sentences>. Will open a draft PR within a week.

3. PR 收到 review 但没人合并

Friendly nudge — anything blocking this from merging? Happy to
make further changes if needed.

4. PR 被静默 30 天

Hi @maintainers, gently bumping this PR. If now's not a good time
to review, no worries — please let me know if I should close it
and re-open later.

5. 自己改方向

Update: I dug deeper and realized my original approach was wrong.
The actual fix needs to happen in <another module>. Closing this
PR; will open a new one against that module.

6. 答其他贡献者的问题

Not a maintainer, but I had the same issue last week. Solution
was <X>. Hope this helps until someone official can confirm.

7. 提议成为 maintainer

I've been contributing here for ~9 months now (12 PRs merged).
If you're open to expanding the maintainer team, I'd be happy
to take on triage / first-line review duties. No pressure if
the team is happy as is.

10.11 本章小结

下一章我们攻克最高强度的英语场景——技术面试。