Git詳解之四 服務器上的Git

服務器上的 Git

到目前爲止,你應該已經學會了使用 Git 來完成日常工作。然而,如果想與他人合作,還需要一個遠程的 Git 倉庫。儘管技術上可以從個人的倉庫裏推送和拉取修改內容,但我們不鼓勵這樣做,因爲一不留心就很容易弄混其他人的進度。另外,你也一定希望合作者們即使在 自己不開機的時候也能從倉庫獲取數據 — 擁有一個更穩定的公共倉庫十分有用。因此,更好的合作方式是建立一個大家都可以訪問的共享倉庫,從那裏推送和拉取數據。我們將把這個倉庫稱爲 “Git 服務器”;代理一個 Git 倉庫只需要花費很少的資源,幾乎從不需要整個服務器來支持它的運行。

架設一臺 Git 服務器並不難。第一步是選擇與服務器通訊的協議。本章第一節將介紹可用的協議以及各自優缺點。下面一節將介紹一些針對各個協議典型的設置以及如何在服務器 上實施。最後,如果你不介意在他人服務器上保存你的代碼,又想免去自己架設和維護服務器的麻煩,倒可以試試我們介紹的幾個倉庫託管服務。

如果你對架設自己的服務器沒興趣,可以跳到本章最後一節去看看如何申請一個代碼託管服務的賬戶然後繼續下一章,我們會在那裏討論分佈式源碼控制環境的林林總總。

遠程倉庫通常只是一個_裸倉庫(bare repository)_ — 即一個沒有當前工作目錄的倉庫。因爲該倉庫只是一個合作媒介,所以不需要從硬盤上取出最新版本的快照;倉庫裏存放的僅僅是 Git 的數據。簡單地說,裸倉庫就是你工作目錄中.git子目錄內的內容。

 

 

4.1  協議

Git 可以使用四種主要的協議來傳輸數據:本地傳輸,SSH 協議,Git 協議和 HTTP 協議。下面分別介紹一下哪些情形應該使用(或避免使用)這些協議。

值得注意的是,除了 HTTP 協議外,其他所有協議都要求在服務器端安裝並運行 Git。

本地協議

最基本的就是_本地協議(Local protocol)_,所謂的遠程倉庫在該協議中的表示,就是硬盤上的另一個目錄。這常見於團隊每一個成員都對一個共享的文件系統(例如 NFS)擁有訪問權,或者比較少見的多人共用同一臺電腦的情況。後面一種情況並不安全,因爲所有代碼倉庫實例都儲存在同一臺電腦裏,增加了災難性數據損失 的可能性。

如果你使用一個共享的文件系統,就可以在一個本地文件系統中克隆倉庫,推送和獲取。克隆的時候只需要將遠程倉庫的路徑作爲 URL 使用,比如下面這樣:

$ git clone /opt/git/project.git

或者這樣:

$ git clone file:///opt/git/project.git

如果在 URL 開頭明確使用 file:// ,那麼 Git 會以一種略微不同的方式運行。如果你只給出路徑,Git 會嘗試使用硬鏈接或直接複製它所需要的文件。如果使用了file:// ,Git 會調用它平時通過網絡來傳輸數據的工序,而這種方式的效率相對較低。使用 file:// 前綴的主要原因是當你需要一個不包含無關引用或對象的乾淨倉庫副本的時候 — 一般指從其他版本控制系統導入的,或類似情形(參見第 9 章的維護任務)。我們這裏僅僅使用普通路徑,這樣更快。

要添加一個本地倉庫作爲現有 Git 項目的遠程倉庫,可以這樣做:

$ git remote add local_proj /opt/git/project.git

然後就可以像在網絡上一樣向這個遠程倉庫推送和獲取數據了。

優點

基於文件倉庫的優點在於它的簡單,同時保留了現存文件的權限和網絡訪問權限。如果你的團隊已經有一個全體共享的文件系統,建立倉庫就十分容易了。你 只需把一份裸倉庫的副本放在大家都能訪問的地方,然後像對其他共享目錄一樣設置讀寫權限就可以了。我們將在下一節“在服務器上部署 Git ”中討論如何導出一個裸倉庫的副本。

這也是從別人工作目錄中獲取工作成果的快捷方法。假如你和你的同事在一個項目中合作,他們想讓你檢出一些東西的時候,運行類似 git pull /home/john/project 通常會比他們推送到服務器,而你再從服務器獲取簡單得多。

缺點

這種方法的缺點是,與基本的網絡連接訪問相比,難以控制從不同位置來的訪問權限。如果你想從家裏的筆記本電腦上推送,就要先掛載遠程硬盤,這和基於網絡連接的訪問相比更加困難和緩慢。

另一個很重要的問題是該方法不一定就是最快的,尤其是對於共享掛載的文件系統。本地倉庫只有在你對數據訪問速度快的時候才快。在同一個服務器上,如果二者同時允許 Git 訪問本地硬盤,通過 NFS 訪問倉庫通常會比 SSH 慢。

SSH 協議

Git 使用的傳輸協議中最常見的可能就是 SSH 了。這是因爲大多數環境已經支持通過 SSH 對服務器的訪問 — 即便還沒有,架設起來也很容易。SSH 也是唯一一個同時支持讀寫操作的網絡協議。另外兩個網絡協議(HTTP 和 Git)通常都是隻讀的,所以雖然二者對大多數人都可用,但執行寫操作時還是需要 SSH。SSH 同時也是一個驗證授權的網絡協議;而因爲其普遍性,一般架設和使用都很容易。

通過 SSH 克隆一個 Git 倉庫,你可以像下面這樣給出 ssh:// 的 URL:

$ git clone ssh://user@server:project.git

或者不指明某個協議 — 這時 Git 會默認使用 SSH :

$ 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 對倉庫進行讀取:

$ 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

這樣就可以了。Git 附帶的 post-update 掛鉤會默認運行合適的命令(git update-server-info)來確保通過 HTTP 的獲取和克隆正常工作。這條命令在你用 SSH 向倉庫推送內容時運行;之後,其他人就可以用下面的命令來克隆倉庫:

$ 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 結尾,像這樣:

$ git clone --bare my_project my_project.git Initialized empty Git repository in /opt/projects/my_project.git/

該命令的輸出或許會讓人有些不解。其實 clone 操作基本上相當於 git init 加 git fetch,所以這裏出現的其實是git init 的輸出,先由它建立一個空目錄,而之後傳輸數據對象的操作並無任何輸出,只是悄悄在幕後執行。現在my_project.git 目錄中已經有了一份 Git 目錄數據的副本。

整體上的效果大致相當於:

$ cp -Rf my_project/.git my_project.git

但在配置文件中有若干小改動,不過對用戶來講,使用方式都一樣,不會有什麼影響。它僅取出 Git 倉庫的必要原始數據,存放在該目錄中,而不會另外創建工作目錄。

把裸倉庫移到服務器上

有了裸倉庫的副本後,剩下的就是把它放到服務器上並設定相關協議。假設一個域名爲 git.example.com 的服務器已經架設好,並可以通過 SSH 訪問,我們打算把所有 Git 倉庫儲存在/opt/git 目錄下。只要把裸倉庫複製過去:

$ scp -r my_project.git [email protected]:/opt/git

現在,所有對該服務器有 SSH 訪問權限,並可讀取 /opt/git 目錄的用戶都可以用下面的命令克隆該項目:

$ git clone [email protected]:/opt/git/my_project.git

如果某個 SSH 用戶對 /opt/git/my_project.git 目錄有寫權限,那他就有推送權限。如果到該項目目錄中運行git init 命令,並加上 --shared 選項,那麼 Git 會自動修改該倉庫目錄的組權限爲可寫(譯註:實際上--shared 可以指定其他行爲,只是默認爲將組權限改爲可寫並執行 g+sx,所以最後會得到 rws。)。

$ ssh [email protected] $ cd /opt/git/my_project.git $ git init --bare --shared

由此可見,根據現有的 Git 倉庫創建一個裸倉庫,然後把它放上你和同事都有 SSH 訪問權的服務器是多麼容易。現在已經可以開始在同一項目上密切合作了。

值得注意的是,這的的確確是架設一個少數人具有連接權的 Git 服務的全部 — 只要在服務器上加入可以用 SSH 登錄的帳號,然後把裸倉庫放在大家都有讀寫權限的地方。一切都準備停當,無需更多。

下面的幾節中,你會了解如何擴展到更復雜的設定。這些內容包含如何避免爲每一個用戶建立一個賬戶,給倉庫添加公共讀取權限,架設網頁界面,使用 Gitosis 工具等等。然而,只是和幾個人在一個不公開的項目上合作的話,僅僅是一個 SSH 服務器和裸倉庫就足夠了,記住這點就可以了。

小型安裝

如果設備較少或者你只想在小型開發團隊裏嘗試 Git ,那麼一切都很簡單。架設 Git 服務最複雜的地方在於賬戶管理。如果需要倉庫對特定的用戶可讀,而給另一部分用戶讀寫權限,那麼訪問和許可的安排就比較困難。

SSH 連接

如果已經有了一個所有開發成員都可以用 SSH 訪問的服務器,架設第一個服務器將變得異常簡單,幾乎什麼都不用做(正如上節中介紹的那樣)。如果需要對倉庫進行更復雜的訪問控制,只要使用服務器操作系統的本地文件訪問許可機制就行了。

如果需要團隊裏的每個人都對倉庫有寫權限,又不能給每個人在服務器上建立賬戶,那麼提供 SSH 連接就是唯一的選擇了。我們假設用來共享倉庫的服務器已經安裝了 SSH 服務,而且你通過它訪問服務器。

有好幾個辦法可以讓團隊的每個人都有訪問權。第一個辦法是給每個人建立一個賬戶,直截了當但略過繁瑣。反覆運行adduser 並給所有人設定臨時密碼可不是好玩的。

第二個辦法是在主機上建立一個 git 賬戶,讓每個需要寫權限的人發送一個 SSH 公鑰,然後將其加入 git 賬戶的~/.ssh/authorized_keys 文件。這樣一來,所有人都將通過 git 賬戶訪問主機。這絲毫不會影響提交的數據 — 訪問主機用的身份不會影響提交對象的提交者信息。

另一個辦法是讓 SSH 服務器通過某個 LDAP 服務,或者其他已經設定好的集中授權機制,來進行授權。只要每個人都能獲得主機的 shell 訪問權,任何可用的 SSH 授權機制都能達到相同效果。

 

4.3  生成 SSH 公鑰

大多數 Git 服務器都會選擇使用 SSH 公鑰來進行授權。系統中的每個用戶都必須提供一個公鑰用於授權,沒有的話就要生成一個。生成公鑰的過程在所有操作系統上都差不多。首先先確認一下是否已經有一個公鑰了。SSH 公鑰默認儲存在賬戶的主目錄下的~/.ssh 目錄。進去看看:

$ cd ~/.ssh $ ls authorized_keys2 id_dsa known_hosts config id_dsa.pub

關鍵是看有沒有用 something 和 something.pub 來命名的一對文件,這個 something 通常就是 id_dsa 或id_rsa。有 .pub 後綴的文件就是公鑰,另一個文件則是密鑰。假如沒有這些文件,或者乾脆連.ssh 目錄都沒有,可以用 ssh-keygen 來創建。該程序在 Linux/Mac 系統上由 SSH 包提供,而在 Windows 上則包含在 MSysGit 包裏:

$ 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 [email protected]

它先要求你確認保存公鑰的位置(.ssh/id_rsa),然後它會讓你重複一個密碼兩次,如果不想在使用公鑰的時候輸入密碼,可以留空。

現在,所有做過這一步的用戶都得把它們的公鑰給你或者 Git 服務器的管理員(假設 SSH 服務被設定爲使用公鑰機制)。他們只需要複製 .pub 文件的內容然後發郵件給管理員。公鑰的樣子大致如下:

$ 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 NrRFi9wrf+M7Q== [email protected]

關於在多個操作系統上設立相同 SSH 公鑰的教程,可以查閱 GitHub 上有關 SSH 公鑰的嚮導:http://github.com/guides/providing-your-ssh-key

 

4.4  架設服務器

現在我們過一邊服務器端架設 SSH 訪問的流程。本例將使用 authorized_keys 方法來給用戶授權。我們還將假定使用類似 Ubuntu 這樣的標準 Linux 發行版。首先,創建一個名爲 ‘git’ 的用戶,併爲其創建一個.ssh 目錄。

$ sudo adduser git $ su git $ cd $ mkdir .ssh

接下來,把開發者的 SSH 公鑰添加到這個用戶的 authorized_keys 文件中。假設你通過電郵收到了幾個公鑰並存到了臨時文件裏。重複一下,公鑰大致看起來是這個樣子:

$ 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 文件尾部即可:

$ 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

現在可以用 --bare 選項運行 git init 來建立一個裸倉庫,這會初始化一個不包含工作目錄的倉庫。

$ cd /opt/git $ mkdir project.git $ cd project.git $ git --bare init

這時,Join,Josie 或者 Jessica 就可以把它加爲遠程倉庫,推送一個分支,從而把第一個版本的項目文件上傳到倉庫裏了。值得注意的是,每次添加一個新項目都需要通過 shell 登入主機並創建一個裸倉庫目錄。我們不妨以gitserver 作爲git 用戶及項目倉庫所在的主機名。如果在網絡內部運行該主機,並在 DNS 中設定 gitserver 指向該主機,那麼以下這些命令都是可用的:

# 在 John 的電腦上 $ 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

這樣,其他人的克隆和推送也一樣變得很簡單:

$ git clone git@gitserver:/opt/git/project.git $ vim README $ git commit -am 'fix for the README file' $ git push origin master

用這個方法可以很快捷地爲少數幾個開發者架設一個可讀寫的 Git 服務。

作爲一個額外的防範措施,你可以用 Git 自帶的 git-shell 工具限制 git 用戶的活動範圍。只要把它設爲git 用戶登入的 shell,那麼該用戶就無法使用普通的 bash 或者 csh 什麼的 shell 程序。編輯 /etc/passwd 文件:

$ sudo vim /etc/passwd

在文件末尾,你應該能找到類似這樣的行:

git:x:1000:1000::/home/git:/bin/sh

把 bin/sh 改爲 /usr/bin/git-shell (或者用 which git-shell 查看它的實際安裝路徑)。該行修改後的樣子如下:

git:x:1000:1000::/home/git:/usr/bin/git-shell

現在 git 用戶只能用 SSH 連接來推送和獲取 Git 倉庫,而不能直接使用主機 shell。嘗試普通 SSH 登錄的話,會看到下面這樣的拒絕信息:

$ ssh git@gitserver fatal: What do you think I am? A shell? Connection to gitserver closed.


4.5  公共訪問

匿名的讀取權限該怎麼實現呢?也許除了內部私有的項目之外,你還需要託管一些開源項目。或者因爲要用一些自動化的服務器來進行編譯,或者有一些經常變化的服務器羣組,而又不想整天生成新的 SSH 密鑰 — 總之,你需要簡單的匿名讀取權限。

或許對小型的配置來說最簡單的辦法就是運行一個靜態 web 服務,把它的根目錄設定爲 Git 倉庫所在的位置,然後開啓本章第一節提到的 post-update 掛鉤。這裏繼續使用之前的例子。假設倉庫處於/opt/git 目錄,主機上運行着 Apache 服務。重申一下,任何 web 服務程序都可以達到相同效果;作爲範例,我們將用一些基本的 Apache 設定來展示大體需要的步驟。

首先,開啓掛鉤:

$ 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 掛鉤是做什麼的呢?其內容大致如下:

$ cat .git/hooks/post-update #!/bin/sh exec git-update-server-info

意思是當通過 SSH 向服務器推送時,Git 將運行這個 git-update-server-info 命令來更新匿名 HTTP 訪問獲取數據時所需要的文件。

接下來,在 Apache 配置文件中添加一個 VirtualHost 條目,把文檔根目錄設爲 Git 項目所在的根目錄。這裏我們假定 DNS 服務已經配置好,會把對.gitserver 的請求發送到這臺主機:

ServerName git.gitserver DocumentRoot /opt/git Order allow, deny allow from all

另外,需要把 /opt/git 目錄的 Unix 用戶組設定爲 www-data ,這樣 web 服務纔可以讀取倉庫內容,因爲運行 CGI 腳本的 Apache 實例進程默認就是以該用戶的身份起來的:

$ chgrp -R www-data /opt/git

重啓 Apache 之後,就可以通過項目的 URL 來克隆該目錄下的倉庫了。

$ git clone http://git.gitserver/project.git

這一招可以讓你在幾分鐘內爲相當數量的用戶架設好基於 HTTP 的讀取權限。另一個提供非授權訪問的簡單方法是開啓一個 Git 守護進程,不過這將要求該進程作爲後臺進程常駐 — 接下來的這一節就要討論這方面的細節。

 

4.6  GitWeb

現在我們的項目已經有了可讀可寫和只讀的連接方式,不過如果能有一個簡單的 web 界面訪問就更好了。Git 自帶一個叫做 GitWeb 的 CGI 腳本,運行效果可以到http://git.kernel.org 這樣的站點體驗下(見圖 4-1)。

Git詳解之四 服務器上的Git

Figure 4-1. 基於網頁的 GitWeb 用戶界面

如果想看看自己項目的效果,不妨用 Git 自帶的一個命令,可以使用類似 lighttpd 或 webrick 這樣輕量級的服務器啓動一個臨時進程。如果是在 Linux 主機上,通常都預裝了lighttpd ,可以到項目目錄中鍵入 git instaweb 來啓動。如果用的是 Mac ,Leopard 預裝了 Ruby,所以webrick 應該是最好的選擇。如果要用 lighttpd 以外的程序來啓動git instaweb,可以通過--httpd 選項指定:

$ 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 選項就可以了:

$ git instaweb --httpd=webrick --stop

如果需要爲團隊或者某個開源項目長期運行 GitWeb,那麼 CGI 腳本就要由正常的網頁服務來運行。一些 Linux 發行版可以通過 apt 或yum 安裝一個叫做 gitweb 的軟件包,不妨首先嚐試一下。我們將快速介紹一下手動安裝 GitWeb 的流程。首先,你需要 Git 的源碼,其中帶有 GitWeb,並能生成定製的 CGI 腳本:

$ 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/

注意,通過指定 GITWEB_PROJECTROOT 變量告訴編譯命令 Git 倉庫的位置。然後,設置 Apache 以 CGI 方式運行該腳本,添加一個 VirtualHost 配置:

ServerName gitserver DocumentRoot /var/www/gitweb Options ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch AllowOverride All order allow,deny Allow from all AddHandler cgi-script cgi DirectoryIndex gitweb.cgi

不難想象,GitWeb 可以使用任何兼容 CGI 的網頁服務來運行;如果偏向使用其他 web 服務器,配置也不會很麻煩。現在,通過 http://gitserver 就可以在線訪問倉庫了,在http://git.server 上還可以通過 HTTP 克隆和獲取倉庫的內容。

 

 

4.7  Gitosis

把所有用戶的公鑰保存在 authorized_keys 文件的做法,只能湊和一陣子,當用戶數量達到幾百人的規模時,管理起來就會十分痛苦。每次改刪用戶都必須登錄服務器不去說,這種做法還缺少必要的權限管理 — 每個人都對所有項目擁有完整的讀寫權限。

幸好我們還可以選擇應用廣泛的 Gitosis 項目。簡單地說,Gitosis 就是一套用來管理 authorized_keys 文件和實現簡單連接限制的腳本。有趣的是,用來添加用戶和設定權限的並非通過網頁程序,而只是管理一個特殊的 Git 倉庫。你只需要在這個特殊倉庫內做好相應的設定,然後推送到服務器上,Gitosis 就會隨之改變運行策略,聽起來就很酷,對吧?

Gitosis 的安裝算不上傻瓜化,但也不算太難。用 Linux 服務器架設起來最簡單 — 以下例子中,我們使用裝有 Ubuntu 8.10 系統的服務器。

Gitosis 的工作依賴於某些 Python 工具,所以首先要安裝 Python 的 setuptools 包,在 Ubuntu 上稱爲 python-setuptools:

$ apt-get install python-setuptools

接下來,從 Gitosis 項目主頁克隆並安裝:

$ git clone git://eagain.net/gitosis.git $ cd gitosis $ sudo python setup.py install

這會安裝幾個供 Gitosis 使用的工具。默認 Gitosis 會把 /home/git 作爲存儲所有 Git 倉庫的根目錄,這沒什麼不好,不過我們之前已經把項目倉庫都放在/opt/git 裏面了,所以爲方便起見,我們可以做一個符號連接,直接劃轉過去,而不必重新配置:

$ ln -s /opt/git /home/git/repositories

Gitosis 將會幫我們管理用戶公鑰,所以先把當前控制文件改名備份,以便稍後重新添加,準備好讓 Gitosis 自動管理authorized_keys 文件:

$ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak

接下來,如果之前把 git 用戶的登錄 shell 改爲 git-shell 命令的話,先恢復 ‘git’ 用戶的登錄 shell。改過之後,大家仍然無法通過該帳號登錄(譯註:因爲authorized_keys 文件已經沒有了。),不過不用擔心,這會交給 Gitosis 來實現。所以現在先打開 /etc/passwd 文件,把這行:

git:x:1000:1000::/home/git:/usr/bin/git-shell

改回:

git:x:1000:1000::/home/git:/bin/sh

好了,現在可以初始化 Gitosis 了。你可以用自己的公鑰執行 gitosis-init 命令,要是公鑰不在服務器上,先臨時複製一份:

$ sudo -H -u git gitosis-init < /tmp/id_dsa.pub Initialized empty Git repository in /opt/git/gitosis-admin.git/ Reinitialized existing Git repository in /opt/git/gitosis-admin.git/

這樣該公鑰的擁有者就能修改用於配置 Gitosis 的那個特殊 Git 倉庫了。接下來,需要手工對該倉庫中的 post-update腳本加上可執行權限:

$ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update

基本上就算是好了。如果設定過程沒出什麼差錯,現在可以試一下用初始化 Gitosis 的公鑰的擁有者身份 SSH 登錄服務器,應該會看到類似下面這樣:

$ ssh git@gitserver PTY allocation request failed on channel 0 fatal: unrecognized command 'gitosis-serve schacon@quaternion' Connection to gitserver closed.

說明 Gitosis 認出了該用戶的身份,但由於沒有運行任何 Git 命令,所以它切斷了連接。那麼,現在運行一個實際的 Git 命令 — 克隆 Gitosis 的控制倉庫:

# 在你本地計算機上 $ git clone git@gitserver:gitosis-admin.git

這會得到一個名爲 gitosis-admin 的工作目錄,主要由兩部分組成:

$ cd gitosis-admin $ find . ./gitosis.conf ./keydir ./keydir/scott.pub

gitosis.conf 文件是用來設置用戶、倉庫和權限的控制文件。keydir 目錄則是保存所有具有訪問權限用戶公鑰的地方— 每人一個。在keydir 裏的文件名(比如上面的 scott.pub)應該跟你的不一樣 — Gitosis 會自動從使用gitosis-init 腳本導入的公鑰尾部的描述中獲取該名字。

看一下 gitosis.conf 文件的內容,它應該只包含與剛剛克隆的 gitosis-admin 相關的信息:

$ cat gitosis.conf [gitosis] [group gitosis-admin] writable = gitosis-admin members = scott

它顯示用戶 scott — 初始化 Gitosis 公鑰的擁有者 — 是唯一能管理 gitosis-admin 項目的人。

現在我們來添加一個新項目。爲此我們要建立一個名爲 mobile 的新段落,在其中羅列手機開發團隊的開發者,以及他們擁有寫權限的項目。由於 ‘scott’ 是系統中的唯一用戶,我們把他設爲唯一用戶,並允許他讀寫名爲iphone_project 的新項目:

[group mobile] writable = iphone_project members = scott

修改完之後,提交 gitosis-admin 裏的改動,並推送到服務器使其生效:

$ git commit -am 'add iphone_project and mobile group' [master]: created 8962da8: "changed name" 1 files changed, 4 insertions(+), 0 deletions(-) $ git push Counting objects: 5, done. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 272 bytes, done. Total 3 (delta 1), reused 0 (delta 0) To git@gitserver:/opt/git/gitosis-admin.git fb27aec..8962da8 master -> master

在新工程 iphone_project 裏首次推送數據到服務器前,得先設定該服務器地址爲遠程倉庫。但你不用事先到服務器上手工創建該項目的裸倉庫— Gitosis 會在第一次遇到推送時自動創建:

$ git remote add origin git@gitserver:iphone_project.git $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. Writing objects: 100% (3/3), 230 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master

請注意,這裏不用指明完整路徑(實際上,如果加上反而沒用),只需要一個冒號加項目名字即可 — Gitosis 會自動幫你映射到實際位置。

要和朋友們在一個項目上協同工作,就得重新添加他們的公鑰。不過這次不用在服務器上一個一個手工添加到~/.ssh/authorized_keys 文件末端,而只需管理keydir 目錄中的公鑰文件。文件的命名將決定在gitosis.conf 中對用戶的標識。現在我們爲 John,Josie 和 Jessica 添加公鑰:

$ cp /tmp/id_rsa.john.pub keydir/john.pub $ cp /tmp/id_rsa.josie.pub keydir/josie.pub $ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub

然後把他們都加進 ‘mobile’ 團隊,讓他們對 iphone_project 具有讀寫權限:

[group mobile] writable = iphone_project members = scott john josie jessica

如果你提交併推送這個修改,四個用戶將同時具有該項目的讀寫權限。

Gitosis 也具有簡單的訪問控制功能。如果想讓 John 只有讀權限,可以這樣做:

[group mobile] writable = iphone_project members = scott josie jessica [group mobile_ro] readonly = iphone_project members = john

現在 John 可以克隆和獲取更新,但 Gitosis 不會允許他向項目推送任何內容。像這樣的組可以隨意創建,多少不限,每個都可以包含若干不同的用戶和項目。甚至還可以指定某個組爲成員之一(在組名前加上@ 前綴),自動繼承該組的成員:

[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

如果遇到意外問題,試試看把 loglevel=DEBUG 加到 [gitosis] 的段落(譯註:把日誌設置爲調試級別,記錄更詳細的運行信息。)。如果一不小心搞錯了配置,失去了推送權限,也可以手工修改服務器上的/home/git/.gitosis.conf 文件 — Gitosis 實際是從該文件讀取信息的。它在得到推送數據時,會把新的gitosis.conf 存到該路徑上。所以如果你手工編輯該文件的話,它會一直保持到下次向 gitosis-admin 推送新版本的配置內容爲止。

 

 

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.

$ 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:

$ 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):

$ 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:

$ git clone gitolite:gitolite-admin $ git clone gitolite:testing

To clone these same repos from any other account:

$ 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:

$ cd ~/gitolite-admin/ $ 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”.

@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.

repo @oss_repos RW int$ = @interns RW eng- = @engineers RW refs/tags/rc[0-9] = @engineers RW+ = @admins

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:

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 RRW, 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:

RW 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:

repo 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:

hello 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 協議的配置設定都很簡單。基本上,只要以守護進程的形式運行該命令即可:

git daemon --reuseaddr --base-path=/opt/git/ /opt/git/

這裏的 --reuseaddr 選項表示在重啓服務前,不等之前的連接超時就立即重啓。而 --base-path 選項則允許克隆項目時不必給出完整路徑。最後面的路徑告訴 Git 守護進程允許開放給用戶訪問的倉庫目錄。假如有防火牆,則需要爲該主機的 9418 端口設置爲允許通信。

以守護進程的形式運行該進程的方法有很多,但主要還得看用的是什麼操作系統。在 Ubuntu 主機上,可以用 Upstart 腳本達成。編輯該文件:

/etc/event.d/local-git-daemon

加入以下內容:

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 進程也會自動啓動。要是進程意外退出或者被殺掉,也會自行重啓。在設置完成後,不重啓計算機就啓動該守護進程,可以運行:

initctl start local-git-daemon

而在其他操作系統上,可以用 xinetd,或者 sysvinit 系統的腳本,或者其他類似的腳本 — 只要能讓那個命令變爲守護進程並可監控。

接下來,我們必須告訴 Gitosis 哪些倉庫允許通過 Git 協議進行匿名只讀訪問。如果每個倉庫都設有各自的段落,可以分別指定是否允許 Git 進程開放給用戶匿名讀取。比如允許通過 Git 協議訪問 iphone_project,可以把下面兩行加到gitosis.conf 文件的末尾:

[repo iphone_project] daemon = yes

在提交和推送完成後,運行中的 Git 守護進程就會響應來自 9418 端口對該項目的訪問請求。

如果不考慮 Gitosis,單單起了 Git 守護進程的話,就必須到每一個允許匿名只讀訪問的倉庫目錄內,創建一個特殊名稱的空文件作爲標誌:

$ cd /path/to/project.git $ touch git-daemon-export-ok

該文件的存在,表明允許 Git 守護進程開放對該項目的匿名只讀訪問。

Gitosis 還能設定哪些項目允許放在 GitWeb 上顯示。先打開 GitWeb 的配置文件 /etc/gitweb.conf,添加以下四行:

$projects_list = "/home/git/gitosis/projects.list"; $projectroot = "/home/git/repositories"; $export_ok = "git-daemon-export-ok"; @git_base_url_list = ('git://gitserver');

接下來,只要配置各個項目在 Gitosis 中的 gitweb 參數,便能達成是否允許 GitWeb 用戶瀏覽該項目。比如,要讓 iphone_project 項目在 GitWeb 裏出現,把repo 的設定改成下面的樣子:

[repo iphone_project] daemon = yes gitweb = yes

在提交併推送過之後,GitWeb 就會自動開始顯示 iphone_project 項目的細節和歷史。

 

 

4.10  Git 託管服務

如果不想經歷自己架設 Git 服務器的麻煩,網絡上有幾個專業的倉庫託管服務可供選擇。這樣做有幾大優點:託管賬戶的建立通常比較省時,方便項目的啓動,而且不涉及服務器的維護和監 控。即使內部創建並運行着自己的服務器,同時爲開源項目提供一個公共託管站點還是有好處的 — 讓開源社區更方便地找到該項目,並給予幫助。

目前,可供選擇的託管服務數量繁多,各有利弊。在 Git 官方 wiki 上的 Githosting 頁面有一個最新的託管服務列表:

http://git.or.cz/gitwiki/GitHosting

由於本書無法全部一一介紹,而本人(譯註:指本書作者 Scott Chacon。)剛好在其中一家公司工作,所以接下來我們將會介紹如何在 GitHub 上建立新賬戶並啓動項目。至於其他託管服務大體也是這麼一個過程,基本的想法都是差不多的。

GitHub 是目前爲止最大的開源 Git 託管服務,並且還是少數同時提供公共代碼和私有代碼託管服務的站點之一,所以你可以在上面同時保存開源和商業代碼。事實上,本書就是放在 GitHub 上合作編著的。(譯註:本書的翻譯也是放在 GitHub 上廣泛協作的。)

GitHub

GitHub 和大多數的代碼託管站點在處理項目命名空間的方式上略有不同。GitHub 的設計更側重於用戶,而不是完全基於項目。也就是說,如果我在 GitHub 上託管一個名爲grit 的項目的話,它的地址不會是 github.com/grit,而是按在用戶底下 github.com/shacon/grit (譯註:本書作者 Scott Chacon 在 GitHub 上的用戶名是shacon。)。不存在所謂某個項目的官方版本,所以假如第一作者放棄了某個項目,它可以無縫轉移到其它用戶的名下。

GitHub 同時也是一個向使用私有倉庫的用戶收取費用的商業公司,但任何人都可以方便快捷地申請到一個免費賬戶,並在上面託管數量不限的開源項目。接下來我們快速介紹一下 GitHub 的基本使用。

建立新賬戶

首先註冊一個免費賬戶。訪問 Pricing and Signup 頁面 http://github.com/plans 並點擊 Free acount 裏的 Sign Up 按鈕(見圖 4-2),進入註冊頁面。

Git詳解之四 服務器上的Git

圖 4-2. GitHub 服務簡介頁面

選擇一個系統中尚未使用的用戶名,提供一個與之相關聯的電郵地址,並輸入密碼(見圖 4-3):

Git詳解之四 服務器上的Git

圖 4-3. GitHub 用戶註冊表單

如果方便,現在就可以提供你的 SSH 公鑰。我們在前文的”小型安裝” 一節介紹過生成新公鑰的方法。把新生成的公鑰複製粘貼到 SSH Public Key 文本框中即可。要是對生成公鑰的步驟不太清楚,也可以點擊 “explain ssh keys” 鏈接,會顯示各個主流操作系統上完成該步驟的介紹。點擊 “I agree,sign me up” 按鈕完成用戶註冊,並轉到該用戶的 dashboard 頁面(見圖 4-4):

Git詳解之四 服務器上的Git

圖 4-4. GitHub 的用戶面板

接下來就可以建立新倉庫了。

建立新倉庫

點擊用戶面板上倉庫旁邊的 “create a new one” 鏈接,顯示 Create a New Repository 的表單(見圖 4-5):

Git詳解之四 服務器上的Git

圖 4-5. 在 GitHub 上建立新倉庫

當然,項目名稱是必不可少的,此外也可以適當描述一下項目的情況或者給出官方站點的地址。然後點擊 “Create Repository” 按鈕,新倉庫就建立起來了(見圖 4-6):

Git詳解之四 服務器上的Git

圖 4-6. GitHub 上各個項目的概要信息

由於尚未提交代碼,點擊項目主頁後 GitHub 會顯示一個簡要的指南,告訴你如何新建一個項目並推送上來,如何從現有項目推送,以及如何從一個公共的 Subversion 倉庫導入項目(見圖 4-7):

Git詳解之四 服務器上的Git

圖 4-7. 新倉庫指南

該指南和本書前文介紹的類似,對於新的項目,需要先在本地初始化爲 Git 項目,添加要管理的文件並作首次提交:

$ git init $ git add . $ git commit -m 'initial commit'

然後在這個本地倉庫內把 GitHub 添加爲遠程倉庫,並推送 master 分支上來:

$ git remote add origin [email protected]:testinguser/iphone_project.git $ git push origin master

現在該項目就託管在 GitHub 上了。你可以把它的 URL 分享給每位對此項目感興趣的人。本例的 URL 是http://github.com/testinguser/iphone_project。而在項目頁面的摘要部分,你會發現有兩個 Git URL 地址(見圖 4-8):

Git詳解之四 服務器上的Git

圖 4-8. 項目摘要中的公共 URL 和私有 URL

Public Clone URL 是一個公開的,只讀的 Git URL,任何人都可以通過它克隆該項目。可以隨意散播這個 URL,比如發佈到個人網站之類的地方等等。

Your Clone URL 是一個基於 SSH 協議的可讀可寫 URL,只有使用與上傳的 SSH 公鑰對應的密鑰來連接時,才能通過它進行讀寫操作。其他用戶訪問該項目頁面時只能看到之前那個公共的 URL,看不到這個私有的 URL。

從 Subversion 導入項目

如果想把某個公共 Subversion 項目導入 Git,GitHub 可以幫忙。在指南的最後有一個指向導入 Subversion 頁面的鏈接。點擊它會看到一個表單,包含有關導入流程的信息以及一個用來粘貼公共 Subversion 項目連接的文本框(見圖 4-9):

Git詳解之四 服務器上的Git

圖 4-9. Subversion 導入界面

如果項目很大,採用非標準結構,或者是私有的,那就無法藉助該工具實現導入。到第 7 章,我們會介紹如何手工導入複雜工程的具體方法。

添加協作開發者

現在把團隊裏的其他人也加進來。如果 John,Josie 和 Jessica 都在 GitHub 註冊了賬戶,要賦予他們對該倉庫的推送權限,可以把他們加爲項目協作者。這樣他們就可以通過各自的公鑰訪問我的這個倉庫了。

點擊項目頁面上方的 “edit” 按鈕或者頂部的 Admin 標籤,進入該項目的管理頁面(見圖 4-10):

Git詳解之四 服務器上的Git

圖 4-10. GitHub 的項目管理頁面

爲了給另一個用戶添加項目的寫權限,點擊 “Add another collaborator” 鏈接,出現一個用於輸入用戶名的表單。在輸入的同時,它會自動跳出一個符合條件的候選名單。找到正確用戶名之後,點 Add 按鈕,把該用戶設爲項目協作者(見圖 4-11):

Git詳解之四 服務器上的Git

圖 4-11. 爲項目添加協作者

添加完協作者之後,就可以在 Repository Collaborators 區域看到他們的名單(見圖 4-12):

Git詳解之四 服務器上的Git

圖 4-12. 項目協作者名單

如果要取消某人的訪問權,點擊 “revoke” 即可取消他的推送權限。對於將來的項目,你可以從現有項目複製協作者名單,或者直接借用協作者羣組。

項目頁面

在推送或從 Subversion 導入項目之後,你會看到一個類似圖 4-13 的項目主頁:

Git詳解之四 服務器上的Git

圖 4-13. GitHub 上的項目主頁

別人訪問你的項目時看到的就是這個頁面。它有若干導航標籤,Commits 標籤用於顯示提交歷史,最新的提交位於最上方,這和 git log 命令的輸出類似。Network 標籤展示所有派生了該項目並做出貢獻的用戶的關係圖譜。Downloads 標籤允許你上傳項目的二進制文件,提供下載該項目各個版本的 tar/zip 包。Wiki 標籤提供了一個用於撰寫文檔或其他項目相關信息的 wiki 站點。Graphs 標籤包含了一些可視化的項目信息與數據。默認打開的 Source 標籤頁面,則列出了該項目的目錄結構和概要信息,並在下方自動展示 README 文件的內容(如果該文件存在的話),此外還會顯示最近一次提交的相關信息。

派生項目

如果要爲一個自己沒有推送權限的項目貢獻代碼,GitHub 鼓勵使用派生(fork)。到那個感興趣的項目主頁上,點擊頁面上方的 “fork” 按鈕,GitHub 就會爲你複製一份該項目的副本到你的倉庫中,這樣你就可以向自己的這個副本推送數據了。

採取這種辦法的好處是,項目擁有者不必忙於應付賦予他人推送權限的工作。隨便誰都可以通過派生得到一個項目副本並在其中展開工作,事後只需要項目維護者將這些副本倉庫加爲遠程倉庫,然後提取更新合併即可。

要派生一個項目,到原始項目的頁面(本例中是 mojombo/chronic)點擊 “fork” 按鈕(見圖 4-14):

Git詳解之四 服務器上的Git

圖 4-14. 點擊 “fork” 按鈕獲得任意項目的可寫副本

幾秒鐘之後,你將進入新建的項目頁面,會顯示該項目派生自哪一個項目(見圖 4-15):

Git詳解之四 服務器上的Git

圖 4-15. 派生後得到的項目副本

GitHub 小結

關於 GitHub 就先介紹這麼多,能夠快速達成這些事情非常重要(譯註:門檻的降低和完成基本任務的簡單高效,對於推動開源項目的協作發展有着舉足輕重的意義。)。短短几 分鐘內,你就能創建一個新賬戶,添加一個項目並開始推送。如果項目是開源的,整個龐大的開發者社區都可以立即訪問它,提供各式各樣的幫助和貢獻。最起碼, 這也是一種 Git 新手立即體驗嘗試 Git 的捷徑。


4.11  小結

我們討論並介紹了一些建立遠程 Git 倉庫的方法,接下來你可以通過這些倉庫同他人分享或合作。

運行自己的服務器意味着更多的控制權以及在防火牆內部操作的可能性,當然這樣的服務器通常需要投入一定的時間精力來架設維護。如果直接託管,雖然能免去這部分工作,但有時出於安全或版權的考慮,有些公司禁止將商業代碼託管到第三方服務商。

所以究竟採取哪種方案,並不是個難以取捨的問題,或者其一,或者相互配合,哪種合適就用哪種。

發佈了41 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章