1. 程式人生 > >服務器上的git

服務器上的git

article resp git repo 成熟 mkdir index options 顯示 locking

服務器上的 Git

到目前為止,你應該已經有辦法使用 Git 來完成日常工作。 然而,為了使用 Git 協作功能,你還需要有遠程的 Git 倉庫。 盡管在技術上你可以從個人倉庫進行推送(push)和拉取(pull)來修改內容,但不鼓勵使用這種方 法,因為一不留心就很容易弄混其他人的進度。 此外,你希望你的合作者們即使在你的電腦未聯機時亦能存取 倉庫 — 擁有一個更可靠的公用倉庫十分有用。 因此,與他人合作的最佳方法即是建立一個你與合作者們都有權 利訪問,且可從那裏推送和拉取資料的共用倉庫。

架設一臺 Git 服務器並不難。 首先,選擇你希望服務器使用的通訊協議。 在本章第一節將介紹可用的協議以及 各自優缺點。 下面一節將解釋使用那些協議的典型設置及如何在你的服務器上運行。 最後,如果你不介意托管 你的代碼在其他人的服務器,且不想經歷設置與維護自己服務器的麻煩,可以試試我們介紹的幾個倉庫托管服 務。

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

一個遠程倉庫通常只是一個裸倉庫(bare repository)— 即一個沒有當前工作目錄的倉庫。 因為該倉庫僅僅作 為合作媒介,不需要從磁碟檢查快照;存放的只有 Git 的資料。 簡單的說,裸倉庫就是你專案目錄內的 .git 子 目錄內容,不包含其他資料。

協議

Git 可以使用四種主要的協議來傳輸資料:本地協議(Local),HTTP 協議,SSH(Secure Shell)協議及 Git 協議。 在此,我們將會討論那些協議及哪些情形應該使用(或避免使用)他們。

本地協議

最基本的就是 本地協議(Local protocol) ,其中的遠程版本庫就是硬盤內的另一個目錄。 這常見於團隊每一 個成員都對一個共享的文件系統(例如一個掛載的 NFS)擁有訪問權,或者比較少見的多人共用同一臺電腦的情 況。 後者並不理想,因為你的所有代碼版本庫如果長存於同一臺電腦,更可能發生災難性的損失。

如果你使用共享文件系統,就可以從本地版本庫克隆(clone)、推送(push)以及拉取(pull)。 像這樣去克 隆一個版本庫或者增加一個遠程到現有的項目中,使用版本庫路徑作為 URL。 例如,克隆一個本地版本庫,可 以執行如下的命令:

  $ git clone /opt/git/project.git

或你可以執行這個命令:

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

如果在 URL 開頭明確的指定 file://,那麽 Git 的行為會略有不同。 如果僅是指定路徑,Git 會嘗試使用硬鏈 接(hard link)或直接復制所需要的文件。 如果指定 file://,Git 會觸發平時用於網路傳輸資料的進程,那

通常是傳輸效率較低的方法。 指定 file:// 的主要目的是取得一個沒有外部參考(extraneous references)或對象(object)的幹凈版本庫副本– 通常是在從其他版本控制系統導入後或一些類似情況(參見 Git 內部原理 for maintenance tasks)需要這麽做。 在此我們將使用普通路徑,因為這樣通常更快。

要增加一個本地版本庫到現有的 Git 項目,可以執行如下的命令:

  $ git remote add local_proj /opt/git/project.git
然後,就可以像在網絡上一樣從遠端版本庫推送和拉取更新了。

優點

基於文件系統的版本庫的優點是簡單,並且直接使用了現有的文件權限和網絡訪問權限。 如果你的團隊已經有 共享文件系統,建立版本庫會十分容易。 只需要像設置其他共享目錄一樣,把一個裸版本庫的副本放到大家都 可以訪問的路徑,並設置好讀/寫的權限,就可以了, 我們會在 在服務器上搭建 Git 討論如何導出一個裸版本 庫。

這也是快速從別人的工作目錄中拉取更新的方法。 如果你和別人一起合作一個項目,他想讓你從版本庫中拉取 更新時,運行類似git pull /home/john/project的命令比推送到服務再取回簡單多了。

缺點

這種方法的缺點是,通常共享文件系統比較難配置,並且比起基本的網絡連接訪問,這不方便從多個位置訪問。
如果你想從家裏推送內容,必須先掛載一個遠程磁盤,相比網絡連接的訪問方式,配置不方便,速度也慢。

值得一提的是,如果你使用的是類似於共享掛載的文件系統時,這個方法不一定是最快的。 訪問本地版本庫的 速度與你訪問數據的速度是一樣的。 在同一個服務器上,如果允許 Git 訪問本地硬盤,一般的通過 NFS 訪問版 本庫要比通過 SSH 訪問慢。

