Git是目前最流行的分布式版本控制工具,而大多数的git用户都是使用ssh协议。gitolite是加在git上的权限控制工具,可以将控制粒度缩小到分支(brach)范围内。也许很多人并没有意识到:gitolite实际上是通过对ssh协议的控制来实现细化的权限设置的。
先来看看什么叫做ssh? ssh的全称为Secure Shell,是一种加密的网络协议。通常被用来登录另一台电脑,并远程地运行一些命令。它的加密方式是通过一个公钥/私钥对,这个密钥对可以由ssh-keygen程序生成。其中,公钥被保存在远端电脑的~/.ssh/authorized_keys文件中,私钥通常保存在本地的%home%/.ssh目录中。这样,当通过ssh协议建立本地到远端的连接时,就不用再输入用户名和密码,而是通过更安全的检测密钥对的方式来验证登陆用户的身份。
现在来看一个authorized_keys文件的片段:
这个文件片段里包含了两个ssh公钥,每个都以ssh-rsa开头。这两个公钥对应的用户都可以用自己的私钥从远端访问本台机器。这个authorized_keys文件保存哪个本地用户的%home%/.ssh目录中,远端访问用户就是以哪个本地用户的身份在本台机器上运行命令。
Gitolite要做到权限控制,一个首要条件是能分辨每个远端访问用户的身份,如果他们都使用同一个本地用户身份,该如何分辨呢?奥秘就在authorized_keys文件中。当使用gitolite时,要增加用户,只需要添加该用户的公钥到gitolite-admin.git的keydir目录中,由gitolite自动将对应得公钥内容添加到authorized_keys文件中,用户不应该自己手动添加,因为gitolite在添加时会在ssh-rsa前面加上command="..."。例如:
command="[path]/gl-auth-command sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t...
command="[path]/gl-auth-command usertwo",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXtCT...
在这两行中,上面一个远端用户会通过命令行告诉gitolite自己是sitaram,而下面一个是usertwo。
那么分支(branch)级别的权限控制又是怎样实现的呢?秘密就是update hook。Git允许用户设定一系列的hook,这些hook使用户能在某些事件(event)发生前获得控制权。例如update hook就是允许用户设定在某个分支(branch)或标签(tag)update操作前触发的命令。当gitolite创建一个新的版本库(repository)时,它会自动的设定一个特别的update hook,这个hook会参照config文件里的设定,决定允许还是拒绝客户断的update请求。因此,gitolite控制下创建新版本库的工作不要自己手动去做,而是通过配置文件,告诉gitolite去自动创建。这个配置文件就在gitolite-admin.git的conf目录中,文件名为gitolite.conf。其初始内容如下:
repo gitolite-admin
RW+ = local
repo testing
RW+ = @all
对应两个版本库:gitolite-admin和testing。现在,我要增加一个名为acq的版本库,只要加上下面两行代码即可:
repo acq
RW+ = @all
@kdis = user1 user2
repo foo
RW+ = sitaram dilbert
RW = alice ashok
R = wally
其中,用户sitaram和dilbert有完全地控制权限,alice和ashok拥有除了"rewind"之外的其他权限,rewind是指强制push a branch 或删除branch或更新(update)tag。用户wally只有读权限。
用户dilbert对名称以pu开头的任何branch都有完全地控制权限,包括pu1, pupu等。
用户dilbert对master分支有完全的控制权限。
用户ashok可以push任何以v开头再加一位数字的tag,例如:v1, v1.0,v2.0rc1,但是不包括v-1和ver1。
RW refs/tags/v0 = ashok
- refs/tags/v0 = @staff
RW refs/tags = @staff
用户ashok可以push v0 tag,而staff组里的成员可以push所有的tag,除了v0之外。