Posted on

# Git详解之四：服务器上的Git

4.1 协议

Git 可以使用四种主要的协议来传输数据：本地传输，SSH 协议，Git 协议和 HTTP 协议。下面分别介绍一下哪些情形应该使用（或避免使用）这些协议。

file

:

///opt/git/project

.git

ssh

:

//user

@server:project.git

1$git clone user@server:project.git 如果不指明用户，Git 会默认使用当前登录的用户名连接服务器。 优点 使用 SSH 的好处有很多。首先，如果你想拥有对网络仓库的写权限，基本上不可能不使用 SSH。其次，SSH 架设相对比较简单 — SSH 守护进程很常见，很多网络管理员都有一些使用经验，而且很多操作系统都自带了它或者相关的管理工具。再次，通过 SSH 进行访问是安全的 — 所有数据传输都是加密和授权的。最后，和 Git 及本地协议一样，SSH 也很高效，会在传输之前尽可能压缩数据。 缺点 SSH 的限制在于你不能通过它实现仓库的匿名访问。即使仅为读取数据，人们也必须在能通过 SSH 访问主机的前提下才能访问仓库，这使得 SSH 不利于开源的项目。如果你仅仅在公司网络里使用，SSH 可能是你唯一需要使用的协议。如果想允许对项目的匿名只读访问，那么除了为自己推送而架设 SSH 协议之外，还需要支持其他协议以便他人访问读取。 Git 协议 接下来是 Git 协议。这是一个包含在 Git 软件包中的特殊守护进程； 它会监听一个提供类似于 SSH 服务的特定端口（9418），而无需任何授权。打算支持 Git 协议的仓库，需要先创建git-export-daemon-ok 文件 — 它是协议进程提供仓库服务的必要条件 — 但除此之外该服务没有什么安全措施。要么所有人都能克隆 Git 仓库，要么谁也不能。这也意味着该协议通常不能用来进行推送。你可以允许推送操作；然而由于没有授权机制，一旦允许该操作，网络上任何一个知道项目 URL 的人将都有推送权限。不用说，这是十分罕见的情况。 优点 Git 协议是现存最快的传输协议。如果你在提供一个有很大访问量的公共项目，或者一个不需要对读操作进行授权的庞大项目，架设一个 Git 守护进程来供应仓库是个不错的选择。它使用与 SSH 协议相同的数据传输机制，但省去了加密和授权的开销。 缺点 Git 协议消极的一面是缺少授权机制。用 Git 协议作为访问项目的唯一方法通常是不可取的。一般的做法是，同时提供 SSH 接口，让几个开发者拥有推送（写）权限，其他人通过git:// 拥有只读权限。Git 协议可能也是最难架设的协议。它要求有单独的守护进程，需要定制 — 我们将在本章的 “Gitosis” 一节详细介绍它的架设 — 需要设定xinetd 或类似的程序，而这些工作就没那么轻松了。该协议还要求防火墙开放 9418 端口，而企业级防火墙一般不允许对这个非标准端口的访问。大型企业级防火墙通常会封锁这个少见的端口。 HTTP/S 协议 最后还有 HTTP 协议。HTTP 或 HTTPS 协议的优美之处在于架设的简便性。基本上，只需要把 Git 的裸仓库文件放在 HTTP 的根目录下，配置一个特定的post-update 挂钩（hook）就可以搞定（Git 挂钩的细节见第 7 章）。此后，每个能访问 Git 仓库所在服务器上 web 服务的人都可以进行克隆操作。下面的操作可以允许通过 HTTP 对仓库进行读取： 1 2 3 4 5$

cd

/var/www/htdocs/

$git clone --bare /path/to/git_project gitproject.git$

cd

gitproject.git

$mv hooks /post-update .sample hooks /post-update$

chmod

a+x hooks

/post-update

