(v1.0, 2011-09-18)
Finish off all japs.
Gerrit是Google公司在Android开源项目中GIT应用上的两个重要创新之一,它是为Git引入的代码审核服务器,其代码审核是强制性的,就是说,向Git版本库的推送必须要经过Gerrit服务器,修订代码必须经过代码审核的工作流程之后,经批准才能合并到正式版本库中。
一、基本原理
1、Gerrit的审核工作流
首先,开发者yuwf通过git命令推送代码到Gerrit管理下的Git版本库,推送的提交转化为代码审核任务,审核任务通过refs/changes/下的引用访问到。代码审核者hz通过WEB界面查看审核任务、代码变更,以及做出通过代码审核或打回等决定(Review)。代码测试者zrb通过refs/changes/下的引用取得修订代码,然后对其进行测试,如果测试通过则将该评审任务设置为校验通过(Verified)。代码库管理者zrm通过提交(Submit)将经过了审核和校验的修订代码合并到版本库对应的分支中(可能需要处理合并冲突等)。
2、基于SSH的GIT服务器
Gerrit是基于SSH协议实现的GIT服务器,其端口不是标准的22,而是29418端口。
3、特殊引用
Gerrit的GIT服务器,禁止用户向refs/heads下的引用执行推送,即不允许用户直接想分支进行提交。为了让开发者能够想GIT服务器提交修订代码,Gerrit只允许用户向特殊的引用refs/for/<branch-name>下执行推送,其中<branch-name>是开发者的工作分支。向refs/for/<branch-name>下推送并不会在其中创建引用,而是为新的提交分配一个ID,称为review-id,并为该review-id的访问建立如下格式的引用refs/changes/nn/<review-id>/m,其中:
·review-id是Gerrit为评审任务顺序而分配的全局唯一标识。
·nn是review-id的后两位数,位数不足补零。
·m是修订号,一般review-id的首次提交修订号为1,如果该修订被打回,重新提交时修订号会自动增长。
4、钩子脚本
为了保证已经提交审核的修订代码通过审核入库(Submit)后,如果被别的分支拣选(cherry-pick)后再推送至服务器时,不会产生新的重复的评审任务,Gerrit设计了一套特殊的方法,即要求每个提交在提交说明中包含Change-Id键值对作为标签;该标签在首次生成时使用特殊的哈希算法以保障其唯一性。执行拣选操作时,提交说明会被保持,即来自原始提交说明中的Change-Id键值对也会不变,这样,当新提交推送到Gerrit服务器时,Gerrit会发现新的提交包含了已经处理过的Change-Id,就不会再为该修订创建新的评审任务和review-id,而是直接将其提交入库。
为了使得GIT提交中包含唯一的Change-Id,Gerrit提供了一个钩子脚本,将该钩子脚本拷贝到开发者的本地GIT库的钩子脚本目录中,即.git/hooks/commit-msg。这个钩子脚本在用户提交时,自动在提交说明中创建Change-Id键值对。
当Gerrit获取到用户向refs/for/<branch-name>推送的提交中包含“Change-Id: I...”的格式时,如果该Change-Id在之前没有见过,则会创建一个新的评审任务并分配新的review-id,并在Gerrit数据库中保存Change-Id和review-id的关联。
如果用户的提交因为某种原因被打回重做,开发者修改之后重新推送到Gerrit时就要注意在提交说明中使用相同的Change-Id(使用--amend提交即可保持原来的提交说明),以免创建新的评审任务;同时,在推送时,要将当前分支推送到efs/changes/<nn>/<review-id>/<m>中,作为该评审任务的一个新的修订,其中<nn>和<review-id>,及之前提交的评审任务的修订号一致,<m>则要人工选择一个新的修订号。
二、基本操作
Gerrit的操作基本集中在WEB界面,通过WEB服务器实现对整个评审工作流程的控制。其他的部分是GIT操作界面或GIT命令(或者repo——Android开源项目的另一创新——封装,本文暂不涉及)。
由于Gerrit基于SSH协议,后者为GIT提供了远程读写操作的标准服务。另一方面,GIT的提交是以邮件地址为根据的,因此,用户必须在第一次登陆是,必须确认自己的有效电子邮件地址和将要用来CLONE版本库的账号的SSH公钥。
用户yuwf登陆Gerrit服务器,修改全名和有效邮件地址,并粘贴SSH公钥:
http://yuwf:1234@192.168.247.111/gerrit/login/
1、SSH密钥对的生成和使用
本版本库与服务器共用同一账号,并采用标准SSH账号访问,即用户账号可以直接登陆到服务器获得shell。因此远程账户需要将SSH公钥追加到版本库所在服务器的对应账号目录(请修改为对应的用户名)。
1 生成本地账号SSH密钥对
$ cd ~yuwf
$ ssh-keygen
2 远程追加到服务器账号公钥列表
$ ssh-copy-id -i .ssh/id_rsa.pub yuwf@192.168.247.111
3 将SSH公钥(Geriit服务器所在的账号和远程执行GIT操作的账号两者都要)内容粘贴到Gerrit登陆的WEB页面中(上图,或下图):
2、通过SSH协议取得GIT版本库
对于拥有shell登陆权限的用户账号,可以用下面的标准的SSH协议语法访问GIT版本库:
ssh://[<username>@]<server>[:<port>]/path/to/repos/myrepo.git
1 配置账号相关的GIT配置
需要在配置好账号相关的GIT,尤其是账号的email,email必须与Gerrit中有效的email地址一致(请修改有效的用户名和邮件地址)。
$ git config --global user.name "<your name>"
$ git config --global user.email <your email>
2 对于采用Gerrit服务器的版本库,使用下面的命令来取得代码:
$ git clone ssh://192.168.247.111:29418/test
3 取得钩子脚本:
$ cd test
$ scp -P 29418 -p 192.168.247.111:/hooks/commit-msg .git/hooks/
3、修改代码并向服务器提交
用户zrm通过CLONE取得代码后,对其进行修订。
1 修改test.c,添加如下代码并保存:
void test_zrm(void)
{
printk("ZRM: Zhang Rongming, <zhangrongming@xxx.cn>\n");
}
2 提交修订
如果新增了文件,添加新文件:
$ git add .
如果删除或修改了文件,使用命令:
$ git add -u
编写说明并提交:
$ git commit -a -s -m "test_zrm"
其中,“-s”参数对于Gerrit的提交是必须的,它用于在提交说明中加入“Signed-off-by:”标记。“–m”是提交说明,如果没有,则自动打开相关联的编辑器,以让提交者编辑提交说明。
3 查看下提交日志
$ git log --pretty=full -1
可以看到有特殊的标签,即“Signed-off-by:”,它是由钩子脚本自动生成的。
4、向审核服务器提交修订
Gerrit服务器不能直接提交,否则会提示“prohibited by Gerrit”错误。正确的做法是,必须向特殊的引用推送,这样Gerrit自动将新提交转为评审任务。
$ git push origin HEAD:refs/for/master
三、审核流程
1、代码评审
以hz用户登录Gerrit服务器:
http://hz:1234@192.168.247.111/gerrit/login/
打开All->Open标签,可以新提交到Gerrit状态为Open的评审任务,如下图:
可以在URL栏中看到 ,这是一个评审编号为2的任务。
点击Diff All Side-by-Side,可以查看变更集,阅读后,可以决定该提交是否应该被接受。再点击Review,进行代码评审:
作为演示,让此次提交通过代码审核:
选择“+1 Looks good to me, but someone else must approve”,点击“Publish Comments”,通过评审。可以在Message文本框中写入评审意见,特别是在打回重做时,需要填写意见,让提交者知道修订的问题所在。
hz作出评审决定后,提交者zrm会收到一封电子邮件,通知其修订的评审结果。
2、评审任务没有通过测试
以yuwf用户登录Gerrit服务器,打开All->Open标签,如图: