优雅地修改他人贡献的 Pull Request

2019 年,我在 Github 上开源了自己的第一个开源项目 hexo-theme-stun,它是一个基于 Hexo 框架的博客主题。值得庆幸的是,在维护期间,有许多 Github 用户为这个项目贡献了 Pull Request。

有时,他人提出的 Pull Request 并不能直接被接纳,往往需要一些小的调整:修改错别字、调整代码逻辑、完善文档等等。最直接的,我们可以通过评论,要求贡献者修改。但沟通是有成本的,而且不够及时。

有没有更便捷的方法?直接将自己的 Commit 追加到某个 Pull Request 中?答案是肯定的。

对于下文的操作,读者可以先在测试项目中验证,然后再应用到实际项目中。

Step 1: 克隆项目

首先,将自己的项目克隆下来:

1
$ git clone git@github.com:liuyib/trial-test.git

Step 2: 添加新的远程仓库

为了修改他人 Fork 的仓库,你需要将其添加到自己的远程仓库列表中:

1
$ git remote add EvanOne0616 https://github.com/EvanOne0616/trial-test.git

现在,当你执行 git remote -v 指令时,就可以看到他人 Fork 的仓库,出现在你的远程仓库列表中:

1
2
3
4
5
$ git remote -v
origin git@github.com:liuyib/trial-test.git (fetch)
origin git@github.com:liuyib/trial-test.git (push)
EvanOne0616 https://github.com/EvanOne0616/trial-test.git (fetch)
EvanOne0616 https://github.com/EvanOne0616/trial-test.git (push)

Step 3: 拉取新的远程仓库

1
$ git fetch EvanOne0616

Step 4: 切换到对应的分支

你需要确认一下,贡献者提出 Pull Request 时所用的分支(如果你不确定他们使用的哪个分支,请看 Pull Request 顶部的信息):

Pull Request Meta Info

有可能你会看到,贡献者提出 Pull Request 时所用的分支显示为 unknown repository,这是因为在你还未合并 Pull Request 之前,该贡献者就把 Fork 的仓库删除了。此时,你只能选择直接合并 Pull Request(任何人都无法再修改此 Pull Request),或者你可以要求贡献者重新发起一个 Pull Request,并告诉他没有合并之前不要删除 Fork 仓库。

在本地,给该分支起一个不重复的名字,例如 EvanOne0616-patch,然后切换到贡献者提出 Pull Request 所用的分支:

1
$ git checkout -b EvanOne0616-patch EvanOne0616/patch-1

Step 5: 提交修改,推送远程

在本地进行你想要的修改,提交 Commit 后,推送到贡献者 Fork 的仓库:

1
2
$ git commit -m "Fix the wrong spelling of the word"
$ git push EvanOne0616 HEAD:patch-1

最后,如果一切顺利,你的 Commit 就自动同步到了 Pull Request 的后面:

Modify Others Pull Request

总结上文

上文详述了指令的具体操作,这里进行总结:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 克隆自己的仓库
$ git clone git@github.com:liuyib/trial-test.git

# 将贡献者 Fork 的仓库地址,添加为新的远程仓库
$ git remote add EvanOne0616 https://github.com/EvanOne0616/trial-test.git

# 拉取贡献者的 Commit
$ git fetch EvanOne0616
# 切换到贡献者提出 Pull Request 所用的分支
$ git checkout -b EvanOne0616-patch EvanOne0616/patch-1

# 你在本地修改代码,然后提交
$ git add .
$ git commit -m "Add some changes"

# 将你的 Commit 提交到贡献者 Fork 的仓库
$ git push EvanOne0616 HEAD:patch-1

其他方式

命令行方式

与上文的操作类似,有另一组指令操作也可以实现同样的效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 克隆自己的仓库
$ git clone git@github.com:liuyib/trial-test.git

# 拉取 Pull Request(其中 patch-1 为贡献者提出 Pull Request 所用的分支名,411 是 Pull Request 的 ID)
$ git pull origin pull/411/head:patch-1
# 切换到贡献者提出 Pull Request 所用的分支
$ git checkout patch-1

# 你在本地修改代码,然后提交
$ git add .
$ git commit -m "Add some changes"

# 将贡献者 Fork 的仓库地址,添加为新的远程仓库
$ git remote add EvanOne0616 https://github.com/EvanOne0616/trial-test.git
# 将你的 Commit 提交到贡献者 Fork 的仓库
$ git push EvanOne0616 patch-1

