背景

对于利用业余时间参与开源项目的同学,由于是间歇性的接触,所以很多问题容易忘。比如基于git的多仓库开源协作模式,如果日常工作中用不到,那么每次参与开源项目时有些细节可能需要重新回忆一下。

本文主要记录我参与开源项目中的易忘点,供后续参考。

DCO Test

有些开源项目的CI workflow中,会对接到的PR进行DCO test,即要求所有commit必须是签名过的,以保证代码所有权归提交者,避免合并后因代码归属引起权利纠纷。

sign-off commit

其实满足DCO test的方法很简单:

命令行中,git commit-s选项即可,比如:

git commit -s -m 'This is my commit message'

jetbrain的idea等编辑器中,在git提交时更多设置里有相关配置:

image-20240221164508229

已经提交PR后修复DCO

如果在commit时不曾sign off,提交PR后提示DCO未通过,那么可以根据github页面上的引导进行重新sign off,以下就是我第一次遇到这个问题时的操作记录

  1. 安装ghbrew install gh
  2. 打开欲修改的PR页面,在code下拉列表中复制checkout命令
  3. 在本地fork的仓库执行checkout命令gh pr checkout $N,将PR拉取到本地。此时gh会交互式询问从哪个仓库拉取pr,应该选择被fork的源仓库,如果选择错误,可以使用gh pr checkout $N --repo $user/$project指定远程仓库
  4. git rebase HEAD~1 --signoff
  5. git push --force-with-lease origin master

直接使用rebase修复

上面的修复过程引入了github的客户端,稍显多余。第一次遇到该问题的时候没太深入研究,后来明白原理后发现,本质上git commit的sign off其实直接用git rebase+force push也可以修改,因为本质上就是对历史commit的修改。

另外,如果不着急跑其他的CI workflow,或者是比较复杂的PR,后面大概率会rebase本地commit,那么DCO test可以随后面的rebase顺带修改,不一定要在第一时间修复。

合并commit

有些PR比较大,开发周期比较长,在开发中可能会经常push代码,到最后快要合并时,需要把fork仓库的commit进行整理、合并。

这里记录合并commit的方法:

  1. 在log中找到要操作commits的最早commit,记录ID
  2. git rebase -i $ID此时会进入编辑commit的编辑器,默认是vim
  3. 后续如果有复杂的rebase操作,可以改用vscode:GIT_EDITOR=code\ --wait git rebase -i $ID
  4. 合并对应rebase中的s命令,将要合并的commit前缀改为s,该commit会向前合并

合并commit主要解决的问题是开发过程和merge后commit不一致的问题。

如何优雅地同步上游仓库

在刚开始fork一个upstream仓库进行开发时,我们是基于upstream的最新状态开发的。但是如果开发到合并的周期比较长,upstream会不断有其他commit产生,这时我们的fork仓库就落后于upstream了。

前几年github网页上好像没有一键同步功能,需要手动fetch upstream然后merge再push。后来github增加了sync fork按钮,则可以直接通过fork仓库main page的sync fork按钮一键同步。

  1. 如果upstream新增的commit和fork仓库的修改没有冲突,那么同步可以自动一键完成
  2. 反之如果有冲突,则不能自动一键完成。我们需要到本次的github PR页面,在尾部会有solve conflict的提示,需要手动solve conflict。
  3. solve conflict会产生一个commit,可以用rebase把这个commit squash到之前的commit中。
  4. 最后,rebase除了能合并commit,还可以调整commit顺序。我们拉取upstream最新commit后,通过rebase把本次PR的commit放到最后,即可实现基于最新的upstream进行PR的效果,这样就能够永远基于upstream最新的状态评估PR了。
  5. 破罐破摔:如果对rebase操作不熟悉,或者冲突过多,一个更加硬核的方法是把自己的commit通过patch保存到本地,然后把fork库hard reset到某个之前未修改的状态然后force push,这时肯定是可以一键sync的,sync后再导入patch,重新commit即可(不要忘记sign off)。注意在这个过程中PR会close,手动re open即可。

参考

GitHub Apps - DCO

巧用 git rebase 合并多个 commit。 - Yxh_blogs - 博客园 (cnblogs.com)

git 合并不相邻的commit - CSDN

文章目录