简体中文 ▾ 主题 ▾ 最新版本 ▾ gitprotocol-http 上次更新于 2.44.0

名称

gitprotocol-http - 基于 HTTP 的 Git 协议

概要

<over-the-wire-protocol>

描述

Git 支持两种基于 HTTP 的传输协议。 一种是 "dumb" 协议,它只需要连接的服务器端的标准 HTTP 服务器,另一种是 "smart" 协议,它需要一个 Git 感知的 CGI (或服务器模块)。 本文档描述了这两种协议。

作为一个设计特性,smart 客户端可以自动将 "dumb" 协议 URL 升级为 smart URL。 这允许所有用户拥有相同的已发布 URL,并且对等方自动选择可用于它们的最有效的传输方式。

URL 格式

通过 HTTP 访问的 Git 存储库的 URL 使用 RFC 1738 记录的标准 HTTP URL 语法,因此它们的形式为

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

在本文档中,占位符 $GIT_URL 将代表最终用户输入的 http:// 存储库 URL。

服务器应该处理所有与 $GIT_URL 匹配的请求,因为 Git 使用的 "smart" 和 "dumb" HTTP 协议都通过将额外的路径组件附加到用户提供的 $GIT_URL 字符串的末尾来操作。

一个 dumb 客户端请求一个松散对象的示例

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

一个对 catch-all 网关的 smart 请求的示例

$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 才能正常工作。 客户端可以按照 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 客户端必须通过发现远程存储库上可用的引用来开始 fetch 或 push 交换。

Dumb 客户端

仅支持 "dumb" 协议的 HTTP 客户端必须通过请求存储库的特殊 info/refs 文件来发现引用。

Dumb 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。 Dumb 服务器不得返回以 application/x-git- 开头的返回类型。

可以返回 Cache-Control 标头以禁用返回实体的缓存。

检查响应时,客户端应仅检查 HTTP 状态代码。 有效响应为 200 OK304 Not Modified

返回的内容是一个 UNIX 格式的文本文件,描述了每个 ref 及其已知值。 该文件应按名称根据 C 语言环境排序进行排序。 该文件不应包含名为 HEAD 的默认 ref。

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

Smart 客户端

支持 "smart" 协议(或 "smart" 和 "dumb" 协议)的 HTTP 客户端必须通过对存储库的 info/refs 文件发出参数化请求来发现引用。

该请求必须包含恰好一个查询参数 service=$servicename,其中 $servicename 必须是客户端希望联系以完成操作的服务名称。 该请求不得包含其他查询参数。

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

dumb 服务器回复

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^{}

smart 服务器回复

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

客户端可以将额外参数 (参见 gitprotocol-pack[5]) 作为冒号分隔的字符串在 Git-Protocol HTTP 标头中发送。

使用 --http-backend-info-refs 选项来 git-upload-pack[1]

Dumb 服务器响应

Dumb 服务器必须以 dumb 服务器回复格式进行响应。

有关 dumb 服务器响应的更详细描述,请参阅前面 dumb 客户端下的部分。

Smart 服务器响应

如果服务器无法识别请求的服务名称,或者服务器管理员已禁用请求的服务名称,则服务器必须以 403 Forbidden HTTP 状态代码进行响应。

否则,smart 服务器必须以请求的服务名称的 smart 服务器回复格式进行响应。

应该使用 Cache-Control 标头来禁用返回实体的缓存。

Content-Type 必须是 application/x-$servicename-advertisement。 如果返回另一种内容类型,客户端应该回退到 dumb 协议。 当回退到 dumb 协议时,客户端不应该向 $GIT_URL/info/refs 发出额外请求,而应该使用已有的响应。 如果客户端不支持 dumb 协议,则必须停止。

客户端必须验证状态代码是否为 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 后面包含 capability 声明。

如果发送了 "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 标头以防止缓存响应。

服务器应该支持此处定义的所有 capabilities。

客户端必须在请求正文中发送至少一个 "want" 命令。除非服务器声明 capability 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:基于引用发现期间看到的内容,构建一个集合 want,其中包含客户端想要从 advertised 获取的对象。

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 flush (0000) 终止。

单个 "want" 或 "have" 命令必须具有一个十六进制格式的对象名称作为其值。必须通过发送多个命令来发送多个对象名称。必须使用通过 object-format capability 协商的对象格式(默认 SHA-1)给出对象名称。

have 列表是通过从 c_pending 中弹出前 32 个提交来创建的。如果 c_pending 为空,则可以提供更少的提交。

如果客户端已发送 256 个 "have" 提交,但尚未从 s_common 收到其中一个,或者客户端已清空 c_pending,它应该包含一个 "done" 命令,以让服务器知道它不会继续。

C: 0009done

S:解析 git-upload-pack 请求

验证 want 中的所有对象是否可直接从引用访问。

服务器可能会向后遍历历史记录或 reflog,以允许稍微过时的请求。

如果未收到任何 "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 标头以防止缓存响应。

服务器应该支持此处定义的所有 capabilities。

客户端必须在请求正文中发送至少一个命令。在请求正文的命令部分,客户端应该发送通过引用发现获得的 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