图形化方式

对于上述两组指令操作,开发者可以根据个人喜好自行选择。但是如果需要经常修改他人贡献的 Pull Request,不管哪一种指令操作,都难免会显得有些繁琐。因此,我们需要一种更为简便的方式 —— 图形化操作。

由于我使用的编辑器是 VS Code,所以对于使用其他编辑器的开发者,下文仅部分有用。

对于图形化 Git 操作,VS Code 已经内置了该功能,在侧边栏中可以找到:

VSCode built-in Git GUI

如果你在 VS Code 的侧边栏中,找不到该功能的图标,那么它可能被隐藏了。有两种方式将其显示:1. 在侧边栏上,单击鼠标右键,然后勾选【源代码管理】。2. 使用快捷键 Ctrl + Shift + G G(该快捷键的使用方法:先按下组合键 Ctrl + Shift + G,松开所有按键后,再按下 G

VS Code 虽然内置了源代码管理功能,但是不够强大,因此我们需要安装 GitLens 插件,两者配合使用。安装 GitLens 之后,在 VS Code 的侧边栏中,会新添一个图标,直接点击该图标就可以使用 GitLens 了。

接下来进入正文:“如何通过图形化界面,来修改他人贡献的 Pull Request”。

1 ) 添加远程仓库

用 VSCode 打开你的项目后,点击侧边栏的【源代码管理】,然后在【源代码管理存储库】中,找到需要处理 Pull Request 的项目。接着点击右面的 【...】 -> 【远程】 -> 【添加远程存储库】:

VSCode built-in Git GUI -- Add Remote

在弹出的输入框中,输入远程仓库的 URL,回车确认后,再输入远程仓库的名称(该名称只是一种标识,方便你区分就好,我习惯使用贡献者的 Github 用户名来充当),按下回车确认后,就把贡献者 Fork 的仓库地址,添加到你本地项目的远程仓库列表中了。

2 ) 拉取 Pull Request 中的代码

在侧边栏的【GitLens】中,点击新添加的远程仓库上的 Fetch 按钮:

VSCode Plugins GitLens -- Fetch Others

接着,找到贡献者提出 Pull Request 所使用的分支(例如 patch-1)。然后,点击右边的箭头(Switch to Branch):

该操作的作用是:以远程的分支(例如 patch-1)为基础,在本地创建一个新的分支。

VSCode Plugins GitLens -- Switch Branch

然后在弹出的对话框中,输入一个本地不存在的分支名(例如 patch-1),最后确认。此时,如果没有意外的话,Pull Request 中的代码就被拉取到了本地。

3 ) 修改 Pull Request 并提交

接下来,根据你自己的想法,在本地修改项目。然后在侧边栏的【源代码管理】中,提交 Commit 信息:

VSCode Plugins GitLens -- Git Add / Commit

最后,将你的 Commit 推送到贡献者 Fork 的仓库。

VSCode built-in Git GUI -- Git Push

如果不出意外的话,你的 Commit 就自动同步到了 Pull Request 的后面 🎉。

Web 方式

还有一种简单的方式,直接在 Github 中在线修改 Pull Request:

Github Pull Request -- Edit File

该方式一次只能修改一个文件,更适用于需要少量修改的 Pull Request。

潜在问题

当你将代码 Push 到贡献者 Fork 的仓库中时,如果遇到类似如下报错信息:

1
2
! [remote rejected] HEAD -> master (permission denied)
error: failed to push some refs to 'https://github.com/EvanOne0616/trial-test.git'

这是因为贡献者在提出的 Pull Request 中,取消勾选了 Allow edits from maintainers 选项。让贡献者重新勾选该选项后,该报错即可解决。

总结全文

在没有修改过他人贡献的 Pull Request 之前,我并不感觉这有多麻烦。直到我第一次遇到该问题,才发现自己手足无措。于是我 Google 到了这个帖子:如何修改人家贡献的 PR,不想先合并再修改,在命令行里跟着这个帖子操作了几遍,并将其中的命令总结下来记在笔记中。此时我的内心是不愿意接受的,自己本以为很简单的事情,没想到这么繁琐。最主要的是,对于开源来说,这是一个常用的操作,如果不能化繁为简,那么时间成本太高,容错率太低。最后,为了简化记忆负担,自己摸索出一套可视化操作的方式,并总结成文,仅供参考 :)


参考资料: