簡體中文 ▾ 主題 ▾ 最新版本 ▾ gitprotocol-http 最後更新於 2.44.0

名稱

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 認證時保護密碼。

會話狀態

Git over HTTP 協議(很像 HTTP 本身)從 HTTP 伺服器端來看是無狀態的。所有狀態必須由客戶端程序保留和管理。這允許伺服器端進行簡單的輪詢負載均衡,而無需擔心狀態管理。

客戶端不得要求伺服器端進行狀態管理才能正常執行。

伺服器不得要求 HTTP Cookie 才能正常執行。客戶端可以在請求處理期間儲存和轉發 HTTP Cookie,如 RFC 2616 (HTTP/1.1) 所述。伺服器應忽略客戶端傳送的任何 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

客戶端必須驗證響應實體的前五個位元組匹配正則表示式 ^[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 執行引用發現。

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”命令中引用未透過引用發現獲得的 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: 使用引用發現來獲取已公佈的引用。

C: 將任何已見物件放入集合 advertised

C: 構建一個空集 common,用於存放稍後確定在兩端都存在的物件。

C: 根據在引用發現期間看到的內容,從 advertised 中構建客戶端想要獲取的物件集合 want

C: 啟動一個佇列 c_pending,按提交時間排序(最新者優先彈出)。新增所有客戶端引用。當一個提交從佇列中彈出時,其父級應自動重新插入。提交必須只進入佇列一次。

一個計算步驟

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 重新整理 (0000) 終止。

單個“want”或“have”命令的值必須是一個十六進位制格式的物件名稱。必須透過傳送多個命令來發送多個物件名稱。物件名稱必須使用透過 object-format 能力協商的物件格式給出(預設為 SHA-1)。

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

如果客戶端已傳送 256 個“have”提交,但尚未從 s_common 收到其中任何一個,或者客戶端已清空 c_pending,它應包含一個“done”命令,以告知伺服器它將不再繼續。

C: 0009done

S: 解析 git-upload-pack 請求

驗證 want 中的所有物件是否可以直接從引用中訪問。

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

如果沒有收到“want”物件,則傳送錯誤:待辦:如果沒有請求“want”行,則定義錯誤。

如果任何“want”物件無法訪問,則傳送錯誤:待辦:如果請求了無效的“want”,則定義錯誤。

建立一個空列表 s_common

如果傳送了“have”

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

對於每個物件,如果伺服器可以從引用中訪問該物件,則將其新增到 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 執行引用發現。

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 頭以防止響應被快取。

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

客戶端必須在請求正文中至少傳送一個命令。在請求正文的命令部分中,客戶端應將透過引用發現獲得的 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