章節 ▾ 第二版

4.1 Git 在伺服器端 - 協議

到目前為止,你應該能夠完成大部分日常 Git 使用任務。然而,要進行 Git 協作,你需要有一個遠端 Git 倉庫。雖然你可以在技術上向個人倉庫推送和拉取更改,但這樣做不被推薦,因為如果不小心,你很容易混淆他們正在進行的工作。此外,你希望你的協作者即使在你的計算機離線時也能訪問倉庫 — — 擁有一個更可靠的通用倉庫通常很有用。因此,與他人協作的首選方法是設定一個你們雙方都能訪問的中間倉庫,並在此倉庫上進行推送和拉取。

執行 Git 伺服器相當簡單。首先,你選擇你的伺服器要支援哪些協議。本章的第一部分將介紹可用的協議以及它們的優缺點。接下來的部分將解釋一些使用這些協議的典型設定以及如何讓你的伺服器正常執行。最後,如果你不介意將程式碼託管在別人的伺服器上,並且不想費心設定和維護自己的伺服器,我們將介紹一些託管選項。

如果你沒有興趣執行自己的伺服器,你可以跳到本章的最後部分,瞭解一些設定託管賬戶的選項,然後繼續閱讀下一章,我們將討論分散式原始碼控制環境中的各種細節。

遠端倉庫通常是裸倉庫 — — 一個沒有工作目錄的 Git 倉庫。由於該倉庫僅用作協作點,因此磁碟上沒有檢出的快照;它只是 Git 資料。簡而言之,裸倉庫就是你的專案 .git 目錄的內容,僅此而已。

協議

Git 可以使用四種不同的協議來傳輸資料:本地 (Local)、HTTP、安全 Shell (SSH) 和 Git 協議。在這裡,我們將討論它們是什麼,以及在什麼基本情況下你會想(或不想)使用它們。

本地協議

最基本的是本地協議,其中遠端倉庫位於同一主機上的另一個目錄中。這通常在團隊中的每個人都有權訪問共享檔案系統(如 NFS 掛載)時使用,或者在不太可能的情況下,每個人都登入到同一臺計算機。後者並不理想,因為你所有的程式碼倉庫例項都將駐留在同一臺計算機上,使得災難性丟失的可能性大大增加。

如果你有一個共享掛載的檔案系統,那麼你可以克隆、推送和拉取一個基於本地檔案的倉庫。要克隆這樣的倉庫,或者將其新增為現有專案的遠端倉庫,請使用倉庫的路徑作為 URL。例如,要克隆一個本地倉庫,你可以執行類似以下的命令:

$ git clone /srv/git/project.git

或者你可以這樣做:

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

如果 URL 開頭明確指定了 file://,Git 的操作方式會略有不同。如果你只指定路徑,Git 會嘗試使用硬連結或直接複製所需檔案。如果你指定了 file://,Git 會啟動它通常用於透過網路傳輸資料的程序,這通常效率較低。指定 file:// 字首的主要原因是如果你想要一個乾淨的倉庫副本,並且剔除了多餘的引用或物件 — — 通常是在從其他 VCS 匯入或類似操作之後(有關維護任務,請參閱 Git Internals)。我們在這裡使用普通路徑,因為這樣做幾乎總是更快。

要將本地倉庫新增到現有的 Git 專案,你可以執行類似以下的命令:

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

然後,你可以透過你的新遠端名稱 local_proj 來推送和拉取該遠端倉庫,就像透過網路進行操作一樣。

優點

基於檔案的倉庫的優點是它們很簡單,並且它們利用現有的檔案許可權和網路訪問。如果你已經有一個整個團隊都可以訪問的共享檔案系統,那麼設定一個倉庫將非常容易。你將裸倉庫副本放在一個每個人都有共享訪問許可權的地方,並像設定任何其他共享目錄一樣設定讀/寫許可權。我們將在 Getting Git on a Server 中討論如何為此目的匯出裸倉庫副本。

對於快速獲取他人工作倉庫中的內容,這也是一個不錯的選擇。如果你和同事正在處理同一個專案,而他們希望你檢查某些內容,執行類似 git pull /home/john/project 的命令通常比他們先推送到遠端伺服器,然後你再從中獲取更容易。

缺點

