Git

名稱

gitprotocol-http - Git 基於 HTTP 的協定

概要

<over-the-wire-protocol>

描述

Git 支援兩種基於 HTTP 的傳輸協定。一種「笨」協定,僅需要在連線的伺服器端有一個標準 HTTP 伺服器,另一種「智慧」協定,則需要一個能感知 Git 的 CGI (或伺服器模組)。此文件描述了這兩種協定。

作為一個設計特點,智慧用戶端可以自動將「笨」協定的 URL 升級為智慧的 URL。這允許所有使用者擁有相同的發佈 URL,並且對等端會自動選擇最有效率的傳輸方式。

URL 格式

使用 HTTP 存取的 Git 儲存庫的 URL 使用 RFC 1738 文件中定義的標準 HTTP URL 語法,因此它們的形式如下:

http://<host>:<port>/<path>?<searchpart>

在此文件中,佔位符 $GIT_URL 將代表最終使用者輸入的 http:// 儲存庫 URL。

伺服器應處理所有與 $GIT_URL 相符的位置的請求,因為 Git 使用的「智慧」和「笨」HTTP 協定都是通過在使用者提供的 $GIT_URL 字串的末尾附加額外的路徑組件來操作的。

一個笨用戶端請求一個鬆散物件的例子

$GIT_URL:     http://example.com:8080/git/repo.git
URL request:  http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355

一個智慧請求到一個全域閘道的例子

$GIT_URL:     http://example.com/daemon.cgi?svc=git&q=
URL request:  http://example.com/daemon.cgi?svc=git&q=/info/refs&service=git-receive-pack

一個請求子模組的例子

$GIT_URL:     http://example.com/git/repo.git/path/submodule.git
URL request:  http://example.com/git/repo.git/path/submodule.git/info/refs

用戶端必須從使用者提供的 $GIT_URL 字串中刪除尾隨的 / (如果存在),以防止空路徑令牌 (//) 出現在傳送到伺服器的任何 URL 中。相容的用戶端必須將 $GIT_URL/info/refs 展開為 foo/info/refs 而不是 foo//info/refs

驗證

如果需要驗證才能存取儲存庫,則會使用標準 HTTP 驗證,並且可以由 HTTP 伺服器軟體設定和強制執行。

由於 Git 儲存庫是透過標準路徑組件存取的,因此伺服器管理員可以在其 HTTP 伺服器中使用基於目錄的權限來控制儲存庫存取。

用戶端應支援 RFC 2617 中描述的基本驗證。伺服器應透過依賴放置在 Git 伺服器軟體前面的 HTTP 伺服器來支援基本驗證。

伺服器不應為了驗證或存取控制而要求 HTTP Cookie。

用戶端和伺服器可以支援其他常見的基於 HTTP 的驗證形式,例如摘要驗證。

SSL

用戶端和伺服器應支援 SSL,尤其是在依賴基本 HTTP 驗證時保護密碼。

會話狀態

從 HTTP 伺服器端的角度來看,透過 HTTP 的 Git 協定 (很像 HTTP 本身) 是無狀態的。所有狀態必須由用戶端程序保留和管理。這允許在伺服器端進行簡單的循環負載平衡,而無需擔心狀態管理。

用戶端為了正常運作,不得要求伺服器端進行狀態管理。

伺服器為了正常運作,不得要求 HTTP Cookie。用戶端可以在請求處理期間,根據 RFC 2616 (HTTP/1.1) 中描述的方式儲存和轉發 HTTP Cookie。伺服器應忽略用戶端傳送的任何 Cookie。

一般請求處理

除非另有說明,否則用戶端和伺服器都應假定所有標準 HTTP 行為。這包括 (但不一定僅限於)

如果 $GIT_URL 上沒有儲存庫,或者與 $GIT_URL 相符的位置所指向的資源不存在,伺服器不得回應 200 OK 回應。伺服器應回應 404 Not Found410 Gone 或任何其他不暗示資源如請求存在的合適 HTTP 狀態碼。

如果 $GIT_URL 上有儲存庫,但目前不允許存取,伺服器必須回應 403 Forbidden HTTP 狀態碼。

伺服器應同時支援 HTTP 1.0 和 HTTP 1.1。伺服器應支援請求和回應主體的區塊編碼。

用戶端應同時支援 HTTP 1.0 和 HTTP 1.1。用戶端應支援請求和回應主體的區塊編碼。

伺服器可以傳回 ETag 和/或 Last-Modified 標頭。

用戶端可以透過包含 If-Modified-Since 和/或 If-None-Match 請求標頭來重新驗證快取的實體。

如果相關標頭出現在請求中且實體沒有變更,伺服器可以傳回 304 Not Modified。用戶端必須將 304 Not Modified 視為與 200 OK 相同,並重複使用快取的實體。

如果 Cache-Control 和/或 Expires 標頭允許快取,用戶端可以重複使用快取的實體,而無需重新驗證。用戶端和伺服器必須遵循 RFC 2616 的快取控制。

探索參考

所有 HTTP 用戶端都必須透過探索遠端儲存庫上可用的參考來開始提取或推送交換。

笨用戶端

僅支援「笨」協定的 HTTP 用戶端必須透過請求儲存庫的特殊 info/refs 檔案來探索參考。

笨 HTTP 用戶端必須對 $GIT_URL/info/refs 發出 GET 請求,而不帶任何搜尋/查詢參數。

C: GET $GIT_URL/info/refs HTTP/1.0
S: 200 OK
S:
S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31	refs/heads/maint
S: d049f6c27a2244e12041955e262a404c7faba355	refs/heads/master
S: 2cb58b79488a98d2721cea644875a8dd0026b115	refs/tags/v1.0
S: a3c2e2402b99163d1d59756e5f207ae21cccba4c	refs/tags/v1.0^{}

傳回的 info/refs 實體的 Content-Type 應為 text/plain; charset=utf-8,但可以是任何內容類型。用戶端不得嘗試驗證傳回的 Content-Type。笨伺服器不得傳回以 application/x-git- 開頭的傳回類型。

可以傳回 Cache-Control 標頭來停用傳回實體的快取。

在檢查回應時,用戶端應僅檢查 HTTP 狀態碼。有效回應為 200 OK304 Not Modified

傳回的內容是一個 UNIX 格式的文字檔,描述每個參考及其已知的值。檔案應根據 C 語言環境排序按名稱排序。檔案不應包含名為 HEAD 的預設參考。

info_refs   =  *( ref_record )
ref_record  =  any_ref / peeled_ref
any_ref     =  obj-id HTAB refname LF
peeled_ref  =  obj-id HTAB refname LF
 obj-id HTAB refname "^{}" LF

智慧用戶端

支援「智慧」協定 (或同時支援「智慧」和「笨」協定) 的 HTTP 用戶端必須透過對儲存庫的 info/refs 檔案發出參數化請求來探索參考。

請求必須正好包含一個查詢參數 service=$servicename,其中 $servicename 必須是用戶端希望聯絡以完成操作的服務名稱。請求不得包含其他查詢參數。

C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0

笨伺服器回覆

S: 200 OK
S:
S: 95dcfa3633004da0049d3d0fa03f80589cbcaf31	refs/heads/maint
S: d049f6c27a2244e12041955e262a404c7faba355	refs/heads/master
S: 2cb58b79488a98d2721cea644875a8dd0026b115	refs/tags/v1.0
S: a3c2e2402b99163d1d59756e5f207ae21cccba4c	refs/tags/v1.0^{}

智慧伺服器回覆

S: 200 OK
S: Content-Type: application/x-git-upload-pack-advertisement
S: Cache-Control: no-cache
S:
S: 001e# service=git-upload-pack\n
S: 0000
S: 004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint\0multi_ack\n
S: 003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master\n
S: 003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0\n
S: 003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}\n
S: 0000

用戶端可以在 Git-Protocol HTTP 標頭中以冒號分隔的字串形式傳送額外參數 (請參閱 gitprotocol-pack[5])。

使用 git-upload-pack[1]--http-backend-info-refs 選項。

笨伺服器回應

笨伺服器必須以笨伺服器回覆格式回應。

請參閱先前在笨用戶端下的章節,以取得笨伺服器回應的更詳細說明。

智慧伺服器回應

如果伺服器無法辨識請求的服務名稱,或伺服器管理員已停用請求的服務名稱,則伺服器必須回應 403 Forbidden HTTP 狀態碼。

否則,智慧伺服器必須以請求的服務名稱的智慧伺服器回覆格式回應。

