鍍金池/ 教程/ Java/ 服務(wù)器上的 Git
起步
Git 分支
自定義 Git
Git 基礎(chǔ)
Git 工具
Git 與其他系統(tǒng)
服務(wù)器上的 Git
Git 內(nèi)部原理
分布式 Git

服務(wù)器上的 Git

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

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

如果你對架設(shè)自己的服務(wù)器沒興趣,可以跳到本章最后一節(jié)去看看如何申請一個代碼托管服務(wù)的賬戶然后繼續(xù)下一章,我們會在那里討論分布式源碼控制環(huán)境的林林總總。

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

協(xié)議

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

值得注意的是,除了 HTTP 協(xié)議外,其他所有協(xié)議都要求在服務(wù)器端安裝并運行 Git。

本地協(xié)議

最基本的就是本地協(xié)議(Local protocol),所謂的遠程倉庫在該協(xié)議中的表示,就是硬盤上的另一個目錄。這常見于團隊每一個成員都對一個共享的文件系統(tǒng)(例如 NFS)擁有訪問權(quán),或者比較少見的多人共用同一臺電腦的情況。后面一種情況并不安全,因為所有代碼倉庫實例都儲存在同一臺電腦里,增加了災(zāi)難性數(shù)據(jù)損失的可能性。

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

$ git clone /opt/git/project.git

或者這樣:

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

如果在 URL 開頭明確使用 file:// ,那么 Git 會以一種略微不同的方式運行。如果你只給出路徑,Git 會嘗試使用硬鏈接或直接復(fù)制它所需要的文件。如果使用了 file:// ,Git 會調(diào)用它平時通過網(wǎng)絡(luò)來傳輸數(shù)據(jù)的工序,而這種方式的效率相對較低。使用 file:// 前綴的主要原因是當你需要一個不包含無關(guān)引用或?qū)ο蟮母蓛魝}庫副本的時候 — 一般指從其他版本控制系統(tǒng)導(dǎo)入的,或類似情形(參見第 9 章的維護任務(wù))。我們這里僅僅使用普通路徑,這樣更快。

要添加一個本地倉庫作為現(xiàn)有 Git 項目的遠程倉庫,可以這樣做:

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

然后就可以像在網(wǎng)絡(luò)上一樣向這個遠程倉庫推送和獲取數(shù)據(jù)了。

優(yōu)點

基于文件倉庫的優(yōu)點在于它的簡單,同時保留了現(xiàn)存文件的權(quán)限和網(wǎng)絡(luò)訪問權(quán)限。如果你的團隊已經(jīng)有一個全體共享的文件系統(tǒng),建立倉庫就十分容易了。你只需把一份裸倉庫的副本放在大家都能訪問的地方,然后像對其他共享目錄一樣設(shè)置讀寫權(quán)限就可以了。我們將在下一節(jié)“在服務(wù)器上部署 Git ”中討論如何導(dǎo)出一個裸倉庫的副本。

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

缺點

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

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

SSH 協(xié)議

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

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

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

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

$ git clone user@server:project.git

如果不指明用戶,Git 會默認使用當前登錄的用戶名連接服務(wù)器。

優(yōu)點

使用 SSH 的好處有很多。首先,如果你想擁有對網(wǎng)絡(luò)倉庫的寫權(quán)限,基本上不可能不使用 SSH。其次,SSH 架設(shè)相對比較簡單 — SSH 守護進程很常見,很多網(wǎng)絡(luò)管理員都有一些使用經(jīng)驗,而且很多操作系統(tǒng)都自帶了它或者相關(guān)的管理工具。再次,通過 SSH 進行訪問是安全的 — 所有數(shù)據(jù)傳輸都是加密和授權(quán)的。最后,和 Git 及本地協(xié)議一樣,SSH 也很高效,會在傳輸之前盡可能壓縮數(shù)據(jù)。

缺點

SSH 的限制在于你不能通過它實現(xiàn)倉庫的匿名訪問。即使僅為讀取數(shù)據(jù),人們也必須在能通過 SSH 訪問主機的前提下才能訪問倉庫,這使得 SSH 不利于開源的項目。如果你僅僅在公司網(wǎng)絡(luò)里使用,SSH 可能是你唯一需要使用的協(xié)議。如果想允許對項目的匿名只讀訪問,那么除了為自己推送而架設(shè) SSH 協(xié)議之外,還需要支持其他協(xié)議以便他人訪問讀取。

Git 協(xié)議