1$git clone http: //example .com /gitproject .git 在本例中，我们使用了 Apache 设定中常用的 /var/www/htdocs 路径，不过你可以使用任何静态 web 服务 — 把裸仓库放在它的目录里就行。 Git 的数据是以最基本的静态文件的形式提供的（关于如何提供文件的详情见第 9 章）。 通过 HTTP 进行推送操作也是可能的，不过这种做法不太常见，并且牵扯到复杂的 WebDAV 设定。由于很少用到，本书将略过对该内容的讨论。如果对 HTTP 推送协议感兴趣，不妨打开这个地址看一下操作方法：http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt 。通过 HTTP 推送的好处之一是你可以使用任何 WebDAV 服务器，不需要为 Git 设定特殊环境；所以如果主机提供商支持通过 WebDAV 更新网站内容，你也可以使用这项功能。 优点 使用 HTTP 协议的好处是易于架设。几条必要的命令就可以让全世界读取到仓库的内容。花费不过几分钟。HTTP 协议不会占用过多服务器资源。因为它一般只用到静态的 HTTP 服务提供所有数据，普通的 Apache 服务器平均每秒能支撑数千个文件的并发访问 — 哪怕让一个小型服务器超载都很难。 你也可以通过 HTTPS 提供只读的仓库，这意味着你可以加密传输内容；你甚至可以要求客户端使用特定签名的 SSL 证书。一般情况下，如果到了这一步，使用 SSH 公共密钥可能是更简单的方案；不过也存在一些特殊情况，这时通过 HTTPS 使用带签名的 SSL 证书或者其他基于 HTTP 的只读连接授权方式是更好的解决方案。 HTTP 还有个额外的好处：HTTP 是一个如此常见的协议，以至于企业级防火墙通常都允许其端口的通信。 缺点 HTTP 协议的消极面在于，相对来说客户端效率更低。克隆或者下载仓库内容可能会花费更多时间，而且 HTTP 传输的体积和网络开销比其他任何一个协议都大。因为它没有按需供应的能力 — 传输过程中没有服务端的动态计算 — 因而 HTTP 协议经常会被称为傻瓜（dumb）协议。更多 HTTP 协议和其他协议效率上的差异见第 9 。 4.2 在服务器上部署 Git 开始架设 Git 服务器前，需要先把现有仓库导出为裸仓库 — 即一个不包含当前工作目录的仓库。做法直截了当，克隆时用 –bare 选项即可。裸仓库的目录名一般以.git 结尾，像这样： 1 2$ git clone --bare my_project my_project.git

Initialized empty Git repository

in

/opt/projects/my_project

.git/

scp

-r my_project.git user@ git.example.com:

/opt/git

1$git clone user@ git.example.com: /opt/git/my_project .git 如果某个 SSH 用户对 /opt/git/my_project.git 目录有写权限，那他就有推送权限。如果到该项目目录中运行 git init 命令，并加上 –shared 选项，那么 Git 会自动修改该仓库目录的组权限为可写（译注：实际上 –shared 可以指定其他行为，只是默认为将组权限改为可写并执行 g+sx，所以最后会得到 rws。）。 1 2 3$

ssh

user@ git.example.com

$cd /opt/git/my_project .git$ git init --bare --shared

SSH 连接

4.3 生成 SSH 公钥

2 3

4 $cd ~/. ssh$

ls

authorized_keys2 id_dsa known_hosts

config id_dsa.pub

1

2 3

4 5

6 7

8 9$ssh -keygen Generating public /private rsa key pair. Enter file in which to save the key ( /Users/schacon/ . ssh /id_rsa ): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/schacon/ . ssh /id_rsa . Your public key has been saved in /Users/schacon/ . ssh /id_rsa .pub. The key fingerprint is: 43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@ agadorlaptop. local 它先要求你确认保存公钥的位置（.ssh/id_rsa），然后它会让你重复一个密码两次，如果不想在使用公钥的时候输入密码，可以留空。 现在，所有做过这一步的用户都得把它们的公钥给你或者 Git 服务器的管理员（假设 SSH 服务被设定为使用公钥机制）。他们只需要复制 .pub 文件的内容然后发邮件给管理员。公钥的样子大致如下： 1 2 3 4 5 6 7$

cat

~/.

ssh

/id_rsa

.pub

ssh

-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom

/BWDSU

GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3

Pbv7kOdJ

/MTyBlWXFCR

+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK

/7XA

t3FaoJoAsncM1Q9x5+3V0Ww68

/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En

mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z

/il8b

+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx

local

4.4 架设服务器

2 3

4 $sudo adduser git$

su

git

$cd$

mkdir

.

ssh

1

2 3

4 5

6 7$cat /tmp/id_rsa .john.pub ssh -rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n /ww +ouN4gSLKssMxXnBOvf9LGt4L ojG6rs6hPB09j9R /T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK +4k Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC /nLF6JLtPofwFBlgc +myiv O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq dAv8JggJICUvax2T9va5 gsg-keypair 只要把它们逐个追加到 authorized_keys 文件尾部即可： 1 2 3$

