本文整理一套从 Fork、本地开发、提交 Pull Request、签署 CLA 到等待维护者审核的完整流程。示例以 Java 项目为背景,但流程适用于大多数 GitHub 开源项目,可作为日常参与开源协作时的操作参考。
1. 先确认要修复的问题
提交 PR 前,先确认三件事:
- 目标分支里确实还没有修复。
- 改动范围足够小,最好只解决一个明确问题。
- 本地能跑过对应测试,或者至少能说明为什么没有跑测试。
以本次示例为例,目标是给 CommonConfiguration 增加 java.sql.Timestamp 的类型转换支持,并补充单元测试。
2. Fork 官方仓库
打开官方仓库页面,例如:
text
https://github.com/<owner>/<repo>
点击右上角 Fork,把仓库复制到自己的 GitHub 账号下。
Fork 完成后,你会得到一个自己的仓库:
text
https://github.com/<your-name>/<repo>
注意:后续代码是推送到自己的 fork 仓库,不是直接推送到官方仓库。
3. 克隆自己的 fork
可以使用 IDEA:
File->New->Project from Version Control...- URL 填自己的 fork 地址:
text
https://github.com/<your-name>/<repo>.git
也可以使用命令:
bash
git clone https://github.com/<your-name>/<repo>.git
cd <repo>
建议开源项目单独放一个干净目录,不要和公司业务项目混在一起。
4. 添加官方仓库为 upstream
进入本地仓库后,先查看远端:
bash
git remote -v
通常自己的 fork 会叫 origin。
添加官方仓库:
bash
git remote add upstream https://github.com/<owner>/<repo>.git
再次确认:
bash
git remote -v
正常应该类似:
text
origin https://github.com/<your-name>/<repo>.git (fetch)
origin https://github.com/<your-name>/<repo>.git (push)
upstream https://github.com/<owner>/<repo>.git (fetch)
upstream https://github.com/<owner>/<repo>.git (push)
5. 从官方目标分支创建自己的 PR 分支
先拉取官方最新代码:
bash
git fetch upstream
确认目标分支存在:
bash
git branch -r
例如目标分支是 2.11,则创建自己的修复分支:
bash
git checkout -b fix/timestamp-converter upstream/2.11
如果目标分支是 main,则类似:
bash
git checkout -b fix/some-issue upstream/main
确认当前分支:
bash
git branch --show-current
6. 配置当前仓库的提交身份
这一步很重要,尤其是在公司电脑上提交开源 PR。
先检查当前提交身份:
bash
git config user.name
git config user.email
建议在当前开源仓库里单独配置 GitHub 已验证的邮箱:
bash
git config user.name "<your-github-name>"
git config user.email "<your-verified-email@example.com>"
这里不建议使用公司电脑默认的本地域名邮箱,例如:
text
username@company-pc
原因是很多开源项目会使用 CLA assistant 校验提交作者。如果 commit 邮箱不是 GitHub 账号中已验证的邮箱,CLA 可能会提示:
text
<commit-author> seems not to be a GitHub user.
Please add the email address used for this commit to your account.
7. 修改代码
只改和本次问题直接相关的文件。
建议遵守几条原则:
- 不顺手格式化全项目。
- 不提交 IDE 配置。
- 不提交本地配置、日志、测试数据。
- 改动越小,维护者越容易 review。
- 有测试就补测试,没有测试也要在 PR 描述里说明。
示例改动:
text
src/main/java/.../CommonConfiguration.java
src/test/java/.../CommonConfigurationTest.java
8. 本地运行测试
根据项目技术栈选择测试命令。
Maven 项目示例:
bash
./mvnw -pl <module-path> -am -Dtest=<TestClassName> -DfailIfNoTests=false test
Windows PowerShell 示例:
powershell
.\mvnw.cmd -pl <module-path> -am -Dtest=<TestClassName> -DfailIfNoTests=false test
如果项目要求指定 JDK,先设置 JAVA_HOME。
PowerShell 示例:
powershell
$env:JAVA_HOME='<your-jdk-path>'
.\mvnw.cmd -pl <module-path> -am -Dtest=<TestClassName> -DfailIfNoTests=false test
例如某些新版本 Java 项目需要 Java 17,如果使用 JDK 8,可能会报:
text
无效的目标发行版: 17
测试通过后,把命令和结果记录下来,后面写 PR 描述时会用到。
9. 检查改动范围
提交前先看状态:
bash
git status
查看改动统计:
bash
git diff --stat
检查是否有空白格式问题:
bash
git diff --check
确认只包含本次 PR 需要的文件。
10. 提交 commit
添加文件:
bash
git add <file1>
git add <file2>
提交:
bash
git commit -m "fix: support Timestamp conversion in CommonConfiguration"
如果是通用场景,commit message 建议保持英文、简短、明确:
text
fix: correct xxx behavior
test: add coverage for xxx
docs: update xxx documentation
提交后检查 commit 作者:
bash
git log -1 --pretty=format:"%an <%ae>"
确认输出的是 GitHub 已验证的邮箱。
11. 如果 commit 邮箱错了怎么办
如果已经提交了,发现作者邮箱不对,例如输出:
text
your-name <local-user@company-pc>
先设置正确身份:
bash
git config user.name "<your-github-name>"
git config user.email "<your-verified-email@example.com>"
然后修正最后一次 commit 的作者:
bash
git commit --amend --reset-author --no-edit
如果这个 commit 已经推送到了自己的 fork,需要强制更新远端分支:
bash
git push --force-with-lease origin <your-branch-name>
注意:优先使用 --force-with-lease,不要随手用 --force。
12. 推送到自己的 fork
推送自己的 PR 分支:
bash
git push origin fix/timestamp-converter
再次强调:这里推送的是自己的 fork 仓库,不是官方仓库。
13. 创建 Pull Request
打开自己的 fork 仓库,GitHub 通常会提示 Compare & pull request。
创建 PR 时重点确认方向:
text
base repository: <owner>/<repo>
base branch: <target-branch>
head repository: <your-name>/<repo>
compare branch: <your-branch-name>
例如:
text
base repository: official/repository
base branch: 2.11
head repository: your-name/repository
compare branch: fix/timestamp-converter
不要把方向选反。
14. PR 标题和描述
标题建议和 commit message 保持一致:
text
fix: support Timestamp conversion in CommonConfiguration
PR 描述可以按下面结构写:
markdown
### What changed
Describe what this PR changes.
### Why
Describe why this change is needed.
### Tests
Describe local tests you ran.
```bash
<test command>
示例:
```markdown
### What changed
Add a global BeanUtils converter for `java.sql.Timestamp`.
### Why
Some bean-copy or mapping scenarios need to convert values from `Date`, numeric timestamps, or strings into `Timestamp`.
Without an explicit converter, these conversions may fail or behave inconsistently.
### Tests
Added unit coverage for:
- `Date` to `Timestamp`
- `Long` to `Timestamp`
- numeric timestamp `String` to `Timestamp`
- formatted datetime `String` to `Timestamp`
Local test command:
```bash
./mvnw -pl <module-path> -am -Dtest=<TestClassName> -DfailIfNoTests=false test
## 15. 签署 CLA
很多开源项目会使用 CLA assistant。
提交 PR 后,如果看到类似提示:
```text
Thank you for your submission!
Please sign our Contributor License Agreement.
点击提示里的 Contributor License Agreement 链接,使用 GitHub 账号授权并签署。
签署完成后,回到 PR 页面,通常有两种方式触发重新检查:
- 点击 CLA assistant 评论里的
recheck。 - 在 PR 下评论:
text
recheck
如果 CLA 仍然失败,优先检查 commit 作者邮箱是否是 GitHub 已验证邮箱:
bash
git log -1 --pretty=format:"%an <%ae>"
常见失败原因:
- commit 使用了没有绑定到 GitHub 的邮箱。
- 邮箱绑定了,但还没有完成 GitHub 验证。
处理方式:
- 去 GitHub
Settings -> Emails添加并验证 commit 邮箱。 - 或者修改 commit 作者邮箱后重新 push。
16. 等待 CI 和维护者审核
PR 创建后,可能会看到几类状态:
text
CLA passed
No conflicts with base branch
Workflow awaiting approval
Static code analysis pending
其中:
CLA passed:协议已签署。No conflicts with base branch:没有分支冲突。Workflow awaiting approval:外部贡献者的 CI 需要维护者批准运行。Static code analysis pending:静态检查等待执行或等待结果。
如果 workflow 需要维护者批准,贡献者通常不能自己处理,只能等待维护者操作。
可以在 PR 下补一句:
text
CLA has been signed. This PR is ready for review. Thanks.
17. 如果维护者要求修改
不要关闭 PR。
在同一个本地分支继续修改:
bash
git status
git add <changed-files>
git commit -m "fix: address review comments"
git push origin <your-branch-name>
PR 会自动更新。
如果只是修改最后一次 commit,也可以:
bash
git commit --amend --no-edit
git push --force-with-lease origin <your-branch-name>
18. 最终检查清单
提交 PR 前检查:
- PR 目标仓库和目标分支正确。
- 分支是从官方目标分支拉出来的。
- 改动范围足够小。
- 没提交公司业务代码。
- 没提交本地配置。
- 没提交 IDE 配置。
- commit 作者邮箱是 GitHub 已验证邮箱。
- commit message 清晰。
- 本地测试已执行,或已说明未执行原因。
- PR 描述说明了修改内容、原因和测试情况。
- CLA 已签署。
- PR 无冲突。
19. 这个流程的本质
整个 GitHub PR 流程可以概括为:
- 官方仓库有一个目标分支。
- 你 fork 一份到自己的 GitHub 账号。
- 你从官方目标分支拉出自己的修复分支。
- 你在自己的分支上修改、提交、推送。
- 你向官方目标分支发起 Pull Request。
- 官方维护者审核后决定是否合并。
也就是说:
text
你的 fork 分支 -> 官方仓库目标分支
你没有直接修改官方仓库,只是请求维护者把你的改动合并进去。