接下來是 Git 協(xié)議。這是一個包含在 Git 軟件包中的特殊守護進程; 它會監(jiān)聽一個提供類似于 SSH 服務(wù)的特定端口(9418),而無需任何授權(quán)。打算支持 Git 協(xié)議的倉庫,需要先創(chuàng)建 git-daemon-export-ok 文件 — 它是協(xié)議進程提供倉庫服務(wù)的必要條件 — 但除此之外該服務(wù)沒有什么安全措施。要么所有人都能克隆 Git 倉庫,要么誰也不能。這也意味著該協(xié)議通常不能用來進行推送。你可以允許推送操作;然而由于沒有授權(quán)機制,一旦允許該操作,網(wǎng)絡(luò)上任何一個知道項目 URL 的人將都有推送權(quán)限。不用說,這是十分罕見的情況。

優(yōu)點

Git 協(xié)議是現(xiàn)存最快的傳輸協(xié)議。如果你在提供一個有很大訪問量的公共項目,或者一個不需要對讀操作進行授權(quán)的龐大項目,架設(shè)一個 Git 守護進程來供應(yīng)倉庫是個不錯的選擇。它使用與 SSH 協(xié)議相同的數(shù)據(jù)傳輸機制,但省去了加密和授權(quán)的開銷。

缺點

Git 協(xié)議消極的一面是缺少授權(quán)機制。用 Git 協(xié)議作為訪問項目的唯一方法通常是不可取的。一般的做法是,同時提供 SSH 接口,讓幾個開發(fā)者擁有推送(寫)權(quán)限,其他人通過 git:// 擁有只讀權(quán)限。 Git 協(xié)議可能也是最難架設(shè)的協(xié)議。它要求有單獨的守護進程,需要定制 — 我們將在本章的 “Gitosis” 一節(jié)詳細介紹它的架設(shè) — 需要設(shè)定 xinetd 或類似的程序,而這些工作就沒那么輕松了。該協(xié)議還要求防火墻開放 9418 端口,而企業(yè)級防火墻一般不允許對這個非標準端口的訪問。大型企業(yè)級防火墻通常會封鎖這個少見的端口。

HTTP/S 協(xié)議

最后還有 HTTP 協(xié)議。HTTP 或 HTTPS 協(xié)議的優(yōu)美之處在于架設(shè)的簡便性。基本上,只需要把 Git 的裸倉庫文件放在 HTTP 的根目錄下,配置一個特定的 post-update 掛鉤(hook)就可以搞定(Git 掛鉤的細節(jié)見第 7 章)。此后,每個能訪問 Git 倉庫所在服務(wù)器上 web 服務(wù)的人都可以進行克隆操作。下面的操作可以允許通過 HTTP 對倉庫進行讀?。?/p>

$ 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 向倉庫推送內(nèi)容時運行;之后,其他人就可以用下面的命令來克隆倉庫:

$ git clone http://example.com/gitproject.git

在本例中,我們使用了 Apache 設(shè)定中常用的 /var/www/htdocs 路徑,不過你可以使用任何靜態(tài) web 服務(wù) — 把裸倉庫放在它的目錄里就行。 Git 的數(shù)據(jù)是以最基本的靜態(tài)文件的形式提供的(關(guān)于如何提供文件的詳情見第 9 章)。

通過 HTTP 進行推送操作也是可能的,不過這種做法不太常見,并且牽扯到復(fù)雜的 WebDAV 設(shè)定。由于很少用到,本書將略過對該內(nèi)容的討論。如果對 HTTP 推送協(xié)議感興趣,不妨打開這個地址看一下操作方法:http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt 。通過 HTTP 推送的好處之一是你可以使用任何 WebDAV 服務(wù)器,不需要為 Git 設(shè)定特殊環(huán)境;所以如果主機提供商支持通過 WebDAV 更新網(wǎng)站內(nèi)容,你也可以使用這項功能。

優(yōu)點

使用 HTTP 協(xié)議的好處是易于架設(shè)。幾條必要的命令就可以讓全世界讀取到倉庫的內(nèi)容。花費不過幾分鐘。HTTP 協(xié)議不會占用過多服務(wù)器資源。因為它一般只用到靜態(tài)的 HTTP 服務(wù)提供所有數(shù)據(jù),普通的 Apache 服務(wù)器平均每秒能支撐數(shù)千個文件的并發(fā)訪問 — 哪怕讓一個小型服務(wù)器超載都很難。

你也可以通過 HTTPS 提供只讀的倉庫,這意味著你可以加密傳輸內(nèi)容;你甚至可以要求客戶端使用特定簽名的 SSL 證書。一般情況下,如果到了這一步,使用 SSH 公共密鑰可能是更簡單的方案;不過也存在一些特殊情況,這時通過 HTTPS 使用帶簽名的 SSL 證書或者其他基于 HTTP 的只讀連接授權(quán)方式是更好的解決方案。

HTTP 還有個額外的好處:HTTP 是一個如此常見的協(xié)議,以至于企業(yè)級防火墻通常都允許其端口的通信。

缺點

HTTP 協(xié)議的消極面在于,相對來說客戶端效率更低。克隆或者下載倉庫內(nèi)容可能會花費更多時間,而且 HTTP 傳輸?shù)捏w積和網(wǎng)絡(luò)開銷比其他任何一個協(xié)議都大。因為它沒有按需供應(yīng)的能力 — 傳輸過程中沒有服務(wù)端的動態(tài)計算 — 因而 HTTP 協(xié)議經(jīng)常會被稱為_傻瓜(dumb)_協(xié)議。更多 HTTP 協(xié)議和其他協(xié)議效率上的差異見第 9 章。

在服務(wù)器上部署 Git

開始架設(shè) Git 服務(wù)器前,需要先把現(xiàn)有倉庫導(dǎo)出為裸倉庫 — 即一個不包含當前工作目錄的倉庫。做法直截了當,克隆時用 --bare 選項即可。裸倉庫的目錄名一般以 .git 結(jié)尾,像這樣:

$ git clone --bare my_project my_project.git
Cloning into bare repository 'my_project.git'...
done.

該命令的輸出或許會讓人有些不解。其實 clone 操作基本上相當于 git initgit fetch,所以這里出現(xiàn)的其實是 git init 的輸出,先由它建立一個空目錄,而之后傳輸數(shù)據(jù)對象的操作并無任何輸出,只是悄悄在幕后執(zhí)行。現(xiàn)在 my_project.git 目錄中已經(jīng)有了一份 Git 目錄數(shù)據(jù)的副本。

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

$ cp -Rf my_project/.git my_project.git

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

把裸倉庫移到服務(wù)器上

有了裸倉庫的副本后,剩下的就是把它放到服務(wù)器上并設(shè)定相關(guān)協(xié)議。假設(shè)一個域名為 git.example.com 的服務(wù)器已經(jīng)架設(shè)好,并可以通過 SSH 訪問,我們打算把所有 Git 倉庫儲存在 /opt/git 目錄下。只要把裸倉庫復(fù)制過去:

$ scp -r my_project.git user@git.example.com:/opt/git

現(xiàn)在,所有對該服務(wù)器有 SSH 訪問權(quán)限,并可讀取 /opt/git 目錄的用戶都可以用下面的命令克隆該項目:

$ git clone user@git.example.com:/opt/git/my_project.git

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

$ ssh user@git.example.com
$ cd /opt/git/my_project.git
$ git init --bare --shared

由此可見,根據(jù)現(xiàn)有的 Git 倉庫創(chuàng)建一個裸倉庫,然后把它放上你和同事都有 SSH 訪問權(quán)的服務(wù)器是多么容易。現(xiàn)在已經(jīng)可以開始在同一項目上密切合作了。

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

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

小型安裝

如果設(shè)備較少或者你只想在小型開發(fā)團隊里嘗試 Git ,那么一切都很簡單。架設(shè) Git 服務(wù)最復(fù)雜的地方在于賬戶管理。如果需要倉庫對特定的用戶可讀,而給另一部分用戶讀寫權(quán)限,那么訪問和許可的安排就比較困難。

SSH 連接

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

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

有好幾個辦法可以讓團隊的每個人都有訪問權(quán)。第一個辦法是給每個人建立一個賬戶,直截了當?shù)赃^繁瑣。反復(fù)運行 adduser 并給所有人設(shè)定臨時密碼可不是好玩的。

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

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

生成 SSH 公鑰

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

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

關(guān)鍵是看有沒有用 somethingsomething.pub 來命名的一對文件,這個 something 通常就是 id_dsaid_rsa。有 .pub 后綴的文件就是公鑰,另一個文件則是密鑰。假如沒有這些文件,或者干脆連 .ssh 目錄都沒有,可以用 ssh-keygen 來創(chuàng)建。該程序在 Linux/Mac 系統(tǒng)上由 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 schacon@agadorlaptop.local

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

現(xiàn)在,所有做過這一步的用戶都得把它們的公鑰給你或者 Git 服務(wù)器的管理員(假設(shè) SSH 服務(wù)被設(shè)定為使用公鑰機制)。他們只需要復(fù)制 .pub 文件的內(nèi)容然后發(fā)郵件給管理員。公鑰的樣子大致如下:

$ 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== schacon@agadorlaptop.local

關(guān)于在多個操作系統(tǒng)上設(shè)立相同 SSH 公鑰的教程,可以查閱 GitHub 上有關(guān) SSH 公鑰的向?qū)В?code>http://github.com/guides/providing-your-ssh-key。

架設(shè)服務(wù)器

現(xiàn)在我們過一邊服務(wù)器端架設(shè) SSH 訪問的流程。本例將使用 authorized_keys 方法來給用戶授權(quán)。我們還將假定使用類似 Ubuntu 這樣的標準 Linux 發(fā)行版。首先,創(chuàng)建一個名為 'git' 的用戶,并為其創(chuàng)建一個 .ssh 目錄。

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

接下來,把開發(fā)者的 SSH 公鑰添加到這個用戶的 authorized_keys 文件中。假設(shè)你通過電郵收到了幾個公鑰并存到了臨時文件里。重復(fù)一下,公鑰大致看起來是這個樣子:

$ 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

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

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

這時,Join,Josie 或者 Jessica 就可以把它加為遠程倉庫,推送一個分支,從而把第一個版本的項目文件上傳到倉庫里了。值得注意的是,每次添加一個新項目都需要通過 shell 登入主機并創(chuàng)建一個裸倉庫目錄。我們不妨以 gitserver 作為 git 用戶及項目倉庫所在的主機名。如果在網(wǎng)絡(luò)內(nèi)部運行該主機,并在 DNS 中設(shè)定 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
$ cd project
$ vim README
$ git commit -am 'fix for the README file'
$ git push origin master

用這個方法可以很快捷地為少數(shù)幾個開發(fā)者架設(shè)一個可讀寫的 Git 服務(wù)。

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

$ sudo vim /etc/passwd

在文件末尾,你應(yīng)該能找到類似這樣的行:

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

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

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

公共訪問

匿名的讀取權(quán)限該怎么實現(xiàn)呢?也許除了內(nèi)部私有的項目之外,你還需要托管一些開源項目?;蛘咭驗橐靡恍┳詣踊姆?wù)器來進行編譯,或者有一些經(jīng)常變化的服務(wù)器群組,而又不想整天生成新的 SSH 密鑰 — 總之,你需要簡單的匿名讀取權(quán)限。

或許對小型的配置來說最簡單的辦法就是運行一個靜態(tài) web 服務(wù),把它的根目錄設(shè)定為 Git 倉庫所在的位置,然后開啟本章第一節(jié)提到的 post-update 掛鉤。這里繼續(xù)使用之前的例子。假設(shè)倉庫處于 /opt/git 目錄,主機上運行著 Apache 服務(wù)。重申一下,任何 web 服務(wù)程序都可以達到相同效果;作為范例,我們將用一些基本的 Apache 設(shè)定來展示大體需要的步驟。

首先,開啟掛鉤:

$ cd project.git
$ mv hooks/post-update.sample hooks/post-update
$ chmod a+x hooks/post-update

post-update 掛鉤是做什么的呢?其內(nèi)容大致如下:

$ cat .git/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

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

接下來,在 Apache 配置文件中添加一個 VirtualHost 條目,把文檔根目錄設(shè)為 Git 項目所在的根目錄。這里我們假定 DNS 服務(wù)已經(jīng)配置好,會把對 .gitserver 的請求發(fā)送到這臺主機:

<VirtualHost *:80>
    ServerName git.gitserver
    DocumentRoot /opt/git
    <Directory /opt/git/>
        Order allow, deny
        allow from all
    </Directory>
</VirtualHost>

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

$ chgrp -R www-data /opt/git

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

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

這一招可以讓你在幾分鐘內(nèi)為相當數(shù)量的用戶架設(shè)好基于 HTTP 的讀取權(quán)限。另一個提供非授權(quán)訪問的簡單方法是開啟一個 Git 守護進程,不過這將要求該進程作為后臺進程常駐 — 接下來的這一節(jié)就要討論這方面的細節(jié)。

GitWeb

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

http://wiki.jikexueyuan.com/project/pro-git/images/18333fig0401-tn.png" alt="" />

Figure 4-1. 基于網(wǎng)頁的 GitWeb 用戶界面

如果想看看自己項目的效果,不妨用 Git 自帶的一個命令,可以使用類似 lighttpdwebrick 這樣輕量級的服務(wù)器啟動一個臨時進程。如果是在 Linux 主機上,通常都預(yù)裝了 lighttpd ,可以到項目目錄中鍵入 git instaweb 來啟動。如果用的是 Mac ,Leopard 預(yù)裝了 Ruby,所以 webrick 應(yīng)該是最好的選擇。如果要用 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 服務(wù),隨之在瀏覽器中顯示該頁,十分簡單。關(guān)閉服務(wù)時,只需在原來的命令后面加上 --stop 選項就可以了:

$ git instaweb --httpd=webrick --stop

如果需要為團隊或者某個開源項目長期運行 GitWeb,那么 CGI 腳本就要由正常的網(wǎng)頁服務(wù)來運行。一些 Linux 發(fā)行版可以通過 aptyum 安裝一個叫做 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
$ sudo cp -Rf gitweb /var/www/

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

<VirtualHost *:80>
    ServerName gitserver
    DocumentRoot /var/www/gitweb
    <Directory /var/www/gitweb>
        Options ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch
        AllowOverride All
        order allow,deny
        Allow from all
        AddHandler cgi-script cgi
        DirectoryIndex gitweb.cgi
    </Directory>
</VirtualHost>

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

Gitosis

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

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

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

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

$ apt-get install python-setuptools

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

$ git clone https://github.com/tv42/gitosis.git
$ cd gitosis
$ sudo python setup.py install

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

$ 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 命令的話,先恢復(fù) 'git' 用戶的登錄 shell。改過之后,大家仍然無法通過該帳號登錄(譯注:因為 authorized_keys 文件已經(jīng)沒有了。),不過不用擔心,這會交給 Gitosis 來實現(xiàn)。所以現(xiàn)在先打開 /etc/passwd 文件,把這行:

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

改回:

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

好了,現(xiàn)在可以初始化 Gitosis 了。你可以用自己的公鑰執(zhí)行 gitosis-init 命令,要是公鑰不在服務(wù)器上,先臨時復(fù)制一份:

$ 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 腳本加上可執(zhí)行權(quán)限:

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

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

$ ssh git@gitserver
PTY allocation request failed on channel 0
ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment.
  Connection to gitserver closed.

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

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

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

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

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

看一下 gitosis.conf 文件的內(nèi)容,它應(yīng)該只包含與剛剛克隆的 gitosis-admin 相關(guān)的信息:

$ cat gitosis.conf
[gitosis]

[group gitosis-admin]
members = scott
writable = gitosis-admin

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

現(xiàn)在我們來添加一個新項目。為此我們要建立一個名為 mobile 的新段落,在其中羅列手機開發(fā)團隊的開發(fā)者,以及他們擁有寫權(quán)限的項目。由于 'scott' 是系統(tǒng)中的唯一用戶,我們把他設(shè)為唯一用戶,并允許他讀寫名為 iphone_project 的新項目:

[group mobile]
members = scott
writable = iphone_project

修改完之后,提交 gitosis-admin 里的改動,并推送到服務(wù)器使其生效:

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

在新工程 iphone_project 里首次推送數(shù)據(jù)到服務(wù)器前,得先設(shè)定該服務(wù)器地址為遠程倉庫。但你不用事先到服務(wù)器上手工創(chuàng)建該項目的裸倉庫— Gitosis 會在第一次遇到推送時自動創(chuàng)建:

$ 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 | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@gitserver:iphone_project.git
 * [new branch]      master -> master

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

要和朋友們在一個項目上協(xié)同工作,就得重新添加他們的公鑰。不過這次不用在服務(wù)器上一個一個手工添加到 ~/.ssh/authorized_keys 文件末端,而只需管理 keydir 目錄中的公鑰文件。文件的命名將決定在 gitosis.conf 中對用戶的標識?,F(xiàn)在我們?yōu)?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 具有讀寫權(quán)限:

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

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

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

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

[group mobile_ro]
members = john
readonly = iphone_project

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

[group mobile_committers]
members = scott josie jessica

[group mobile]
members   = @mobile_committers
writable  = iphone_project

[group mobile_2]
members   = @mobile_committers john
writable  = another_iphone_project

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

Gitolite

本節(jié)作為Gitolite的一個快速指南,指導(dǎo)基本的安裝和設(shè)置。不能完全替代隨Gitolite自帶的大量文檔。而且可能會隨時改變本節(jié)內(nèi)容,因此你也許想看看最新的版本

Gitolite是在Git之上的一個授權(quán)層,依托sshd或者httpd來進行認證。(概括:認證是確定用戶是誰,授權(quán)是決定該用戶是否被允許做他想做的事情)。

Gitolite允許你定義訪問許可而不只作用于倉庫,而同樣于倉庫中的每個branch和tag name。你可以定義確切的人(或一組人)只能push特定的"refs"(或者branches或者tags)而不是其他人。