cat

/tmp/id_rsa

.john.pub >> ~/.

ssh

/authorized_keys

$cat /tmp/id_rsa .josie.pub >> ~/. ssh /authorized_keys$

cat

/tmp/id_rsa

.jessica.pub >> ~/.

ssh

/authorized_keys

1

2 3

4 $cd /opt/git$

mkdir

project.git

$cd project.git$ git --bare init

/# 在 John 的电脑上 1

2 3

4 5

6 $cd myproject$ git init

$git add .$ git commit -m

'initial commit'

$git remote add origin git@gitserver: /opt/git/project .git$ git push origin master

1

2 3

4 $git clone git@gitserver: /opt/git/project .git$ vim README

$git commit -am 'fix for the README file'$ git push origin master

ssh

git@gitserver

fatal: What

do

you think I am? A shell?

Connection to gitserver closed.

4.5 公共访问

2 3$cd project.git$

mv

hooks

/post-update

.sample hooks

/post-update

$chmod a+x hooks /post-update 如果用的是 Git 1.6 之前的版本，则可以省略 mv 命令 — Git 是从较晚的版本才开始在挂钩实例的结尾添加 .sample 后缀名的。 post-update 挂钩是做什么的呢？其内容大致如下： 1 2 3$

cat

.git

/hooks/post-update

/#!/bin/sh

exec

git-update-server-info

1

2 3

4 ServerName git.gitserver

DocumentRoot

/opt/git Order allow, deny

allow from all

//git

.gitserver

/project

.git

4.6 GitWeb

Figure 4-1. 基于网页的 GitWeb 用户界面

2 3$git instaweb --httpd=webrick [2009-02-21 10:02:21] INFO WEBrick 1.3.1 [2009-02-21 10:02:21] INFO ruby 1.8.6 (2008-03-03) [universal-darwin9.0] 这会在 1234 端口开启一个 HTTPD 服务，随之在浏览器中显示该页，十分简单。关闭服务时，只需在原来的命令后面加上 –stop 选项就可以了： 1$ git instaweb --httpd=webrick --stop

1

2 3

4 5$git clone git: //git .kernel.org /pub/scm/git/git .git$

cd

git/

$make GITWEB_PROJECTROOT= "/opt/git" \ prefix= /usr gitweb /gitweb .cgi$

sudo

cp

-Rf gitweb

/var/www/

1

2 3

4 5

6 7

8 ServerName gitserver

DocumentRoot

AllowOverride All

order allow,deny

Allow from all

DirectoryIndex gitweb.cgi

4.7 Gitosis

Gitosis 的安装算不上傻瓜化，但也不算太难。用 Linux 服务器架设起来最简单 — 以下例子中，我们使用装有 Ubuntu 8.10 系统的服务器。

Gitosis 的工作依赖于某些 Python 工具，所以首先要安装 Python 的 setuptools 包，在 Ubuntu 上称为 python-setuptools： 1$apt-get install python-setuptools 接下来，从 Gitosis 项目主页克隆并安装： 1 2 3$ git clone git:

//eagain

.net

/gitosis

.git

$cd gitosis$

sudo

python setup.py

install

1$ln -s /opt/git /home/git/repositories Gitosis 将会帮我们管理用户公钥，所以先把当前控制文件改名备份，以便稍后重新添加，准备好让 Gitosis 自动管理 authorized_keys 文件： 1$

mv

/home/git/

.

ssh

/authorized_keys

/home/git/

.

ssh

/ak

.bak

1git:x:1000:1000::

/home/git

:

/usr/bin/git-shell

1git:x:1000:1000::

/home/git

:

/bin/sh

gitosis-init 命令，要是公钥不在服务器上，先临时复制一份：

1

2 3$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 脚本加上可执行权限： 1$

sudo

chmod

755

.git

/hooks/post-update

1

2 3

4 $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 里的改动，并推送到服务器使其生效： 1 2 3 4 5 6 7 8 9 10$ 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 里首次推送数据到服务器前，得先设定该服务器地址为远程仓库。但你不用事先到服务器上手工创建该项目的裸仓库— Gitosis 会在第一次遇到推送时自动创建： 1 2 3 4 5 6 7 8$ 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 添加公钥： 1 2 3$

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

1

2 3[group mobile]

