我昨天给归藏的 guizang-ppt-skill 提了一个 PR,从满心忐忑到顺利发出,整个过程踩了不少坑,也学到了很多。这篇文章把完整的 PR 提交流程和踩坑经验分享出来,希望能帮到想做开源贡献但不敢迈出第一步的人。

背景

我本地有一个 Claude Code Skill 的仓库,做了一些功能增强——WYSIWYG 编辑面板、PPTX 导出、文档提取器,加起来 1600 多行代码。我想把这些改动词贡献回上游,但有几个心理障碍:

  • “我才改了这么点东西,好意思交吗?”
  • “1600 行会不会太多,作者会烦吗?”
  • “我直接推到一个新仓库算不算偷别人的代码?”
  • “英文不好,commit message 写英文还是中文?”

如果你也有类似的顾虑,往下看。

第一步:搞清楚许可证,别怕”偷代码”

很多新手以为”拿了别人的代码改名发布就是盗窃”——这是最大的误解。

去仓库根目录找 LICENSE 文件。guizang-ppt-skill 用的是 AGPL-3.0,这意味着:

  • ✅ 可以 fork
  • ✅ 可以修改
  • ✅ 可以重新发布、甚至改名
  • ⚠️ 必须保留原始版权声明和许可证
  • ⚠️ 衍生作品也必须用 AGPL-3.0

开源协议不是你贡献的障碍,而是保障。 只要遵守协议,你做的任何事情都合法。

小技巧:GitHub 仓库右侧边栏有许可证信息,点进去就能看到你能做什么、不能做什么。

第二步:Fork 仓库

这是物理上必须要你做的一步。在你自己的 GitHub 账号下创建一个副本:

随便打开仓库首页,点右上角 Fork 按钮 → Create fork,10 秒搞定。

Fork 完之后,你的账号下就多了一个 你的用户名/guizang-ppt-skill 的仓库。

为什么必须 fork?因为你对上游仓库没有写权限,只能推到自己的副本,再从副本开 PR 到上游。

第三步:把本地改动迁移到 fork

很多人卡在这一步。常见错误:

❌ 错误做法:直接在上游仓库上开发

1
2
git clone https://github.com/op7418/guizang-ppt-skill.git  # 直接 clone 上游
# 然后在上游的 main 分支上改代码...

这样改完之后你 push 不回去(没权限),而且本地 main 分支已经和上游混在一起了。

✅ 正确做法:双 remote 模式

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 把 fork 添加为第二个远程仓库
git remote add fork https://github.com/你的用户名/guizang-ppt-skill.git

# 2. 从上游 main 创建新分支(而不是在上游的 main 上直接改)
git fetch origin main
git checkout -b feat/我的功能 origin/main

# 3. 在新分支上做你的改动
# ...

# 4. 推到你的 fork
git push fork feat/我的功能

最终你的 remote 长这样:

1
2
origin  → https://github.com/op7418/guizang-ppt-skill.git   (上游,只读)
fork → https://github.com/你的用户名/guizang-ppt-skill.git (你的副本,可写)

核心原则:永远不要在上游的 main 分支上直接开发。 每次 PR 从 origin/main 开新分支,推到 fork

第四步:控制 PR 的范围——这一步最关键

这是我踩的最大的坑。最初我的改动包含了四个独立功能:

功能 行数 是否应该在一个 PR 里?
WYSIWYG 编辑面板 ~500 行
PPTX 导出 ~300 行 ❌ 拆出去
文档提取器 ~300 行 ❌ 拆出去
注意事项栏组件 ~30 行 ❌ 太个性化,不该交

PR 的第一原则是聚焦(Focused)。 每个 PR 只做一件事。为什么?

  1. 降低 reviewer 的心智负担——review 500 行和 review 1600 行完全是两种体验
  2. 提高被合并的概率——如果四个功能里有一个被拒,整个 PR 都会被拒
  3. 贡献记录更好看——3 个 merged PR 比 1 个好看得多

我怎么拆的?用 Git 的分支隔离:

1
2
3
4
5
6
7
8
# 从上游 main 开干净分支
git checkout -b feat/edit-panel origin/main