應使用 Cache-Control 標頭來停用傳回實體的快取。

Content-Type 必須為 application/x-$servicename-advertisement。如果傳回其他內容類型,用戶端應回復為笨協定。當回復為笨協定時,用戶端不應向 $GIT_URL/info/refs 發出額外請求,而應使用已有的回應。如果用戶端不支援笨協定,則不得繼續。

用戶端必須驗證狀態碼是 200 OK304 Not Modified

用戶端必須驗證回應實體的前五個位元組是否符合 regex ^[0-9a-f]{4}#。如果此測試失敗,用戶端不得繼續。

用戶端必須將整個回應解析為 pkt-line 記錄的序列。

用戶端必須驗證第一個 pkt-line 是 # service=$servicename。伺服器必須將 $servicename 設定為請求參數值。伺服器應在此行結尾處包含 LF。用戶端必須忽略行結尾處的 LF。

伺服器必須使用魔術 0000 結尾 pkt-line 標記終止回應。

傳回的回應是一個 pkt-line 資料流,描述每個參考及其已知的值。資料流應根據 C 語言環境排序按名稱排序。資料流應將名為 HEAD 的預設參考作為第一個參考。資料流必須在第一個參考上的 NUL 後面包含功能宣告。

如果將 "version=1" 作為額外參數傳送,則傳回的回應包含 "version 1"。

smart_reply     =  PKT-LINE("# service=$servicename" LF)
     "0000"
     *1("version 1")
     ref_list
     "0000"
ref_list        =  empty_list / non_empty_list
empty_list      =  PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)
non_empty_list  =  PKT-LINE(obj-id SP name NUL cap_list LF)
     *ref_record