writable = iphone_project

members = scott john josie jessica

Gitosis 也具有简单的访问控制功能。如果想让 John 只有读权限，可以这样做： 1

2 3

4 5

6 [group mobile]

writable = iphone_project

members = scott josie jessica

[group mobile_ro]

= iphone_project

members = john

1

2 3

4 5

6 7

8 [group mobile_committers]

members = scott josie jessica [group mobile]

writable = iphone_project

members = @mobile_committers

[group mobile_2]

writable = another_iphone_project

members = @mobile_committers john

4.8 Gitolite

Note: the latest copy of this section of the ProGit book is always available within thegitolite documentation. The author would also like to humbly state that, while this section is accurate, andcan (and often has) been used to install gitolite without reading any other documentation, it is of necessity not complete, and cannot completely replace the enormous amount of documentation that gitolite comes with.

Git has started to become very popular in corporate environments, which tend to have some additional requirements in terms of access control. Gitolite was originally created to help with those requirements, but it turns out that it’s equally useful in the open source world: the Fedora Project controls access to their package management repositories (over 10,000 of them!) using gitolite, and this is probably the largest gitolite installation anywhere too.

Gitolite allows you to specify permissions not just by repository, but also by branch or tag names within each repository. That is, you can specify that certain people (or groups of people) can only push certain “refs” (branches or tags) but not others.

Installing

Installing Gitolite is very easy, even if you don’t read the extensive documentation that comes with it. You need an account on a Unix server of some kind; various Linux flavours, and Solaris 10, have been tested. You do not need root access, assuming git, perl, and an openssh compatible ssh server are already installed. In the examples below, we will use thegitolite account on a host called gitserver.

Gitolite is somewhat unusual as far as “server” software goes – access is via ssh, and so every userid on the server is a potential “gitolite host”. As a result, there is a notion of “installing” the software itself, and then “setting up” a user as a “gitolite host”.

Gitolite has 4 methods of installation. People using Fedora or Debian systems can obtain an RPM or a DEB and install that. People with root access can install it manually. In these two methods, any user on the system can then become a “gitolite host”.

People without root access can install it within their own userids. And finally, gitolite can be installed by running a scripton the workstation, from a bash shell. (Even the bash that comes with msysgit will do, in case you’re wondering.)

We will describe this last method in this article; for the other methods please see the documentation.

You start by obtaining public key based access to your server, so that you can log in from your workstation to the server without getting a password prompt. The following method works on Linux; for other workstation OSs you may have to do this manually. We assume you already had a key pair generated using ssh-keygen. 1$ssh -copy- id -i ~/. ssh /id_rsa gitolite@gitserver This will ask you for the password to the gitolite account, and then set up public key access. This isessential for the install script, so check to make sure you can run a command without getting a password prompt: 1 2$

ssh

gitolite@gitserver

pwd

/home/gitolite

Next, you clone Gitolite from the project’s main site and run the “easy install” script (the third argument is your name as you would like it to appear in the resulting gitolite-admin repository):

1

2 3$git clone git: //github .com /sitaramc/gitolite$

cd

gitolite

/src

$. /gl-easy-install -q gitolite gitserver sitaram And you’re done! Gitolite has now been installed on the server, and you now have a brand new repository calledgitolite-admin in the home directory of your workstation. You administer your gitolite setup by making changes to this repository and pushing. That last command does produce a fair amount of output, which might be interesting to read. Also, the first time you run this, a new keypair is created; you will have to choose a passphrase or hit enter for none. Why a second keypair is needed, and how it is used, is explained in the “ssh troubleshooting” document that comes with Gitolite. (Hey the documentation has to be good forsomething!) Repos named gitolite-admin and testing are created on the server by default. If you wish to clone either of these locally (from an account that has SSH console access to the gitolite account viaauthorized_keys), type: 1 2$ git clone gitolite:gitolite-admin

$git clone gitolite:testing To clone these same repos from any other account: 1 2$ git clone gitolite@servername:gitolite-admin

$git clone gitolite@servername:testing Customising the Install While the default, quick, install works for most people, there are some ways to customise the install if you need to. If you omit the-q argument, you get a “verbose” mode install – detailed information on what the install is doing at each step. The verbose mode also allows you to change certain server-side parameters, such as the location of the actual repositories, by editing an “rc” file that the server uses. This “rc” file is liberally commented so you should be able to make any changes you need quite easily, save it, and continue. This file also contains various settings that you can change to enable or disable some of gitolite’s advanced features. Config File and Access Control Rules Once the install is done, you switch to the gitolite-admin repository (placed in your HOME directory) and poke around to see what you got: 1 2 3 4 5 6 7 8 9 10 11 12 13$

