Gitolite 教程

如果不是要和他人協同開發,Git 根本就不需要架設服務器。Git 在本地可以直接使用本地版本庫的路徑完成 git 版本庫間的操作。

但是如果需要和他人分享版本庫、協作開發,就需要能夠通過特定的網絡協議操作 Git 庫。

Git 支持的協議很豐富,架設服務器的選擇也很多,不同的方案有着各自的優缺點。

  HTTP GIT-DAEMON SSH GITOSIS, GITOLITE
服務架設難易度 簡單 中等 簡單 複雜
匿名讀取 支持 支持 否* 否*
身份認證 支持 支持 支持
版本庫寫操作 支持 支持 支持
企業級授權支持 支持
是否支持遠程建庫 支持

注:

  • SSH 協議和基於 SSH 的 Gitolite 等可以通過空口令帳號實現匿名訪問。

1   SSH 協議

SSH 協議用於爲 Git 提供遠程讀寫操作,是遠程寫操作的標準服務,在智能HTTP協議出現之前,甚至是寫操作的唯一標準服務。

對於擁有 SHELL 權限的 SSH 登錄帳號,可以直接用下面的 git 命令訪問,例如:

$ git clone <username>@<server>:/path/to/repo.git

說明:

  • <username> 是服務器 <server> 上的用戶帳號。
  • /path/to/repo.git 是服務器中版本庫的絕對路徑。若用相對路徑則相對於 username 用戶的主目錄而言。
  • 如果採用口令認證,不能像 HTTPS 協議那樣可以在 URL 中同時給出登錄名和口令,必須每次連接時輸入。
  • 如果採用公鑰認證,則無須輸入口令。

SSH 協議來實現 Git 服務,有如下方式:

  • 其一是用標準的 ssh 帳號訪問版本庫。即用戶帳號可以直接登錄到服務器,獲得 shell。

  • 另外的方式是,所有用戶都使用同一個專用的 SSH 帳號訪問版本庫。各個用戶通過公鑰認證的方式用此專用 SSH 帳號訪問版本庫。而用戶在連接時使用的不同的公鑰可以用於區分不同的用戶身份。

    Gitosis 和 Gitolite 就是實現該方式的兩個服務器軟件。

標準SSH帳號和專用SSH帳號的區別在於:

  標準SSH GITOSIS/GITOLITE
帳號 每個用戶一個帳號 所有用戶共用同一個帳號
認證方式 口令或公鑰認證 公鑰認證
用戶是否能直接登錄 shell
安全性
管理員是否需要 shell
版本庫路徑 相對路徑或絕對路徑 相對路徑
授權方式 操作系統中用戶組和目錄權限 通過配置文件授權
對分支進行寫授權 Gitolite
對路徑進行寫授權 Gitolite
架設難易度 簡單 複雜

實際上,標準SSH,也可以用公鑰認證的方式實現所有用戶共用同一個帳號。不過這類似於把一個公共帳號的登錄口令同時告訴給多個人。

  • 在服務器端(server)創建一個公共帳號,例如 anonymous 。

  • 管理員收集需要訪問 git 服務的用戶公鑰。如: user1.pubuser2.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 服務器軟件的基礎。

1.1   SSH 公鑰認證

關於公鑰認證的原理,維基百科上的這個條目是一個很好的起點: 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

說明:

  • 該命令會提示輸入用戶 user 在 server 上的SSH登錄口令。
  • 當此命令執行成功後,再以 user 用戶登錄 server 遠程主機時,不必輸入口令直接登錄。
  • 該命令實際上將 .ssh/id_rsa.pub 公鑰文件追加到遠程主機 server 的 user 主目錄下的 .ssh/authorized_keys 文件中。

檢查公鑰認證是否生效,運行SSH到遠程主機,正常的話應該直接登錄成功。如果要求輸入口令則表明公鑰認證配置存在問題。如果SSH服務存在問題,可以通過查看服務器端的 /var/log/auth.log 進行診斷。

1.2   SSH 主機別名

在實際應用中,有時需要使用多套公鑰/私鑰對,例如:

  • 使用缺省的公鑰訪問 git 帳號,獲取 shell,進行管理員維護工作。
  • 使用單獨創建的公鑰訪問 git 帳號,執行 git 命令。
  • 訪問 github(免費的Git服務託管商)採用其他公鑰。

如何創建指定名稱的公鑰/私鑰對呢?還是用 ssh-keygen 命令,如下:

$ ssh-keygen -f ~/.ssh/<filename>

注:

  • 將 <filename> 替換爲有意義的名稱。
  • 會在 ~/.ssh 目錄下創建指定的公鑰/私鑰對。 文件 <filename> 是私鑰,文件 <filename>.pub 是公鑰。

將新生成的公鑰添加到遠程主機的 .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

含義爲:

  • 登錄的 SSH 主機爲 bj.ossxp.com 。
  • 登錄時使用的用戶名爲 git 。
  • 認證時使用的公鑰文件爲 ~/.ssh/jiangxin.pub 。

2   Gitolite 服務架設

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 安裝在服務器( 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 。

2.1   安裝 Gitolite

Gitolite 要求 git 的版本必須是 1.6.2 或以上的版本,並且服務器要提供 SSH 服務。下面是 Gitolite 的安裝過程。

2.1.1   服務器端創建專用帳號

安裝 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 服務軟件了。

2.1.2   Gitolite 的安裝/升級

本節的名字稱爲安裝/升級,是因爲 Gitolite 的安裝和升級可以採用下列同樣的步驟。

Gitolite 安裝可以在客戶端執行,而不需要在服務器端操作,非常方便。安裝 Gitolite 的前提是:

  • 已經在服務器端創建了專有帳號,如 git 。
  • 管理員能夠以 git 用戶身份通過公鑰認證,無口令方式登錄方式登錄服務器。

安裝和升級都可以按照下面的步驟進行:

  • 使用 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" (不帶引號)。

  • 至此完成安裝。

2.1.3   關於 SSH 主機別名

在安裝過程中,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
    

2.1.4   其他的安裝方法

上面介紹的是在客戶端遠程安裝 Gitolite,是最常用和推薦的方法。當然還可以直接在服務器上安裝。

  1. 首先也要在服務器端先創建一個專用的帳號,如: git 。
$ sudo adduser --system --shell /bin/bash --group git
  1. 將管理員公鑰複製到服務器上。

管理員在客戶端執行下面的命令:

$ scp ~/.ssh/id_rsa.pub server:/tmp/admin.pub
  1. 服務器端安裝 Gitolite。

推薦採用源碼方式安裝,因爲如果以平臺自帶軟件包模式安裝 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 gitolite
    

    Redhat 則使用 yum 命令安裝。

  1. 在服務器端以專用帳號執行安裝腳本。

例如服務器端的專用帳號爲 git。

$ sudo su - git
$ gl-setup /tmp/admin.pub
  1. 管理員在客戶端,克隆 gitolite-admin 庫
$ git clone git@server:gitolite-admin

升級 Gitolite:

  • 只需要執行上面的第3個步驟即可完成升級。
  • 如果修改或增加了新的了鉤子腳本,還需要重新執行第4個步驟。
  • Gitolite 升級有可能要求修改配置文件: ~/.gitolite.rc 。

2.2   管理 Gitolite

2.2.1   管理員克隆 gitolite-admin 管理庫

當 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

      缺省設置的測試版本庫,設置爲任何人都可以讀寫以及強制更新。

2.2.2   增加新用戶

增加新用戶,就是允許新用戶能夠通過其公鑰訪問 Git 服務。只要將新用戶的公鑰添加到 gitolite-admin 版本庫的 keydir 目錄下,即完成新用戶的添加。

  • 管理員從用戶獲取公鑰,並將公鑰按照 username.pub 格式進行重命名。

    用戶可以通過郵件或者其他方式將公鑰傳遞給管理員,切記不要將私鑰誤傳給管理員。如果發生私鑰泄漏,馬上重新生成新的公鑰/私鑰對,並將新的公鑰傳遞給管理員,並申請將舊的公鑰作廢。

    用戶從不同的客戶端主機訪問有着不同的公鑰,如果希望使用同一個用戶名進行授權,可以按照[email protected] 方式命名公鑰文件,和名爲 username@pub 的公鑰指向同一個用戶 username 。

    Gitolite 也支持郵件地址格式的公鑰,即形如 [email protected] 的公鑰。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 鉤子腳本的輸出。其中的警告是說新添加的三個用戶在授權文件中沒有被引用。接下來我們便看看如何修改授權文件,以及如何爲用戶添加授權。

2.2.3   更改授權

新用戶添加完畢,可能需要重新進行授權。更改授權的方法也非常簡單,即修改 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
    

2.3   Gitolite 授權詳解

2.3.1   授權文件的基本語法

下面我們看一個不那麼簡單的授權文件:

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 分支。 (僅此分支,精確匹配)。

2.3.2   定義用戶組和版本庫組

在 conf/gitolite.conf 授權文件中,可以定義用戶組或者版本庫組。組名稱以 @ 字符開頭,可以包含一個或多個成員。成員之間用空格分開。

  • 例如定義管理員組:

    @admin = jiangxin wangsheng
    
  • 組可以嵌套:

    @staff = @admin @engineers tester1
    
  • 除了作爲用戶組外,同樣語法也適用於版本庫組。

    版本庫組和用戶組的定義沒有任何區別,只是在版本庫授權指令中處於不同的位置。即位於授權指令中的版本庫位置則代表版本庫組,位於授權指令中的用戶位置則代表用戶組。

2.3.3   版本庫ACL

一個版本庫可以包含多條授權指令,這些授權指令組成了一個版本庫的權限控制列表(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 的含義是允許刪除和正則引用匹配的引用(分支或里程碑等)。

2.3.4   Gitolite 授權機制

Gitolite 的授權實際分爲兩個階段,第一個階段稱爲前Git階段,即在 Git 命令執行前,由 SSH 鏈接觸發的 gl-auth-command 命令執行的授權檢查。包括:

  • 版本庫的讀。

    用戶必須擁有版本庫至少一個分支的下列權限之一: RRW, 或 RW+ ,則整個版本庫包含所有分支對用戶均可讀。

    而版本庫分支實際上在這個階段獲取不到,即版本庫的讀取不能按照分支授權,只能是版本庫的整體授權。

  • 版本庫的寫。

    版本庫的寫授權,則要在兩個階段分別進行檢查。第一階段的檢查是看用戶是否擁有下列權限之一: RWRW+ 或者C 授權。

    第二個階段檢查分支以及是否擁有強制更新。具體見後面的描述。

  • 版本庫的創建。

    僅對正則表達式定義的通配符版本庫有效。即擁有 C 授權的用戶,可以創建和對應正則表達式匹配的版本庫。同時該用戶也擁有對版本庫的讀寫權限。

對授權的第二個階段的檢查,實際上是通過 update 鉤子腳本進行的。

  • 因爲版本庫的讀操作不執行 update 鉤子,所以讀操作只在授權的第一個階段(前Git階段)進行檢查,授權的第二個階段對版本庫的讀授權無任何影響。
  • 鉤子腳本 update 針對 PUSH 操作的各個分支進行逐一檢查,因此第二個階段可以進行鍼對分支寫操作的精細授權。
  • 在這個階段也可以獲取到要更新的新的和老的 ref 的 SHA 摘要,因此也可以進行是否有回滾(rewind)的發生,即是否允許強制更新,還可以對分支的創建和刪除進行授權檢測。
  • 基於路徑的寫授權,也是在這個階段進行的。

2.4   版本庫授權案例

Gitolite 的授權非常強大也非常複雜,因此從版本庫授權的實際案例來學習非常行之有效。

2.4.1   對整個版本庫進行授權

授權文件如下:

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 只有讀操作權限,而沒有寫操作。

2.4.2   通配符版本庫的授權

授權文件如下:

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 用戶沒有任何權限,不能讀寫。

  • 和之前的例子相同的是:

    • 用戶 test1 對版本庫具有寫的權限。
    • 禁用指令,讓用戶 badboy 對版本庫只具有讀操作的權限。
  • 版本庫的創建者還可以使用 setperms 命令爲版本庫添加授權。具體用法參見下面的示例。

2.4.3   用戶自己的版本庫空間

授權文件如下:

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
    

2.4.4   對引用的授權:傳統模式

傳統的引用授權,指的是授權指令中不包含 RWCRWDRWCDRW+CRW+DRW+CD 授權關鍵字,只採用 RW,RW+ 的傳統授權關鍵字。

在只使用傳統的授權關鍵字的情況下,有如下注意事項:

  • rewind 必須擁有 + 的授權。
  • 創建引用必須擁有 W 的授權。
  • 刪除引用必須擁有 + 的授權。
  • 如果沒有在授權指令中提供引用相關的參數,相當於提供 refs/.* 作爲引用的參數,意味着對所有引用均有效。

授權文件:

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 授權指令,所以不涉及到分支的寫授權。

2.4.5   對引用的授權:擴展模式

擴展模式的引用授權,指的是該版本庫的授權指令出現了下列授權關鍵字中的一個或多個: RWCRWDRWCD,RW+CRW+DRW+CD 。

  • rewind 必須擁有 + 的授權。
  • 創建引用必須擁有 C 的授權。
  • 刪除引用必須擁有 D 的授權。

授權文件:

repo test/repo2
    RW+C = @administrators
    RW+  = @dev
    RW   = @test

repo test/repo3
    RW+CD = @administrators
    RW+C  = @dev
    RW    = @test

說明:

對於版本庫 test/repo2.git :

  • 用戶組 @administrators 中的用戶,具有創建和刪除引用的權限,並且能強制 PUSH。
  • 用戶組 @dev 中的用戶,不能創建引用,但可以刪除引用,以及可以強制 PUSH。
  • 用戶組 @test 中的用戶,可以 PUSH 到任何引用,但是不能創建引用,不能刪除引用,也不能強制 PUSH。

對於版本庫 test/repo3.git :

  • 用戶組 @administrators 中的用戶,具有創建和刪除引用的權限,並且能強制 PUSH。
  • 用戶組 @dev 中的用戶,可以創建引用,並能夠強制 PUSH,但不能刪除引用,
  • 用戶組 @test 中的用戶,可以 PUSH 到任何引用,但是不能創建引用,不能刪除引用,也不能強制 PUSH。

2.4.6   對引用的授權:禁用規則的使用

授權文件:

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

說明:

  • 用戶 jiangxin 可以寫任何里程碑,包括以 v 加上數字開頭的里程碑。
  • 用戶 dev1, dev2 和 @others 組,只能寫除了以 v 加上數字開頭之外的其他里程碑。
  • 其中以 - 開頭的授權指令建立禁用規則。禁用規則只在授權的第二階段有效,因此不能對用戶的讀取進行限制!

2.4.7   用戶分支

和創建用戶空間(使用了 CREATOR 關鍵字)的版本庫類似,還可以在一個版本庫內,允許管理自己名字空間( USER關鍵字)下的分支。在正則引用的參數中出現的 USER 關鍵字會被替換爲用戶的 ID。

授權文件:

repo test/repo4
    RW+CD = @administrators
    RW+CD refs/personal/USER/  = @all
    RW+    master = @dev

說明:

  • 用戶組 @administrators 中的用戶,對所有引用具有創建和刪除引用的權限,並且能強制 PUSH。
  • 所有用戶都可以在 refs/personal/<userid>/ (自己的名字空間)下創建、刪除引用。但是不能修改其他人的引用。
  • 用戶組 @dev 中的用戶,對 master 分支具有讀寫和強制更新的權限,但是不能刪除。

2.4.8   對路徑的寫授權

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

說明:

  • 第2行,初級程序員 @junior_devs 和高級程序員 @senior_devs 可以對版本庫 foo 進行讀寫操作。
  • 第4行,設定高級程序員 @senior_devs 對所有文件( NAME/ )進行寫操作。
  • 第5行和第6行,設定初級程序員 @junior_devs 對除了根目錄的 Makefile 文件外的其他文件 ,具有寫權限。

2.5   創建新版本庫

Gitolite 維護的版本庫位於安裝用戶主目錄下的 repositories 目錄中,即如果安裝用戶爲 git ,則版本庫都創建在 /home/git/repositories 目錄之下。可以通過配置文件 .gitolite.rc 修改缺省的版本庫的根路徑。

$REPO_BASE="repositories";

有多種創建版本庫的方式。一種是在授權文件中用 repo 指令設置版本庫(未使用正則表達式的版本庫)的授權,當對 gitolite-admin 版本庫執行 git push 操作,自動在服務端創建新的版本庫。另外一種方式是在授權文件中用正則表達式定義的版本庫,不會即時創建,而是被授權的用戶在遠程創建後PUSH到服務器上完成創建。

注意,在授權文件中創建的版本庫名稱不要帶 .git 後綴,在創建版本庫過程中會自動在版本庫後面追加 .git 後綴。

2.5.1   在配置文件中出現的版本庫,即時生成

我們嘗試在授權文件 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

還有一種版本庫語法,是用正則表達式定義的版本庫,這類版本庫因爲所指的版本庫並不確定,因此不會自動創建。

2.5.2   通配符版本庫,管理員通過push創建

通配符版本庫是用正則表達式語法定義的版本庫,所指的非某一個版本庫而是和名稱相符的一組版本庫。首先要想使用通配符版本庫,需要在服務器端安裝用戶(如 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 一個不存在的版本庫,會報錯退出。

2.5.3   直接在服務器端創建

當版本庫的數量很多的時候,在服務器端直接通過 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

除了鉤子腳本要注意以外,還要確保服務器端版本庫目錄的權限和屬主。

2.6   對 Gitolite 的改進

筆者對 Gitolite 進行擴展和改進,涉及到的內容主要包括:

  • 通配符版本庫的創建方式和授權。

    原來的實現是克隆即創建(克隆者需要被授予 C 的權限)。同時還要通過另外的授權語句爲用戶設置 RW 權限,否則創建者沒有讀和寫權限。

    新的實現是通過 PUSH 創建版本庫(PUSH 者需要被授予 C 權限)。不必再爲創建者賦予 RW 等權限,創建者自動具有對版本庫最高的授權。

  • 避免通配符版本庫誤判。

    通配符版本庫誤判,會導致在服務器端創建錯誤的版本庫。新的設計還可以在通配符版本庫的正則表達式前或後添加 ^或 $ 字符,而不會造成授權文件編輯錯誤。

  • 改變缺省配置。

    缺省安裝即支持通配符版本庫。

  • 版本庫重定向。

    Gitosis 的一個很重要的功能:版本庫名稱重定向,沒有在 Gitolite 中實現。我們爲 Gitolite 增加了這個功能。

    在Git服務器架設的開始,版本庫的命名可能非常隨意,例如 redmine 的版本庫直接放在根下,例如: redmine-0.9.x.gitredmine-1.0.x.git, ... 當 redmine 項目越來越複雜,可能就需要將其放在子目錄下進行管理,例如放到ossxp/redmine/ 目錄下。

    只需要在 Gitolite 的授權文件中添加下面一行 map 語句,就可以實現版本庫名稱重定向。使用舊的地址的用戶不必重新檢出,可以繼續使用。

    map (redmine.*) = ossxp/redmine/$1
    

2.7   Gitolite 功能拓展

2.7.1   版本庫鏡像

Git 版本庫控制系統往往並不需要設計特別的容災備份,因爲每一個Git用戶就是一個備份。但是下面的情況,就很有必要考慮容災了。

  • Git 版本庫的使用者很少(每個庫可能只有一個用戶)。
  • 版本庫檢出只限制在辦公區並且服務器也在辦公區內(所有雞蛋在一個籃子裏)。
  • Git 版本庫採用集中式的應用模型,需要建立雙機熱備(以便在故障出現時,實現快速的服務器切換)。

Gitolite 提供了服務器間版本庫同步的設置。原理是:

  • 主服務器通過配置文件 ~/.gitolite.rc 中的變量 $ENV{GL_SLAVES} 設置鏡像服務器的地址。
  • 從服務器通過配置文件 ~/.gitolite.rc 中的變量 $GL_SLAVE_MODE 設置從服務器模式。
  • 從主服務器端運行腳本 gl-mirror-sync 可以實現批量的版本庫鏡像。
  • 主服務器的每一個版本庫都配置 post-receive 鉤子,一旦有提交,即時同步到鏡像版本庫。

在多個服務器之間設置 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。

2.7.2   Gitweb 和 Gitdaemon 支持

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"
  • 第1行,爲名爲 reponame 的版本庫設定描述。
  • 第1行,同時設定版本庫的屬主名稱,和一行版本庫描述。

對於通配符版本庫,使用這種方法則很不現實。Gitolite 提供了 SSH 子命令,供版本庫的創建者使用。

$ ssh git@server setdesc description...
$ ssh git@server getdesc
  • 第一條指令用於設置版本庫的描述信息。
  • 第二條指令顯示版本庫的描述信息。

至於生成 Gitweb 所用的項目列表文件,缺省創建在用戶主目錄下的 projects.list 文件中。對於所有啓用 Gitweb 的 [repo] 小節設定的版本庫,或者通過版本庫描述隱式聲明的版本庫加入到版本庫列表中。

2.7.3   其他功能拓展和參考

Gitolite 源碼的 doc 目錄包含用 markdown 標記語言編寫的手冊,可以直接在 Github 上查看。也可以使用markdown 的文檔編輯工具將 .mkd 文檔轉換爲 html 文檔。轉換工具很多,有:rdiscount, Bluefeather, Maruku, BlueCloth2 等等。

在這些參考文檔中,你可以發現 Gitolite 包含的更多的小功能或者祕籍,包括:

  • 版本庫設置。

    在授權文件通過 git config 指令爲版本庫進行附加的設置。例如:

    repo gitolite
        config hooks.mailinglist = [email protected]
        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 的版本庫進行全局的授權。

    但是不能在 @all 版本庫中對 @all 用戶組進行授權。

  • 版本庫非常或者用戶非常之多(幾千個)的時候,需要使用 大配置文件 模式。

    因爲 Gitolite 的授權文件要先編譯才能生效,而編譯文件的大小是和用戶以及版本庫數量的乘積成正比的。選擇大配置文件模式,則不對用戶組和版本庫組進行擴展。

    參見: doc/big-config.mkd 。

  • 授權文件支持包含語句,可以將授權文件分成多個獨立的單元。

  • 執行外部命令,如 rsync。

  • Subversion 版本庫支持。

    如果在同一個服務器上以 svn+ssh 方式運行 Subversion 服務器,可以使用同一套公鑰,同時爲用戶提供 Git 和 Subversion 服務。

  • HTTP 口令文件維護。通過 htpasswd SSH 子命令實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章