golang源码工程是如何提交代码的

前言:

golang是一门非常年轻的语言,背靠工程实践非常强大的google, 在开源的研发流程上也是处处凸显google的工程师文化, 本文简要讲述在golang源码仓库中提交一个commit的过程及其涉及到的持续交付的知识

相关链接:

golang源码, 在线快速阅读源码

golang官方仓库的贡献指南: 非常详细, 是我目前见过最详细的提交指南了

Gerrit:不同于其他的github开源项目, golang有它独立的一套代码评审系统, 基于, 可以把它当做一个纯粹的code-review系统

主干开发: golang的仓库的开发主要是基于主干开发的方式

基本步骤:

  1. 注册为贡献者,具体参考, 主要的内容是 注册 Gerrit账户,签署开发者协议,下载 git-codereview 客户端
  2. 在写代码之前,首先需要搜索一下已有的issues, 看是否有已有的解决方案或者议题, 如果没有找到,可以为本次要解决的问题打开一个issues, 标记一下, 防止其他人重复劳动
  3. 在开发完代码之后, 下一步就是准备往golang仓库发起代码评审(code review)

发起代码评审有两种方式:

  1. 基于github开源的玩法, 从自己fork出来的分支往golang仓库发起 Pull Request,例如:Pull Request
  2. 直接基于Gerrit + git-codereview工具发起代码评审, 例如: gerrit代码评审

基于github发起PR

golang的代码评审主要还是在gerrit中处理的, 但是为了照顾广大开源开发者的习惯, golang团队很贴心的做了几个github的机器人, 会自动将PR的内容同步到gerrit中, 一个PR中我们可以看到这两个机器人:

  1. googlebot 一般会检查当前的开发者是否签署了开发者协议。
  2. gopherbot 自动将当前的PR的内容在gerrit中创建一个代码评审, 并且会同步gerrit评审的消息到PR中。可以看做是两个评审系统的同步工具

下图为googlebot检查是否签署开发者协议
golang-clabot
下图为goherbot同步PR到gerrit
golang-goherbot
下图为gerrit代码评审界面
golang-cr

在github中PR的作用其实就是代码评审, 而Gerrit的功能也是类似, 所以这不用过多纠结着两者之间的差别, 简单来说就是Google的工程师觉得Github PR那套评审不好用, 就用Gerrit代替了它。 那么怎么代替呢? 具体的步骤类似如下:

  1. 给当前的仓库配置github的钩子,监听PR的发起与更新事件。
  2. 当发起PR时, 触发对应的钩子, 在钩子中创建 Gerrit代码评审单关联当前的PR
  3. 当Gerrit中有评论时, goherbot会将评论同步到PR中, 开发者可以修改代码并提交, 此时也会触发PR的更新和 gerrit评审的更新
  4. 当评审通过时, 在Gerrit中, maintainers可以通过添加Run-TryBot Label, TryBots会触发pre-submit的检查, golang基于GKE搭建了自己的持续集成系统:build dashboard
  5. 当code-review通过且TryBots的pre-submit检查通过之后,代码会自动被合入master,会在master创建一个合并提交(squash commit),原分支的所有新增的commit会被压缩成一个commit, 并且这个commit会带上当前code-review的链接, 方便追踪代码的改动
  6. 代码的提交统一使用cherry-pick的方式提交到主干。这里就比较强调单个PR之间的原子性了。

基于Gerrit + git-codereview发起代码评审

需要从 https://go.googlesource.com/go clone出 github/golang代码库的镜像仓库,并新建分支进行开发

使用基于Gerrit + git-codereview发起的代码评审相当于绕过github提供的Pull Request功能, 直接创建gerrit的评审, 代码评审code review通过+TryBots运行通过, Gerrrit会自动将commit cherry-pick到github golang仓库master分支

Commit-提交信息的格式:

一个好的提交格式类似这样:

1
2
3
4
5
6
7
8
9
math: improve Sin, Cos and Tan precision for very large arguments

The existing implementation has poor numerical properties for
large arguments, so use the McGillicutty algorithm to improve
accuracy above 1e10.

The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm

Fixes #159

首行要简要的表达出本次提交的作用

中间主体部分详细描述改动

最后一行是相关issues的引用, 关联issues, 方便回溯改动的背景

Submitting

一次提交包括如下三次检查:

1. 发起代码评审前本地运行检查

go的仓库提供了一个all.bash的脚步, 方便开发者快速在本地执行代码风格检查和单元测试, 一般会做成增量检查的方式, 降低开发者等待的时间, 这一步主要保证当前的改动代码分支是可以通过检查的

1
2
$ cd go/src
$ ./all.bash

2. pre-submit

在gerrit的评审中, tryBots会触发运行pre-submmit, 这一步一般会模拟合入代码, 并运行相应的增量的检查, 这一步主要保证当前分支的代码与主干最新的提交合并之后应该是可以通过检查的

3. post-submmit

当代码合入master之后, 要执行master的全面的检查,这是三层检查中最后一道,也是代码质量的最重要的一道防线

上述的三个检查其实有个专业的术语叫做“6步提交法”
6步提交法