cd

~

$ls conf/ keydir/$

find

conf keydir -

type

f

conf

/gitolite

.conf

keydir

/sitaram

.pub

$cat conf /gitolite .conf /#gitolite conf /# please see conf/example.conf for details on syntax and features repo gitolite-admin RW+ = sitaram repo testing RW+ = @all Notice that “sitaram” (the last argument in the gl-easy-install command you gave earlier) has read-write permissions on thegitolite-admin repository as well as a public key file of the same name. The config file syntax for gitolite is liberally documented in conf/example.conf, so we’ll only mention some highlights here. You can group users or repos for convenience. The group names are just like macros; when defining them, it doesn’t even matter whether they are projects or users; that distinction is only made when youuse the “macro”. 1 2 3 4 5 6 @oss_repos = linux perl rakudo git gitolite @secret_repos = fenestra pear @admins = scott /# Adams, not Chacon, sorry @interns = ashok /# get the spelling right, Scott! @engineers = sitaram dilbert wally alice @staff = @admins @engineers @interns You can control permissions at the “ref” level. In the following example, interns can only push the “int” branch. Engineers can push any branch whose name starts with “eng-“, and tags that start with “rc” followed by a digit. And the admins can do anything (including rewind) to any ref. 1 2 3 4 5repo @oss_repos RW int$ = @interns

RW eng- = @engineers

RW refs

/tags/rc

[0-9] = @engineers

The expression after the RW or RW+ is a regular expression (regex) that the refname (ref) being pushed is matched against. So we call it a “refex”! Of course, a refex can be far more powerful than shown here, so don’t overdo it if you’re not comfortable with perl regexes.

Also, as you probably guessed, Gitolite prefixes refs/heads/ as a syntactic convenience if the refex does not begin withrefs/.

An important feature of the config file’s syntax is that all the rules for a repository need not be in one place. You can keep all the common stuff together, like the rules for alloss_repos shown above, then add specific rules for specific cases later on, like so: 1

2 repo gitolite

RW+ = sitaram

That rule will just get added to the ruleset for the gitolite repository.

At this point you might be wondering how the access control rules are actually applied, so let’s go over that briefly.

There are two levels of access control in gitolite. The first is at the repository level; if you have read (or write) access toany ref in the repository, then you have read (or write) access to the repository.

The second level, applicable only to “write” access, is by branch or tag within a repository. The username, the access being attempted (W or+), and the refname being updated are known. The access rules are checked in order of appearance in the config file, looking for a match for this combination (but remember that the refname is regex-matched, not merely string-matched). If a match is found, the push succeeds. A fallthrough results in access being denied.

Advanced Access Control with “deny” rules

So far, we’ve only seen permissions to be one or R, RW, orRW+. However, gitolite allows another permission: -, standing for “deny”. This gives you a lot more power, at the expense of some complexity, because now fallthrough is not theonly way for access to be denied, so the order of the rules now matters!

Let us say, in the situation above, we want engineers to be able to rewind any branchexcept master and integ. Here’s how to do that: 1

2 3RW master integ = @engineers

• master integ = @engineers

RW+ = @engineers

Again, you simply follow the rules top down until you hit a match for your access mode, or a deny. Non-rewind push to master or integ is allowed by the first rule. A rewind push to those refs does not match the first rule, drops down to the second, and is therefore denied. Any push (rewind or non-rewind) to refs other than master or integ won’t match the first two rules anyway, and the third rule allows it.

Restricting pushes by files changed

In addition to restricting what branches a user can push changes to, you can also restrict what files they are allowed to touch. For example, perhaps the Makefile (or some other program) is really not supposed to be changed by just anyone, because a lot of things depend on it or would break if the changes are not done just right. You can tell gitolite:

1

2 3

4 5repo foo

RW = @junior_devs @senior_devs RW NAME/ = @senior_devs

• NAME

/Makefile

= @junior_devs

RW NAME/ = @junior_devs

This powerful feature is documented in conf/example.conf.

Personal Branches

Gitolite also has a feature called “personal branches” (or rather, “personal branch namespace”) that can be very useful in a corporate environment.

