Git 的传输协议是如何工作的

Chr*_*oph 6 git

我使用 Git 已经一年多了,现在我必须向我们组中的其他人解释它。这就是为什么我需要更多的背景知识。\n去年我浏览了 Git 书籍的大部分内容,最近我继续阅读第 10 章。在第10.6章中章我完全陷入困境:

\n\n
\n

让\xe2\x80\x99s 遵循 simplegit 库的 http-fetch 过程:

\n\n
$ git clone http://server/simplegit-progit.git\n
Run Code Online (Sandbox Code Playgroud)\n\n

该命令所做的第一件事是下拉 info/refs 文件。\n 该文件是由 update-server-info 命令写入的,这就是为什么\n 您需要将其启用为接收后挂钩,以便HTTP\n 传输正常工作:

\n\n
=> GET info/refs\nca82a6dff817ec66f44342007202690a93763949     refs/heads/master\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

我有一个小型测试仓库https://github.com/to_my/repo并且git clone运行良好。但

\n\n
    \n
  • 文件夹在哪里info/refs?我只找到了/.git/info/exclude之后clone...
  • \n
  • 我应该如何使用该update-server-info命令?它是 git clone 的一部分吗?
  • \n
  • 我完全迷失了“...这就是为什么你需要将其启用为接收后挂钩”,尽管我了解挂钩(我认为)并使用预提交挂钩来自动增加包版本。
  • \n
  • 我无法GET info/refs在 git bash 工作中获取该命令。
  • \n
\n\n

抱歉,如果问题很愚蠢,但我只是不明白如何将文档中的这些部分放在一起。

\n

Von*_*onC 8

注意:从 Git 2.18(2018 年第 2 季度)开始,git 传输协议随已实现的 v2 一起发展。
对于 Git 2.26(2020 年第一季度),它是默认的. 2.27中没有(2020 年第 2 季度,请参阅本答案末尾,以及后续答案)。又是 2.28(2020 年第三季度)

请参阅提交 a4d78ce、提交0f1dc53提交 237ffed提交 884e586提交 8ff14ed提交 49e85e9 、提交 f08a5d4 、提交 f1f4d8a、提交edc9caf 提交176e85c提交 b1c2edf提交 1aa8dde提交 40f c51e提交 f7e2050提交 685fbd3提交 3145ea9提交5b872ff提交 230d7dd提交 b4be741提交 1af8ae1(2018 年 3 月 15 日),作者:Brandon Williams ( )(由Junio C Hamano 合并 -- --提交 9bfa0f9中,2018 年 5 月 8 日)mbrandonw
gitster

完整规格位于Documentation/technical/protocol-v2.txt

