內容目录

上一个主题

5. 搭建Git服务器

下一个主题

5.2. 使用Git协议

本页

5.1. 使用HTTP协议

HTTP协议是版本控制工具普遍采用的协议,具有安全(HTTPS),方便(跨越防火墙)等优点。Git在 1.6.6版本之前对HTTP协议支持有限,是哑协议,访问效率低,但是在1.6.6之后,通过一个CGI实现了智能的HTTP协议支持。

5.1.1. 哑传输协议

所谓的哑传输协议(dumb protocol)就是在Git服务器和Git客户端的会话过程中只使用了相关协议提供的基本传输功能,而未针对Git的传输特点进行相关优化设计。采用哑协议,Git客户端和服务器间的通讯缺乏效率,用户使用时最直观的体验之一就是在操作过程没有进度提示,应用会一直停在那里直到整个通讯过程处理完毕。

但是哑传输协议配置起来却非常的简单。通过哑HTTP协议提供Git服务,基本上就是把包含Git版本库的目录通过HTTP服务器共享出来。下面的Apache配置片段就将整个目录/path/to/repos共享,然后就可以通过地址http://<服务器名称>/git/<版本库名称>访问该共享目录下所有的Git版本库。

Alias /git /path/to/repos

<Directory /path/to/repos>
    Options FollowSymLinks
    AllowOverride None
    Order Allow,Deny
    Allow from all
</Directory>

如果以为直接把现存的Git版本库移动到该目录下就可以直接用HTTP协议访问,可就大错特错了。因为哑协议下的Git版本库需要包含两个特殊的文件,并且这两个文件要随Git版本库更新。例如将一个包含提交数据的裸版本库复制到路径/path/to/repos/myrepos.git中,然后使用下面命令克隆该版本库(服务器名称为server),可能会看到如下错误:

$ git clone http://server/git/myrepos.git
正克隆到 'myrepos'...
fatal: repository 'http://server/git/myrepos.git/' not found

这时,您仅需在Git版本库目录下执行git update-server-info命令即可在Git版本库中创建哑协议需要的相关文件。

$ git update-server-info

然后该Git版本库即可正常访问了。如下:

$ git clone http://server/git/myrepos.git
正克隆到 'myrepos'...
检查连接... 完成。

从上面的介绍中可以看出在使用哑HTTP协议时,服务器端运行git update-server-info的重要性。运行该命令会产生或更新两个文件:

  • 文件.git/info/refs:该文件中包含了版本库中所有的引用列表,每一个引用都指向正确的SHA1哈希值。
  • 文件.git/objects/info/packs:该文件记录Git对象库中打包文件列表。

正是通过这两个文件,Git客户端才检索到版本库的引用列表和对象库的包列表,从而实现对版本库的读取操作。

为支持哑HTTP协议,必须在版本库更新后及时更新上述两个文件。幸好Git版本库的钩子脚本post-update可以帮助完成这个无聊的工作。在版本库的hooks目录下创建可执行脚本文件post-update,内容如下:

#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".

exec git update-server-info

哑HTTP协议也可以对版本库写操作提供支持,即允许客户端向服务器推送。这需要在Apache中为版本库设置WebDAV,并配置口令认证。例如下面的Apache配置片段:

Alias /git /path/to/repos

<Directory /path/to/repos>
    Options FollowSymLinks
    AllowOverride None
    Order Allow,Deny
    Allow from all

    # 启用 WebDAV
    DAV on

    # 简单口令认证
    AuthType Basic
    AuthName "Git Repository"
    AuthBasicProvider file
    # 该口令文件用 htpasswd 命令进行管理
    AuthUserFile /path/to/git-passwd
    Require valid-user

    # 基于主机IP的认证和基于口令的认证必须同时满足
    Satisfy All
</Directory>

配置了口令认证后,最好使用HTTPS协议访问服务器,以避免因为口令在网络中明文传输造成口令泄露。还可以在URL地址中加上用户名,以免在连接过程中的重复输入。下面的示例中以特定用户(如:jiangxin)身份访问版本库:

  • 如果版本库尚未克隆,使用如下命令克隆:

    $ git clone https://jiangxin@server/git/myrepo.git
    
  • 如果已经克隆了版本库,可以执行下面命令修改远程origin版本库的URL地址:

    $ cd myrepos
    $ git remote set-url origin https://jiangxin@server/git/myrepo.git
    $ git pull
    