安裝

安裝Gitolite非常簡單, 你甚至不用讀自帶的那一大堆文檔。你需要一個unix服務(wù)器上的賬戶;許多l(xiāng)inux變種和solaris 10都已經(jīng)試過了。你不需要root訪問,假設(shè)git,perl,和一個openssh兼容的ssh服務(wù)器已經(jīng)裝好了。在下面的例子里,我們會用git賬戶在gitserver進行。

Gitolite是不同于“服務(wù)”的軟件 -- 其通過ssh訪問, 而且每個在服務(wù)器上的userid都是一個潛在的“gitolite主機”。我們在這里描述最簡單的安裝方法,對于其他方法,請參考其文檔。

開始,在你的服務(wù)器上創(chuàng)建一個名為git的用戶,然后以這個用戶登錄。從你的工作站拷貝你的SSH公鑰(也就是你用ssh-keygen默認生成的~/.ssh/id_dsa.pub文件),重命名為<yourname>.pub(我們這里使用scott.pub作為例子)。然后執(zhí)行下面的命令:

$ git clone git://github.com/sitaramc/gitolite
$ gitolite/install -ln
    # assumes $HOME/bin exists and is in your $PATH
$ gitolite setup -pk $HOME/scott.pub

最后一個命令在服務(wù)器上創(chuàng)建了一個名為gitolite-admin的Git倉庫。

最后,回到你的工作站,執(zhí)行git clone git@gitserver:gitolite-admin。然后你就完成了!Gitolite現(xiàn)在已經(jīng)安裝在了服務(wù)器上,在你的工作站上,你也有一個名為gitolite-admin的新倉庫。你可用通過更改這個倉庫以及推送到服務(wù)器上來管理你的Gitolite配置。

定制安裝

默認快速安裝對大多數(shù)人都管用,還有一些定制安裝方法如果你用的上的話。一些設(shè)置可以通過編輯rc文件來簡單地改變,但是如果這個不夠,有關(guān)于定制Gitolite的文檔供參考。

配置文件和訪問規(guī)則

安裝結(jié)束后,你切換到gitolite-admin倉庫(放在你的HOME目錄)然后看看都有啥:

$ cd ~/gitolite-admin/
$ ls
conf/  keydir/
$ find conf keydir -type f
conf/gitolite.conf
keydir/scott.pub
$ cat conf/gitolite.conf

repo gitolite-admin
    RW+                 = scott

repo testing
    RW+                 = @all

注意 "scott" ( 之前用gl-setup 命令時候的 pubkey 名稱) 有讀寫權(quán)限而且在 gitolite-admin 倉庫里有一個同名的公鑰文件。

添加用戶很簡單。為了添加一個名為alice的用戶,獲取她的公鑰,命名為alice.pub,然后放到在你工作站上的gitolite-admin克隆的keydir目錄。添加,提交,然后推送更改。這樣用戶就被添加了。

gitolite配置文件的語法在conf/example.conf里,我們只會提到一些主要的。

你可以給用戶或者倉庫分組。分組名就像一些宏;定義的時候,無所謂他們是工程還是用戶;區(qū)別在于你使用“宏”的時候

@oss_repos      = linux perl rakudo git gitolite
@secret_repos   = fenestra pear

@admins         = scott
@interns        = ashok
@engineers      = sitaram dilbert wally alice
@staff          = @admins @engineers @interns

你可以控制許可在”ref“級別。在下面的例子里,實習生可以push ”int“分支。工程師可以push任何有"eng-"開頭的branch,還有refs/tags下面用"rc"開頭的后面跟數(shù)字的。而且管理員可以隨便更改(包括rewind)對任何參考名。

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

RWorRW+之后的表達式是正則表達式(regex)對應(yīng)著后面的push用的參考名字(ref)。所以我們叫它”參考正則“(refex)!當然,一個refex可以比這里表現(xiàn)的更強大,所以如果你對perl的正則表達式不熟的話就不要改過頭。

同樣,你可能猜到了,Gitolite字頭refs/heads/是一個便捷句法如果參考正則沒有用refs/開頭。

一個這個配置文件語法的重要功能是,所有的倉庫的規(guī)則不需要在同一個位置。你能報所有普通的東西放在一起,就像上面的對所有oss_repos的規(guī)則那樣,然后建一個特殊的規(guī)則對后面的特殊案例,就像:

repo gitolite
    RW+                     = sitaram

那條規(guī)則剛剛加入規(guī)則集的 gitolite 倉庫.

這次你可能會想要知道訪問控制規(guī)則是如何應(yīng)用的,我們簡要介紹一下。

在gitolite里有兩級訪問控制。第一是在倉庫級別;如果你已經(jīng)讀或者寫訪問過了任何在倉庫里的參考,那么你已經(jīng)讀或者寫訪問倉庫了。

第二級,應(yīng)用只能寫訪問,通過在倉庫里的branch或者tag。用戶名如果嘗試過訪問 (W+),參考名被更新為已知。訪問規(guī)則檢查是否出現(xiàn)在配置文件里,為這個聯(lián)合尋找匹配 (但是記得參考名是正則匹配的,不是字符串匹配的)。如果匹配被找到了,push就成功了。不匹配的訪問會被拒絕。

帶'拒絕'的高級訪問控制

目前,我們只看過了許可是R,RW, 或者RW+這樣子的。但是gitolite還允許另外一種許可:-,代表 ”拒絕“。這個給了你更多的能力,當然也有一點復(fù)雜,因為不匹配并不是唯一的拒絕訪問的方法,因此規(guī)則的順序變得無關(guān)了!

這么說好了,在前面的情況中,我們想要工程師可以rewind任意branch除了master和integ。 這里是如何做到的

    RW  master integ    = @engineers
    -   master integ    = @engineers
    RW+                 = @engineers

你再一次簡單跟隨規(guī)則從上至下知道你找到一個匹配你的訪問模式的,或者拒絕。非rewind push到master或者integ 被第一條規(guī)則允許。一個rewind push到那些refs不匹配第一條規(guī)則,掉到第二條,因此被拒絕。任何push(rewind或非rewind)到參考或者其他master或者integ不會被前兩條規(guī)則匹配,即被第三條規(guī)則允許。

通過改變文件限制 push

此外限制用戶push改變到哪條branch的,你也可以限制哪個文件他們可以碰的到。比如, 可能Makefile (或者其他哪些程序) 真的不能被任何人做任何改動,因為好多東西都靠著它呢,或者如果某些改變剛好不對就會崩潰。你可以告訴 gitolite:

repo foo
    RW                      =   @junior_devs @senior_devs

    -   VREF/NAME/Makefile  =   @junior_devs

這是一個強力的公能寫在 conf/example.conf里。

個人分支

Gitolite也支持一個叫”個人分支“的功能 (或者叫, ”個人分支命名空間“) 在合作環(huán)境里非常有用。

在 git世界里許多代碼交換通過”pull“請求發(fā)生。然而在合作環(huán)境里,委任制的訪問是‘絕不’,一個開發(fā)者工作站不能認證,你必須push到中心服務(wù)器并且叫其他人從那里pull。

這個通常會引起一些branch名稱簇變成像 VCS里一樣集中化,加上設(shè)置許可變成管理員的苦差事。