最終,這個協議並不保護倉庫避免意外的損壞。 每一個用戶都有“遠程”目錄的完整 shell 權限,沒有方法可以 阻止他們修改或刪除 Git 內部文件和損壞倉庫。

HTTP 協議

Git 通過 HTTP 通信有兩種模式。 在 Git 1.6.6 版本之前只有一個方式可用,十分簡單並且通常是只讀模式的。 Git 1.6.6 版本引入了一種新的、更智能的協議,讓 Git 可以像通過 SSH 那樣智能的協商和傳輸數據。 之後幾 年,這個新的 HTTP 協議因為其簡單、智能變的十分流行。 新版本的 HTTP 協議一般被稱為“智能” HTTP 協 議,舊版本的一般被稱為“啞” HTTP 協議。 我們先了解一下新的“智能” HTTP 協議。

智能(Smart) HTTP 協議

“智能” HTTP 協議的運行方式和 SSH 及 Git 協議類似,只是運行在標準的 HTTP/S 端口上並且可以使用各種 HTTP 驗證機制,這意味著使用起來會比 SSH 協議簡單的多,比如可以使用 HTTP 協議的用戶名/密碼的基礎 授權,免去設置 SSH 公鑰。

智能 HTTP 協議或許已經是最流行的使用 Git 的方式了,它即支持像 git:// 協議一樣設置匿名服務,也可以像

SSH 協議一樣提供傳輸時的授權和加密。 而且只用一個 URL 就可以都做到,省去了為不同的需求設置不同的 URL。 如果你要推送到一個需要授權的服務器上(一般來講都需要),服務器會提示你輸入用戶名和密碼。 從 服務器獲取數據時也一樣。