第一次连接服务器,会提示输入口令。正确输入口令后,完成克隆或版本库的更新。试着在版本库中添加新的提交,然后执行git push推送到HTTP服务器。

如果推送失败,可能是WebDAV配置的问题,或者是版本库的文件、目录的权限不正确(需要能够被执行Apache进程的用户可以读写)。一个诊断Apache的小窍门是查看和跟踪Apache的配置文件[1]。如下:

$ tail -f /var/www/error.log

5.1.2. 智能HTTP协议

Git 1.6.6之后的版本,提供了针对HTTP协议的CGI程序git-http-backend,实现了智能的HTTP协议支持。同时也要求Git客户端的版本也不低于1.6.6。

查看文件git-http-backend的安装位置,可以用如下命令。

$ ls $(git --exec-path)/git-http-backend
/usr/lib/git-core/git-http-backend

在Apache2中为Git配置智能HTTP协议如下。

SetEnv GIT_PROJECT_ROOT /var/www/git
SetEnv GIT_HTTP_EXPORT_ALL
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

说明:

  • 第一行设置版本库的根目录为/var/www/git

  • 第二行设置所有版本库均可访问,无论是否在版本库中存在git-daemon-export-ok文件。

    缺省只有在版本库目录中存在文件git-daemon-export-ok,该版本库才可以访问。这个文件是git-daemon服务的一个特性。

  • 第三行,就是使用git-http-backendCGI脚本来相应客户端的请求。

    当用地址http://server/git/myrepo.git访问时,即由此CGI提供服务。

写操作授权

上面的配置只能提供版本库的读取服务,若想提供基于HTTP协议的写操作,必须添加认证的配置指令。当用户通过认证后,才能对版本库进行写操作。

下面的Apache配置,在前面配置的基础上,为Git写操作提供授权:

<LocationMatch "^/git/.*/git-receive-pack$">
  AuthType Basic
  AuthName "Git Access"
  AuthType Basic
  AuthBasicProvider file
  AuthUserFile /path/to/passwd/file
  ...
</LocationMatch>

读和写均需授权

如果需要对读操作也进行授权,那就更简单了,一个Location语句就够了。

<Location /git/private>
  AuthType Basic
  AuthName "Git Access"
  AuthType Basic
  AuthBasicProvider file
  AuthUserFile /path/to/passwd/file
  ...
</Location>

对静态文件的直接访问

如果对静态文件的访问不经过CGI程序,直接由Apache提供服务,会提高访问性能。

下面的设置对Git版本库中的objects目录下文件的访问,不经过CGI。

SetEnv GIT_PROJECT_ROOT /var/www/git

AliasMatch ^/git/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$          /var/www/git/$1
AliasMatch ^/git/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /var/www/git/$1
ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/

Git的智能HTTP服务彻底打破了以前哑传输协议给HTTP协议带来的恶劣印象,让HTTP协议成为Git服务的一个重要选项。但是在授权的管理上,智能HTTP服务仅仅依赖Apache自身的授权模型,相比后面要介绍的Gitosis和Gitolite,可管理性要弱的多。

  • 创建版本库只能在服务器端进行,不能通过远程客户端进行。
  • 配置认证和授权,也只能在服务器端进行,不能在客户端远程配置。
  • 版本库的写操作授权只能进行非零即壹的授权,不能针对分支甚至路径进行授权。

需要企业级的版本库管理,还需要考虑后面介绍的基于SSH协议的Gitolite或Gitosis。

5.1.3. Gitweb服务器

前面介绍的HTTP哑协议和智能HTTP协议服务架设,都可以用于提供Git版本库的读写服务,而本节介绍的Gitweb作为一个Web应用,只提供版本库的图形化浏览功能,而不能提供版本库本身的读写。

Gitweb是用Perl语言开发的CGI脚本,架设比较方便。Gitweb支持多个版本库,可以对版本库进行目录浏览(包括历史版本),可以查看文件内容,查看提交历史,提供搜索以及RSS feed支持。也可以提供目录文件的打包下载等。图27-1就是kernel.org上的Gitweb示例。

../images/gitweb-kernel-org_full.png

图27-1:Gitweb界面(kernel.org)

5.1.3.1. Gitweb安装