Gitolite讓你定義一個”個人的“或者”亂七八糟的”命名空間字首給每個開發(fā)人員(比如,refs/personal/<devname>/*);看在doc/3-faq-tips-etc.mkd里的"personal branches"一段獲取細節(jié)。

"通配符" 倉庫

Gitolite 允許你定義帶通配符的倉庫(其實還是perl正則式), 比如隨便整個例子的話assignments/s[0-9][0-9]/a[0-9][0-9]。 這是一個非常有用的功能,需要通過設(shè)置$GL_WILDREPOS = 1; 在 rc文件中啟用。允許你安排一個新許可模式("C")允許用戶創(chuàng)建倉庫基于通配符,自動分配擁有權(quán)對特定用戶 - 創(chuàng)建者,允許他交出 R和 RW許可給其他合作用戶等等。這個功能在doc/4-wildcard-repositories.mkd文檔里

其他功能

我們用一些其他功能的例子結(jié)束這段討論,這些以及其他功能都在 "faqs, tips, etc" 和其他文檔里。

記錄: Gitolite 記錄所有成功的訪問。如果你太放松給了別人 rewind許可 (RW+) 和其他孩子弄沒了 "master", 記錄文件會救你的命,如果其他簡單快速的找到SHA都不管用。

訪問權(quán)報告: 另一個方便的功能是你嘗試用ssh連接到服務(wù)器的時候發(fā)生了什么。Gitolite告訴你哪個 repos你訪問過,那個訪問可能是什么。這里是例子:

    hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4

         R     anu-wsd
         R     entrans
         R  W  git-notes
         R  W  gitolite
         R  W  gitolite-admin
         R     indic_web_input
         R     shreelipi_converter

委托:真正的大安裝,你可以把責任委托給一組倉庫給不同的人然后讓他們獨立管理那些部分。這個減少了主管理者的負擔,讓他瓶頸更小。這個功能在他自己的文檔目錄里的 doc/下面。

鏡像: Gitolite可以幫助你維護多個鏡像,如果主服務(wù)器掛掉的話在他們之間很容易切換。

Git 守護進程

對于提供公共的,非授權(quán)的只讀訪問,我們可以拋棄 HTTP 協(xié)議,改用 Git 自己的協(xié)議,這主要是出于性能和速度的考慮。Git 協(xié)議遠比 HTTP 協(xié)議高效,因而訪問速度也快,所以它能節(jié)省很多用戶的時間。

重申一下,這一點只適用于非授權(quán)的只讀訪問。如果建在防火墻之外的服務(wù)器上,那么它所提供的服務(wù)應(yīng)該只是那些公開的只讀項目。如果是在防火墻之內(nèi)的服務(wù)器上,可用于支撐大量參與人員或自動系統(tǒng)(用于持續(xù)集成或編譯的主機)只讀訪問的項目,這樣可以省去逐一配置 SSH 公鑰的麻煩。

但不管哪種情形,Git 協(xié)議的配置設(shè)定都很簡單。基本上,只要以守護進程的形式運行該命令即可:

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

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

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

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

加入以下內(nèi)容:

start on startup
stop on shutdown
exec /usr/bin/git daemon \
    --user=git --group=git \
    --reuseaddr \
    --base-path=/opt/git/ \
    /opt/git/
respawn

出于安全考慮,強烈建議用一個對倉庫只有讀取權(quán)限的用戶身份來運行該進程 — 只需要簡單地新建一個名為 git-ro 的用戶(譯注:新建用戶默認對倉庫文件不具備寫權(quán)限,但這取決于倉庫目錄的權(quán)限設(shè)定。務(wù)必確認 git-ro 對倉庫只能讀不能寫。),并用它的身份來啟動進程。這里為了簡化,后面我們還是用之前運行 Gitosis 的用戶 'git'。

這樣一來,當你重啟計算機時,Git 進程也會自動啟動。要是進程意外退出或者被殺掉,也會自行重啟。在設(shè)置完成后,不重啟計算機就啟動該守護進程,可以運行:

initctl start local-git-daemon

而在其他操作系統(tǒng)上,可以用 xinetd,或者 sysvinit 系統(tǒng)的腳本,或者其他類似的腳本 — 只要能讓那個命令變?yōu)槭刈o進程并可監(jiān)控。

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

[repo iphone_project]
daemon = yes

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

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

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

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

Gitosis 還能設(shè)定哪些項目允許放在 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 參數(shù),便能達成是否允許 GitWeb 用戶瀏覽該項目。比如,要讓 iphone_project 項目在 GitWeb 里出現(xiàn),把 repo 的設(shè)定改成下面的樣子:

[repo iphone_project]
daemon = yes
gitweb = yes

在提交并推送過之后,GitWeb 就會自動開始顯示 iphone_project 項目的細節(jié)和歷史。

Git 托管服務(wù)

如果不想經(jīng)歷自己架設(shè) Git 服務(wù)器的麻煩,網(wǎng)絡(luò)上有幾個專業(yè)的倉庫托管服務(wù)可供選擇。這樣做有幾大優(yōu)點:托管賬戶的建立通常比較省時,方便項目的啟動,而且不涉及服務(wù)器的維護和監(jiān)控。即使內(nèi)部創(chuàng)建并運行著自己的服務(wù)器,同時為開源項目提供一個公共托管站點還是有好處的 — 讓開源社區(qū)更方便地找到該項目,并給予幫助。

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

https://git.wiki.kernel.org/index.php/GitHosting

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

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

GitHub

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

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

建立新賬戶

首先注冊一個免費賬戶。訪問 "Plans and pricing" 頁面 https://github.com/pricing 并點擊 Free acount 里的 Sign Up 按鈕(見圖 4-2),進入注冊頁面。

http://wiki.jikexueyuan.com/project/pro-git/images/18333fig0402-tn.png" alt="" />

圖 4-2. GitHub 服務(wù)簡介頁面

選擇一個系統(tǒng)中尚未使用的用戶名,提供一個與之相關(guān)聯(lián)的電郵地址,并輸入密碼(見圖 4-3):

http://wiki.jikexueyuan.com/project/pro-git/images/18333fig0403-tn.png" alt="" />

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

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

http://wiki.jikexueyuan.com/project/pro-git/images/18333fig0404-tn.png" alt="" />

上一篇:Git 分支下一篇:Git 內(nèi)部原理