此方法的缺點是與基本的網路訪問相比,共享訪問通常更難設定和從多個位置訪問。如果你想在家時從筆記型電腦推送,你必須掛載遠端磁碟,這與基於網路的訪問相比可能很困難且速度很慢。

需要注意的是,如果你使用的是某種共享掛載,這不一定是速度最快的選項。本地倉庫僅在你能快速訪問資料時才快速。NFS 上的倉庫通常比同一伺服器上的 SSH 倉庫慢,因為 Git 可以直接從每個系統的本地磁碟執行。

最後,此協議不能防止倉庫受到意外損壞。每個使用者都可以完全訪問“遠端”目錄的 shell,沒有任何東西可以阻止他們更改或刪除 Git 內部檔案並損壞倉庫。

HTTP 協議

Git 可以使用兩種不同的模式透過 HTTP 進行通訊。在 Git 1.6.6 之前,只有一種非常簡單且通常是隻讀的方式。在 1.6.6 版本中,引入了一種新的、更智慧的協議,該協議允許 Git 以類似於 SSH 的方式智慧地協商資料傳輸。在過去的幾年裡,這種新的 HTTP 協議變得非常流行,因為它對使用者來說更簡單,並且在通訊方式上更智慧。新版本通常被稱為智慧 HTTP 協議,而舊版本被稱為 HTTP 協議。我們將首先介紹較新的智慧 HTTP 協議。

智慧 HTTP

智慧 HTTP 的工作方式與 SSH 或 Git 協議非常相似,但它執行在標準的 HTTPS 埠上,並可以使用各種 HTTP 身份驗證機制,這意味著它通常比 SSH 等更容易使用,因為你可以使用使用者名稱/密碼身份驗證,而無需設定 SSH 金鑰。

它可能已經成為現在使用 Git 最流行的方式,因為它既可以像 git:// 協議那樣設定為匿名提供服務,也可以像 SSH 協議那樣透過身份驗證和加密進行推送。你不必為這些不同的功能設定不同的 URL,現在可以使用同一個 URL。如果你嘗試推送,而倉庫需要身份驗證(通常情況下是這樣),伺服器可以提示輸入使用者名稱和密碼。讀取訪問也是如此。

事實上,對於 GitHub 等服務,你用來線上檢視倉庫的 URL(例如,https://github.com/schacon/simplegit)就是你可以用來克隆、以及(如果你有許可權)推送的相同 URL。

啞 HTTP

如果伺服器沒有響應 Git HTTP 智慧服務,Git 客戶端將嘗試回退到更簡單的 HTTP 協議。啞協議期望裸 Git 倉庫像普通檔案一樣由 Web 伺服器提供。啞 HTTP 的魅力在於其設定的簡單性。基本上,你只需將一個裸 Git 倉庫放在你的 HTTP 文件根目錄下,並設定一個特定的 post-update 鉤子,即可完成(請參閱 Git Hooks)。此時,任何可以訪問你放置倉庫的 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 Internals 章節)。

通常,你會選擇執行一個讀/寫智慧 HTTP 伺服器,或者簡單地以啞方式將檔案設為只讀訪問。很少會同時執行這兩種服務。

優點

我們將專注於智慧 HTTP 協議的優點。

擁有一個統一的 URL 用於所有型別的訪問,並且只在需要身份驗證時才提示伺服器,這使得終端使用者使用起來非常方便。能夠使用使用者名稱和密碼進行身份驗證也是比 SSH 的一大優勢,因為使用者無需在本地生成 SSH 金鑰並將公鑰上傳到伺服器即可進行互動。對於不太成熟的使用者,或在 SSH 不太常見的系統上的使用者來說,這是一個可用性的主要優勢。它也是一種非常快速高效的協議,與 SSH 協議類似。

你還可以透過 HTTPS 提供只讀倉庫,這意味著你可以加密內容傳輸;或者你可以進一步要求客戶端使用特定的簽名 SSL 證書。

另一個好處是 HTTP 和 HTTPS 是非常常用的協議,因此企業防火牆通常設定為允許透過其埠進行流量。

缺點

與某些伺服器上的 SSH 相比,透過 HTTPS 的 Git 設定可能有點棘手。除此之外,其他協議在提供 Git 內容方面幾乎沒有比智慧 HTTP 更有優勢的地方。