各个Linux平台都会提供Gitweb软件包。如在Debian/Ubuntu上安装Gitweb:

$ sudo aptitude install gitweb

安装文件列表:

  • 配置文件:/etc/gitweb.conf
  • Apache配置文件:/etc/apache2/conf.d/gitweb。默认设置用URL地址/gitweb来访问Gitweb服务。
  • CGI脚本:/usr/share/gitweb/index.cgi
  • 其他附属文件:/usr/share/gitweb/*,如:图片和css等。

5.1.3.2. Gitweb配置

编辑/etc/gitweb.conf,更改Gitweb的默认设置。

  • 版本库根目录的设置。

    $projectroot = "/var/cache/git";
    
  • 访问版本库多种协议的地址设置。

    Gitweb可以为每个版本库显示访问的协议地址。可以在列表中填入多个地址。

    @git_base_url_list = ("git://bj.ossxp.com/git", "ssh://git\@bj.ossxp.com", "http://bj.ossxp.com/git");
    
  • 增加 actions 菜单

    $feature{'actions'}{'default'} = [('git', 'git://bj.ossxp.com/git/%n', 'tree')];
    
  • 在首页上显示自定义信息

    设定自定义HTML的文件名。

    $home_text = "indextext.html";
    

    在CGI脚本所在的目录下,创建indextext.html文件。下面是我们公司(北京群英汇信息技术有限公司)内部gitweb自定义首页的内容。

    <html>
    <head>
    </head>
    <body>
    <h2>群英汇 - git 代码库</h2>
    <ul>
      <li>点击版本库,进入相应的版本库页面,有 URL 指向一个 git://... 的检出链接</li>
      <li>使用命令 git clone git://... 来克隆一个版本库</li>
      <li>对于名称中含有 <i>-gitsvn</i> 字样的代码库, 是用 git-svn 从 svn 代码库镜像而来的。对于它们的镜像,需要做进一步的工作。
        <ul>
          <li>要将 git 库的远程分支(.git/ref/remotes/*) 也同步到本地!
            <pre>
            $ git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
            $ git fetch
            </pre>
          </li>
          <li>如果需要克隆库和 Subversion 同步。用 git-svn 初始化代码库,并使得相关配置和源保持一致 </li>
        </ul>
      </li>
    </ul>
    </body>
    </html>
    
  • 版本库列表。

    缺省扫描版本库根目录,查找版本库。如果版本库非常多,这个查找过程可能很耗时,可以提供一个文本文件包含版本库的列表,会加速Gitweb显示初始化。

    # $projects_list = $projectroot;
    $projects_list = "/home/git/gitosis/projects.list";
    

    后面介绍的Gitosis和Gitolite都可以自动生成这么一个版本库列表,供Gitweb使用。

  • Gitweb菜单定制。

    • 在tree view文件的旁边显示追溯(blame)链接。

      $feature{'blame'}{'default'} = [1];
      $feature{'blame'}{'override'} = 1;
      
    • 可以通过版本库的配置文件config对版本库进行单独设置。

      下面的设置覆盖Gitweb的全局设置,不对该项目显示blame菜单。

      [gitweb]
      blame = 0
      
    • 为每个tree添加快照(snapshot)下载链接。

      $feature{'pickaxe'}{'default'} = [1];
      $feature{'pickaxe'}{'override'} = 1;
      $feature{'snapshot'}{'default'} = ['zip', 'tgz'];
      $feature{'snapshot'}{'override'} = 1;
      

5.1.3.3. 版本库的Gitweb相关设置

可以通过Git版本库下的配置文件,定制版本库在Gitweb下的显示。

  • 文件description

    提供一行简短的git库描述。显示在版本库列表中。

    也可以通过config配置文件中的gitweb.description进行设置。但是文件优先。

  • 文件README.html

    提供更详细的项目描述,显示在Gitweb项目页面中。

  • 文件cloneurl

    版本库访问的URL地址,一个一行。

  • 文件config

    通过[gitweb]小节的配置,覆盖Gitweb全局设置。

    • gitweb.owner用于显示版本库的创建者。
    • gitweb.description显示项目的简短描述,也可以通过description文件来提供。(文件优先)
    • gitweb.url显示项目的URL列表,也可以通过cloneurl文件来提供。(文件优先)
[1]Apache日志文件的位置参见Apache配置文件中ErrorLog指令的设定。