设置和配置
获取和创建项目
基本快照
分支与合并
共享和更新项目
检查和比较
打补丁
调试
电子邮件
外部系统
服务器管理
指南
管理
底层命令
- 2.44.1 → 2.50.1 无更改
-
2.44.0
2024-02-23
- 2.43.2 → 2.43.7 无变更
-
2.43.1
2024-02-09
-
2.43.0
2023-11-20
- 2.38.1 → 2.42.4 无更改
-
2.38.0
2022-10-02
描述
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 的认证形式,例如摘要认证。
会话状态
Git over HTTP 协议(很像 HTTP 本身)从 HTTP 服务器端来看是无状态的。所有状态必须由客户端进程保留和管理。这允许服务器端进行简单的轮询负载均衡,而无需担心状态管理。
客户端不得要求服务器端进行状态管理才能正常运行。
服务器不得要求 HTTP Cookie 才能正常运行。客户端可以在请求处理期间存储和转发 HTTP Cookie,如 RFC 2616 (HTTP/1.1) 所述。服务器应忽略客户端发送的任何 Cookie。
通用请求处理
除非另有说明,客户端和服务器都应假定所有标准 HTTP 行为。这包括(但不限于)
如果在 $GIT_URL
没有仓库,或者由与 $GIT_URL
匹配的位置指向的资源不存在,服务器不得响应 200
OK
。服务器应响应 404
Not
Found
、410
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
OK
或 304
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
OK
或 304
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-want
或 allow-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
待办:进一步完善此文档。