如果你使用 HTTP 進行身份驗證推送,提供憑據有時比使用 SSH 金鑰更復雜。但是,有幾種憑據快取工具可供使用,包括 macOS 上的 Keychain access 和 Windows 上的 Credential Manager,可以使這個過程相當順暢。請閱讀 Credential Storage,瞭解如何在你的系統上設定安全的 HTTP 密碼快取。

SSH 協議

自託管 Git 時,SSH 是一種常見的傳輸協議。這是因為在大多數地方 SSH 訪問伺服器已經設定好了 — — 如果沒有,也很容易設定。SSH 也是一種經過身份驗證的網路協議,並且由於其普遍性,通常易於設定和使用。

要透過 SSH 克隆 Git 倉庫,你可以像這樣指定一個 ssh:// URL:

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

或者你可以使用更短的類似 scp 的 SSH 協議語法:

$ git clone [user@]server:project.git

在上述兩種情況下,如果你不指定可選的使用者名稱,Git 會假定你當前登入的使用者。

優點

使用 SSH 的優點很多。首先,SSH 相對容易設定 — — SSH 守護程序很常見,許多網路管理員都有使用它們的經驗,許多作業系統發行版都已配置了它們或提供了管理它們的工具。其次,SSH 訪問是安全的 — — 所有資料傳輸都經過加密和身份驗證。最後,與 HTTPS、Git 和本地協議一樣,SSH 也很高效,能在傳輸前儘可能壓縮資料。

缺點

SSH 的負面之處在於它不支援匿名訪問你的 Git 倉庫。如果你使用 SSH,人們必須擁有你機器的 SSH 訪問許可權,即使是隻讀的,這使得 SSH 不利於開源專案,因為人們可能只是想克隆你的倉庫來檢查它。如果你僅在公司網路內使用它,SSH 可能是你唯一需要處理的協議。如果你想為你的專案提供匿名的只讀訪問,同時又想使用 SSH,你將需要設定 SSH 來進行推送,但需要其他方式供他人獲取。

Git 協議

最後,我們有 Git 協議。這是一種 Git 自帶的特殊守護程序;它監聽一個專用埠 (9418),提供與 SSH 協議類似的服務,但完全沒有身份驗證或加密。為了透過 Git 協議提供倉庫,你必須建立一個 git-daemon-export-ok 檔案 — — 沒有這個檔案,守護程序就不會提供倉庫 — — 但除此之外,沒有安全性。要麼 Git 倉庫可供所有人克隆,要麼不可。這意味著該協議通常不支援推送。你可以啟用推送訪問,但鑑於缺乏身份驗證,網際網路上任何發現你的專案 URL 的人都可以推送到該專案。可以說,這種情況非常罕見。

優點

Git 協議通常是可用的最快的網路傳輸協議。如果你為公共專案提供大量流量,或者為一個不需要讀取訪問身份驗證的非常大的專案提供服務,你可能需要設定一個 Git 守護程序來為你提供專案服務。它使用與 SSH 協議相同的​​資料傳輸機制,但沒有加密和身份驗證的開銷。

缺點

由於缺乏 TLS 或其他加密,透過 git:// 克隆可能會導致任意程式碼執行漏洞,因此應避免使用,除非你瞭解自己在做什麼。

  • 如果你執行 git clone git://example.com/project.git,控制例如你路由器的攻擊者可以修改你剛剛克隆的倉庫,並在其中插入惡意程式碼。如果你隨後編譯/執行你剛克隆的程式碼,你將執行惡意程式碼。執行 git clone http://example.com/project.git 也應出於同樣的原因避免。

  • 執行 git clone https://example.com/project.git 不存在同樣的問題(除非攻擊者能夠提供 example.com 的 TLS 證書)。執行 git clone git@example.com:project.git 僅在你接受錯誤的 SSH 金鑰指紋時存在此問題。

它也沒有身份驗證,也就是說,任何人都可以克隆倉庫(儘管這通常正是你想要的)。它也可能是最難設定的協議。它必須執行自己的守護程序,這需要 xinetdsystemd 配置之類的東西,這並不總是那麼容易。它還需要防火牆訪問埠 9418,而這並不是企業防火牆總是允許的標準埠。在大公司的防火牆後面,這個不常用的埠通常會被阻止。