# 只把编辑面板相关的文件从旧分支捡过来
git checkout 旧分支 -- assets/edit-panel/ scripts/inject-edit-panel.mjs

# 模板文件和文档需要手动做精准编辑,不要整个文件搬过来
# 手动编辑 assets/template*.html、SKILL.md、checklist.md...

最忌讳的就是 git checkout 旧分支 -- SKILL.md 这种操作——它会把你旧分支上所有改动(包括 PPTX 导出、文档提取等不相关的内容)全部带过来。

怎么判断什么东西不该进 PR?

问自己一句话:“这个功能是只有我需要,还是对所有用户都有价值?”

我那 30 行的 precaution-bar 注意事项栏组件就是一个典型例子——它是我某个特殊实验 PPT 里才需要的 UI 组件,不具备通用性,果断删掉。

第五步:Commit message 用什么语言?

guizang-ppt-skill 是一个中文仓库,README、SKILL.md、checklist 全是中文写的。这种仓库用英文 commit message 反而突兀。

原则:跟着仓库的语言习惯走。 仓库是中文就用中文,仓库是英文就用英文。

一个合格的 commit message 结构:

1
2
3
4
5
6
7
feat: 一句话概括做了什么

详细说明(可选,但推荐):
- 为什么要做这个
- 怎么实现的
- 涉及哪些文件
- 有什么注意事项

我的最终 commit message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
feat: 添加 WYSIWYG 编辑面板(外置注入架构)

新增浏览器端可视化编辑器,用户生成 PPT 后可按 E 键打开面板...

设计思路:
编辑面板代码存放在 assets/edit-panel/ 独立文件中...

使用方式:
1. 按正常流程生成 PPT
2. 运行注入脚本
3. 浏览器按 E 键...

文件清单:
- assets/edit-panel/editor.js — 编辑器核心逻辑
- scripts/inject-edit-panel.mjs — 注入脚本
...

第六步:开 PR

推送完后,终端会给你一个链接:

1
2
remote: Create a pull request for 'feat/edit-panel' on GitHub by visiting:
remote: https://github.com/你的用户名/guizang-ppt-skill/pull/new/feat/edit-panel

点进去,GitHub 会自动识别你要合入的目标(上游的 main 分支)。PR 标题用 commit message 的第一行,描述可以粘贴 commit message 的正文。

然后点 Create pull request,完事。

第七步:等待 review,别焦虑

PR 提交之后才是真正考验心态的时候。几个心理准备:

  • 作者可能几天甚至几周才回复——这是正常的。开源维护者大多是用业余时间,别催
  • 作者可能提修改意见——这是好事,说明他在认真看。按要求改就行
  • 作者可能拒绝——不代表你做得不好,可能是方向不合或者他已经在做类似的东西
  • PR 被合并之前,你的 fork 可以继续迭代——在原分支上改完 push 就行,PR 会自动更新

回顾:一份 PR 提交前自检清单

1
2
3
4
5
6
7
8
□ 仓库的许可证允许我贡献吗?
□ 我先 fork 了吗?(不是直接 clone 上游)
□ 我是在新分支上开发的吗?(不是 main)
□ 这个 PR 只做一件事吗?(一个 PR = 一个功能)
□ 有没有夹带只对我个人有用的私货?
□ Commit message 用了仓库的语言吗?
□ 有没有把 node_modules 误提交进去?(git status 看一遍)
□ PR 描述写清楚为什么做、做了什么了吗?

总结

给开源项目提 PR 这件事,最难的不是代码,是心理。你永远觉得自己的代码不够好、不够重要、不值得交。 但开源社区的本质就是”有人需要 → 有人做了 → 交回去让大家都能用”。你做的功能如果对你有用,大概率对别人也有用。

而且从实操角度,提 PR 比 fork 后独立维护省力得多——上游的 bug 修复和功能更新你自动受益,不需要自己手动同步。你的名字还会出现在贡献者列表里,下次面试的时候这就是实打实的开源贡献记录。

去吧,翻翻你本地那些改了不敢交的仓库,挑一个最小的,先把手弄脏。