cap-list        =  capability *(SP capability)
capability      =  1*(LC_ALPHA / DIGIT / "-" / "_")
LC_ALPHA        =  %x61-7A
ref_record      =  any_ref / peeled_ref
any_ref         =  PKT-LINE(obj-id SP name LF)
peeled_ref      =  PKT-LINE(obj-id SP name LF)
     PKT-LINE(obj-id SP name "^{}" LF

智慧服務 git-upload-pack

此服務從 $GIT_URL 指向的儲存庫讀取。

客戶端必須先使用 $GIT_URL/info/refs?service=git-upload-pack 執行 ref 探索。

C: POST $GIT_URL/git-upload-pack HTTP/1.0
C: Content-Type: application/x-git-upload-pack-request
C:
C: 0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7\n
C: 0032have 441b40d833fdfa93eb2908e52742248faf0ee993\n
C: 0000
S: 200 OK
S: Content-Type: application/x-git-upload-pack-result
S: Cache-Control: no-cache
S:
S: ....ACK %s, continue
S: ....NAK

客戶端不得重複使用或重新驗證快取的響應。伺服器必須包含足夠的 Cache-Control 標頭以防止快取響應。

伺服器應支援此處定義的所有功能。

客戶端必須在請求主體中至少發送一個 "want" 命令。除非伺服器宣告 allow-tip-sha1-in-wantallow-reachable-sha1-in-want 功能,否則客戶端不得在 "want" 命令中引用在 ref 探索所獲得的響應中未出現的 ID。

compute_request   =  want_list
       have_list
       request_end
request_end       =  "0000" / "done"
want_list         =  PKT-LINE(want SP cap_list LF)
       *(want_pkt)
want_pkt          =  PKT-LINE(want LF)
want              =  "want" SP id
cap_list          =  capability *(SP capability)
have_list         =  *PKT-LINE("have" SP id LF)

待辦事項:進一步記錄此內容。

協商演算法

選擇最小封包的計算方式如下(C = 客戶端,S = 伺服器)

初始步驟

C:使用 ref 探索取得宣告的 ref。

C:將任何看到的物件放入集合 advertised 中。

C:建立一個空的集合 common,以保存稍後確定兩端都有的物件。

C:根據在 ref 探索期間看到的內容,從 advertised 中建立客戶端想要提取的物件集合 want

C:啟動一個佇列 c_pending,並依提交時間排序(優先彈出最新的)。加入所有客戶端 ref。當從佇列中彈出提交時,其父提交應自動插回。提交必須僅進入佇列一次。

單一計算步驟

C:發送一個 $GIT_URL/git-upload-pack 請求

C: 0032want <want-#1>...............................
C: 0032want <want-#2>...............................
....
C: 0032have <common-#1>.............................
C: 0032have <common-#2>.............................
....
C: 0032have <have-#1>...............................
C: 0032have <have-#2>...............................
....
C: 0000

資料流以「命令」組織,每個命令在 pkt-line 中單獨出現。在命令列中,第一個空格之前的文字是命令名稱,該行的其餘部分到第一個 LF 則是值。命令列以 LF 作為 pkt-line 值的最後一個位元組終止。

命令必須依以下順序出現(如果它們出現在請求資料流中)

  • "want"

  • "have"

資料流以 pkt-line flush (0000) 終止。

單一 "want" 或 "have" 命令必須有一個十六進位格式的物件名稱作為其值。必須透過發送多個命令來發送多個物件名稱。物件名稱必須使用透過 object-format 功能協商的物件格式給定(預設 SHA-1)。

have 列表是透過從 c_pending 中彈出前 32 個提交建立的。如果 c_pending 為空,則可以提供較少的提交。

如果客戶端已發送 256 個 "have" 提交,但尚未從 s_common 中收到其中一個回覆,或者客戶端已清空 c_pending,則它應包含 "done" 命令,以告知伺服器它不會繼續。

C: 0009done

S:解析 git-upload-pack 請求

驗證 want 中的所有物件是否可直接從 ref 存取。

伺服器可以向後遍歷歷史記錄或透過 reflog,以允許稍微過期的請求。

如果沒有收到 "want" 物件,則發送錯誤:待辦事項:如果沒有請求 "want" 行,則定義錯誤。

如果任何 "want" 物件不可存取,則發送錯誤:待辦事項:如果請求了無效的 "want",則定義錯誤。

建立一個空列表 s_common

如果已發送 "have"

按照客戶端提供的順序迴圈遍歷物件。

對於每個物件,如果伺服器具有可從 ref 存取的物件,則將其添加到 s_common。如果將提交添加到 s_common,則不要添加任何祖先,即使它們也出現在 have 中。

S:發送 git-upload-pack 響應

如果伺服器已找到要打包的封閉物件集,或者請求以 "done" 結尾,則它會以封包回應。待辦事項:記錄基於封包的回應

S: PACK...

返回的資料流是 git-upload-pack 服務支援的 side-band-64k 協定,並且封包嵌入到資料流 1 中。來自伺服器端的進度訊息可能會出現在資料流 2 中。

此處將「封閉物件集」定義為從每個 "want" 到至少一個 "common" 物件具有至少一條路徑。

如果伺服器需要更多資訊,則它會以狀態繼續回應:待辦事項:記錄非封包回應

C:解析 upload-pack 回應:待辦事項:記錄解析回應

執行另一個計算步驟。

智慧型服務 git-receive-pack

此服務從 $GIT_URL 指向的儲存庫讀取。

客戶端必須先使用 $GIT_URL/info/refs?service=git-receive-pack 執行 ref 探索。

C: POST $GIT_URL/git-receive-pack HTTP/1.0
C: Content-Type: application/x-git-receive-pack-request
C:
C: ....0a53e9ddeaddad63ad106860237bbf53411d11a7 441b40d833fdfa93eb2908e52742248faf0ee993 refs/heads/maint\0 report-status
C: 0000
C: PACK....
S: 200 OK
S: Content-Type: application/x-git-receive-pack-result
S: Cache-Control: no-cache
S:
S: ....

客戶端不得重複使用或重新驗證快取的響應。伺服器必須包含足夠的 Cache-Control 標頭以防止快取響應。

伺服器應支援此處定義的所有功能。

客戶端必須在請求主體中至少發送一個命令。在請求主體的命令部分中,客戶端應發送透過 ref 探索取得的 ID 作為 old_id。

update_request  =  command_list
     "PACK" <binary-data>
command_list    =  PKT-LINE(command NUL cap_list LF)
     *(command_pkt)
command_pkt     =  PKT-LINE(command LF)
cap_list        =  *(SP capability) SP
command         =  create / delete / update
create          =  zero-id SP new_id SP name
delete          =  old_id SP zero-id SP name
update          =  old_id SP new_id SP name

待辦事項:進一步記錄此內容。

GIT

屬於 git[1] 套件的一部分

scroll-to-top