可是若是须要和他人分享版本库、协做开发,就须要可以经过特定的网络协议操做 Git 库。 html
Git 支持的协议很丰富,架设服务器的选择也不少,不一样的方案有着各自的优缺点。 git
HTTP GIT-DAEMON SSH GITOSIS, GITOLITE 服务架设难易度 简单 中等 简单 复杂 匿名读取 支持 支持 否* 否* 身份认证 支持 否 支持 支持 版本库写操做 支持 否 支持 支持 企业级受权支持 否 否 否 支持 是否支持远程建库 否 否 否 支持
注: 程序员
SSH 协议用于为 Git 提供远程读写操做,是远程写操做的标准服务,在智能HTTP协议出现以前,甚至是写操做的惟一标准服务。 github
对于拥有 SHELL 权限的 SSH 登陆账号,能够直接用下面的 git 命令访问,例如: web
$ git clone <username>@<server>:/path/to/repo.git
说明: 正则表达式
SSH 协议来实现 Git 服务,有以下方式: 算法
其一是用标准的 ssh 账号访问版本库。即用户账号能够直接登陆到服务器,得到 shell。 shell
另外的方式是,全部用户都使用同一个专用的 SSH 账号访问版本库。各个用户经过公钥认证的方式用此专用 SSH 账号访问版本库。而用户在链接时使用的不一样的公钥能够用于区分不一样的用户身份。 数组
Gitosis 和 Gitolite 就是实现该方式的两个服务器软件。 安全
标准SSH账号和专用SSH账号的区别在于:
标准SSH GITOSIS/GITOLITE 账号 每一个用户一个账号 全部用户共用同一个账号 认证方式 口令或公钥认证 公钥认证 用户是否能直接登陆 shell 是 否 安全性 差 好 管理员是否须要 shell 是 否 版本库路径 相对路径或绝对路径 相对路径 受权方式 操做系统中用户组和目录权限 经过配置文件受权 对分支进行写受权 否 Gitolite 对路径进行写受权 否 Gitolite 架设难易度 简单 复杂
实际上,标准SSH,也能够用公钥认证的方式实现全部用户共用同一个账号。不过这相似于把一个公共账号的登陆口令同时告诉给多我的。
在服务器端(server)建立一个公共账号,例如 anonymous 。
管理员收集须要访问 git 服务的用户公钥。如: user1.pub, user2.pub 。
使用 ssh-copy-id 命令远程将各个 git 用户的公钥加入服务器(server)的公钥认证列表中。
$ ssh-copy-id -i user1.pub anonymous@server $ ssh-copy-id -i user2.pub anonymous@server
若是直接在服务器上操做,则直接将文件追加到 authorized_keys 文件中。
$ cat /path/to/user1.pub >> ~anonymous/.ssh/authorized_keys $ cat /path/to/user2.pub >> ~anonymous/.ssh/authorized_keys
在服务器端的 anonymous 用户主目录下创建 git 库,就能够实现多个用户利用同一个系统账号(git) 访问 Git 服务了。
这样作除了免除了逐一设置账号,以及用户无需口令认证以外,标准SSH部署 Git 服务的缺点一个也很多,并且由于用户之间没法区分,更没法进行针对用户受权。
下面重点介绍一下 SSH 公钥认证,由于它们是后面介绍的 Gitosis 和 Gitolite 服务器软件的基础。
关于公钥认证的原理,维基百科上的这个条目是一个很好的起点: http://en.wikipedia.org/wiki/Public-key_cryptography 。
若是你的主目录下不存在 .ssh 目录,说明你的 SSH 公钥/私钥对还没有建立。能够用这个命令建立:
$ ssh-keygen
该命令会在用户主目录下建立 .ssh 目录,并在其中建立两个文件:
id_rsa
私钥文件。是基于 RSA 算法建立。该私钥文件要妥善保管,不要泄漏。
id_rsa.pub
公钥文件。和 id_rsa 文件是一对儿,该文件做为公钥文件,能够公开。
建立了本身的公钥/私钥对后,就可使用下面的命令,实现无口令登陆远程服务器,即用公钥认证取代口令认证。
$ ssh-copy-id -i .ssh/id_rsa.pub user@server
说明:
检查公钥认证是否生效,运行SSH到远程主机,正常的话应该直接登陆成功。若是要求输入口令则代表公钥认证配置存在问题。若是SSH服务存在问题,能够经过查看服务器端的 /var/log/auth.log 进行诊断。
在实际应用中,有时须要使用多套公钥/私钥对,例如:
如何建立指定名称的公钥/私钥对呢?仍是用 ssh-keygen 命令,以下:
$ ssh-keygen -f ~/.ssh/<filename>
注:
将新生成的公钥添加到远程主机的 .ssh/authorized_keys 文件中,创建新的公钥认证。例如:
$ ssh-copy-id -i .ssh/<filename>.pub user@server
这样,就有两个公钥用于登陆主机 server,那么当执行下面的 ssh 登陆指令,用到的是那个公钥呢?
$ ssh user@server
固然是缺省公钥 ~/.ssh/id_rsa.pub 。那么如何用新建的公钥链接 server 呢?
SSH 的客户端配置文件 ~/.ssh/config 能够经过建立主机别名,在链接主机时,使用特定的公钥。例如 ~/.ssh/config 文件中的下列配置:
host bj user git hostname bj.ossxp.com port 22 identityfile ~/.ssh/jiangxin
当执行
$ ssh bj
或者执行
$ git clone bj:path/to/repo.git
含义为:
Gitolite 是一款 Perl 语言开发的 Git 服务管理工具,经过公钥对用户进行认证,并可以经过配置文件对写操做进行基于分支和路径的的精细受权。Gitolite 采用的是 SSH 协议而且使用 SSH 公钥认证,所以须要您对 SSH 很是熟悉,不管是管理员仍是普通用户。所以在开始以前,请确认已经通读过以前的“SSH 协议”一章。
Gitolite 的官方网址是: http://github.com/sitaramc/gitolite 。从提交日志里能够看出做者是 Sitaram Chamarty,最先的提交开始于 2009年8月。做者是受到了 Gitosis 的启发,开发了这款功能更为强大和易于安装的软件。Gitolite 的命名,做者的原意是 Gitosis 和 lite 的组合,不过由于 Gitolite 的功能愈来愈强大,已经超越了 Gitosis,所以做者笑称 Gitolite 能够看做是 Github-lite —— 轻量级的 Github。
我是在2010年8月才发现 Gitolite 这个项目,并尝试将公司基于 Gitosis 的管理系统迁移至 Gitolite。在迁移和使用过程当中,增长和改进了一些实现,如:通配符版本库的建立过程,对建立者的受权,版本库名称映射等。本文关于 Gitolite 的介绍也是基于我改进的 Gitosis 的版本。
原做者的版本库地址:
笔者改进后的 Gitolite 分支:
Gitolite 的实现机制归纳以下:
Gitolite 安装在服务器( server ) 某个账号之下,例如 git 账号。
管理员经过 git 命令检出名为 gitolite-admin 的版本库。
$ git clone git@server:gitolite-admin.git
管理员将 git 用户的公钥保存在 gitolite-admin 库的 keydir 目录下,并编辑 conf/gitolite.conf 文件为用户受权。
当管理员对 gitolite-admin 库的修改提交并 PUSH 到服务器以后,服务器上 gitolite-admin 版本库的钩子脚本将执行相应的设置工做。
新用户公钥自动追加到服务器端安装账号的 .ssh/authorized_keys 中,并设置该用户的 shell 为 gitolite 的一条命令 gl-auth-command 。
command="/home/git/.gitolite/src/gl-auth-command jiangxin",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa <公钥内容来自于 jiangxin.pub ...>
更新服务器端的受权文件 ~/.gitolite/conf/gitolite.conf 。
编译受权文件 ~/.gitolite/conf/gitolite.conf-compiled.pm 。
用户能够用 git 命令访问受权的版本库。
当用户以 git 用户登陆 ssh 服务时,由于公钥认证的相关设置,再也不直接进入 shell 环境,而是打印服务器端 git 库受权信息后立刻退出。
即用户不会经过 git 用户进入服务器的 shell,也就不会对系统的安全形成威胁。
当管理员受权,用户能够远程在服务器上建立新版本库。
下面介绍 Gitolite 的部署和使用。在下面的示例中,约定:服务器的名称为 server ,Gitolite 的安装账号为 git ,管理员的 ID 为 admin 。
Gitolite 要求 git 的版本必须是 1.6.2 或以上的版本,而且服务器要提供 SSH 服务。下面是 Gitolite 的安装过程。
安装 Gitolite,首先要在服务器端建立专用账号,全部用户都经过此账号访问 Git 库。通常为方便易记,选择 git 做为专用账号名称。
$ sudo adduser --system --shell /bin/bash --group git
建立用户 git,并设置用户的 shell 为可登陆的 shell,如 /bin/bash,同时添加同名的用户组。
有的系统,只容许特定的用户组(如 ssh 用户组)的用户才能够经过 SSH 协议登陆,这就须要将新建的 git 用户添加到 ssh 用户组中。
$ sudo adduser git ssh
为 git 用户设置口令。当整个 git 服务配置完成,运行正常后,建议取消 git 的口令,只容许公钥认证。
$ sudo passwd git
管理员在客户端使用下面的命令,创建无口令登陆:
$ ssh-copy-id git@server
至此,咱们已经完成了安装 git 服务的准备工做,能够开始安装 Gitolite 服务软件了。
本节的名字称为安装/升级,是由于 Gitolite 的安装和升级能够采用下列一样的步骤。
Gitolite 安装能够在客户端执行,而不须要在服务器端操做,很是方便。安装 Gitolite 的前提是:
安装和升级均可以按照下面的步骤进行:
使用 git 下载 Gitolite 的源代码。
$ git clone git://github.com/ossxp-com/gitolite.git
进入 gitolite/src 目录,执行安装。
$ cd gitolite/src $ ./gl-easy-install git server admin
命令 gl-easy-install 的第一个参数 git 是服务器上建立的专用账号ID,第二个参数 server 是服务器IP或者域名,第三个参数 admin 是管理员ID。
首先显示版本信息。
------------------------------------------------------------------------ you are upgrading (or installing first-time) to v1.5.4-22-g4024621 Note: getting '(unknown)' for the 'from' version should only happen once. Getting '(unknown)' for the 'to' version means you are probably installing from a tar file dump, not a real clone. This is not an error but it's nice to have those version numbers in case you need support. Try and install from a clone
自动建立名为 admin 的私钥/公钥对。
gl-easy-install 命令行的最后一个参数即用于设定管理员ID,这里设置为 admin 。
------------------------------------------------------------------------ the next command will create a new keypair for your gitolite access The pubkey will be /home/jiangxin/.ssh/admin.pub. You will have to choose a passphrase or hit enter for none. I recommend not having a passphrase for now, *especially* if you do not have a passphrase for the key which you are already using to get server access! Add one using 'ssh-keygen -p' after all the setup is done and you've successfully cloned and pushed the gitolite-admin repo. After that, install 'keychain' or something similar, and add the following command to your bashrc (since this is a non-default key) ssh-add $HOME/.ssh/admin This makes using passphrases very convenient.
若是公钥已经存在,会弹出警告。
------------------------------------------------------------------------ Hmmm... pubkey /home/jiangxin/.ssh/admin.pub exists; should I just (re-)use it? IMPORTANT: once the install completes, *this* key can no longer be used to get a command line on the server -- it will be used by gitolite, for git access only. If that is a problem, please ABORT now. doc/6-ssh-troubleshooting.mkd will explain what is happening here, if you need more info.
自动修改客户端的 .ssh/config 文件,增长别名主机。
即当访问主机 gitolite 时,会自动用名为 admin.pub 的公钥,以 git 用户身份,链接服务器
------------------------------------------------------------------------ creating settings for your gitolite access in /home/jiangxin/.ssh/config; these are the lines that will be appended to your ~/.ssh/config: host gitolite user git hostname server port 22 identityfile ~/.ssh/admin
上传脚本文件到服务器,完成服务器端软件的安装。
gl-dont-panic 100% 3106 3.0KB/s 00:00 gl-conf-convert 100% 2325 2.3KB/s 00:00 gl-setup-authkeys 100% 1572 1.5KB/s 00:00 ... gitolite-hooked 100% 0 0.0KB/s 00:00 update 100% 4922 4.8KB/s 00:00 ------------------------------------------------------------------------ the gitolite rc file needs to be edited by hand. The defaults are sensible, so if you wish, you can just exit the editor. Otherwise, make any changes you wish and save it. Read the comments to understand what is what -- the rc file's documentation is inline. Please remember this file will actually be copied to the server, and that all the paths etc. represent paths on the server!
自动打开编辑器(vi),编辑 .gitolite.rc 文件,编辑结束,上传到服务器。
如下为缺省配置,通常无须改变:
$REPO_BASE="repositories";
用于设置 Git 服务器的根目录,缺省是 Git 用户主目录下的 repositories 目录,可使用绝对路径。全部 Git 库都将部署在该目录下。
$REPO_UMASK = 0007; # gets you 'rwxrwx---'
版本库建立使用的掩码。即新创建版本库的权限为 'rwxrwx---'。
$GL_BIG_CONFIG = 0;
若是受权文件很是复杂,更改此项配置为1,以避免产生庞大的受权编译文件。
$GL_WILDREPOS = 1;
缺省支持通配符版本库受权。
该配置文件为 perl 语法,注意保持文件格式和语法。退出 vi 编辑器,输入 ":q" (不带引号)。
至此完成安装。
在安装过程当中,gitolite 建立了名为 admin 的公钥/私钥对,以名为 admin.pub 的公钥链接服务器,由 gitolite 提供服务。可是若是直接链接服务器,使用的是缺省的公钥,会直接进入 shell。
那么如何可以根据须要选择不一样的公钥来链接 git 服务器呢?
别忘了咱们在前面介绍过的 SSH 主机别名。实际上刚刚在安装 gitolite 的时候,就已经自动为咱们建立了一个主机别名。 打开 ~/.ssh/config 文件,能够看到相似内容,若是对主机别名不满意,能够修改。
host gitolite user git hostname server port 22 identityfile ~/.ssh/admin
即:
像下面这样输入 SSH 命令,会直接进入 shell,由于使用的是缺省的公钥。
$ ssh git@server
像下面这样输入 SSH 命令,则不会进入 shell。由于使用名为 admin.pub 的公钥,会显示 git 受权信息并立刻退出。
$ ssh gitolite
上面介绍的是在客户端远程安装 Gitolite,是最经常使用和推荐的方法。固然还能够直接在服务器上安装。
$ sudo adduser --system --shell /bin/bash --group git
管理员在客户端执行下面的命令:
$ scp ~/.ssh/id_rsa.pub server:/tmp/admin.pub
推荐采用源码方式安装,由于若是以平台自带软件包模式安装 Gitolite,其中不包含咱们对 Gitolite 的改进。
从源码安装。
使用 git 下载 Gitolite 的源代码。
$ git clone git://github.com/ossxp-com/gitolite.git建立目录。
$ sudo mkdir -p /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks进入 gitolite/src 目录,执行安装。
$ cd gitolite/src $ sudo ./gl-system-install /usr/local/bin /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks采用平台自带的软件包安装。
例如在 Debian/Ubuntu 平台,执行下面命令:
$ sudo aptitude install gitoliteRedhat 则使用 yum 命令安装。
例如服务器端的专用账号为 git。
$ sudo su - git $ gl-setup /tmp/admin.pub
$ git clone git@server:gitolite-admin
升级 Gitolite:
当 gitolite 安装完成后,在服务器端自动建立了一个用于 gitolite 自身管理的 git 库: gitolite-admin.git 。
克隆 gitolite-admin.git 库。别忘了使用SSH主机别名:
$ git clone gitolite:gitolite-admin.git $ git clone gitolite:gitolite-admin.git Initialized empty Git repository in /data/tmp/gitolite-admin/.git/ remote: Counting objects: 6, done. remote: Compressing objects: 100% (4/4), done. remote: Total 6 (delta 0), reused 0 (delta 0) Receiving objects: 100% (6/6), done. $ cd gitolite-admin/ $ ls -F conf/ keydir/ $ ls conf gitolite.conf $ ls keydir/ admin.pub
咱们能够看出 gitolite-admin 目录下有两个目录 conf/ 和 keydir/ 。
keydir/admin.pub 文件
目录 keydir 下初始时只有一个用户公钥,即 amdin 用户的公钥。
conf/gitolite.conf 文件
该文件为受权文件。初始内容为:
#gitolite conf # please see conf/example.conf for details on syntax and features repo gitolite-admin RW+ = admin repo testing RW+ = @all
缺省受权文件中只设置了两个版本库的受权:
gitolite-admin
即本版本库(gitolite管理版本库)只有 admin 用户有读写和强制更新的权限。
testing
缺省设置的测试版本库,设置为任何人均可以读写以及强制更新。
增长新用户,就是容许新用户可以经过其公钥访问 Git 服务。只要将新用户的公钥添加到 gitolite-admin 版本库的 keydir 目录下,即完成新用户的添加。
管理员从用户获取公钥,并将公钥按照 username.pub 格式进行重命名。
用户能够经过邮件或者其余方式将公钥传递给管理员,切记不要将私钥误传给管理员。若是发生私钥泄漏,立刻从新生成新的公钥/私钥对,并将新的公钥传递给管理员,并申请将旧的公钥做废。
用户从不一样的客户端主机访问有着不一样的公钥,若是但愿使用同一个用户名进行受权,能够按照 username@host.pub方式命名公钥文件,和名为 username@pub 的公钥指向同一个用户 username 。
Gitolite 也支持邮件地址格式的公钥,即形如 username@gmail.com.pub 的公钥。Gitolite 可以很智能的区分是以邮件地址命名的公钥仍是相同用户在不一样主机上的公钥。若是是邮件地址命名的公钥,将以整个邮件地址做为用户名。
管理员进入 gitolite-admin 本地克隆版本库中,复制新用户公钥到 keydir 目录。
$ cp /path/to/dev1.pub keydir/ $ cp /path/to/dev2.pub keydir/ $ cp /path/to/jiangxin.pub keydir/
执行 git add 命令,将公钥添加入版本库。
$ git add keydir $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: keydir/dev1.pub # new file: keydir/dev2.pub # new file: keydir/jiangxin.pub #
执行 git commit,完成提交。
$ git commit -m "add user: jiangxin, dev1, dev2" [master bd81884] add user: jiangxin, dev1, dev2 3 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 keydir/dev1.pub create mode 100644 keydir/dev2.pub create mode 100644 keydir/jiangxin.pub
执行 git push,同步到服务器,才真正完成新用户的添加。
$ git push Counting objects: 8, done. Delta compression using up to 2 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 1.38 KiB, done. Total 6 (delta 0), reused 0 (delta 0) remote: Already on 'master' remote: remote: ***** WARNING ***** remote: the following users (pubkey files in parens) do not appear in the config file: remote: dev1(dev1.pub),dev2(dev2.pub),jiangxin(jiangxin.pub)
若是咱们这时查看服务器端 ~git/.ssh/authorized_keys 文件,会发现新增的用户公钥也附加其中:
# gitolite start command="/home/git/.gitolite/src/gl-auth-command admin",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty <用户admin的公钥...> command="/home/git/.gitolite/src/gl-auth-command dev1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty <用户dev1的公钥...> command="/home/git/.gitolite/src/gl-auth-command dev2",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty <用户dev2的公钥...> command="/home/git/.gitolite/src/gl-auth-command jiangxin",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty <用户jiangxin的公钥...> # gitolite end
在以前执行 git push 后的输出中,以 remote 标识的输出是服务器端执行 post-update 钩子脚本的输出。其中的警告是说新添加的三个用户在受权文件中没有被引用。接下来咱们便看看如何修改受权文件,以及如何为用户添加受权。
新用户添加完毕,可能须要从新进行受权。更改受权的方法也很是简单,即修改 conf/gitolite.conf 配置文件,提交并 push。
管理员进入 gitolite-admin 本地克隆版本库中,编辑 conf/gitolite.conf 。
$ vi conf/gitolite.conf
受权指令比较复杂,咱们先经过创建新用户组尝试一下更改受权文件。
考虑到以前咱们增长了三个用户公钥以后,服务器端发出了用户还没有在受权文件中出现的警告。咱们就在这个示例中解决这个问题。
例如咱们在其中加入用户组 @team1,将新添加的用户 jiangxin, dev1, dev2 都归属到这个组中。
咱们只须要在 conf/gitolite.conf 文件的文件头加入以下指令。用户之间用空格分隔。
@team1 = dev1 dev2 jiangxin
编辑完毕退出。咱们能够用 git diff 命令查看改动:
咱们还修改了版本库 testing 的受权,将 @all 用户组改成咱们新创建的 @team1 用户组。
$ git diff diff --git a/conf/gitolite.conf b/conf/gitolite.conf index 6c5fdf8..f983a84 100644 --- a/conf/gitolite.conf +++ b/conf/gitolite.conf @@ -1,10 +1,12 @@ #gitolite conf # please see conf/example.conf for details on syntax and features +@team1 = dev1 dev2 jiangxin + repo gitolite-admin RW+ = admin repo testing - RW+ = @all + RW+ = @team1
编辑结束,提交改动。
$ git add conf/gitolite.conf $ git commit -q -m "new team @team1 auth for repo testing."
执行 git push ,同步到服务器,才真正完成受权文件的编辑。
咱们能够注意到,PUSH 后的输出中没有了警告。
$ git push Counting objects: 7, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 398 bytes, done. Total 4 (delta 1), reused 0 (delta 0) remote: Already on 'master' To gitadmin.bj:gitolite-admin.git bd81884..79b29e4 master -> master
下面咱们看一个不那么简单的受权文件:
1 @admin = jiangxin wangsheng 2 3 repo gitolite-admin 4 RW+ = jiangxin 5 6 repo ossxp/.+ 7 C = @admin 8 RW = @all 9 10 repo testing 11 RW+ = @admin 12 RW master = junio 13 RW+ pu = junio 14 RW cogito$ = pasky 15 RW bw/ = linus 16 - = somebody 17 RW tmp/ = @all 18 RW refs/tags/v[0-9] = junio
在上面的示例中,咱们演示了不少受权指令。
第1行,定义了用户组 @admin ,包含两个用户 jiangxin 和 wangsheng。
第3-4行,定义了版本库 gitolite-admin。并指定只有用户 jiangxin 才可以访问,并拥有读(R)写(W)和强制更新(+)的权限。
第6行,经过正则表达式定义了一组版本库,即在 ossxp/ 目录下的全部版本库。
第7行,用户组 @admin 中的用户,能够在 ossxp/ 目录下建立版本库。
建立版本库的用户,具备对版本库操做的全部权限。
第8行,全部用户均可以读写 ossxp 目录下的版本库,但不能强制更新。
第9行开始,定义的 testing 版本库受权使用了引用受权语法。
第11行,用户组 @admin 对全部的分支和里程碑拥有读写、重置、添加和删除的受权。
第12行,用户 junio 能够读写 master 分支。(还包括名字以 master 开头的其余分支,若是有的话)。
第13行,用户 junio 能够读写、强制更新、建立以及删除 pu 开头的分支。
第14行,用户 pasky 能够读写 cogito 分支。 (仅此分支,精确匹配)。
在 conf/gitolite.conf 受权文件中,能够定义用户组或者版本库组。组名称以 @ 字符开头,能够包含一个或多个成员。成员之间用空格分开。
例如定义管理员组:
@admin = jiangxin wangsheng
组能够嵌套:
@staff = @admin @engineers tester1
除了做为用户组外,一样语法也适用于版本库组。
版本库组和用户组的定义没有任何区别,只是在版本库受权指令中处于不一样的位置。即位于受权指令中的版本库位置则表明版本库组,位于受权指令中的用户位置则表明用户组。
一个版本库能够包含多条受权指令,这些受权指令组成了一个版本库的权限控制列表(ACL)。
例如:
repo testing RW+ = jiangxin @admin RW = @dev @test R = @all
每个版本库受权都以一条 repo 指令开始。
指令 repo 后面是版本库列表,版本之间用空格分开,还能够包括版本库组。
注意:版本库名称不要添加 .git 后缀。在版本库建立过程当中会自动添加 .git 后缀。
repo sandbox/test1 sandbox/test2 @test_repos
repo 指令后面的版本库也能够用正则表达式定义的 通配符版本库 。
正则表达式匹配时,会自动在 通配符版本库 的先后加上前缀 ^ 和后缀 $ 。这一点和后面将介绍的正则引用(refex)大不同。
repo ossxp/.+
不过有时候使用了过于简单的正则表达式如: "myrepo." ,有可能产生歧义,让 Gitolite 误认为是普通版本库名称,在服务器端自动建立名为 myrepo..git 的版本库。解决歧义的一个办法是:在正则表达式的前面插入 ^ 符号,或者在表达式后面添加 $ 符号,形如:"^myrepo.$"。
在 repo 指令以后,是缩进的一条或者多条受权指令。受权指令的语法:
<权限> [零个或多个正则表达式匹配的引用] = <user> [<user> ...]
每条指令必须指定一个权限。权限能够用下面的任意一个权限关键字:
C, R, RW, RW+, RWC, RW+C, RWD, RW+D, RWCD, RW+CD 。
权限后面包含一个可选的 refex(正则引用)列表。
正则表达式格式的引用,简称正则引用(refex),对 Git 版本库的引用(分支,里程碑等)进行匹配。
若是在受权指令中省略正则引用,意味着对所有的 Git 引用(分支,里程碑等)都有效。
正则引用若是不以 refs/ 开头,会自动添加 refs/heads/ 做为前缀。
正则引用若是不以 $ 结尾,意味着后面能够匹配任意字符,至关于添加 .*$ 做为后缀。
权限后面也能够包含一个以 NAME/ 开头的路径列表,进行基于路径的受权。
受权指令以等号(=)为标记分为先后两段,等号后面的是用户列表。
用户之间用空格分隔,而且可使用用户组。
不一样的受权关键字有不一样的含义,有的受权关键字只用在 特定 的场合。
C
C 表明建立。仅在 通配符版本库 受权时可使用。用于指定谁能够建立和通配符匹配的版本库。
R, RW, 和 RW+
R 为只读。RW 为读写权限。RW+ 含义为除了具备读写外,还能够对 rewind 的提交强制 PUSH。
RWC, RW+C
只有当受权指令中定义了正则引用(正则表达式定义的分支、里程碑等),才可使用该受权指令。其中 C 的含义是容许建立和正则引用匹配的引用(分支或里程碑等)。
RWD, RW+D
只有当受权指令中定义了正则引用(正则表达式定义的分支、里程碑等),才可使用该受权指令。其中 D 的含义是容许删除和正则引用匹配的引用(分支或里程碑等)。
RWCD, RW+CD
只有当受权指令中定义了正则引用(正则表达式定义的分支、里程碑等),才可使用该受权指令。其中 C 的含义是容许建立和正则引用匹配的引用(分支或里程碑等),D 的含义是容许删除和正则引用匹配的引用(分支或里程碑等)。
Gitolite 的受权实际分为两个阶段,第一个阶段称为前Git阶段,即在 Git 命令执行前,由 SSH 连接触发的 gl-auth-command 命令执行的受权检查。包括:
版本库的读。
用户必须拥有版本库至少一个分支的下列权限之一: R, RW, 或 RW+ ,则整个版本库包含全部分支对用户都可读。
而版本库分支实际上在这个阶段获取不到,即版本库的读取不能按照分支受权,只能是版本库的总体受权。
版本库的写。
版本库的写受权,则要在两个阶段分别进行检查。第一阶段的检查是看用户是否拥有下列权限之一: RW, RW+ 或者 C受权。
第二个阶段检查分支以及是否拥有强制更新。具体见后面的描述。
版本库的建立。
仅对正则表达式定义的通配符版本库有效。即拥有 C 受权的用户,能够建立和对应正则表达式匹配的版本库。同时该用户也拥有对版本库的读写权限。
对受权的第二个阶段的检查,其实是经过 update 钩子脚本进行的。
Gitolite 的受权很是强大也很是复杂,所以从版本库受权的实际案例来学习很是行之有效。
受权文件以下:
1 @admin = jiangxin 2 @dev = dev1 dev2 badboy jiangxin 3 @test = test1 test2 4 5 repo testing 6 R = @test 7 - = badboy 8 RW = @dev test1 9 RW+ = @admin
说明:
用户 test1 对版本库具备写的权限。
第6行定义了 test1 所属的用户组 @test 具备只读权限。第8行定义了 test1 用户具备读写权限。
Gitolite 的实现是读权限和写权限分别进行判断并汇总(并集),从而 test1 用户具备读写权限。
用户 jiangxin 对版本库具备写的权限,并能强制PUSH。
第9行受权指令中的加号(+)含义是容许强制 PUSH。
禁用指令,让用户 badboy 对版本库只具备读操做的权限。
第7行的指令以减号(-)开始,是一条禁用指令。禁用指令只在受权的第二阶段起做用,即只对写操做起做用,不会对badboy 用户的读权限施加影响。
在第8行的指令中, badboy 所在的 @dev 组拥有读取权限。但禁用规则会对写操做起做用,致使 badboy 只有读操做权限,而没有写操做。
受权文件以下:
1 @administrators = jiangxin admin 2 @dev = dev1 dev2 badboy 3 @test = test1 test2 4 5 repo sandbox/.+$ 6 C = @administrators 7 R = @test 8 - = badboy 9 RW = @dev test1
这个受权文件中的版本库名称中使用了正则表达式,匹配在 sandbox 下的任意版本库。
Tip
正则表达式末尾的 $ 有着特殊的含义,表明匹配字符串的结尾,明确告诉 Gitolite 这个版本库是通配符版本库。
由于加号 + 既能够做为普通字符出如今版本库的命名中,又能够做为正则表达式中特殊含义的字符,若是 Gitolite 将受权文件中的通配符版本库误判为普通版本库,就会自动在服务器端建立该版本库,这是可能管理员不但愿发生的。
在版本库结尾添加一个 $ 字符,就明确表示该版本库为正则表达式定义的通配符版本库。
我修改了 Gitolite 的代码,能正确判断部分正则表达式,可是最好仍是对简单的正则表达式添加 ^ 做为前缀,或者添加 $做为后缀,避免误判。
正则表达式定义的通配符版本库不会自动建立。须要管理员手动建立。
Gitolite 原来对通配符版本库的实现是克隆即建立,可是这样很容易由于录入错误致使错误的版本库意外被建立。群英汇改进的 Gitolite 须要经过 PUSH 建立版本库。
以 admin 用户的身份建立版本库 sandbox/repos1.git 。
$ git push git-admin-server:sandbox/repos1.git master
建立完毕后,咱们对各个用户的权限进行测试,会发现:
用户 admin 对版本库具备写的权限。
这并非由于第6行的受权指令为 @administrators 授予了 C 的权限。而是由于该版本库是由 admin 用户建立的,建立者具备对版本库彻底的读写权限。
服务器端该版本库目录自动生成的 gl-creator 文件记录了建立者 ID 为 admin 。
用户 jiangxin 对版本库没有读写权限。
虽然用户 jiangxin 和用户 admin 同样均可以在 sandbox/ 下建立版本库,可是因为 sandbox/repos1.git 已经存在而且不是 jiangxin 用户建立的,因此 jiangxin 用户没有任何权限,不能读写。
和以前的例子相同的是:
版本库的建立者还可使用 setperms 命令为版本库添加受权。具体用法参见下面的示例。
受权文件以下:
1 @administrators = jiangxin admin 2 3 repo users/CREATOR/.+$ 4 C = @all 5 R = @administrators
说明:
用户能够在本身的名字空间( /usrs/<userid>/ )下,本身建立版本库。
$ git push dev1@server:users/dev1/repos1.git master
设置管理员组对任何用户在 users/ 目录下建立的版本库都有只读权限。
用户可使用 setperms 为本身的版本库进行二次受权
$ ssh dev1@server setperms users/dev1/repos1.git R = dev2 RW = jiangxin ^D
即在输入 setperms 命令后,进入一个编辑界面,输入 ^D(Ctrl+D)结束编辑。
也可使用输入重定向,先将受权写入文件,再用 setperms 命令加载。
$ cat > perms << EOF R = dev2 RW = jiangxin EOF $ ssh dev1@server setperms < perms
用户可使用 getperms 查看对本身版本库的受权
$ ssh dev1@server getperms users/dev1/repos1.git R = dev2 RW = jiangxin
传统的引用受权,指的是受权指令中不包含 RWC, RWD, RWCD, RW+C, RW+D, RW+CD 受权关键字,只采用 RW,RW+ 的传统受权关键字。
在只使用传统的受权关键字的状况下,有以下注意事项:
受权文件:
1 @administrators = jiangxin admin 2 @dev = dev1 dev2 badboy 3 4 repo test/repo1 5 RW+ = @administrators 6 RW master refs/heads/feature/ = @dev 7 R = @test
说明:
第5行,版本库 test/repo1 ,管理员组用户 jiangxin 和 admin 能够任意建立和删除引用,而且能够强制 PUSH。
第6行的规则看似只对 master 和 refs/heads/feature/* 的引用受权,实际上 @dev 能够读取全部名字空间的引用。这是由于读取操做没法得到 ref 相关内容。
即用户组 @dev 的用户只能对 master 分支,以及以 feature/ 开头的分支进行写操做,但不能强制 PUSH 和删除。至于其余分支和里程碑,则只能读不能写。
至于用户组 @test 的用户,由于使用了 R 受权指令,因此不涉及到分支的写受权。
扩展模式的引用受权,指的是该版本库的受权指令出现了下列受权关键字中的一个或多个: RWC, RWD, RWCD, RW+C,RW+D, RW+CD 。
受权文件:
repo test/repo2 RW+C = @administrators RW+ = @dev RW = @test repo test/repo3 RW+CD = @administrators RW+C = @dev RW = @test
说明:
对于版本库 test/repo2.git :
对于版本库 test/repo3.git :
受权文件:
1 repo testing ... 12 RW refs/tags/v[0-9] = jiangxin 13 - refs/tags/v[0-9] = dev1 dev2 @others 14 RW refs/tags/ = jiangxin dev1 dev2 @others
说明:
和建立用户空间(使用了 CREATOR 关键字)的版本库相似,还能够在一个版本库内,容许管理本身名字空间( USER 关键字)下的分支。在正则引用的参数中出现的 USER 关键字会被替换为用户的 ID。
受权文件:
repo test/repo4 RW+CD = @administrators RW+CD refs/personal/USER/ = @all RW+ master = @dev
说明:
Gitolite 也实现了对路径的写操做的精细受权,而且很是巧妙的是:在实现上增长的代码能够忽略不计。这是由于 Gitolite 把对路径看成是特殊格式的引用的受权。
在受权文件中,若是一个版本库的受权指令中的正则引用字段出现了以 NAME/ 开头的引用,则代表该受权指令是针对路径进行的写受权,而且该版本库要进行基于路径的写受权判断。
示例:
1 repo foo 2 RW = @junior_devs @senior_devs 3 4 RW NAME/ = @senior_devs 5 - NAME/Makefile = @junior_devs 6 RW NAME/ = @junior_devs
说明:
Gitolite 维护的版本库位于安装用户主目录下的 repositories 目录中,即若是安装用户为 git ,则版本库都建立在 /home/git/repositories 目录之下。能够经过配置文件 .gitolite.rc 修改缺省的版本库的根路径。
$REPO_BASE="repositories";
有多种建立版本库的方式。一种是在受权文件中用 repo 指令设置版本库(未使用正则表达式的版本库)的受权,当对 gitolite-admin 版本库执行 git push 操做,自动在服务端建立新的版本库。另一种方式是在受权文件中用正则表达式定义的版本库,不会即时建立,而是被受权的用户在远程建立后PUSH到服务器上完成建立。
注意,在受权文件中建立的版本库名称不要带 .git 后缀,在建立版本库过程当中会自动在版本库后面追加 .git 后缀。
咱们尝试在受权文件 conf/gitolite.conf 中加入一段新的版本库受权指令,而这个版本库尚不存在。新添加到受权文件中的内容:
repo testing2 RW+ = @all
而后将受权文件的修改提交并 PUSH 到服务器,咱们会看到受权文件中添加新受权的版本库 testing2 被自动建立。
$ git push Counting objects: 7, done. Delta compression using up to 2 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (4/4), 375 bytes, done. Total 4 (delta 1), reused 0 (delta 0) remote: Already on 'master' remote: creating testing2... remote: Initialized empty Git repository in /home/git/repositories/testing2.git/ To gitadmin.bj:gitolite-admin.git 278e54b..b6f05c1 master -> master
注意其中带 remote 标识的输出,咱们看到版本库 testing2.git 被自动初始化了。
此外使用版本库组的语法(即用 @ 建立的组,用做版本库),也会被自动建立。例以下面的受权文件片断设定了一个包含两个版本库的组 @testing ,当将新配置文件 PUSH 到服务器上的时候,会自动建立 testing3.git 和 testing4.git 。
@testing = testing3 testing4 repo @testing RW+ = @all
还有一种版本库语法,是用正则表达式定义的版本库,这类版本库由于所指的版本库并不肯定,所以不会自动建立。
通配符版本库是用正则表达式语法定义的版本库,所指的非某一个版本库而是和名称相符的一组版本库。首先要想使用通配符版本库,须要在服务器端安装用户(如 git )用户的主目录下的配置文件 .gitolite.rc 中,包含以下配置:
$GL_WILDREPOS = 1;
使用通配符版本库,能够对一组版本库进行受权,很是有效。可是版本库的建立则不像前面介绍的那样,不会在受权文件 PUSH 到服务器时建立,而是拥有版本库建立受权(C)的用户手工进行建立。
对于用通配符设置的版本库,用 C 指令指定可以建立此版本库的管理员(拥有建立版本库的受权)。例如:
repo ossxp/.+ C = jiangxin RW = dev1 dev2
管理员 jinagxin 能够建立路径符合正则表达式 "ossxp/.+" 的版本库,用户 dev1 和 dev2 对版本库具备读写(可是没有强制更新)权限。
使用该方法建立版本库后,建立者的 uid 将被记录在版本库目录下的 gl-creator 文件中。该账号具备对该版本库最高的权限。该通配符版本库的受权指令中若是出现 CREATOR 将被建立者的 uid 替换。
本地建库
$ mkdir somerepo $ cd somerepo $ git init $ git commit --allow-empty
使用 git remote 指令添加远程的源
$ git remote add origin jiangxin@server:ossxp/somerepo.git
运行 git push 完成在服务器端版本库的建立
$ git push origin master
克隆即建立,仍是PUSH即建立?
Gitolite 的原始实现是通配符版本库的管理员在对不存在的版本库执行 clone 操做时,自动建立。可是我认为这不是一个好的实践,会常常由于 clone 的 URL 写错,致使在服务器端建立垃圾版本库。所以我从新改造了 gitolite 通配符版本库建立的实现,改成在对版本库进行 PUSH 的时候进行建立,而 clone 一个不存在的版本库,会报错退出。
当版本库的数量不少的时候,在服务器端直接经过 git 命令建立或者经过复制建立可能会更方便。可是要注意,在服务器端手工建立的版本库和 Gitolite 建立的版本库最大的不一样在于钩子脚本。若是不能为手工建立的版本库正确设定版本库的钩子,会致使失去一些 Gitolite 特有的功能。例如:失去分支受权的功能。
一个由 Gitolite 建立的版本库,hooks 目录下有三个钩子脚本实际上连接到 gitolite 安装目录下的相应的脚本文件中:
gitolite-hooked -> /home/git/.gitolite/hooks/common/gitolite-hooked post-receive.mirrorpush -> /home/git/.gitolite/hooks/common/post-receive.mirrorpush update -> /home/git/.gitolite/hooks/common/update
那么手工在服务器上建立的版本库,有没有自动更新钩子脚本的方法呢?
有,就是从新执行一遍 gitolite 的安装,会自动更新版本库的钩子脚本。安装过程一路按回车便可。
$ cd gitolite/src $ ./gl-easy-install git server admin
除了钩子脚本要注意之外,还要确保服务器端版本库目录的权限和属主。
笔者对 Gitolite 进行扩展和改进,涉及到的内容主要包括:
通配符版本库的建立方式和受权。
原来的实现是克隆即建立(克隆者须要被授予 C 的权限)。同时还要经过另外的受权语句为用户设置 RW 权限,不然建立者没有读和写权限。
新的实现是经过 PUSH 建立版本库(PUSH 者须要被授予 C 权限)。没必要再为建立者赋予 RW 等权限,建立者自动具备对版本库最高的受权。
避免通配符版本库误判。
通配符版本库误判,会致使在服务器端建立错误的版本库。新的设计还能够在通配符版本库的正则表达式前或后添加 ^或 $ 字符,而不会形成受权文件编辑错误。
改变缺省配置。
缺省安装即支持通配符版本库。
版本库重定向。
Gitosis 的一个很重要的功能:版本库名称重定向,没有在 Gitolite 中实现。咱们为 Gitolite 增长了这个功能。
在Git服务器架设的开始,版本库的命名可能很是随意,例如 redmine 的版本库直接放在根下,例如: redmine-0.9.x.git, redmine-1.0.x.git, ... 当 redmine 项目愈来愈复杂,可能就须要将其放在子目录下进行管理,例如放到ossxp/redmine/ 目录下。
只须要在 Gitolite 的受权文件中添加下面一行 map 语句,就能够实现版本库名称重定向。使用旧的地址的用户没必要从新检出,能够继续使用。
map (redmine.*) = ossxp/redmine/$1
Git 版本库控制系统每每并不须要设计特别的容灾备份,由于每个Git用户就是一个备份。可是下面的状况,就颇有必要考虑容灾了。
Gitolite 提供了服务器间版本库同步的设置。原理是:
在多个服务器之间设置 Git 库镜像的方法是:
每一个服务器都要安装 Gitolite 软件,并且要启用 post-receive 钩子。
缺省的钩子在源代码的 hooks/common 目录下,名称为 post-receive.mirrorpush ,要将其更名为 post-receive 。不然版本库的 post-receive 脚本不能生效。
主服务器配置到从服务器的公钥认证,而且配置使用特殊的 SHELL: gl-mirror-shell 。
这是由于主服务器在向从服务器同步版本库的时候,若是从服务器版本库没有建立,直接经过 SSH 登陆到从服务器,执行建立命令。所以须要经过一个特殊的SHELL,可以同时支持 Gitolite 的受权访问以及 SHELL 环境。这个特殊的 SHELL 就是 gl-mirror-shell 。并且这个 SHELL,经过特殊的环境变量绕过服务器的权限检查,避免由于受权问题致使同步失败。
实际应用中,不光主服务器,每一个服务器都进行相似设置,目的是主从服务器可能相互切换。
在 Gitolite 不一样的安装模式下, gl-mirror-shell 的安装位置可能不一样。下面的命令用于在服务器端设置其余服务器访问时使用这个特殊的 SHELL。
假设在服务器 foo 上,安装来自服务器 bar 和 baz 的公钥认证。公钥分别是 bar.pub 和 baz.pub。
对于在客户端安装方式部署的 Gitolite:
# 在服务器 foo 上执行: $ export GL_ADMINDIR=` cd $HOME;perl -e 'do ".gitolite.rc"; print $GL_ADMINDIR'` $ cat bar.pub baz.pub | sed -e 's,^,command="'$GL_ADMINDIR'/src/gl-mirror-shell" ,' >> ~/.ssh/authorized_keys
对于在服务器端安装方式部署的 Gitolite, gl-mirror-shell 直接就能够在路径中找到。
# 在服务器 foo 上执行: $ cat bar.pub baz.pub | sed -e 's,^,command="'$(which gl-mirror-shell)'" ,' >> ~/.ssh/authorized_keys
在 foo 服务器上设置完毕,能够从服务器 bar 或者 baz 上远程执行:
执行命令后退出
$ ssh git@foo pwd
进入 shell
$ ssh git@foo bash -i
在从服务器上设置配置文件 ~/.gitolite.rc 。
进行以下设置后,将不容许用户直接 PUSH 到从服务器。可是主服务器仍然能够 PUSH 到从服务器,是由于主服务器版本库在 PUSH 到从服务器时,使用了特殊的环境变量,可以跳过从服务器版本库的 update 脚本。
$GL_SLAVE_MODE = 1
在主服务器上设置配置文件 ~/.gitolite.rc 。
须要配置到从服务器的 SSH 链接,能够设置多个,用空格分隔。注意使用单引号,避免 @ 字符被 Perl 看成数组解析。
$ENV{GL_SLAVES} = 'gitolite@bar gitolite@baz';
在主服务器端执行 gl-mirror-sync 进行一次完整的数据同步。
须要以 Gitolite 安装用户身份(如git)执行。例如在服务器 foo 上执行到从服务器 bar 的同步。
$ gl-mirror-sync gitolite@bar
以后,每当用户向主版本库同步,都会经过版本库的 post-receive 钩子即时同步到从版本库。
主从版本库的切换。
切换很是简单,就是修改 ~/.gitolite.rc 配置文件,修改 $GL_SLAVE_MODE 设置:主服务器设置为 0,从服务器设置为1。
Gitolite 和 git-daemon 的整合很简单,就是在版本库目录中建立一个空文件 git-daemon-export-ok 。
Gitolite 和 Gitweb 的整合,则提供了两个方面的内容。一个是能够设置版本库的描述信息,用于在 gitweb 的项目列表页面显示。另一个是自动生成项目的列表文件供 Gitweb 参卡,避免 Gitweb 使用效率低的目录递归搜索查找 Git 版本库列表。
能够在受权文件中设定版本库的描述信息,并在 gitolite-admin 管理库更新时建立到版本库的 description 文件中。
reponame = "one line of description" reponame "owner name" = "one line of description"
对于通配符版本库,使用这种方法则很不现实。Gitolite 提供了 SSH 子命令,供版本库的建立者使用。
$ ssh git@server setdesc description... $ ssh git@server getdesc
至于生成 Gitweb 所用的项目列表文件,缺省建立在用户主目录下的 projects.list 文件中。对于全部启用 Gitweb 的 [repo] 小节设定的版本库,或者经过版本库描述隐式声明的版本库加入到版本库列表中。
Gitolite 源码的 doc 目录包含用 markdown 标记语言编写的手册,能够直接在 Github 上查看。也可使用 markdown 的文档编辑工具将 .mkd 文档转换为 html 文档。转换工具不少,有:rdiscount, Bluefeather, Maruku, BlueCloth2 等等。
在这些参考文档中,你能够发现 Gitolite 包含的更多的小功能或者秘籍,包括:
版本库设置。
在受权文件经过 git config 指令为版本库进行附加的设置。例如:
repo gitolite config hooks.mailinglist = gitolite-commits@example.tld config hooks.emailprefix = "[gitolite] " config foo.bar = "" config foo.baz =
多级管理员受权。
能够为不一样版本库设定管理员,操做 gitolite-admin 库的部分受权文件。参见: doc/5-delegation.mkd 。
自定义钩子脚本。
由于 Gitolite 占用了几个钩子脚本,若是须要对同名钩子进行扩展,Gitolite 提供了级联的钩子脚本,将定制放在级联的钩子脚本里。
例如:经过自定义 gitolite-admin 的 post-update.secondary 脚本,以实现无需登陆服务器,更改 .gitolite.rc 文件。参见: doc/shell-games.mkd 。
关于钩子脚本的建立和维护,参见: doc/hook-propagation.mkd 。
管理员自定义命令。
经过设置配置文件中的 $GL_ADC_PATH 变量,在远程执行该目录下的可执行脚本,如: rmrepo 。
具体参考: doc/admin-defined-commands.mkd 。
建立匿名 SSH 认证。
容许匿名用户访问 Gitolite 提供的 git 服务。即创建一个和 gitolite 服务器端账号同 id 和主目录的用户,并设置其的特定 shell,而且容许口令为空。
具体参考: doc/mob-branches.mkd 。
能够经过名为 @all 的版本库进行全局的受权。
版本库很是或者用户很是之多(几千个)的时候,须要使用 大配置文件 模式。
由于 Gitolite 的受权文件要先编译才能生效,而编译文件的大小是和用户以及版本库数量的乘积成正比的。选择大配置文件模式,则不对用户组和版本库组进行扩展。
参见: doc/big-config.mkd 。
受权文件支持包含语句,能够将受权文件分红多个独立的单元。
执行外部命令,如 rsync。
Subversion 版本库支持。
若是在同一个服务器上以 svn+ssh 方式运行 Subversion 服务器,可使用同一套公钥,同时为用户提供 Git 和 Subversion 服务。
HTTP 口令文件维护。经过 htpasswd SSH 子命令实现。