Pro Git
professional version control
To help translate the book, please fork the book at GitHub and push your contributions.
权限管理器 Gitosis
把所有用户的公钥保存在 authorized_keys
文件的做法只能暂时奏效。当用户数量到了几百人的时候,它会变成一种痛苦。每一次都必须进入服务器的 shell,而且缺少对连接的限制——文件里的每个人都对所有项目拥有读写权限。
现在,是时候向广泛使用的软件 Gitosis 求救了。Gitosis 简单的说就是一套用来管理 authorized_keys
文件和实现简单连接限制的脚本。最有意思的是,该软件用来添加用户和设定权限的界面不是网页,而是一个特殊的 Git 仓库。你只需要设定好某个项目;然后推送,Gitosis 就会随之改变服务器设定,酷吧?
Gitosis 的安装算不上傻瓜化,不过也不算太难。用 Linux 服务器架设起来最简单——以下例子中的服务器使用 Ubuntu 8.10 系统。
Gitosis 需要使用部分 Python 工具,所以首先要安装 Python 的 setuptools 包,在 Ubuntu 中名为 python-setuptools:
$ apt-get install python-setuptools
接下来,从项目主页克隆和安装 Gitosis:
$ git clone git://eagain.net/gitosis.git
$ cd gitosis
$ sudo python setup.py install
这会安装几个 Gitosis 用的可执行文件。现在,Gitosis 想把它的仓库放在 /home/git
,倒也可以。不过我们的仓库已经建立在 /opt/git
了,这时可以创建一个文件连接,而不用从头开始重新配置:
$ ln -s /opt/git /home/git/repositories
Gitosis 将为我们管理公钥,所以当前的文件需要删除,以后再重新添加公钥,并且让 Gitosis 自动控制 authorized_keys
文件。现在,把 authorized_keys
文件移走:
$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak
然后恢复 ‘git’ 用户的 shell,假设之前把它改成了 git-shell
命令。其他人仍然不能通过它来登录系统,不过这次有 Gitosis 帮我们实现。所以现在把 /etc/passwd
文件的这一行
git:x:1000:1000::/home/git:/usr/bin/git-shell
恢复成:
git:x:1000:1000::/home/git:/bin/sh
现在就可以初始化 Gitosis 了。需要通过自己的公钥来运行 gitosis-init
。如果公钥不在服务器上,则必须复制一份:
$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub
Initialized empty Git repository in /opt/git/gitosis-admin.git/
Reinitialized existing Git repository in /opt/git/gitosis-admin.git/
这样该公钥的拥有者就能修改包含着 Gitosis 设置的那个 Git 仓库了。然后手动将这个新的控制仓库中的 post-update
脚本加上执行权限。
$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update
万事俱备了。如果设定过程没出什么差错,现在可以试一下用初始化 Gitosis 公钥的拥有者身份 SSH 进服务器。看到的结果应该和下面类似:
$ ssh git@gitserver
PTY allocation request failed on channel 0
fatal: unrecognized command 'gitosis-serve schacon@quaternion'
Connection to gitserver closed.
说明 Gitosis 认出了该用户的身份,但由于没有运行任何 Git 命令所以它切断了连接。所以,现在运行一个确切的 Git 命令——克隆 Gitosis 的控制仓库:
# 在自己的电脑上
$ git clone git@gitserver:gitosis-admin.git
得到一个名为 gitosis-admin
的目录,主要由两部分组成:
$ cd gitosis-admin
$ find .
./gitosis.conf
./keydir
./keydir/scott.pub
gitosis.conf
文件是用来设置用户、仓库和权限的控制文件。keydir
目录则是保存所有具有访问权限用户公钥的地方——每人一个。你 keydir
中的文件名(前例中的 scott.pub
)应该有所不同—— Gitosis 从使用 gitosis-init
脚本导入的公钥尾部的描述中获取该名。
看一下 gitosis.conf
的内容,它应该只包含与刚刚克隆的 gitosis-admin
相关的信息:
$ cat gitosis.conf
[gitosis]
[group gitosis-admin]
writable = gitosis-admin
members = scott
它显示用户 scott
——初始化 Gitosis 公钥的拥有者——是唯一能访问 gitosis-admin
项目的人。
现在我们添加一个新的项目。我们将添加一个名为 mobile
的新节段,在这里罗列手机开发团队的开发者以及他们需要访问权限的项目。由于 ‘scott’ 是系统中的唯一用户,我们把它加成唯一的用户,从创建一个叫做 iphone_project
的新项目开始:
[group mobile]
writable = iphone_project
members = scott
一旦修改了 gitosis-admin
项目的内容,只有提交并推送至服务器才能使之生效:
$ git commit -am 'add iphone_project and mobile group'
[master]: created 8962da8: "changed name"
1 files changed, 4 insertions(+), 0 deletions(-)
$ git push
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 272 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitserver:/opt/git/gitosis-admin.git
fb27aec..8962da8 master -> master
第一次向新工程 iphone_project
的推送需要在本地的版本中把服务器添加为一个 remote 然后推送。从此手动为新项目在服务器上创建纯仓库的麻烦就是历史了—— Gitosis 会在第一次遇到推送的时候自动创建它们:
$ git remote add origin git@gitserver:iphone_project.git
$ git push origin master
Initialized empty Git repository in /opt/git/iphone_project.git/
Counting objects: 3, done.
Writing objects: 100% (3/3), 230 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@gitserver:iphone_project.git
* [new branch] master -> master
注意到路径被忽略了(加上它反而没用),只有一个冒号加项目的名字—— Gitosis 会为你找到项目的位置。
要和朋友们共同在一个项目上共同工作,就得重新添加他们的公钥。不过这次不用在服务器上一个一个手动添加到 ~/.ssh/authorized_keys
文件末端,而是在 keydir
目录为每一个公钥添加一个文件。文件的命名将决定在 gitosis.conf
文件中用户的称呼。现在我们为 John,Josie 和 Jessica 添加公钥:
$ cp /tmp/id_rsa.john.pub keydir/john.pub
$ cp /tmp/id_rsa.josie.pub keydir/josie.pub
$ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub
然后把他们都加进 ‘mobile’ 团队,让他们对 iphone_project
具有读写权限:
[group mobile]
writable = iphone_project
members = scott john josie jessica
如果你提交并推送这个修改,四个用户将同时具有该项目的读写权限。
Gitosis 也具有简单的访问控制功能。如果想让 John 只有读权限,可以这样做:
[group mobile]
writable = iphone_project
members = scott josie jessica
[group mobile_ro]
readonly = iphone_project
members = john
现在 John 可以克隆和获取更新,但 Gitosis 不会允许他向项目推送任何内容。这样的组可以有尽可能有随意多个,每一个包含不同的用户和项目。甚至可以指定某个组为成员,来继承它所有的成员。
如果出现了什么问题,把 loglevel=DEBUG
加入到 [gitosis]
部分或许有帮助(译注:把日志设置到调试级别,记录更详细的信息)。如果你一不小心搞错了配置,失去了推送权限,可以手动修改服务器上的 /home/git/.gitosis
文件—— Gitosis 从该文件读取信息。一次推送会把 gitosis.conf
保存在服务器上。如果你手动编辑该文件,它将在你下次向 gitosis-admin
推送之前它将保持原样。