GitHub的fork是代码协作的重要方式。一方面,在自己的fork中做出的修改,可以通过提出pull request,合并到上游仓库(或其他分支);另一方面,上游仓库或别人的fork有了更新,就可以反过来应用到我们自己的fork中,只需启动一个反方向的pull request。
但是,GitHub的pull request存在一个问题:不能采用他人的个别提交(即cherry-pick),而只能把他人比你新的所有提交一同合并。于是,如果:
- 你自己在本地仓库作出了大量修改,但只想把个别提交发送给上游仓库;
- 或者是上游仓库有一些提交不适合你,你不想把它们一并合并到你的代码库中;
- 又或是你的项目是完全独立的,只想选择性地接受上游的部分提交,
这几种情况下,所有的提交都会算在一次pull request内,直接进行pull request有可能会导致难以预料的后果(比如弄乱上游仓库的代码、引起Bug)。
对于这种情况,可以善用Git的“远端(remote)”和“分支(branch)”功能,实现上游仓库和自己的fork(为方便起见,下文称“你的仓库”)的协同工作,再借助cherry-pick只采纳个别提交,从而弥补GitHub的缺陷。
情形一:选择个别提交到上游仓库
第一步——增加远端
Git默认的远端仓库叫origin
,实际上,它支持添加多个远端仓库。我们把上游仓库添加进来,取名为upstream
:
1 |
|
第二步——根据上游分支建立patch
分支
GitHub的pull request支持对特定分支进行比较。这时如果用于跟远端比较的分支只包括了你需要的提交,就不至于把你做的所有提交一股脑儿加上去了。我们建立一个专门的分支用于发起pull request,选择性应用我们的提交。命名时带上patch
这样的关键字,以确保辨识度。
假设我们要同步的上游分支是master
。首先把上游仓库同步到本地:
1 |
|
然后上游仓库master
分支的基础上建立一个新的patch-1
分支:
1 |
|
注意:如果不事先使用
git fetch
,则git checkout
的过程会失败,提示找不到分支upstream/master
。
第三步——找出要pull request的提交
这时就会自动切换到新分支patch_1
中。我们可以先切换回本地的工作分支(如master
):
1 |
|
然后浏览提交日志:
1 |
|
在提交日志里,把你需要pull request的提交ID记录下来。下方提交日志的范例中,commit
字样后面的十六进制文本就是提交ID,通常只记前七位就可以了:
1 |
|
第四步——cherry pick
这里假设要以上例中第二、第三个提交来发起pull request。
首先切换到patch-1
分支:
1 |
|
然后运行cherry pick,应用上述两个提交:
1 |
|
命令的输出结果如下所示,跟平时使用git commit
的输出是一样的:
1 |
|
第五步——推送分支
Cherry pick完成后,把patch-1
分支推到GitHub上自己的fork:
1 |
|
第六步——发起pull request
登录GitHub,然后像往常一样,从自己的仓库发起pull request。但要注意,你的仓库一侧用于比较的分支应该选择刚刚创建的patch-1
分支。
第七步——删除patch
分支
如果上游仓库接受了你的pull request,你就可以把patch-1
分支删除了:
1 |
|
情形二:拣选上游仓库的提交
第一步——增加远端
我们同样把上游仓库添加进来,取名为upstream
:
1 |
|
第二步——拉取上游分支
然后我们从上游仓库拉取所需分支(如master
)的内容,保存到本地。
首先,把上游仓库同步到本地:
1 |
|
然后,把上游仓库的master
分支下载下来,保存到一个新分支master-upstream
当中:
1 |
|
拉取后就会自动切换到该新分支下,这样就可以像管理你的分支一样进行操作了,一些适用于本地分支的命令(如git merge
、git diff
、git cherry-pick
)均可使用。
如果之前已经进行过上述步骤,则使用git pull
更新本地的上游仓库:
1 |
|
第三步——找出要采用的提交
在master-upstream
分支下,查看提交记录:
1 |
|
然后记下你要采用的提交ID。
第四步——cherry pick
重新切换回你的仓库分支,然后使用git cherry-pick
应用提交(以下提交ID为示例):
1 |
|
第五步——把修改推到你的仓库
完成之后,直接把你的提交推到远程仓库:
1 |
|
参考资料
- 本文作者: 爱拼安小匠
- 本文链接: https://anclark.github.io/2021/02/12/Git/Git_Sync_Commits/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0(署名-非商用-禁止演绎 3.0) 许可协议。转载请注明出处!