三类代码协同模式,你要如何选?——AGit-Flow

AGit-Flow:兼顾开源和私有项目的集中式协同模型

阿里巴巴内部的代码平台在2019年实现了一种集中式工作流——不需要仓库派生,就可以让只读用户贡献代码。这种集中式工作流既适合于开源项目,又适合于私有项目。因其核心实现基于阿里云代码团队定制版的Git(AGit),因此将此工作流命名为 AGit Flow。
AGit Flow在设计上参考了 Gerrit,使用体验和 Gerrit 类似。在2020年,阿里巴巴将这一成果核心代码贡献到Git社区,对Git服务端和Git客户端能力进行了扩展。参见:《Git2.29让Git成功“牵手”Gerrit》[2]
在2023年6月,由阿里云代码团队参与建设的AtomGit开源平台上线,标志着首次将 AGit 工作流带入到了开源社区(atomgit.com)[3]。

AGit 工作流的使用

AGit 工作流在设计上参考了 Gerrit。
Gerrit 是谷歌开发的代码平台,被Android、OpenStack 等项目拿来管理各自的研发协同。Gerrit 的仓库格式也是 Git,但是服务端实现采用了 Java 开发的Git兼容工具 jGit 而非原生 Git,除了带有谷歌风格的逐提交代码评审之外,还实现了无需派生仓库、所有贡献者基于同一个上游仓库进行协同的集中式工作流。Gerrit 这一集中式工作流既适合开源项目,也适合私有项目。但是因为 jGit 在性能和功能上落后于原生 Git,且 Gerrit 的使用体验、可扩展性存在的问题,导致 Gerrit 协同模式没有 GitHub 工作流那样的被人熟知和使用广泛。
在2020年,阿里巴巴向 Git 社区贡献两个功能扩展[4],一个成为Git服务端的功能扩展(proc-receive 挂钩),一个成为Git客户端功能扩展(report-status-v2 能力)。这样代码平台的设计者可以在服务端针对用户的 git 推送行为进行相应的扩展,体验上类似Gerrit,但是能力更加强大。即:
  • 用户向仓库的特殊引用(如refs/for/master)推送,生成代码评审。其中特殊引用 refs/for/master在服务端并不存在,也不会因为用户的推送操作而被创建,用户的推送操作被服务端扩展程序接管,创建代码评审。

  • 客户端收到服务端操作的真实结果,并向用户报告。例如:Git客户端通过 report-status-v2协议接收到服务端真实的操作行为,在服务端创建了代码评审(如:refs/changes/123/head)。
在如下的示例中,有两个角色参与到协同中。开发者向服务端仓库推送,创建了编号为123的代码评审(CR#123),评审者亦能下载、修改和上传代码评审中的提交。
上图中的开发者,执行如下操作:
  1. 开发者将远程上游仓库克隆到本地,并在本地创建开发分支。

    • git clone https://codeup.aliyun.com/$group/$repo.git

  1. 开发者创建本地分支(topic)。

    • git switch -c topic master

  1. 在本地分支中开发。

    • git add <file>

    • git commit -s

  1. 执行特别的推送命令。如下所示,将本地提交推送到远端不存在也不会被创建的一个虚拟分支(引用)中,该虚拟分支的格式为 refs/for/<目标分支>/<本地分支>。服务端识别这个特殊的推送操作,在服务端创建代码评审。

    • git push origin HEAD:refs/for/master/topic

  1. 上述推送命令的特殊目标分支被服务端识别,自动创建代码评审(如编号 123 的代码评审:CR #123)。

  2. 本地仓库继续修改,创建或更新提交。

    • git add <file>

    • git commit -s

  1. 执行同样的推送命令,刷新远程仓库中的代码评审(CR #123)。
上图中的代码评审者参与代码评审过程中,可以下载代码评审(CR #123)到本地进行线下评审,亦可参与代码协同,更新 CR #123 上的提交。说明如下:
  1. 评审者可以下载编号 123 的代码评审相关提交到本地,进行线下评审。

    • git fetch origin refs/changes/123/head

  1. 评审者创建本地分支(如 rev-branch)。

    • git switch -c rev-branch FETCH_HEAD

  1. 评审者在本地分支创建新提交。

    • git add <file>

    • git commit -s --fixup HEAD

  1. 评审者执行特殊推送命令,更新代码评审中的提交,供原作者参考。该命令中使用了特别的推送参数 -o review=123用于更新指定代码评审。示例如下:

    • git push -o review=123 origin HEAD:refs/for/master

优势和缺点

AGit-Flow 的优势:
  1. 人人皆可贡献,只读用户也可以参与代码开发,适合于开源场景。

  2. 同时也适合于企业私有仓库的开发场景。因为不存在仓库派生,不像 GitHub 工作流那样因派生熔断导致仓库授权失去管控,因此既适合于开源代码开发场景,又适合于企业私有项目的开发场景。

  3. 开发者工作在同一个仓库中,服务端仓库无需同步操作。即不需要 GitHub 工作流那样要进行上游仓库、派生仓库、本地仓库的三方同步操作。

  4. 操作步骤简化,命令行推送操作直接创建代码评审,无需通过 web 界面创建代码评审。

  5. 适合于多仓库项目的场景。可以参考 Android 项目管理多仓库的方案。

AGit-Flow 的缺点:Git 推送命令行比较长,使用特殊的目标引用(refs/for/<branch>/<topic>)或特殊的推送参数,需要学习和适应。


推送评审模式

基于阿里云贡献给 Git 社区的两大核心功能(服务端 proc-receive 挂钩和客户端 report-status-v2 扩展),阿里云·云效代码平台创造了推送评审模式,实现对仓库分支、标签的全生命周期管理。
推送评审模式内部测试中,将于2023年底正式商用。
推送评审的使用方法:
  • 向已有分支推送:不更新分支,而是创建一个新的代码评审,或更新已有的相关代码评审。

  • 推送操作欲创建分支/标签:不直接创建分支/标签,而是创建一个审核单,审核通过后执行分支/标签的创建操作。

  • 推送操作欲删除分支/标签:不直接删除分支/标签,而是创建一个审核单,审核通过后执行分支/标签的删除操作。

  • 向分支强制推送:不更新分支,而是创建一个审核单,审核通过后执行分支的强制更新操作。

  • 管理员可以在推送命令中加入参数绕过推送评审,使得推送操作直接生效。如:

    • git push -o review=no origin <新分支> :<待删除分支>

    • git push -o review=no --force-with-lease