事實上,類似 GitHub 的服務,你在網頁上看到的 URL (比如, https://github.com/schacon/simplegit[]),和你在克隆、推送(如果你有權限)時使用的是一樣 的。

啞(Dumb) HTTP 協議

如果服務器沒有提供智能 HTTP 協議的服務,Git 客戶端會嘗試使用更簡單的“啞” HTTP 協議。 啞 HTTP 協議 裏 web 服務器僅把裸版本庫當作普通文件來對待,提供文件服務。 啞 HTTP 協議的優美之處在於設置起來簡 單。 基本上,只需要把一個裸版本庫放在 HTTP 跟目錄,設置一個叫做 post-update 的掛鉤就可以了(見 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 https://example.com/gitproject.git

這裏我們用了 Apache 裏設置了常用的路徑 /var/www/htdocs,不過你可以使用任何靜態 web 服務器 —— 只 需要把裸版本庫放到正確的目錄下就可以。 Git 的數據是以基本的靜態文件形式提供的(詳情見 Git 內部原 理)。

通常的,會在可以提供讀/寫的智能 HTTP 服務和簡單的只讀的啞 HTTP 服務之間選一個。 極少會將二者混合 提供服務。

優點

我們將只關註智能 HTTP 協議的優點。

不同的訪問方式只需要一個 URL 以及服務器只在需要授權時提示輸入授權信息,這兩個簡便性讓終端用戶使用 Git 變得非常簡單。 相比 SSH 協議,可以使用用戶名/密碼授權是一個很大的優勢,這樣用戶就不必須在使用 Git 之前先在本地生成 SSH 密鑰對再把公鑰上傳到服務器。 對非資深的使用者,或者系統上缺少 SSH 相關程序 的使用者,HTTP 協議的可用性是主要的優勢。 與 SSH 協議類似,HTTP 協議也非常快和高效。

你也可以在 HTTPS 協議上提供只讀版本庫的服務,如此你在傳輸數據的時候就可以加密數據;或者,你甚至可以讓客戶端使用指定 的 SSL 證書。

另一個好處是 HTTP/S 協議被廣泛使用,一般的企業防火墻都會允許這些端口的數據通過。

缺點

在一些服務器上,架設 HTTP/S 協議的服務端會比 SSH 協議的棘手一些。 除了這一點,用其他協議提供 Git 服 務與 “智能” HTTP 協議相比就幾乎沒有優勢了。

如果你在 HTTP 上使用需授權的推送,管理憑證會比使用 SSH 密鑰認證麻煩一些。 然而,你可以選擇使用憑證 存儲工具,比如 OSX 的 Keychain 或者 Windows 的憑證管理器。 參考 憑證存儲 如何安全地保存 HTTP 密碼。

SSH 協議

架設 Git 服務器時常用 SSH 協議作為傳輸協議。 因為大多數環境下已經支持通過 SSH 訪問 —— 即時沒有也比較 很容易架設。 SSH 協議也是一個驗證授權的網絡協議;並且,因為其普遍性,架設和使用都很容易。

通過 SSH 協議克隆版本庫,你可以指定一個 ssh:// 的 URL: $ git clone ssh://user@server/project.git

或者使用一個簡短的 scp 式的寫法:

  $ git clone user@server:project.git

你也可以不指定用戶,Git 會使用當前登錄的用戶名。

優勢

用 SSH 協議的優勢有很多。 首先,SSH 架設相對簡單 —— SSH 守護進程很常見,多數管理員都有使用經驗, 並且多數操作系統都包含了它及相關的管理工具。 其次,通過 SSH 訪問是安全的 —— 所有傳輸數據都要經過授 權和加密。 最後,與 HTTP/S 協議、Git 協議及本地協議一樣,SSH 協議很高效,在傳輸前也會盡量壓縮數據。

缺點

SSH 協議的缺點在於你不能通過他實現匿名訪問。 即便只要讀取數據,使用者也要有通過 SSH 訪問你的主機的 權限,這使得 SSH 協議不利於開源的項目。 如果你只在公司網絡使用,SSH 協議可能是你唯一要用到的協議。 如果你要同時提供匿名只讀訪問和 SSH 協議,那麽你除了為自己推送架設 SSH 服務以外,還得架設一個可以讓 其他人訪問的服務。

Git 協議

接下來是 Git 協議。 這是包含在 Git 裏的一個特殊的守護進程;它監聽在一個特定的端口(9418),類似於 SSH 服務,但是訪問無需任何授權。 要讓版本庫支持 Git 協議,需要先創建一個 git-daemon-export-ok 文 件 —— 它是 Git 協議守護進程為這個版本庫提供服務的必要條件 —— 但是除此之外沒有任何安全措施。 要麽誰 都可以克隆這個版本庫,要麽誰也不能。 這意味這,通常不能通過 Git 協議推送。 由於沒有授權機制,一旦你 開放推送操作,意味著網絡上知道這個項目 URL 的人都可以向項目推送數據。 不用說,極少會有人這麽做。

優點

目前,Git 協議是 Git 使用的網絡傳輸協議裏最快的。 如果你的項目有很大的訪問量,或者你的項目很龐大並且 不需要為寫進行用戶授權,架設 Git 守護進程來提供服務是不錯的選擇。 它使用與 SSH 相同的數據傳輸機制, 但是省去了加密和授權的開銷。

缺點

Git 協議缺點是缺乏授權機制。 把 Git 協議作為訪問項目版本庫的唯一手段是不可取的。 一般的做法裏,會同時 提供 SSH 或者 HTTPS 協議的訪問服務,只讓少數幾個開發者有推送(寫)權限,其他人通過 git:// 訪問只有 讀權限。 Git 協議也許也是最難架設的。 它要求有自己的守護進程,這就要配置 xinetd 或者其他的程序,這些 工作並不簡單。 它還要求防火墻開放 9418 端口,但是企業防火墻一般不會開放這個非標準端口。 而大型的企 業防火墻通常會封鎖這個端口。

在服務器上搭建 Git

現在我們將討論如何在你自己的服務器上搭建 Git 服務來運行這些協議。

NOTE

這裏我們將要演示在 Linux 服務器上進行一次基本且簡化的安裝所需的命令與步驟,當然在 Mac 或 Windows 服務器上同樣可以運行這些服務。 事實上,在你的計算機基礎架構中建立 一個生產環境服務器,將不可避免的使用到不同的安全措施與操作系統工具。但是,希望你 能從本節中獲得一些必要的知識。

在開始架設 Git 服務器前,需要把現有倉庫導出為裸倉庫——即一個不包含當前工作目錄的倉庫。 這通常是很簡 單的。 為了通過克隆你的倉庫來創建一個新的裸倉庫,你需要在克隆命令後加上 `--bare`選項 按照慣例,裸倉 庫目錄名以 .git 結尾,就像這樣:

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

現在,你的 my_project.git 目錄中應該有 Git 目錄的副本了。 整體上效果大致相當於

$ cp -Rf my_project/.git my_project.git

雖然在配置文件中有若幹不同,但是對於你的目的來說,這兩種方式都是一樣的。 它只取出 Git 倉庫自身,不要 工作目錄,然後特別為它單獨創建一個目錄。

把裸倉庫放到服務器上

既然你有了裸倉庫的副本,剩下要做的就是把裸倉庫放到服務器上並設置你的協議。 假設一個域名為 git.example.com 的服務器已經架設好,並可以通過 SSH 連接,你想把所有的 Git 倉庫放在 /opt/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 會自動修改該倉庫目錄的組權限 為可寫。

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

由此可見,根據現有的 Git 倉庫創建一個裸倉庫,然後把它放上你和協作者都有 SSH 訪問權的服務器是多麽容 易。 現在你們已經準備好在同一項目上展開合作了。

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

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

小型安裝

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

SSH 連接

如果你有一臺所有開發者都可以用 SSH 連接的服務器,架設你的第一個倉庫就十分簡單了,因為你幾乎什麽都 不用做(正如我們上一節所說的)。 如果你想在你的倉庫上設置更復雜的訪問控制權限,只要使用服務器操作 系統的普通的文件系統權限就行了。

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

有幾個方法可以使你給團隊每個成員提供訪問權。 第一個就是給團隊裏的每個人創建賬號,這種方法很直接但 也很麻煩。 或許你不會想要為每個人運行一次 adduser 並且設置臨時密碼。

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

另一個辦法是讓 SSH 服務器通過某個 LDAP 服務,或者其他已經設定好的集中授權機制,來進行授權。 只要每 個用戶可以獲得主機的 shell 訪問權限,任何 SSH 授權機制你都可視為是有效的。

生成 SSH 公鑰

如前所述,許多 Git 服務器都使用 SSH 公鑰進行認證。 為了向 Git 服務器提供 SSH 公鑰,如果某系統用戶尚未 擁有密鑰,必須事先為其生成一份。 這個過程在所有操作系統上都是相似的。 首先,你需要確認自己是否已經 擁有密鑰。 默認情況下,用戶的 SSH 密鑰存儲在其 ~/.ssh 目錄下。 進入該目錄並列出其中內容,你便可以快 速確認自己是否已擁有密鑰:

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

我們需要尋找一對以 id_dsa 或 id_rsa 命名的文件,其中一個帶有 .pub 擴展名。 .pub 文件是你的公鑰,另 一個則是私鑰。 如果找不到這樣的文件(或者根本沒有 .ssh 目錄),你可以通過運行 ssh-keygen 程序來創 建它們。在 Linux/Mac 系統中,ssh-keygen 隨 SSH 軟件包提供;在 Windows 上,該程序包含於 MSysGit 軟 件包中。

  $ ssh-keygen
  Generating public/private rsa key pair.
  Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
  Created directory ‘/home/schacon/.ssh‘.
  Enter passphrase (empty for no passphrase):
  Enter same passphrase again:
  Your identification has been saved in /home/schacon/.ssh/id_rsa.
  Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
  The key fingerprint is:
  d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 [email protected]

首先 ssh-keygen 會確認密鑰的存儲位置(默認是 .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 密鑰指南 https://help.github.com/articles/generating-ssh-keys。

配置服務器

我們來看看如何配置服務器端的 SSH 訪問。 本例中,我們將使用 authorized_keys 方法來對用戶進行認證。 同時我們假設你使用的操作系統是標準的 Linux 發行版,比如 Ubuntu。 首先,創建一個操作系統用戶 git,並 為其建立一個 .ssh 目錄。

  $ sudo adduser git
  $ su git
  $ cd
  $ mkdir .ssh && chmod 700 .ssh
  $ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys

接著,我們需要為系統用戶 git 的 authorized_keys 文件添加一些開發者 SSH 公鑰。 假設我們已經獲得了 若幹受信任的公鑰,並將它們保存在臨時文件中。 與前文類似,這些公鑰看起來是這樣的:

  $ cat /tmp/id_rsa.john.pub
  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L
  ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k
  Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez
  Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv
  O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq
  dAv8JggJICUvax2T9va5 gsg-keypair

將這些公鑰加入系統用戶 git 的 .ssh 目錄下 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 init --bare
  Initialized empty Git repository in /opt/git/project.git/

接著,John、Josie 或者 Jessica 中的任意一人可以將他們項目的最初版本推送到這個倉庫中,他只需將此倉庫 設置為項目的遠程倉庫並向其推送分支。 請註意,每添加一個新項目,都需要有人登錄服務器取得 shell,並創 建一個裸倉庫。 我們假定這個設置了 git 用戶和 Git 倉庫的服務器使用 gitserver 作為主機名。 同時,假設 該服務器運行在內網,並且你已在 DNS 配置中將 gitserver 指向此服務器。那麽我們可以運行如下命令(假 定 myproject 是已有項目且其中已包含文件):

  # on John‘s computer
  $ 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

通過這種方法,你可以快速搭建一個具有讀寫權限、面向多個開發者的 Git 服務器。 需要註意的是,目前所有(獲得授權的)開發者用戶都能以系統用戶 git 的身份登錄服務器從而獲得一個普通

shell。 如果你想對此加以限制,則需要修改 passwd 文件中(git 用戶所對應)的 shell 值。

借助一個名為 git-shell 的受限 shell 工具,你可以方便地將用戶 git 的活動限制在與 Git 相關的範圍內。該 工具隨 Git 軟件包一同提供。 如果將 git-shell 設置為用戶 git 的登錄 shell(login shell),那麽用戶 git 便不能獲得此服務器的普通 shell 訪問權限。 若要使用 git-shell,需要用它替換掉 bash 或 csh,使其成為系 統用戶的登錄 shell。 為進行上述操作,首先你必須確保 git-shell 已存在於 /etc/shells 文件中:

  $ cat /etc/shells   # see if `git-shell` is already in there.  If not...
  $ which git-shell   # make sure git-shell is installed on your system.
  $ sudo vim /etc/shells  # and add the path to git-shell from last command

現在你可以使用chsh <username>命令修改任一系統用戶的shell:
$ sudo chsh git # and enter the path to git-shell, usually: /usr/bin/git-

shell

這樣,用戶 git 就只能利用 SSH 連接對 Git 倉庫進行推送和拉取操作,而不能登錄機器並取得普通 shell。 如果 試圖登錄,你會發現嘗試被拒絕,像這樣:

  $ ssh git@gitserver
  fatal: Interactive git shell is not enabled.
  hint: ~/git-shell-commands should exist and have read and execute access.
  Connection to gitserver closed.

現在,網絡相關的 Git 命令依然能夠正常工作,但是開發者用戶已經無法得到一個普通 shell 了。 正如輸出信息 所提示的,你也可以在 git 用戶的家目錄下建立一個目錄,來對 git-shell 命令進行一定程度的自定義。 比 如,你可以限制掉某些本應被服務器接受的 Git 命令,或者對剛才的 SSH 拒絕登錄信息進行自定義,這樣,當 有開發者用戶以類似方式嘗試登錄時,便會看到你的信息。 要了解更多有關自定義 shell 的信息,請運行 git help shell。

Git 守護進程

接下來我們將通過 “Git” 協議建立一個基於守護進程的倉庫。 對於快速且無需授權的 Git 數據訪問,這是一個 理想之選。 請註意,因為其不包含授權服務,任何通過該協議管理的內容將在其網絡上公開。

如果運行在防火墻之外的服務器上,它應該只對那些公開的只讀項目服務。 如果運行在防火墻之內的服務器 上,它可用於支撐大量參與人員或自動系統(用於持續集成或編譯的主機)只讀訪問的項目,這樣可以省去逐一 配置 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-shell 一樣,同樣使用 git 用戶來運行 它。

當你重啟機器時,你的 Git 守護進程將會自動啟動,並且如果進程被意外結束它會自動重新運行。 為了在不重啟 的情況下直接運行,你可以運行以下命令:

initctl start local-git-daemon

在其他系統中,你可以使用 sysvinit 系統中的 xinetd 腳本,或者另外的方式來實現 - 只要你能夠將其命令守 護進程化並實現監控。

接下來,你需要告訴 Git 哪些倉庫允許基於服務器的無授權訪問。 你可以在每個倉庫下創建一個名為 git- daemon-export-ok 的文件來實現。

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

該文件將允許 Git 提供無需授權的項目訪問服務。

Smart HTTP

我們一般通過 SSH 進行授權訪問,通過 git:// 進行無授權訪問,但是還有一種協議可以同時實現以上兩種方式的 訪問。 設置 Smart HTTP 一般只需要在服務器上啟用一個 Git 自帶的名為 git-http-backend 的 CGI 腳本。 該 CGI 腳本將會讀取由 git fetch 或 git push 命令向 HTTP URL 發送的請求路徑和頭部信息,來判斷該客 戶端是否支持 HTTP 通信(不低於 1.6.6 版本的客戶端支持此特性)。 如果 CGI 發現該客戶端支持智 能(Smart)模式,它將會以智能模式與它進行通信,否則它將會回落到啞(Dumb)模式下(因此它可以對某 些老的客戶端實現向下兼容)。

在完成以上簡單的安裝步驟後, 我們將用 Apache 來作為 CGI 服務器。 如果你沒有安裝 Apache,你可以在 Linux 環境下執行如下或類似的命令來安裝:

  $ sudo apt-get install apache2 apache2-utils
  $ a2enmod cgi alias env

該操作將會啟用 mod_cgi, mod_alias, 和 mod_env 等 Apache 模塊, 這些模塊都是使該功能正常工作所必 須的。

接下來我們要向 Apache 配置文件添加一些內容,來讓 git-http-backend 作為 Web 服務器對 /git 路徑請 求的處理器。

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

如果留空 GIT_HTTP_EXPORT_ALL 這個環境變量,Git 將只對無授權客戶端提供帶 git-daemon-export-ok 文件的版本庫,就像 Git 守護進程一樣。

接著你需要讓 Apache 接受通過該路徑的請求,添加如下的內容至 Apache 配置文件:

  <Directory "/usr/lib/git-core*">
     Options ExecCGI Indexes
     Order allow,deny
     Allow from all
     Require all granted
  </Directory>
最後,如果想實現寫操作授權驗證,使用如下的未授權屏蔽配置即可:
  <LocationMatch "^/git/.*/git-receive-pack$">
      AuthType Basic
      AuthName "Git Access"
      AuthUserFile /opt/git/.htpasswd
      Require valid-user
  </LocationMatch>

這需要你創建一個包含所有合法用戶密碼的 .htaccess 文件。 以下是一個添加 “schacon” 用戶到此文件的 例子:

  $ htdigest -c /opt/git/.htpasswd "Git Access" schacon

你可以通過許多方式添加 Apache 授權用戶,選擇使用其中一種方式即可。 以上僅僅只是我們可以找到的最簡 單的一個例子。 如果願意的話,你也可以通過 SSL 運行它,以保證所有數據是在加密狀態下進行傳輸的。

我們不想深入去講解 Apache 配置文件,因為你可能會使用不同的 Web 服務器,或者可能有不同的授權需求。 它的主要原理是使用一個 Git 附帶的,名為 git-http-backend 的 CGI。它被引用來處理協商通過 HTTP 發送 和接收的數據。 它本身並不包含任何授權功能,但是授權功能可以在 Web 服務器層引用它時被輕松實現。 你可 以在任何所有可以處理 CGI 的 Web 服務器上辦到這點,所以隨便挑一個你最熟悉的 Web 服務器試手吧。

欲了解更多的有關配置 Apache 授權訪問的信息,請通過以下鏈接瀏覽 Apache 文檔:

http://httpd.apache.org/docs/current/howto/auth.html

GitWeb

如果你對項目有讀寫權限或只讀權限,你可能需要建立起一個基於網頁的簡易查看器。 Git 提供了一個叫做 GitWeb 的 CGI 腳本來做這項工作。

NOTE

Figure 49. GitWeb 的網頁用戶界面

如果你想要查看 GitWeb 如何展示你的項目,並且在服務器上安裝了輕量級網絡服務器比如 lighttpd 或 webrick, Git 提供了一個命令來讓你啟動一個臨時的服務器。 在 Linux 系統的電腦上,lighttpd 通常已經 安裝了,所以你只需要在項目目錄裏執行 git instaweb 命令即可。 如果你使用 Mac 系統, Mac OS X Leopard 系統已經預安裝了 Ruby,所以 webrick 或許是你最好的選擇。 如果不想使用 lighttpd 啟動 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 端口的 HTTP 服務器,並且自動打開了瀏覽器。 這對你來說十分方便。 當你已 經完成了工作並想關閉這個服務器,你可以執行同一個命令,並加上 --stop 選項:

  $ git instaweb --httpd=webrick --stop

如果你現在想為你的團隊或你托管的開源項目持續的運行這個頁面,你需要通過普通的 Web 服務器來設置 CGI 腳本。 一些 Linux 發行版的軟件庫有 gitweb 包,可以通過 apt 或 yum 來安裝,你可以先試試。 接下來我們來

快速的了解一下如何手動安裝 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
      SUBDIR gitweb
      SUBDIR ../
  make[2]: `GIT-VERSION-FILE‘ is up to date.
      GEN gitweb.cgi
      GEN static/gitweb.js
  $ sudo cp -Rf gitweb /var/www/

需要註意的是,你需要在命令中指定 GITWEB_PROJECTROOT 變量來讓程序知道你的 Git 版本庫的位置。 現 在,你需要在 Apache 中使用這個 CGI 腳本,你需要為此添加一個虛擬主機:

  <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 或 Perl 的網絡服務器架設;如果你需要的話,架設起來應該不會 很困難。 現在,你可以訪問 http://gitserver/ 在線查看你的版本庫。

GitLab

雖然 GitWeb 相當簡單。 但如果你正在尋找一個更現代,功能更全的 Git 服務器,這裏有幾個開源的解決方案可 供你選擇安裝。 因為 GitLab 是其中最出名的一個,我們將它作為示例並討論它的安裝和使用。 這比 GitWeb 要 復雜的多並且需要更多的維護,但它的確是一個功能更全的選擇。

安裝

GitLab 是一個數據庫支持的 web 應用,所以相比於其他 git 服務器,它的安裝過程涉及到更多的東西。 幸運的 是,這個過程有非常詳細的文檔說明和支持。

這裏有一些可參考的方法幫你安裝 GitLab 。 為了更快速的啟動和運行,你可以下載虛擬機鏡像或者在

https://bitnami.com/stack/gitlab 上獲取一鍵安裝包,同時調整配置使之符合你特定的環境。 Bitnami 的一個優點在於它的登錄界面(通過 alt-&rarr 鍵進入;);它會告訴你安裝好的 GitLab 的 IP 地址以及默認的 用戶名和密碼。

Figure 50. Bitnami GitLab 虛擬機登錄界面。

無論如何,跟著 GitLab 社區版的 readme 文件一步步來,你可以在這裏找到它 https://gitlab.com/gitlab- org/gitlab-ce/tree/master 。 在這裏你將會在主菜單中找到安裝 GitLab 的幫助,一個可以在 Digital Ocean 上 運行的虛擬機,以及 RPM 和 DEB 包(都是測試版)。 這裏還有 “非官方” 的引導讓 GitLab 運行在非標準的操 作系統和數據庫上,一個全手動的安裝腳本,以及許多其他的話題。

管理

GitLab 的管理界面是通過網絡進入的。 將你的瀏覽器轉到已經安裝 GitLab 的 主機名或 IP 地址,然後以管理員 身份登錄即可。 默認的用戶名是 [email protected],默認的密碼是 5iveL!fe(你會得到類似 請登錄後盡 快更換密碼 的提示)。 登錄後,點擊主欄上方靠右位置的 “Admin area” 圖標進行管理。

Figure 51. GitLab 主欄的 “Admin area” 圖標。

使用者

GitLab 上的用戶指的是對應協作者的帳號。 用戶帳號沒有很多復雜的地方,主要是包含登錄數據的用戶信息集 合。 每一個用戶賬號都有一個 命名空間 ,即該用戶項目的邏輯集合。 如果一個叫 jane 的用戶擁有一個名稱是

project 的項目,那麽這個項目的 url 會是 http://server/jane/project 。

Figure 52. GitLab 用戶管理界面。

移除一個用戶有兩種方法。 “屏蔽(Blocking)” 一個用戶阻止他登錄 GitLab 實例,但是該用戶命名空間下的 所有數據仍然會被保存,並且仍可以通過該用戶提交對應的登錄郵箱鏈接回他的個人信息頁。

而另一方面,“銷毀(Destroying)” 一個用戶,會徹底的將他從數據庫和文件系統中移除。 他命名空間下的 所有項目和數據都會被刪除,擁有的任何組也會被移除。 這顯然是一個更永久且更具破壞力的行為,所以很少 用到這種方法。

一個 GitLab 的組是一些項目的集合,連同關於多少用戶可以訪問這些項目的數據。 每一個組都有一個項目命名 空間(與用戶一樣),所以如果一個叫 training 的組擁有一個名稱是 materials 的項目,那麽這個項目的 url 會是 http://server/training/materials 。

Figure 53. GitLab組 管理界面。

每一個組都有許多用戶與之關聯,每一個用戶對組中的項目以及組本身的權限都有級別區分。 權限的範圍從 “ 訪客”(僅能提問題和討論) 到 “擁有者”(完全控制組、成員和項目)。 權限的種類太多以至於難以在這裏 一一列舉,不過在 GitLab 的管理界面上有幫助鏈接。

項目

一個 GitLab 的項目相當於 git 的版本庫。 每一個項目都屬於一個用戶或者一個組的單個命名空間。 如果這個項 目屬於一個用戶,那麽這個擁有者對所有可以獲取這個項目的人擁有直接管理權;如果這個項目屬於一個組,那 麽該組中用戶級別的權限也會起作用。

每一個項目都有一個可視級別,控制著誰可以看到這個項目頁面和倉庫。 如果一個項目是 私有 的,這個項目的 擁有者必須明確授權從而使特定的用戶可以訪問。 一個 內部 的項目可以被所有登錄的人看到,而一個 公開 的 項目則是對所有人可見的。 註意,這種控制既包括 git “fetch” 的使用也包括對項目 web 用戶界面的訪問。

鉤子

GitLab 在項目和系統級別上都支持鉤子程序。 對任意級別,當有相關事件發生時,GitLab 的服務器會執行一個 包含描述性 JSON 數據的 HTTP 請求。 這是自動化連接你的 git 版本庫和 GitLab 實例到其他的開發工具,比如 CI 服務器,聊天室,或者部署工具的一個極好方法。

基本用途

你想要在 GitLab 做的第一件事就是建立一個新項目。 這通過點擊工具欄上的 “+” 圖標完成。 你會被要求填寫 項目名稱,也就是這個項目所屬的命名空間,以及它的可視層級。 絕大多數的設定並不是永久的,可以通過設 置界面重新調整。 點擊 “Create Project”,你就完成了。

項目存在後,你可能會想將它與本地的 Git 版本庫連接。 每一個項目都可以通過 HTTPS 或者 SSH 連接,任意兩 者都可以被用來配置遠程 Git。 在項目主頁的頂欄可以看到這個項目的 URLs。 對於一個存在的本地版本庫,這

個命令將會向主機位置添加一個叫 gitlab 的遠程倉庫:
$ git remote add gitlab https://server/namespace/project.git

如果你的本地沒有版本庫的副本,你可以這樣做:
  $ git clone https://server/namespace/project.git

web 用戶界面提供了幾個有用的獲取版本庫信息的網頁。 每一個項目的主頁都顯示了最近的活動,並且通過頂 部的鏈接可以使你瀏覽項目文件以及提交日誌。

一起工作

在一個 GitLab 項目上一起工作的最簡單方法就是賦予協作者對 git 版本庫的直接 push 權限。 你可以通過項目 設定的 “Members(成員)” 部分向一個項目添加寫作者,並且將這個新的協作者與一個訪問級別關聯(不同 的訪問級別在 組 中已簡單討論)。 通過賦予一個協作者 “Developer(開發者)” 或者更高的訪問級別,這個 用戶就可以毫無約束地直接向版本庫或者向分支進行提交。

另外一個讓合作更解耦的方法就是使用合並請求。 它的優點在於讓任何能夠看到這個項目的協作者在被管控的 情況下對這個項目作出貢獻。 可以直接訪問的協作者能夠簡單的創建一個分支,向這個分支進行提交,也可以 開啟一個向 master 或者其他任何一個分支的合並請求。 對版本庫沒有推送權限的協作者則可以 “fork” 這個 版本庫(即創建屬於自己的這個庫的副本),向 那個 副本進行提交,然後從那個副本開啟一個到主項目的合並 請求。 這個模型使得項目擁有者完全控制著向版本庫的提交,以及什麽時候允許加入陌生協作者的貢獻。

在 GitLab 中合並請求和問題是一個長久討論的主要部分。 每一個合並請求都允許在提出改變的行進行討論(它 支持一個輕量級的代碼審查),也允許對一個總體性話題進行討論。 兩者都可以被分配給用戶,或者組織到 milestones(裏程碑) 界面。

這個部分主要聚焦於在 GitLab 中與 Git 相關的特性,但是 GitLab 作為一個成熟的系統,它提供了許多其他產品 來幫助你協同工作,例如項目 wiki 與系統維護工具。 GitLab 的一個優點在於,服務器設置和運行以後,你將很 少需要調整配置文件或通過 SSH 連接服務器;絕大多數的管理和日常使用都可以在瀏覽器界面中完成。

第三方托管的選擇

如果不想設立自己的 Git 服務器,你可以選擇將你的 Git 項目托管到一個外部專業的托管網站。 這帶來了一些好 處:一個托管網站可以用來快速建立並開始項目,且無需進行服務器維護和監控工作。 即使你在內部設立並且 運行了自己的服務器,你仍然可以把你的開源代碼托管在公共托管網站 - 這通常更有助於開源社區來發現和幫助 你。

現在,有非常多的托管供你選擇,每個選擇都有不同的優缺點。 欲查看最新列表,請瀏覽 Git 維基的 GitHosting 頁面 https://git.wiki.kernel.org/index.php/GitHosting

我們會在 GitHub 詳細講解 GitHub,作為目前最大的 Git 托管平臺,你很可能需要與托管在 GitHub 上的項目進 行交互,而且你也很可能並不想去設立你自己的 Git 服務器。

總結

你有多種遠程存取 Git 倉庫的選擇便於與其他人合作或是分享你的工作。

運行你自己的服務器將有許多權限且允許你運行該服務於你自己的防火墻內,但如此通常需要耗費你大量的時間 去設置與維護服務器。 如果你放置你的資料於托管服務器內,可輕易的設置與維護;無論如何,你必須能夠保 存你的代碼在其他服務器,且某些組織不允許此作法。 這將直接了當的決定哪個作法或組合的方式較適合你或 你的組織。

服務器上的git