A lot of code exchange in the git world happens by “please pull” requests. In a corporate environment, however, unauthenticated access is a no-no, and a developer workstation cannot do authentication, so you have to push to the central server and ask someone to pull from there.

This would normally cause the same branch name clutter as in a centralised VCS, plus setting up permissions for this becomes a chore for the admin.

Gitolite lets you define a “personal” or “scratch” namespace prefix for each developer (for example,refs/personal/ //* ); see the “personal branches” section in doc/3-faq-tips-etc.mkd for details.

“Wildcard” repositories

Gitolite allows you to specify repositories with wildcards (actually perl regexes), like, for exampleassignments/s[0-9][0-9]/a[0-9][0-9], to pick a random example. This is avery powerful feature, which has to be enabled by setting $GL_WILDREPOS = 1; in the rc file. It allows you to assign a new permission mode (”C”) which allows users to create repositories based on such wild cards, automatically assigns ownership to the specific user who created it, allows him/her to hand out R and RW permissions to other users to collaborate, etc. This feature is documented indoc/4-wildcard-repositories.mkd. Other Features We’ll round off this discussion with a sampling of other features, all of which, and many more, are described in great detail in the “faqs, tips, etc” and other documents. Logging: Gitolite logs all successful accesses. If you were somewhat relaxed about giving people rewind permissions (RW+) and some kid blew away “master”, the log file is a life saver, in terms of easily and quickly finding the SHA that got hosed. Git outside normal PATH: One extremely useful convenience feature in gitolite is support for git installed outside the normal$PATH (this is more common than you think; some corporate environments or even some hosting providers refuse to install things system-wide and you end up putting them in your own directories). Normally, you are forced to make theclient-side git aware of this non-standard location of the git binaries in some way. With gitolite, just choose a verbose install and set$GIT_PATH in the “rc” files. No client-side changes are required after that Access rights reporting: Another convenient feature is what happens when you try and just ssh to the server. Gitolite shows you what repos you have access to, and what that access may be. Here’s an example: 1 2 3 4 5 6 7 8 9hello sitaram, the gitolite version here is v1.5.4-19-ga3397d4 the gitolite config gives you the following access: R anu-wsd R entrans R W git-notes R W gitolite R W gitolite-admin R indic_web_input R shreelipi_converter Delegation: For really large installations, you can delegate responsibility for groups of repositories to various people and have them manage those pieces independently. This reduces the load on the main admin, and makes him less of a bottleneck. This feature has its own documentation file in the doc/ directory. Gitweb support: Gitolite supports gitweb in several ways. You can specify which repos are visible via gitweb. You can set the “owner” and “description” for gitweb from the gitolite config file. Gitweb has a mechanism for you to implement access control based on HTTP authentication, so you can make it use the “compiled” config file that gitolite produces, which means the same access control rules (for read access) apply for gitweb and gitolite. Mirroring: Gitolite can help you maintain multiple mirrors, and switch between them easily if the primary server goes down. 4.9 Git 守护进程 对于提供公共的，非授权的只读访问，我们可以抛弃 HTTP 协议，改用 Git 自己的协议，这主要是出于性能和速度的考虑。Git 协议远比 HTTP 协议高效，因而访问速度也快，所以它能节省很多用户的时间。 重申一下，这一点只适用于非授权的只读访问。如果建在防火墙之外的服务器上，那么它所提供的服务应该只是那些公开的只读项目。如果是在防火墙之内的 服务器上，可用于支撑大量参与人员或自动系统（用于持续集成或编译的主机）只读访问的项目，这样可以省去逐一配置 SSH 公钥的麻烦。 但不管哪种情形，Git 协议的配置设定都很简单。基本上，只要以守护进程的形式运行该命令即可： 1git daemon --reuseaddr --base-path= /opt/git/ /opt/git/ 这里的 –reuseaddr 选项表示在重启服务前，不等之前的连接超时就立即重启。而 –base-path 选项则允许克隆项目时不必给出完整路径。最后面的路径告诉 Git 守护进程允许开放给用户访问的仓库目录。假如有防火墙，则需要为该主机的 9418 端口设置为允许通信。 以守护进程的形式运行该进程的方法有很多，但主要还得看用的是什么操作系统。在 Ubuntu 主机上，可以用 Upstart 脚本达成。编辑该文件： 1/etc/event .d /local-git-daemon 加入以下内容： 1 2 3 4 5 6 7 8 start on startup stop on shutdown exec /usr/bin/git daemon \ --user=git --group=git \ --reuseaddr \ --base-path= /opt/git/ \ /opt/git/ respawn 出于安全考虑，强烈建议用一个对仓库只有读取权限的用户身份来运行该进程 — 只需要简单地新建一个名为 git-ro 的用户（译注：新建用户默认对仓库文件不具备写权限，但这取决于仓库目录的权限设定。务必确认git-ro 对仓库只能读不能写。），并用它的身份来启动进程。这里为了简化，后面我们还是用之前运行 Gitosis 的用户 ‘git’。 这样一来，当你重启计算机时，Git 进程也会自动启动。要是进程意外退出或者被杀掉，也会自行重启。在设置完成后，不重启计算机就启动该守护进程，可以运行： 1initctl start local -git-daemon 而在其他操作系统上，可以用 xinetd，或者 sysvinit 系统的脚本，或者其他类似的脚本 — 只要能让那个命令变为守护进程并可监控。 接下来，我们必须告诉 Gitosis 哪些仓库允许通过 Git 协议进行匿名只读访问。如果每个仓库都设有各自的段落，可以分别指定是否允许 Git 进程开放给用户匿名读取。比如允许通过 Git 协议访问 iphone_project，可以把下面两行加到gitosis.conf 文件的末尾： 1 2 [repo iphone_project] daemon = yes 在提交和推送完成后，运行中的 Git 守护进程就会响应来自 9418 端口对该项目的访问请求。 如果不考虑 Gitosis，单单起了 Git 守护进程的话，就必须到每一个允许匿名只读访问的仓库目录内，创建一个特殊名称的空文件作为标志： 1 2$

cd

/path/to/project

.git

$touch git-daemon- export -ok 该文件的存在，表明允许 Git 守护进程开放对该项目的匿名只读访问。 Gitosis 还能设定哪些项目允许放在 GitWeb 上显示。先打开 GitWeb 的配置文件 /etc/gitweb.conf，添加以下四行： 1 2 3 4$projects_list =

"/home/git/gitosis/projects.list"

;

$projectroot = "/home/git/repositories" ;$export_ok =

"git-daemon-export-ok"

;

@git_base_url_list = (

'git://gitserver'

);

1

2 3[repo iphone_project]

daemon =

yes

gitweb =

yes

4.10 Git 托管服务

//git

.or.cz

/gitwiki/GitHosting

GitHub 是目前为止最大的开源 Git 托管服务，并且还是少数同时提供公共代码和私有代码托管服务的站点之一，所以你可以在上面同时保存开源和商业代码。事实上，本书就是放在 GitHub 上合作编著的。（译注：本书的翻译也是放在 GitHub 上广泛协作的。）

GitHub

GitHub 和大多数的代码托管站点在处理项目命名空间的方式上略有不同。GitHub 的设计更侧重于用户，而不是完全基于项目。也就是说，如果我在 GitHub 上托管一个名为grit 的项目的话，它的地址不会是 github.com/grit，而是按在用户底下 github.com/shacon/grit （译注：本书作者 Scott Chacon 在 GitHub 上的用户名是shacon。）。不存在所谓某个项目的官方版本，所以假如第一作者放弃了某个项目，它可以无缝转移到其它用户的名下。

GitHub 同时也是一个向使用私有仓库的用户收取费用的商业公司，但任何人都可以方便快捷地申请到一个免费账户，并在上面托管数量不限的开源项目。接下来我们快速介绍一下 GitHub 的基本使用。

2 3$git init$ git add .

$git commit -m 'initial commit' 然后在这个本地仓库内把 GitHub 添加为远程仓库，并推送 master 分支上来： 1 2$ git remote add origin git@ github.com:testinguser

/iphone_project

.git

\$ git push origin master

Public Clone URL 是一个公开的，只读的 Git URL，任何人都可以通过它克隆该项目。可以随意散播这个 URL，比如发布到个人网站之类的地方等等。

Your Clone URL 是一个基于 SSH 协议的可读可写 URL，只有使用与上传的 SSH 公钥对应的密钥来连接时，才能通过它进行读写操作。其他用户访问该项目页面时只能看到之前那个公共的 URL，看不到这个私有的 URL。

GitHub 小结

4.11 小结

(*1 个评分，平均: 4.00*)