协议 v2 将在以下方面对 v1 进行改进:

  • 单个服务将支持多个命令,而不是多个服务名称
  • 由于功能被移至协议的自己的部分,因此可以轻松扩展,不再隐藏在字节后面NUL并受到字节大小的限制pkt-line
  • 分离出隐藏在NUL字节后面的其他信息(例如,代理字符串作为一种功能,并且可以使用 'ls-refs' 请求符号引用
  • 除非明确要求,否则参考广告将被省略
  • ls-refs 命令显式请求一些参考
  • 设计时考虑到了 http 和 stateless-rpc。通过清晰的刷新语义,http 远程帮助程序可以简单地充当代理

在协议 v2 中,通信是面向命令的
当第一次联系服务器时,将公布一个功能列表。其中一些功能是客户端可以请求执行的命令。命令完成后,客户端可以重用该连接并请求执行其他命令。

info/refs保留由客户端查询的服务器端点,如 HTTP 传输部分中所述:

当使用http://https://传输时,客户端会发出一个“智能” info/refs请求,如 中所述,并通过在标头中http-protocol.txt提供“”来请求使用 v2 。version=2Git-Protocol

C: Git-Protocol: version=2
C:
C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
Run Code Online (Sandbox Code Playgroud)

v2 服务器会回复:

   S: 200 OK
   S: <Some headers>
   S: ...
   S:
   S: 000eversion 2\n
   S: <capability-advertisement>
Run Code Online (Sandbox Code Playgroud)

然后直接向服务发出后续请求 $GIT_URL/git-upload-pack。(这对于 git-receive-pack 来说是一样的)。

目标是拥有更多功能:

有两种不同类型的能力:

  • 正常功能,可用于传达信息或改变请求的行为,以及
  • 命令,这是客户端想要执行的核心操作(获取、推送等)。

默认情况下,协议版本 2 是无状态的
这意味着所有命令必须仅持续一轮并且从服务器端的角度来看是无状态的,除非客户端请求了指示状态应由服务器维护的能力。

客户端不得要求服务器端进行状态管理才能正常运行。
这允许在服务器端进行简单的循环负载平衡,而无需担心状态管理。

最后:

ls-refs是用于在 v2 中请求参考广告的命令。
与当前的参考广告不同,ls-refs它接受可用于限制从服务器发送的参考的参数。

和:

fetch是用于获取 v2 中的包文件的命令。
它可以被视为 v1 fetch 的修改版本,其中引用广告被删除(因为该ls-refs命令填补了该角色),并且消息格式经过调整以消除冗余并允许轻松添加未来的扩展。


自该提交(5 月 10 日)以来,协议 V2 已在Brandon Williams的 Google 博客文章“ Git 协议版本 2 简介”中正式宣布(5 月 28 日) 。

在这两种情况下:

基本命令中不支持的附加功能将以空格分隔的功能列表的形式作为功能通告中的命令值进行通告:“ <command>=<feature 1> <feature 2>


另请参阅Brandon Williams的提交 5e3548e提交 ff47322提交 ecc3e53(2018 年 4 月 23 日(由Junio C Hamano 合并 -- --提交 41267e9中,2018 年 5 月 23 日)mbrandonw
gitster

serve: 介绍一下server-option能力

将“ server-option”功能引入协议版本 2。
这使未来的客户端能够在使用协议版本 2 时在命令请求中发送服务器特定选项。

fetch:使用协议 v2 时发送服务器选项

教导fetch通过“ -o”或“ --server-option”在命令行上指定服务器选项来选择性地接受服务器选项。
当使用协议版本 2 执行通信时,这些服务器选项将发送到远程端fetch

如果使用 v2 以外的协议进行通信,则提供的选项将被忽略并且不会发送到远程端。

对 也做了同样的事情git ls-remote


传输协议 v2 学会了支持2017 年 12 月使用 Git 2.16看到的部分克隆。

请参阅Jonathan Tan的提交 ba95710提交 5459268(2018 年 5 月 3 日)和提交 7cc6ed2(2018 年 5 月 2 日(由Junio C Hamano 合并 -- --提交 54db5c0中,2018 年 5 月 30 日)jhowtan
gitster

{fetch,upload}-pack:支持协议v2中的过滤器

fetch-pack/upload-pack 协议 v2 是独立于过滤器参数(在部分获取中使用)开发的,因此不包含对其的支持。添加对过滤器参数的支持。

与传统协议一样,服务器filter仅在uploadpack.allowfilter配置时才会通告并支持“ ”。

与旧协议一样,如果--filter指定了“”,客户端会继续发出警告,但服务器不会通告它。


Git 2.19(2018 年第 3 季度)改进了 git 传输协议 v2 的 fetch 部分:

请参阅提交 ec06283提交 d093bc7提交 d30fe89提交 af1c90d提交 21bcf6e(2018 年 6 月 14 日)和提交 af00855提交 34c2903(2018 年 6 月 6 日),作者:Jonathan Tan ( jhowtan)
(由Junio C Hamano 合并 -- gitster--提交 af8ac73中,2018 年 8 月 2 日)

fetch-pack:介绍谈判者API

引入新文件fetch-negotiator.{h,c},其中包含一个API,在该API后面抽象了协商的细节。

fetch-pack:使用参考广告。修剪“已”发送

在使用 v2 协议的协商中,fetch-pack 有时不会充分利用 ref 通告中获得的信息:具体来说,如果服务器通告客户端也拥有的提交,则客户端永远不需要通知服务器它已经拥有提交的父级,因为它可以告诉服务器它具有广告的提交,并且它知道服务器可以并且将会推断其余的内容。


Git 2.20(2018 年第 4 季度)修复git ls-remotes

请参阅Jeff King的提交 6a139cd提交 631f0f8(2018 年 10 月 31 日(由Junio C Hamano 合并 -- --提交 81c365b中,2018 年 11 月 13 日)peff
gitster

git ls-remote $there foo被协议 v2 的最近更新所破坏,并停止显示与 ' foo' 匹配但不匹配的 引用refs/{heads,tags}/foo,该问题已得到修复。


Git 2.20 修复了git fetch在通过协议 v2 进行通信时解析对方响应时有点松散的问题。

请参阅Jonathan Tan ( )提交的提交 5400b2a(2018 年 10 月 19 日)。(由Junio C Hamano 合并 -- --提交 67cf2fa中,2018 年 11 月 13 日)jhowtan
gitster

fetch-pack:更精确地解析 v2 响应

协议 v2 响应中的每个部分后面都跟随一个DELIM数据包(指示要跟随更多部分)或一个FLUSH数据包(指示没有要跟随的部分)。

但在解析“ acknowledgments”部分时,do_fetch_pack_v2()可以自由地接受两者,但仅根据“ acknowledgments”部分的内容而不是是否已阅读来DELIM确定是否继续阅读FLUSH

符合协议的服务器没有问题,但在与提供意外附加部分的服务器通信时可能会导致混乱的错误消息。new-section考虑一个在“”之后发送“”的服务器acknowledgments

  • 客户端写入请求
    • 客户端读取不包含“ready”的“acknowledgments”部分,然后DELIM
    • 由于没有“准备好”,客户需要继续协商,并写请求
    • 客户端读取“ new-section”,并向最终用户报告“预期‘确认’,收到‘’ new-section

对于调试所涉及的 Git 实现的人员来说,错误消息令人困惑,因为new-section没有收到响应最新请求的“”,而是响应第一个请求。

一种解决方案是始终在之后继续阅读DELIM,但在这种情况下,我们可以做得更好。

从协议中我们知道:

  • “准备好”意味着至少包文件部分即将到来(因此,DELIM)并且:
  • 没有“准备好”意味着后面没有任何部分(因此,FLUSH)。

因此,教导process_acks()要强制执行这一点。


Git 2.21 将为 fetch pack 带来对 V2 协议的实际官方支持:

请参阅Jeff King提交的 e20b419(2018 年 12 月 18 日) ( )(由Junio C Hamano 合并 -- --提交 d3b0178中,2019 年 1 月 29 日)peff
gitster

fetch-pack:支持协议版本2

当协议版本2的脚手架最初在 8f6982b中添加时(“ protocol:引入enumprotocol_version值protocol_v2”,2018-03-14,Git v2.18)。如以下所示:

git log -p -G'support for protocol v2 not implemented yet' --full-diff --reverse v2.17.0..v2.20.0
Run Code Online (Sandbox Code Playgroud)

许多脚手架“死亡”占位符已被删除,但我们还没有抽出时间来进行打包。

这里“从 cmdline 获取引用”的测试非常少。在WIP GIT_TEST_PROTOCOL_VERSION=2模式下运行整个测试套件时,有更好的覆盖率,理想情况下我们应该有更好的覆盖率,而无需调用特殊的测试模式。


Git 2.22(2019 年第 2 季度)添加了:“ ”在讨论协议版本 2 时git clone学习了一个新选项。--server-option

请参阅Jonathan Tan ( )提交的提交 6e98305提交 35eb824(2019 年 4 月 12 日)。(由Junio C Hamano 合并 -- --提交 6d3df8e中,2019 年 5 月 8 日)jhowtan
gitster

clone:使用协议 v2 时发送服务器选项

Commit 5e3548e(“ fetch:使用协议 v2 时发送服务器选项”,2018-04-24,Git v2.18.0-rc0)教导“ fetch”使用协议 v2 时发送服务器选项的能力,但不是“ clone”。该能力由“ ”或“ ”
触发。-o--server-option

教导“克隆clone”相同的能力,只是因为“ clone”已经具有“ -o”作为另一个参数,所以教导“克隆”仅接收“ --server-option”。


tor*_*rek 3

\n

文件夹 info/refs 在哪里?我只在克隆后找到 /.git/info/exclude...

\n
\n\n

没有这样的文件夹(它不是目录,但是如果那里有文件.git/info/refs,那么 \xe2\x80\x94 \xe2\x80\x94 将是该文件所在的位置。

\n\n
\n

我应该如何使用 update-server-info 命令?它是 git clone 的一部分吗?

\n
\n\n

一般来说,您不应该使用它:它仅用于“哑”传输。“智能”(双向对话)传输不需要它。

\n\n
\n

我完全迷失了“...这就是为什么你需要将其启用为接收后挂钩”,尽管我了解挂钩(我认为)并使用预提交挂钩来自动增加包版本。

\n
\n\n

如果出于某种原因,您想要启用哑传输,则每次需要创建或更新多个文件时,您都需要运行某些文件来创建或更新它们。每当引用发生变化时,文件info/refs就需要更新,因此运行“某些内容”的好地方是在接收后挂钩中。这个“东西”就是命令git update-server-info

\n\n

请注意,如果您没有在服务器上运行仅推送的裸存储库,则运行接收后脚本git update-server-info是不够的,因为可以通过其他方式(git commit例如手动)添加提交和其他对象。在这种情况下,您可以使用 cron 作业等在时钟驱动的基础上创建或更新哑传输信息。

\n\n
\n

我无法获取命令GET info/refs在 git bash 工作中获取该命令。

\n
\n\n

如果该文件存在,您将通过 HTTP 获取它,例如从浏览器或使用curl

\n