简体   繁体   English

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

[英]How does Git's transfer protocol work

I am working with Git for more than one year and now I have to explain it to others in our group.我使用 Git 已经一年多了,现在我必须向我们组中的其他人解释它。 That is why I need a bit more backround.这就是为什么我需要更多的背景。 I went thourgh most of the Git Book in the last year and recently I continued with chapter 10. In chapter10.6 I got completely stuck:去年我阅读了 Git Book 的大部分内容,最近我继续阅读第 10 章。在第10.6章中,我完全卡住了:

Let's follow the http-fetch process for the simplegit library:让我们遵循 simplegit 库的 http-fetch 过程:

 $ git clone http://server/simplegit-progit.git

The first thing this command does is pull down the info/refs file.这个命令做的第一件事是拉下 info/refs 文件。 This file is written by the update-server-info command, which is why you need to enable that as a post-receive hook in order for the HTTP transport to work properly:此文件由 update-server-info 命令编写,这就是为什么您需要将其启用为 post-receive 挂钩以使 HTTP 传输正常工作的原因:

 => GET info/refs ca82a6dff817ec66f44342007202690a93763949 refs/heads/master

I have a small test repo https://github.com/to_my/repo and git clone works well.我有一个小的测试仓库https://github.com/to_my/repo并且git clone运行良好。 But

  • Where is the folder info/refs ?文件夹info/refs在哪里? I only find a /.git/info/exclude afther the clone ...我只在clone找到了/.git/info/exclude ...
  • How should I use the update-server-info command?我应该如何使用update-server-info命令? Is it part of git clone somehow?它是 git clone 的一部分吗?
  • I am competely lost with "...which is why you need to enable that as a post-receive hook" although I understand hooks (I thought) and use a pre-commit hook for automatically increasing the package version.我完全迷失于“......这就是为什么你需要将其作为接收后挂钩启用”,尽管我了解挂钩(我认为)并使用预提交挂钩来自动增加包版本。
  • I can't get the command GET info/refs in git bash work.我无法在 git bash 工作中获取命令GET info/refs

Sorry if the questions are stupid, but I just don't understand how to put these pieces from the documentation together.对不起,如果问题很愚蠢,但我只是不明白如何将文档中的这些部分放在一起。

Well, you're getting into plumbing details;好吧,您正在了解管道细节; even if you have to explain Git to a team of coworkers, I'm surprised by the idea that this level of detail would be needed...即使您必须向一组同事解释 Git,我对需要这种详细程度的想法感到惊讶......

Anyway, the info/refs file would only exist on a remote meant to be accessed by HTTP with a dumb server.无论如何, info/refs文件只会存在于一个远程服务器上,该远程服务器旨在通过 HTTP 使用一个哑服务器进行访问。 You probably won't find it (and don't need it) in your local repo.您可能不会在本地存储库中找到它(并且不需要它)。 (The remote in this scenario is probably a bare repo, btw, so info would be at the repo root, as bare repos don't have a work tree and place the files you're used to seeing in .git at the root instead.) (这种情况下的遥控器可能是一个裸仓库,顺便说一句,所以info将在仓库根目录中,因为裸仓库没有工作树,而是将您习惯在.git中看到的文件放在根目录下.)

If our remote is in something like github, tfs, etc... then you just don't need to worry about any of this as the server will manage things just fine.如果我们的遥控器在 github、tfs 等中......那么你就不需要担心任何这些,因为服务器会很好地管理这些事情。 I guess if you served the repo as static content from a plain old web server then this would matter, and you'd have to set up the hook.我想如果您将 repo 作为来自普通旧 Web 服务器的静态内容提供,那么这很重要,您必须设置挂钩。

Most users will never use or see the update-server-info command;大多数用户永远不会使用或看到update-server-info命令; as its name suggests, it's for repos on the server side - remotes - to compensate for the lack of a git-aware HTTP server.顾名思义,它用于服务器端的 repos - 远程 - 以弥补 git-aware HTTP 服务器的缺乏。

The post-receive hook is invoked after receiving a push; post-receive 钩子在收到推送后被调用; so on a dumb server scenario, you set this hook on the remote so that when you push to it, it responds by updating certain information (like the refs file).所以在一个愚蠢的服务器场景中,你在远程设置这个钩子,这样当你推送到它时,它会通过更新某些信息(如 refs 文件)来响应。

The GET command you're looking at is an HTTP command, run when necessary by the git client when you do a fetch.您正在查看的GET命令是一个 HTTP 命令,当您执行提取操作时,由 git 客户端在必要时运行。

Note: starting Git 2.18 (Q2 2018), the git transfer protocol evolves with a v2 which is implemented.注意:从 Git 2.18(2018 年第二季度)开始,git 传输协议随着 v2 的实现而发展。
With Git 2.26 (Q1 2020), it is the default .在 Git 2.26(2020 年第一季度)中,它是默认的. It is not in 2.27 (Q2 2020, see the end of this answer, and the follow-up answer ).不在2.27(2020 年第二季度,请参阅此答案的结尾以及后续答案)。 It is again in 2.28 (Q3 2020)再次出现在 2.28(2020 年第三季度)

See commit a4d78ce , commit 0f1dc53 , commit 237ffed , commit 884e586 , commit 8ff14ed , commit 49e85e9 , commit f08a5d4 , commit f1f4d8a , commit edc9caf , commit 176e85c , commit b1c2edf , commit 1aa8dde , commit 40fc51e , commit f7e2050 , commit 685fbd3 , commit 3145ea9 , commit 5b872ff , commit 230d7dd , commit b4be741 , commit 1af8ae1 (15 Mar 2018) by Brandon Williams ( mbrandonw ) .提交a4d78ce提交0f1dc53提交237ffed提交884e586提交8ff14ed提交49e85e9提交f08a5d4提交f1f4d8a提交edc9caf提交176e85c提交b1c2edf提交1aa8dde提交40fc51e提交f7e2050提交685fbd3提交3145ea9提交5b872ff提交 230d7dd提交 b4be741提交 1af8ae1 (2018 年 3 月 15 日),由Brandon Williams ( mbrandonw ) mbrandonw
(Merged by Junio C Hamano -- gitster -- in commit 9bfa0f9 , 08 May 2018) (由Junio C gitster合并-- gitster -- in commit 9bfa0f9 ,2018 年 5 月 8 日)

The full specification is in Documentation/technical/protocol-v2.txt :完整的规范在Documentation/technical/protocol-v2.txt

Protocol v2 will improve upon v1 in the following ways:协议 v2 将在以下方面改进 v1:

  • Instead of multiple service names, multiple commands will be supported by a single service单个服务将支持多个命令,而不是多个服务名称
  • Easily extendable as capabilities are moved into their own section of the protocol, no longer being hidden behind a NUL byte and limited by the size of a pkt-line易于扩展,因为功能被移动到协议的它们自己的部分,不再隐藏在NUL字节后面并受pkt-line大小的限制
  • Separate out other information hidden behind NUL bytes (eg agent string as a capability and symrefs can be requested using 'ls-refs' )分离出隐藏在NUL字节后面的其他信息(例如,代理字符串作为一种能力和symrefs 可以使用 'ls-refs' 请求
  • Reference advertisement will be omitted unless explicitly requested除非明确要求,否则将省略参考广告
  • ls-refs command to explicitly request some refs ls-refs 命令显式请求一些引用
  • Designed with http and stateless-rpc in mind.设计时考虑了 http 和 stateless-rpc。 With clear flush semantics the http remote helper can simply act as a proxy通过清晰的刷新语义,http 远程助手可以简单地充当代理

In protocol v2 communication is command oriented .在协议 v2 中,通信是面向命令的
When first contacting a server a list of capabilities will advertised.当第一次联系服务器时,将公布功能列表。 Some of these capabilities will be commands which a client can request be executed.其中一些功能将是客户端可以请求执行的命令。 Once a command has completed, a client can reuse the connection and request that other commands be executed.命令完成后,客户端可以重用连接并请求执行其他命令。

info/refs remains server endpoint to be queried by a client, as explained in HTTP Transport section: info/refs仍然是客户端要查询的服务器端点,如 HTTP 传输部分所述:

When using the http:// or https:// transport a client makes a "smart" info/refs request as described in http-protocol.txt and requests that v2 be used by supplying " version=2 " in the Git-Protocol header.当使用http://https://传输时,客户端会按照http-protocol.txt描述发出“智能” info/refs请求,并通过在Git-Protocol提供“ version=2 ”来请求使用 v2标题。

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

A v2 server would reply: v2 服务器会回复:

   S: 200 OK
   S: <Some headers>
   S: ...
   S:
   S: 000eversion 2\n
   S: <capability-advertisement>

Subsequent requests are then made directly to the service $GIT_URL/git-upload-pack .然后直接向服务$GIT_URL/git-upload-pack发出后续请求。 (This works the same for git-receive-pack). (这对于 git-receive-pack 也是一样的)。

The goal is to have more capabilities:目标是拥有更多功能:

There are two different types of capabilities:有两种不同类型的能力:

  • normal capabilities, which can be used to to convey information or alter the behavior of a request, and正常能力,可用于传达信息或改变请求的行为,以及
  • commands , which are the core actions that a client wants to perform (fetch, push, etc). commands ,这是客户端想要执行的核心操作(获取、推送等)。

Protocol version 2 is stateless by default .默认情况下,协议版本 2 是无状态的
This means that all commands must only last a single round and be stateless from the perspective of the server side, unless the client has requested a capability indicating that state should be maintained by the server.这意味着所有命令只能持续一个回合并且从服务器端的角度来看是无状态的,除非客户端请求了一个能力,表明状态应该由服务器维护。

Clients MUST NOT require state management on the server side in order to function correctly.客户端必须不需要服务器端的状态管理才能正常运行。
This permits simple round-robin load-balancing on the server side, without needing to worry about state management.这允许在服务器端进行简单的循环负载平衡,而无需担心状态管理。

Finally:最后:

ls-refs is the command used to request a reference advertisement in v2. ls-refs是用于在 v2 中请求参考广告的命令。
Unlike the current reference advertisement, ls-refs takes in arguments which can be used to limit the refs sent from the server.与当前的引用广告不同, ls-refs接受可用于限制从服务器发送的引用的参数。

And:和:

fetch is the command used to fetch a packfile in v2. fetch是用于在 v2 中fetch的命令。
It can be looked at as a modified version of the v1 fetch where the ref-advertisement is stripped out (since the ls-refs command fills that role) and the message format is tweaked to eliminate redundancies and permit easy addition of future extensions.它可以看作是 v1 fetch 的修改版本,其中去除了 ref-advertisement(因为ls-refs命令填补了该角色)并且调整了消息格式以消除冗余并允许轻松添加未来的扩展。


Since that commit (May 10th), the protocol V2 has officially been announced (May 28th) in the Google blog post " Introducing Git protocol version 2 " by Brandon Williams .自那次提交(5 月 10 日)以来, Brandon Williams在谷歌博客文章“ 介绍 Git 协议版本 2 ”中正式宣布了协议 V2(5 月 28 日)。

In both cases:在这两种情况下:

Additional features not supported in the base command will be advertised as the value of the command in the capability advertisement in the form of a space separated list of features: " <command>=<feature 1> <feature 2> "基本命令中不支持的其他功能将以空格分隔的功能列表的形式作为能力公告中的命令值进行公告:“ <command>=<feature 1> <feature 2>


See also commit 5e3548e , commit ff47322 , commit ecc3e53 (23 Apr 2018) by Brandon Williams ( mbrandonw ) .另请参阅Brandon Williams ( mbrandonw ) 的commit 5e3548ecommit ff47322commit ecc3e53 (2018 年 4 月 23 日
(Merged by Junio C Hamano -- gitster -- in commit 41267e9 , 23 May 2018) (由Junio C gitster合并-- gitster -- in commit 41267e9 ,2018 年 5 月 23 日)

serve : introduce the server-option capability serve :引入server-option功能

Introduce the " server-option " capability to protocol version 2.向协议版本 2 引入“ server-option ”功能。
This enables future clients the ability to send server specific options in command requests when using protocol version 2.这使未来的客户端能够在使用协议版本 2 时在命令请求中发送特定于服务器的选项。

fetch : send server options when using protocol v2 fetch : 使用协议 v2 时发送服务器选项

Teach fetch to optionally accept server options by specifying them on the cmdline via ' -o ' or ' --server-option '.通过在 cmdline 上通过“ -o ”或“ --server-option ”指定它们,教fetch有选择地接受服务器选项。
These server options are sent to the remote end when performing a fetch communicating using protocol version 2.当使用协议版本 2 执行fetch通信时,这些服务器选项被发送到远程端。

If communicating using a protocol other than v2 the provided options are ignored and not sent to the remote end.如果使用 v2 以外的协议进行通信,则提供的选项将被忽略并且不会发送到远程端。

Same is done for git ls-remote . git ls-remote


And the transfer protocol v2 learned to support the partial clone seen in Dec. 2017 with Git 2.16 .传输协议 v2 学会了支持在201712 月使用 Git 2.16看到的部分克隆。

See commit ba95710 , commit 5459268 (03 May 2018), and commit 7cc6ed2 (02 May 2018) by Jonathan Tan ( jhowtan ) .请参阅Jonathan Tan ( jhowtan ) 的commit ba95710commit 5459268 (2018 年 5 月 3 日)和commit 7cc6ed2 (2018 年 5 月 2 日
(Merged by Junio C Hamano -- gitster -- in commit 54db5c0 , 30 May 2018) (由Junio C gitster合并-- gitster -- in commit 54db5c0 ,2018 年 5 月 30 日)

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

The fetch-pack/upload-pack protocol v2 was developed independently of the filter parameter (used in partial fetches), thus it did not include support for it. fetch-pack/upload-pack 协议 v2 是独立于过滤器参数(用于部分提取)开发的,因此它不包括对它的支持。 Add support for the filter parameter.添加对过滤器参数的支持。

Like in the legacy protocol, the server advertises and supports " filter " only if uploadpack.allowfilter is configured.与旧协议一样,只有在配置了uploadpack.allowfilter ,服务器才会通告并支持“ filter ”。

Like in the legacy protocol, the client continues with a warning if " --filter " is specified, but the server does not advertise it.就像在旧协议中一样,如果指定了“ --filter ”,客户端会继续发出警告,但服务器不会通告它。


Git 2.19 (Q3 2018) improves the fetch part of the git transfer protocol v2: Git 2.19(2018 年第三季度)改进了 git 传输协议 v2 的 fetch 部分:

See commit ec06283 , commit d093bc7 , commit d30fe89 , commit af1c90d , commit 21bcf6e (14 Jun 2018), and commit af00855 , commit 34c2903 (06 Jun 2018) by Jonathan Tan ( jhowtan ) .请参阅提交 ec06283提交 d093bc7提交 d30fe89提交 af1c90d提交 21bcf6e (2018 年 6 月 14 日)和提交 af00855提交 34c2903 (2018 年 6 月 6 日) jhowtan Tan)
(Merged by Junio C Hamano -- gitster -- in commit af8ac73 , 02 Aug 2018) (由Junio C gitster合并-- gitster -- in commit af8ac73 ,2018 年 8 月 2 日)

fetch-pack : introduce negotiator API fetch-pack : 引入谈判器 API

Introduce the new files fetch-negotiator.{h,c} , which contains an API behind which the details of negotiation are abstracted引入新文件fetch-negotiator.{h,c} ,其中包含一个 API,在该 API 后面抽象了协商的细节

fetch-pack : use ref adv. fetch-pack : 使用 ref adv。 to prune "have" sent修剪“有”发送

In negotiation using protocol v2, fetch-pack sometimes does not make full use of the information obtained in the ref advertisement: specifically, that if the server advertises a commit that the client also has, the client never needs to inform the server that it has the commit's parents, since it can just tell the server that it has the advertised commit and it knows that the server can and will infer the rest.在使用协议 v2 进行协商时,fetch-pack 有时不会充分利用在 ref 广告中获得的信息:具体而言,如果服务器广告客户端也有的提交,则客户端永远不需要通知服务器它有提交的父项,因为它可以告诉服务器它有广告提交,并且它知道服务器可以并且将推断出其余的提交。


Git 2.20 (Q4 2018) fixes git ls-remotes : Git 2.20(2018 年第四季度)修复了git ls-remotes

See commit 6a139cd , commit 631f0f8 (31 Oct 2018) by Jeff King ( peff ) .请参阅Jeff King ( peff ) 的commit 6a139cdcommit 631f0f8 (2018 年 10 月 31 日
(Merged by Junio C Hamano -- gitster -- in commit 81c365b , 13 Nov 2018) (由Junio C gitster合并-- gitster -- in commit 81c365b ,2018 年 11 月 13 日)

git ls-remote $there foo was broken by recent update for the protocol v2 and stopped showing refs that match ' foo ' that are not refs/{heads,tags}/foo , which has been fixed. git ls-remote $there foo被协议 v2 的最近更新破坏了,并停止显示匹配“ foo ”但不是refs/{heads,tags}/foo ,这已被修复。


And Git 2.20 fixes git fetch , which was a bit loose in parsing responses from the other side when talking over the protocol v2. Git 2.20 修复了git fetch ,当通过 v2 协议讨论时,它在解析来自另一端的响应时有点松散。

See commit 5400b2a (19 Oct 2018) by Jonathan Tan ( jhowtan ) .请参阅Jonathan Tan ( jhowtan ) 的commit 5400b2a (2018 年 10 月 19 日
(Merged by Junio C Hamano -- gitster -- in commit 67cf2fa , 13 Nov 2018) (由Junio C gitster合并-- gitster -- in commit 67cf2fa ,2018 年 11 月 13 日)

fetch-pack : be more precise in parsing v2 response fetch-pack :更精确地解析 v2 响应

Each section in a protocol v2 response is followed by either a DELIM packet (indicating more sections to follow) or a FLUSH packet (indicating none to follow).协议 v2 响应中的每个部分后跟一个DELIM数据包(表示要跟随更多部分)或FLUSH数据包(表示没有要跟随)。

But when parsing the " acknowledgments " section, do_fetch_pack_v2() is liberal in accepting both, but determines whether to continue reading or not based solely on the contents of the " acknowledgments " section, not on whether DELIM or FLUSH was read.但是在解析“ acknowledgments ”部分时, do_fetch_pack_v2()可以自由地接受两者,但仅根据“ acknowledgments ”部分的内容来决定是否继续阅读,而不是根据是否读取了DELIMFLUSH

There is no issue with a protocol-compliant server, but can result in confusing error messages when communicating with a server that serves unexpected additional sections.与协议兼容的服务器没有问题,但在与提供意外附加部分的服务器通信时可能会导致混乱的错误消息。 Consider a server that sends " new-section " after " acknowledgments ":考虑一个在“ acknowledgments ”之后发送“ new-section ”的服务器:

  • client writes request客户写请求
    • client reads the "acknowledgments" section which contains no "ready", then DELIM客户端读取不包含“就绪”的“确认”部分,然后DELIM
    • since there was no "ready", client needs to continue negotiation, and writes request由于没有“准备好”,客户端需要继续协商,并写入请求
    • client reads " new-section ", and reports to the end user "expected 'acknowledgments', received ' new-section '"客户端读取“ new-section ”,并向最终用户报告“预期的‘确认’,收到‘ new-section ’”

For the person debugging the involved Git implementation(s), the error message is confusing in that " new-section " was not received in response to the latest request, but to the first one.对于调试所涉及的 Git 实现的人来说,错误消息令人困惑,因为“ new-section ”不是响应最新请求而收到的,而是第一个。

One solution is to always continue reading after DELIM , but in this case, we can do better.一种解决方案是始终在DELIM之后继续阅读,但在这种情况下,我们可以做得更好。

We know from the protocol that:我们从协议中知道:

  • "ready" means at least the packfile section is coming (hence, DELIM ) and that: “准备好”意味着至少 packfile 部分即将到来(因此, DELIM )并且:
  • no "ready" means that no sections are to follow (hence, FLUSH ).没有“准备好”意味着没有要遵循的部分(因此, FLUSH )。

So teach process_acks() to enforce this.所以教process_acks()来执行这个。


Git 2.21 will bring an actual official support of the V2 protocol for fetch pack: Git 2.21 将为 fetch pack 带来对 V2 协议的实际官方支持:

See commit e20b419 (18 Dec 2018) by Jeff King ( peff ) .请参阅Jeff King ( peff ) 提交的 e20b419 (2018 年 12 月 18 日
(Merged by Junio C Hamano -- gitster -- in commit d3b0178 , 29 Jan 2019) (由Junio C gitster合并-- gitster -- in commit d3b0178 ,2019 年 1 月 29 日)

fetch-pack : support protocol version 2 fetch-pack : 支持协议版本 2

When the scaffolding for protocol version 2 was initially added in 8f6982b (" protocol : introduce enum protocol_version value protocol_v2", 2018-03-14, Git v2.18).当协议版本 2 的脚手架最初在8f6982b 中添加时(“ protocol :引入enum协议_版本值协议_v2”,2018-03-14,Git v2.18)。 As seen in:如中所示:

 git log -p -G'support for protocol v2 not implemented yet' --full-diff --reverse v2.17.0..v2.20.0

Many of those scaffolding "die" placeholders were removed, but we hadn't gotten around to fetch-pack yet.许多脚手架“死”占位符已被删除,但我们还没有开始 fetch-pack 。

The test here for "fetch refs from cmdline" is very minimal.此处对“从 cmdline 获取 refs”的测试非常少。 There's much better coverage when running the entire test suite under the WIP GIT_TEST_PROTOCOL_VERSION=2 mode , we should ideally have better coverage without needing to invoke a special test mode.WIP GIT_TEST_PROTOCOL_VERSION=2模式下运行整个测试套件时,覆盖范围要好得多,理想情况,我们应该有更好的覆盖范围,而无需调用特殊的测试模式。


Git 2.22 (Q2 2019) adds: " git clone " learned a new --server-option option when talking over the protocol version 2. Git 2.22(2019 年第二季度)补充说:“ git clone ”在讨论协议版本 2 时学习了一个新的--server-option选项。

See commit 6e98305 , commit 35eb824 (12 Apr 2019) by Jonathan Tan ( jhowtan ) .请参阅Jonathan Tan ( jhowtan ) 的commit 6e98305commit 35eb824 (2019 年 4 月 12 日
(Merged by Junio C Hamano -- gitster -- in commit 6d3df8e , 08 May 2019) (由Junio C gitster合并gitster 提交 6d3df8e ,2019 年 5 月 8 日)

clone : send server options when using protocol v2 clone :使用协议 v2 时发送服务器选项

Commit 5e3548e (" fetch : send server options when using protocol v2", 2018-04-24, Git v2.18.0-rc0) taught " fetch " the ability to send server options when using protocol v2, but not " clone ". Commit 5e3548e (“ fetch : send server options when using protocol v2”,2018-04-24,Git v2.18.0-rc0)教导了“ fetch ”在使用协议v2时发送服务器选项的能力,而不是“ clone ”。
This ability is triggered by " -o " or " --server-option ".此功能由“ -o ”或“ --server-option ”触发。

Teach " clone " the same ability, except that because " clone " already has " -o " for another parameter, teach "clone" only to receive " --server-option ".教“ clone ”同样的能力,除了因为“ clone ”已经有“ -o ”作为另一个参数,教“clone”只接受“ --server-option ”。

Explain in the documentation, both for clone and for fetch, that server handling of server options are server-specific.在文档中解释克隆和获取,服务器选项的服务器处理是特定于服务器的。
This is similar to receive-pack 's handling of push options - currently, they are just sent to hooks to interpret as they see fit.这类似于receive-pack对推送选项的处理——目前,它们只是被发送到钩子以在它们认为合适的时候进行解释。


Note: Git 2.12 has introduced a git serve command in commit ed10cb9 by Brandon Williams :注意:Git 2.12 在Brandon Williams 的commit ed10cb9 中引入了一个 git serve 命令:

serve : introduce git-serve serve : 引入git-serve

Introduce git-serve , the base server for protocol version 2.介绍git-serve ,协议版本 2 的基础服务器。

Protocol version 2 is intended to be a replacement for Git's current wire protocol.协议版本 2 旨在替代 Git 当前的有线协议。
The intention is that it will be a simpler, less wasteful protocol which can evolve over time.目的是它会是一个更简单、更少浪费的协议,可以随着时间的推移而发展。

Protocol version 2 improves upon version 1 by eliminating the initial ref advertisement.协议版本 2 通过消除初始引用广告对版本 1 进行了改进。
In its place a server will export a list of capabilities and commands which it supports in a capability advertisement.取而代之的是,服务器将在功能公告中导出它支持的功能和命令列表。
A client can then request that a particular command be executed by providing a number of capabilities and command specific parameters.然后,客户端可以通过提供许多功能和命令特定参数来请求执行特定命令。
At the completion of a command, a client can request that another command be executed or can terminate the connection by sending a flush packet.在命令完成时,客户端可以请求执行另一个命令,或者可以通过发送刷新数据包来终止连接。

But... Git 2.22 does amend that, with commit b7ce24d by Johannes Schindelin:但是...... Git 2.22 确实修改了这一点,由 Johannes Schindelin 提交 b7ce24d

Turn git serve into a test helpergit serve变成测试助手

The git serve built-in was introduced in ed10cb9 ( serve : introduce git-serve , 2018-03-15, Git v2.18.0-rc0) as a backend to serve Git protocol v2, probably originally intended to be spawned by git upload-pack .内建的git serve是在ed10cb9serve :introduction git-serve , 2018-03-15, Git v2.18.0-rc0)中引入git-serve ,作为服务 Git 协议 v2 的后端,可能最初打算由git upload-pack产生 - git upload-pack

However, in the version that the protocol v2 patches made it into core Git, git upload-pack calls the serve() function directly instead of spawning git serve ;但是,在协议 v2 补丁使其成为核心 Git 的版本中, git upload-pack直接调用serve()函数而不是生成git serve The only reason in life for git serve to survive as a built-in command is to provide a way to test the protocol v2 functionality. git serve作为内置命令存在的唯一原因是提供一种测试协议 v2 功能的方法。

Meaning that it does not even have to be a built-in that is installed with end-user facing Git installations, but it can be a test helper instead.这意味着它甚至不必是与面向最终用户的 Git 安装一起安装的内置程序,但它可以是一个测试助手。

Let's make it so.让我们这样做吧。


Git 2.23 (Q2 2019) will make update-server-info more efficient, since it learned not to rewrite the file with the same contents. Git 2.23(2019 年第二季度)将使 update-server-info 更加高效,因为它学会了不使用相同的内容重写文件。

See commit f4f476b (13 May 2019) by Eric Wong ( ele828 ) .请参阅Eric Wong ( ele828 ) 的提交 f4f476b (2019 年 5 月 13 日
(Merged by Junio C Hamano -- gitster -- in commit 813a3a2 , 13 Jun 2019) (由Junio C gitster合并-- gitster -- in commit 813a3a2 ,2019 年 6 月 13 日)

update-server-info : avoid needless overwrites update-server-info : 避免不必要的覆盖

Do not change the existing info/refs and objects/info/packs files if they match the existing content on the filesystem.如果现有的info/refsobjects/info/packs文件与文件系统上的现有内容匹配,则不要更改它们。
This is intended to preserve mtime and make it easier for dumb HTTP pollers to rely on the If-Modified-Since header.这是为了保留 mtime并使愚蠢的 HTTP 轮询器更容易依赖If-Modified-Since标头。

Combined with stdio and kernel buffering;结合stdio和内核缓冲; the kernel should be able to avoid block layer writes and reduce wear for small files.内核应该能够避免块层写入并减少小文件的磨损。

As a result, the --force option is no longer needed.因此,不再需要--force选项。
So stop documenting it, but let it remain for compatibility (and debugging, if necessary).所以停止记录它,但让它保持兼容性(和调试,如果需要)。

And Git 2.22.1 will also fix the server side support for " git fetch ", which used to show incorrect value for the HEAD symbolic ref when the namespace feature is in use. Git 2.22.1 还将修复服务器端对“ git fetch ”的支持,该支持在使用命名空间功能时会显示 HEAD 符号引用的错误值。

See commit 533e088 (23 May 2019) by Jeff King ( peff ) .请参阅Jeff King ( peff ) 的commit 533e088 (2019 年 5 月 23 日
(Merged by Junio C Hamano -- gitster -- in commit 5ca0db3 , 25 Jul 2019) (由Junio C gitster合并-- gitster -- in commit 5ca0db3 ,2019 年 7 月 25 日)

upload-pack : strip namespace from symref data upload-pack :从 symref 数据中去除命名空间

Since 7171d8c ( upload-pack : send symbolic ref information as capability, 2013-09-17, Git v1.8.4.3), we've sent cloning and fetching clients special information about which branch HEAD is pointing to, so that they don't have to guess based on matching up commit ids.7171d8cupload-pack : 发送符号 ref 信息作为能力,2013-09-17,Git v1.8.4.3)以来,我们已经发送克隆和获取客户端关于 HEAD 指向哪个分支的特殊信息,以便他们不不必根据匹配提交 ID 进行猜测。

However, this feature has never worked properly with the GIT_NAMESPACE feature.但是,此功能从未与GIT_NAMESPACE功能一起正常工作。 Because upload-pack uses head_ref_namespaced(find_symref) , we do find and report on refs/namespaces/foo/HEAD instead of the actual HEAD of the repo.因为upload-pack使用head_ref_namespaced(find_symref) ,我们确实查找和报告refs/namespaces/foo/HEAD而不是 repo 的实际HEAD
This makes sense, since the branch pointed to by the top-level HEAD may not be advertised at all.这是有道理的,因为顶级HEAD指向的分支可能根本不会被通告。

But we do two things wrong:但是我们做错了两件事:

  1. We report the full name refs/namespaces/foo/HEAD , instead of just HEAD.我们报告全名refs/namespaces/foo/HEAD ,而不仅仅是 HEAD。
    Meaning no client is going to bother doing anything with that symref, since we're not otherwise advertising it.这意味着没有客户会费心用那个 symref 做任何事情,因为我们不会以其他方式宣传它。
  2. We report the symref destination using its full name (eg, refs/namespaces/foo/refs/heads/master ).我们使用其全名报告 symref 目的地(例如, refs/namespaces/foo/refs/heads/master )。 That's similarly useless to the client, who only saw " refs/heads/master " in the advertisement.这对客户来说同样没用,他们只在广告中看到“ refs/heads/master ”。

We should be stripping the namespace prefix off of both places (which this patch fixes) .我们应该去掉两个地方的命名空间前缀(这个补丁修复了)

Likely nobody noticed because we tend to do the right thing anyway.可能没有人注意到,因为无论如何我们都倾向于做正确的事情。
Bug (1) means that we said nothing about HEAD (just refs/namespace/foo/HEAD ).错误 (1) 意味着我们没有提及HEAD (只是refs/namespace/foo/HEAD )。 And so the client half of the code, from a45b5f0 ( connect : annotate refs with their symref information in get_remote_head() , 2013-09-17, Git v1.8.4.3), does not annotate HEAD, and we use the fallback in guess_remote_head() , matching refs by object id.因此,来自a45b5f0的客户端代码的一半( connect : annotate refs with their symref information in get_remote_head() , 2013-09-17, Git v1.8.4.3),没有注释 HEAD,我们在guess_remote_head() ,通过对象 id 匹配 refs。
Which is usually right.这通常是正确的。 It only falls down in ambiguous cases, like the one laid out in the included test.它只会在模棱两可的情况下失败,例如包含的测试中列出的情况。

This also means that we don't have to worry about breaking anybody who was putting pre-stripped names into their namespace symrefs when we fix bug (2).这也意味着当我们修复错误 (2) 时,我们不必担心破坏将预先剥离的名称放入其命名空间 symrefs 的任何人。
Because of bug (1), nobody would have been using the symref we advertised in the first place (not to mention that those symrefs would have appeared broken for any non-namespaced access).由于错误 (1),没有人会使用我们首先宣传的 symref(更不用说那些 symref 会因任何非命名空间访问而损坏)。

Note that we have separate fixes here for the v0 and v2 protocols.请注意,我们在此处针对 v0 和 v2 协议分别进行了修复。
The symref advertisement moved in v2 to be a part of the ls-refs command. symref 广告在 v2 中移动,成为ls-refs命令的一部分。
This actually gets part (1) right, since the symref annotation piggy-backs on the existing ref advertisement, which is properly stripped.这实际上使第 (1) 部分正确,因为 symref 注释捎带在现有的 ref 广告上,该广告已被正确剥离。
But it still needs a fix for part (2).但它仍然需要修复第 (2) 部分。


With Git 2.25.1 (Feb. 2020), the unnecessary round-trip when running " ls-remote " over the stateless RPC mechanism is reduced.使用 Git 2.25.1(2020 年 2 月),减少了通过无状态 RPC 机制运行“ ls-remote ”时不必要的往返。

See discussion :讨论

A colleague (Jon Simons) today pointed out an interesting behavior of git ls-remote with protocol v2: it makes a second POST request and sends only a flush packet.一位同事 (Jon Simons) 今天指出了使用协议 v2 的git ls-remote一个有趣行为:它发出第二个 POST 请求并且只发送一个刷新数据包。
This can be demonstrated with the following:这可以通过以下方式证明:

 GIT_CURL_VERBOSE=1 git -c protocol.version=2 ls-remote origin

The Content-Length header on the second request will be exactly 4 bytes.第二个请求的 Content-Length 标头正好是 4 个字节。

See commit 4d8cab9 (08 Jan 2020) by Jeff King ( peff ) .请参阅Jeff King ( peff ) 的commit 4d8cab9 (08 Jan 2020 )
(Merged by Junio C Hamano -- gitster -- in commit 45f47ff , 22 Jan 2020) (由Junio C gitster合并-- gitster -- in commit 45f47ff ,2020 年 1 月 22 日)

transport : don't flush when disconnecting stateless-rpc helper transport :断开 stateless-rpc helper 时不要刷新

Signed-off-by: Jeff King签字人:Jeff King

Since ba227857d2 ("Reduce the number of connects when fetching", 2008-02-04, Git v1.5.5-rc0 -- merge ), when we disconnect a git transport, we send a final flush packet.由于ba227857d2 ("Reduce the number of connected when fetching", 2008-02-04, Git v1.5.5-rc0 -- merge ),当我们断开一个 git 传输时,我们发送一个最终的刷新数据包。
This cleanly tells the other side that we're done, and avoids the other side complaining "the remote end hung up unexpectedly" (though we'd only see that for transports that pass along the server stderr, like ssh or local-host).这清楚地告诉另一方我们已经完成,并避免另一方抱怨“远程端意外挂断”(尽管我们只会看到通过服务器标准错误的传输,如 ssh 或本地主机) .

But when we've initiated a v2 stateless-connect session over a transport helper, there's no point in sending this flush packet.但是当我们通过传输助手启动 v2 无状态连接会话时,发送这个刷新数据包就没有意义了。 Each operation we've performed is self-contained, and the other side is fine with us hanging up between operations.我们执行的每个操作都是独立的,另一方可以在操作之间挂断。

But much worse, by sending the flush packet we may cause the helper to issue an entirely new request _just _ to send the flush packet.但更糟糕的是,通过发送刷新数据包,我们可能会导致助手发出一个全新的请求_just _ 来发送刷新数据包。 So we can incur an extra network request just to say "by the way, we have nothing more to send".所以我们可能会产生一个额外的网络请求,只是说“顺便说一下,我们没有更多的东西要发送”。

Let's drop this extra flush packet.让我们丢弃这个额外的冲洗包。 As the test shows, this reduces the number of POSTs required for a v2 ls-remote over http from 2 to 1.正如测试所示,这将 v2 ls-remote通过 http 所需的 POST 数量从 2 减少到 1。


With Git 2.26 (Q1 2020), The test-lint machinery knew to check "VAR=VAL shell_function" construct, but did not check "VAR= shell_function", which has been corrected.在 Git 2.26(2020 年第一季度)中,test-lint 机器知道检查“VAR=VAL shell_function"构造,但没有检查“VAR= shell_function",这已得到纠正。

See commit d6509da , commit a7fbf12 , commit c7973f2 (26 Dec 2019) by Jonathan Nieder ( artagnon ) .请参阅Jonathan Nieder ( artagnon ) 的commit d6509dacommit a7fbf12commit c7973f2 (2019 年 12 月 26 日
(Merged by Junio C Hamano -- gitster -- in commit c7372c9 , 30 Jan 2020) (由Junio C gitster合并-- gitster -- in commit c7372c9 ,2020 年 1 月 30 日)

fetch test : mark test of "skipping" haves as v0-only fetch test : 将“跳过”的标记测试标记为 v0-only

Signed-off-by: Jonathan Nieder签字人:乔纳森·尼德

Since 633a53179e (fetch test: avoid use of "VAR= cmd" with a shell function, 2019-12-26), t5552.5 (do not send "have" with ancestors of commits that server ACKed) fails when run with GIT_TEST_PROTOCOL_VERSION=2 .由于633a53179e (获取测试:避免使用带有 shell 函数的“VAR= cmd”,2019 年 12 月 26 日),当使用GIT_TEST_PROTOCOL_VERSION=2运行时,t5552.5(不要发送带有服务器确认的提交的祖先的“have”)失败GIT_TEST_PROTOCOL_VERSION=2 .

The cause:原因:

The progression of " have "s sent in negotiation depends on whether we are using a stateless RPC based transport or a stateful bidirectional one (see for example 44d8dc54e7 , "Fix potential local deadlock during fetch-pack", 2011-03-29, Git v1.7.5-rc0). have ”在协商中发送的进展取决于我们使用的是基于无状态 RPC 的传输还是有状态的双向传输(参见例如44d8dc54e7 ,“Fix potential local deadlock during fetch-pack”, 2011-03-29, Git v1.7.5-rc0)。

In protocol v2, all transports are stateless transports, while in protocol v0, transports such as local access and SSH are stateful.在协议 v2 中,所有传输都是无状态传输,而在协议 v0 中,本地访问和 SSH 等传输是有状态的。

In stateful transports, the number of " have "s to send multiplies by two each round until we reach PIPESAFE_FLUSH (that is, 32), and then it increases by PIPESAFE_FLUSH each round.在有状态传输中,每轮发送的“ have ”数乘以 2,直到达到PIPESAFE_FLUSH (即 32),然后PIPESAFE_FLUSH增加PIPESAFE_FLUSH

In stateless transport, the count multiplies by two each round until we reach LARGE_FLUSH (which is 16384) and then multiplies by 1.1 each round after that.在无状态传输中,计数每轮乘以 2,直到达到LARGE_FLUSH (即 16384),然后每轮乘以 1.1。

Moreover, in stateful transports, as fetch-pack.c explains:此外,在有状态传输中,如fetch-pack.c解释的:

We keep one window "ahead" of the other side, and will wait for an ACK only on the next one.我们保持一个窗口“领先”于另一侧,并且仅在下一个窗口等待ACK

This affects t5552.5 because it looks for " have "s from the negotiator that appear in that second window.这会影响t5552.5因为它会从第二个窗口中出现的谈判器中查找“ have ”。

With protocol version 2, the second window never arrives, and the test fails.使用协议版本 2,第二个窗口永远不会到达,测试失败。

Until 633a53179e (2019-12-26), a previous test in the same file contained直到633a53179e (2019-12-26),同一文件中的先前测试包含

GIT_TEST_PROTOCOL_VERSION= trace_fetch client origin to_fetch

In many common shells (eg bash when run as " sh "), the setting of GIT_TEST_PROTOCOL_VERSION to the empty string lasts beyond the intended duration of the trace_fetch invocation.在许多常见的 shell 中(例如,当作为“ sh ”运行时的 bash),将GIT_TEST_PROTOCOL_VERSION设置为空字符串的持续时间超出了trace_fetch调用的预期持续时间。

This causes it to override the GIT_TEST_PROTOCOL_VERSION setting that was passed in to the test during the remainder of the test script, so t5552.5 never got run using protocol v2 on those shells, regardless of the GIT_TEST_PROTOCOL_VERSION setting from the environment.这会导致它覆盖在测试脚本的其余部分传递给测试的GIT_TEST_PROTOCOL_VERSION设置,因此t5552.5永远不会在这些 shell 上使用协议 v2 运行,无论环境中的GIT_TEST_PROTOCOL_VERSION设置如何。

633a53179e fixed that, revealing the failing test. 633a53179e修复了这个问题,揭示了失败的测试。

Where is the folder info/refs?文件夹信息/参考在哪里? I only find a /.git/info/exclude afther the clone...我只在克隆之后找到了 /.git/info/exclude ...

There is no such folder (it's not a directory ), but that— .git/info/refs —would be where the file would be, if there were a file there.没有这样的文件夹(它不是目录),但是如果那里有文件,那么.git/info/refs将是文件所在的位置。

How should I use the update-server-info command?我应该如何使用 update-server-info 命令? Is it part of git clone somehow?它是 git clone 的一部分吗?

In general, you should not use it: it's only for "dumb" transports.在一般情况下,你应该使用它:它只是为“哑巴”运输机。 "Smart" (two way conversation) transports don't need it. “智能”(双向对话)传输不需要它。

I am competely lost with "...which is why you need to enable that as a post-receive hook" although I understand hooks (I thought) and use a pre-commit hook for automatically increasing the package version.我完全迷失于“......这就是为什么你需要将其作为接收后挂钩启用”,尽管我了解挂钩(我认为)并使用预提交挂钩来自动增加包版本。

If, for some reason, you want to enable dumb transports, you need to run something to create or update several files every time they need creating or updating.如果出于某种原因,您想要启用哑传输,则每次需要创建或更新时,您都需要运行一些程序来创建或更新多个文件。 The info/refs file needs to be updated whenever references change, so a good place to run the "something" is in a post-receive hook. info/refs文件需要在引用更改时更新,因此运行“某事”的好地方是在 post-receive 挂钩中。 The "something" is the command git update-server-info . “东西”是命令git update-server-info

Note that if you are not running a push-only bare repository on a server, having a post-receive script run git update-server-info is not sufficient, since commits and other objects can be added by other means (manual git commit s for instance).请注意,如果您没有在服务器上运行仅推送的裸存储库,那么使用 post-receive 脚本运行git update-server-info是不够的,因为可以通过其他方式添加提交和其他对象(手动git commit s例如)。 In this case you might use, eg, a cron job to create-or-update dumb-transport information on a clock-driven basis.在这种情况下,您可以使用,例如,一个 cron 作业在时钟驱动的基础上创建或更新哑传输信息。

I can't get the command GET info/refs in git bash work.我无法在 git bash 工作中获取命令GET info/refs

If the file existed, you would obtain it via HTTP, eg, from a browser or with the curl command.如果文件存在,您将通过 HTTP 获取它,例如,从浏览器或使用curl命令。

Another aspect of the git transfer protocol is in its packet management, including ACKs when requesting "HAVE": git 传输协议的另一个方面是它的数据包管理,包括请求“HAVE”时的 ACK:

Before Git 2.27 (Q2 2020), the server-end of the v2 protocol to serve " git clone " and " git fetch " was not prepared to see a delim packets at unexpected places, which led to a crash.在 Git 2.27(2020 年第二季度)之前,为“ git clone ”和“ git fetch ”提供服务的 v2 协议的服务器端没有准备好在意外的地方看到 delim 数据包,这导致了崩溃。

See commit cacae43 (29 Mar 2020), and commit 4845b77 , commit 88124ab (27 Mar 2020) by Jeff King ( peff ) .请参阅Jeff King ( peff ) 的commit cacae43 (2020 年 3 月 29 日)和commit 4845b77、88124ab (2020 年 3 月 27 日
(Merged by Junio C Hamano -- gitster -- in commit 5ee5788 , 22 Apr 2020) (由Junio C gitster合并gitster 提交 5ee5788,2020年 4 月 22 日)

upload-pack : handle unexpected delim packets upload-pack : 处理意外的 delim 数据包

Signed-off-by: Jeff King签字人:Jeff King

When processing the arguments list for a v2 ls-refs or fetch command, we loop like this:在处理 v2 ls-refsfetch命令的参数列表时,我们循环如下:

 while (packet_reader_read(request) != PACKET_READ_FLUSH) { const char *arg = request->line; ...handle arg... }

to read and handle packets until we see a flush.读取和处理数据包,直到我们看到刷新。 The hidden assumption here is that anything except PACKET_READ_FLUSH will give us valid packet data to read.这里隐藏的假设是除了PACKET_READ_FLUSH之外的任何东西都会给我们提供有效的数据包数据来读取。 But that's not true;但事实并非如此。 PACKET_READ_DELIM or PACKET_READ_EOF will leave >packet->line as NULL , and we'll segfault trying to look at it . PACKET_READ_DELIMPACKET_READ_EOF会将>packet->line保留为NULL我们将尝试查看它的段错误

Instead, we should follow the more careful model demonstrated on the client side (eg, in process_capabilities_v2) : keep looping as long as we get normal packets, and then make sure that we broke out of the loop due to a real flush.相反,我们应该遵循在客户端展示的更谨慎的模型(例如,在process_capabilities_v2) :只要我们得到正常的数据包就保持循环,然后确保我们由于真正的刷新而跳出循环。 That fixes the segfault and correctly diagnoses any unexpected input from the client.这修复了段错误并正确诊断来自客户端的任何意外输入。


Before Git 2.27 (Q2 2020), the upload-pack protocol v2 gave up too early before finding a common ancestor, resulting in a wasteful fetch from a fork of a project.在 Git 2.27(2020 年第 2 季度)之前,upload-pack 协议 v2 在找到共同祖先之前过早放弃,导致从项目的分支中进行浪费性的获取。

This has been corrected to match the behaviour of v0 protocol.这已被更正以匹配 v0 协议的行为。

See commit 2f0a093 , commit 4fa3f00 , commit d1185aa (28 Apr 2020) by Jonathan Tan ( jhowtan ) .请参阅Jonathan Tan ( jhowtan ) 的commit 2f0a093commit 4fa3f00commit d1185aa (2020 年 4 月 28 日
(Merged by Junio C Hamano -- gitster -- in commit 0b07eec , 01 May 2020) (由Junio C gitster合并-- gitster -- in commit 0b07eec ,2020 年 5 月 1 日)

fetch-pack : in protocol v2, in_vain only after ACK fetch-pack : 在协议 v2 中, in_vain仅在 ACK 之后

Signed-off-by: Jonathan Tan签字人:Jonathan Tan
Reviewed-by: Jonathan Nieder审核人:乔纳森·尼德

When fetching, Git stops negotiation when it has sent at least MAX_IN_VAIN (which is 256) "have" lines without having any of them ACK-ed.获取时,Git 在发送了至少MAX_IN_VAIN (即 256)行“有”行而没有任何行 ACK 时停止协商。
But this is supposed to trigger only after the first ACK, as pack-protocol.txt says:但这应该仅在第一个 ACK​​ 之后触发,如pack-protocol.txt所说:

However, the 256 limit only turns on in the canonical client implementation if we have received at least one "ACK %s continue" during a prior round.但是,如果我们在前一轮中至少收到一个“ACK %s continue”,则只有在规范客户端实现中才会启用 256 限制。 This helps to ensure that at least one common ancestor is found before we give up entirely.这有助于确保在我们完全放弃之前至少找到一个共同的祖先。

The code path for protocol v0 observes this, but not protocol v2, resulting in shorter negotiation rounds but significantly larger packfiles.协议 v0 的代码路径观察到这一点,但没有观察到协议 v2,导致协商轮次更短,但包文件明显更大。
Teach the code path for protocol v2 to check this criterion only after at least one ACK was received.教导协议 v2 的代码路径仅在收到至少一个 ACK​​ 后检查此标准。


As a result of the work in 2.27 (where v2 was not the default), v2 is again the default with 2.28.由于 2.27 中的工作(其中 v2不是默认值),v2 再次成为 2.28 的默认值。

See commit 3697caf :提交 3697caf

config : let feature.experimental imply protocol.version=2 config :让 feature.experimental 意味着protocol.version=2

Git 2.26 used protocol v2 as its default protocol, but soon after release, users noticed that the protocol v2 negotiation code was prone to fail when fetching from some remotes that are far ahead of others (such as linux-next.git versus Linus's linux.git ). Git 2.26 使用协议 v2 作为其默认协议,但发布后不久,用户注意到协议 v2 协商代码在从一些遥遥领先的远程获取时容易失败(例如linux-next.git与 Linus 的linux.git )。
That has been fixed by 0b07eec (Merge branch ' jt/v2-fetch-nego-fix ', 2020-05-01, Git v2.27.0-rc0), but to be cautious, we are using protocol v0 as the default in 2.27 to buy some time for any other unanticipated issues to surface.这已由0b07eec (Merge branch ' jt/v2-fetch-nego-fix ', 2020-05-01, Git v2.27.0-rc0) jt/v2-fetch-nego-fix但要小心,我们在 2.27 中使用协议 v0 作为默认值为任何其他未预料到的问题争取一些时间。

To that end, let's ensure that users requesting the bleeding edge using the feature.experimental flag do get protocol v2.为此,让我们确保使用 feature.experimental 标志请求最前沿的用户确实获得协议 v2。
This way, we can gain experience with a wider audience for the new protocol version and be more confident when it is time to enable it by default for all users in some future Git version.通过这种方式,我们可以在更广泛的受众中获得新协议版本的经验,并更有信心在未来的某个 Git 版本中为所有用户默认启用它。

Implementation note: this isn't with the rest of the feature.experimental options in repo-settings.c because those are tied to a repository object, whereas this code path is used for operations like " git ls-remote " that do not require a repository.实现说明:这与repo-settings.c的其余feature.experimental选项无关,因为它们与存储库对象相关联,而此代码路径用于不需要的操作,例如“ git ls-remote ”一个存储库。


With Git 2.28 (Q3 2020), the "fetch/clone" protocol has been updated to allow the server to instruct the clients to grab pre-packaged packfile(s) in addition to the packed object data coming over the wire .在 Git 2.28(2020 年第 3 季度)中,“获取/克隆”协议已更新,以允许服务器指示客户端除了通过网络传输的打包对象数据外,还可以获取预先打包的打包文件

See commit cae2ee1 (15 Jun 2020) by Ramsay Jones (``) .请参阅Ramsay Jones (``) 的commit cae2ee1 (2020 年 6 月 15 日)
See commit dd4b732 , commit 9da69a6 , commit acaaca7 , commit cd8402e , commit fd194dd , commit 8d5d2a3 , commit 8e6adb6 , commit eb05349 , commit 9cb3cab (10 Jun 2020) by Jonathan Tan ( jhowtan ) .请参阅提交 dd4b732提交 9da69a6提交 acaaca7提交 cd8402e提交 fd194dd提交 8d5d2a3提交 8e6adb6提交 eb05349提交 9cb3cab (2020 年 6 月 10 日)(乔纳森·谭( jhowtan )作者)
(Merged by Junio C Hamano -- gitster -- in commit 34e849b , 25 Jun 2020) (由Junio C gitster合并-- gitster -- in commit 34e849b ,2020 年 6 月 25 日)

fetch-pack : support more than one pack lockfile fetch-pack : 支持多包锁文件

Signed-off-by: Jonathan Tan签字人:Jonathan Tan

Whenever a fetch results in a packfile being downloaded, a .keep file is generated, so that the packfile can be preserved (from, say, a running "git repack") until refs are written referring to the contents of the packfile.每当获取导致下载包文件时,就会生成一个 .keep 文件,以便可以保留包文件(例如,来自正在运行的“git repack”),直到写入引用包文件的内容为止。

In a subsequent patch, a successful fetch using protocol v2 may result in more than one .keep file being generated.在后续补丁中,使用协议 v2 成功获取可能会导致生成多个 .keep 文件。 Therefore, teach fetch_pack() and the transport mechanism to support multiple .keep files.因此,教授fetch_pack()和传输机制以支持多个 .keep 文件。

Implementation notes:实施注意事项:

  • builtin/fetch-pack.c normally does not generate .keep files, and thus is unaffected by this or future changes. builtin/fetch-pack.c通常不会生成.keep文件,因此不受此更改或未来更改的影响。
    However, it has an undocumented " --lock-pack " feature, used by remote-curl.c when implementing the " fetch " remote helper command.然而,它有一个未remote-curl.c--lock-pack ”特性,在实现“ fetch ”远程帮助命令时由remote-curl.c使用。
    In keeping with the remote helper protocol, only one " lock " line will ever be written;与远程助手协议保持一致,只会写入一个“ lock ”行; the rest will result in warnings to stderr.其余的将导致对 stderr 的警告。
    However, in practice, warnings will never be written because the remote-curl.c " fetch " is only used for protocol v0/v1 (which will not generate multiple .keep files).然而,在实践中,警告永远不会被写入,因为remote-curl.c " fetch " 仅用于协议 v0/v1(不会生成多个.keep文件)。 (Protocol v2 uses the "stateless-connect" command, not the " fetch " command.) (协议 v2 使用“stateless-connect”命令,而不是“ fetch ”命令。)

  • connected.c has an optimization in that connectivity checks on a ref need not be done if the target object is in a pack known to be self-contained and connected. connected.c有一个优化,如果目标对象在一个已知是自包含和连接的包中,则不需要对 ref 进行连接检查。 If there are multiple packfiles, this optimization can no longer be done.如果有多个包文件,则无法再进行此优化。

Cf.参见Packfile URIs 包文件 URI

This feature allows servers to serve part of their packfile response as URIs.此功能允许服务器将其包文件响应的一部分作为 URI 提供服务。 This allows server designs that improve scalability in bandwidth and CPU usage (for example, by serving some data through a CDN), and (in the future) provides some measure of resumability to clients.这允许服务器设计提高带宽和 CPU 使用率的可扩展性(例如,通过 CDN 提供一些数据),并且(在未来)为客户端提供一些可恢复性措施。

This feature is available only in protocol version 2.此功能仅在协议版本 2 中可用。


" git fetch --depth= ( man ) " over the stateless RPC / smart HTTP transport handled EOF from the client poorly at the server end. git fetch --depth= ( man ) ”通过无状态RPC /智能HTTP传输在服务器端处理来自客户端的EOF很差。

This is fixed, as part of the transport protocol, in Git 2.30 (Q1 2021).作为传输协议的一部分,这已在 Git 2.30(2021 年第一季度)中得到修复。

See commit fb3d1a0 (30 Oct 2020) by Daniel Duvall ( marxarelli ) .请参阅Daniel Duvall ( marxarelli ) 的提交 fb3d1a0 (2020 年 10 月 30 日)
(Merged by Junio C Hamano -- gitster -- in commit d1169be , 18 Nov 2020) (由Junio C gitster合并-- gitster -- in commit d1169be ,2020 年 11 月 18 日)

upload-pack : allow stateless client EOF just prior to haves upload-pack : 在haves之前允许无状态客户端 EOF

Signed-off-by: Daniel Duvall签字人:Daniel Duvall

During stateless packfile negotiation where a depth is given, stateless RPC clients (eg git-remote-curl ) will send multiple upload-pack requests with the first containing only the wants/shallows/deepens/filters and the subsequent containing haves/done.在给定深度的无状态包文件协商期间,无状态 RPC 客户端(例如git-remote-curl )将发送多个upload-pack请求,第一个只包含需要/浅层/深度/过滤器,随后包含有/完成。

When upload-pack handles such requests, entering get_common_commits without checking whether the client has hung up can result in unexpected EOF during the negotiation loop and a die() with message " fatal: the remote end hung up unexpectedly ".upload-pack处理此类请求时, get_common_commits不检查客户端是否挂断的情况下输入get_common_commits可能会导致协商循环期间出现意外的EOF 以及带有消息“ fatal: the remote end hung up unexpectedly ”的die()

Real world effects include:现实世界的影响包括:

  • A client speaking to git-http-backend via a server that doesn't check the exit codes of CGIs (eg mod_cgi) doesn't know and doesn't care about the fatal.通过不检查 CGI 退出代码的服务器(例如mod_cgi)git-http-backend对话的客户端不知道也不关心致命的。 It continues to process the response body as normal.它继续像往常一样处理响应正文。
  • A client speaking to a server that does check the exit code and returns an errant HTTP status as a result will fail with the message " error: RPC failed; HTTP 500 curl 22 The requested URL returned error: 500. "客户端与服务器通信并检查退出代码并返回错误的 HTTP 状态作为结果将失败并显示消息“ error: RPC failed; HTTP 500 curl 22 The requested URL returned error: 500.
  • Admins running servers that surface the failure must workaround it by patching code that handles execution of git-http-backend to ignore exit codes or take other heuristic approaches.运行出现故障的服务器的管理员必须通过修补处理git-http-backend执行的代码来解决它,以忽略退出代码或采取其他启发式方法。
  • Admins may have to deal with " hung up unexpectedly " log spam related to the failures even in cases where the exit code isn't surfaced as an HTTP server-side error status.管理员可能不得不处理与故障相关的“ hung up unexpectedly ”日志垃圾邮件,即使在退出代码未显示为 HTTP 服务器端错误状态的情况下也是如此。

To avoid these EOF related fatals, have upload-pack gently peek for an EOF between the sending of shallow/unshallow lines (followed by flush) and the reading of client haves .为了避免这些EOF相关严重错误,有upload-pack轻轻偷看为浅/ unshallow线(接着冲洗)发送之间的EOF和客户端的读取haves
If the client has hung up at this point, exit normally.如果此时客户端已挂断,则正常退出。

With Git 2.30 (Q1 2021), the transport layer was taught to optionally exchange the session ID assigned by the trace2 subsystem during fetch/push transactions.在 Git 2.30(2021 年第一季度)中,传输层被教导在获取/推送事务期间选择性地交换由trace2子系统分配的会话 ID。

See commit a2a066d , commit 8c48700 , commit 8295946 , commit 1e905bb , commit 23bf486 , commit 6b5b6e4 , commit 8073d75 , commit 791e1ad , commit e97e1cf , commit 81bd549 , commit f5cdbe4 (11 Nov 2020) by Josh Steadmon ( steadmon ) .提交a2a066d提交8c48700提交8295946提交1e905bb提交23bf486提交6b5b6e4提交8073d75提交791e1ad提交e97e1cf提交81bd549提交f5cdbe4由(2020年11月11日)约什Steadmon( steadmon
(Merged by Junio C Hamano -- gitster -- in commit 01b8886 , 08 Dec 2020) (由Junio C gitster合并gitster 提交 01b8886,2020年 12 月 8 日)

serve : advertise session ID in v2 capabilities serve :在 v2 功能中通告会话 ID

Signed-off-by: Josh Steadmon签字人:Josh Steadmon

When transfer.advertiseSID is true, advertise the server's session ID for all protocol v2 connections via the new session-id capability.当 transfer.advertiseSID 为 true 时,通过新的 session-id 功能为所有协议 v2 连接通告服务器的会话 ID。

And:和:

docs : new capability to advertise session IDs docs :广告会话 ID 的新功能

Signed-off-by: Josh Steadmon签字人:Josh Steadmon

In future patches, we will add the ability for Git servers and clients to advertise unique session IDs via protocol capabilities.在未来的补丁中,我们将添加 Git 服务器和客户端通过协议功能通告唯一会话 ID 的功能。 This allows for easier debugging when both client and server logs are available.当客户端和服务器日志都可用时,这允许更轻松的调试。

technical/protocol-capabilities now includes in its man page : technical/protocol-capabilities现在包含在其手册页中

session-id=<session id>


The server may advertise a session ID that can be used to identify this process across multiple requests.服务器可能会通告一个会话 ID,该 ID 可用于跨多个请求识别此进程。 The client may advertise its own session ID back to the server as well.客户端也可以将自己的会话 ID 通告回服务器。

Session IDs should be unique to a given process.会话 ID 对于给定的进程应该是唯一的。 They must fit within a packet-line, and must not contain non-printable or whitespace characters.它们必须适合数据包行,并且不得包含不可打印或空白字符。

technical/protocol-v2 now includes in its man page : technical/protocol-v2现在包含在其手册页中

session-id=<session id>

 The server may advertise a session ID that can be used to identify this process across multiple requests. The client may advertise its own session ID back to the server as well. Session IDs should be unique to a given process. They must fit within a packet-line, and must not contain non-printable or whitespace characters.

Other new fix With Git 2.30 (Q1 2021): Git 2.30(2021 年第一季度)的其他新修复:

" fetch-pack " could pass NULL pointer to unlink when it sees an invalid filename; fetch-pack ”在看到无效文件名时可以传递NULL指针以unlink the error checking has been tightened to make this impossible.错误检查已被收紧,使这成为不可能。

See commit 6031af3 (30 Nov 2020) by René Scharfe ( rscharfe ) .请参阅René Scharfe ( rscharfe ) 的commit 6031af3 (2020 年 11 月 30 日
(Merged by Junio C Hamano -- gitster -- in commit eae47db , 08 Dec 2020) (由Junio C gitster -- gitster --提交 eae47db 中合并,2020 年 12 月 8 日)

fetch-pack : disregard invalid pack lockfiles fetch-pack : 忽略无效的包锁文件

Signed-off-by: René Scharfe签字人:René Scharfe
Reviewed-by: Taylor Blau审核人:Taylor Blau

9da69a6539 (" fetch-pack : support more than one pack lockfile", 2020-06-10, Git v2.28.0-rc0 -- merge listed in batch #5 ) started to use a string_list for pack lockfile names instead of a single string pointer. 9da69a6539 (" fetch-pack : support more than one pack lockfile", 2020-06-10, Git v2.28.0-rc0 -- 合并批处理#5中列出)开始使用string_list作为pack string_list名称而不是单个字符串指针。
It removed a NULL check from transport_unlock_pack() as well, which is the function that eventually deletes these lockfiles and releases their name strings.它也从transport_unlock_pack()删除了一个NULL检查,这是最终删除这些锁文件并释放它们的名称字符串的函数。

index_pack_lockfile() can return NULL if it doesn't like the contents it reads from the file descriptor passed to it. index_pack_lockfile()不喜欢它从传递给它的文件描述符中读取的内容,它可以返回NULL
unlink(2) is declared to not accept NULL pointers (at least with glibc). unlink(2) 被声明为不接受NULL指针(至少对于 glibc)。
Undefined Behavior Sanitizer together with Address Sanitizer detects a case where a NULL lockfile name is passed to unlink(2) by transport_unlock_pack() in t1060 ( make SANITIZE=address,undefined; cd t; ./t1060-object-corruption.sh ). Undefined Behavior Sanitizer 与 Address Sanitizer 一起检测在 t1060 中通过transport_unlock_pack()NULL锁文件名传递给 unlink(2) 的情况( make SANITIZE=address,undefined; cd t; ./t1060-object-corruption.sh )。

Reinstate the NULL check to avoid undefined behavior, but put it right at the source, so that the number of items in the string_list reflects the number of valid lockfiles.恢复NULL检查以避免未定义的行为,但将其放在源头上,以便string_list的项目数反映有效锁文件的数量。


That transport layer v2 might not be compatible with the commit graph introduced originally in Git 2.18 (Q2 2018) (the precomputed information necessary for ancestry traversal in a separate file to optimize graph walking)该传输层 v2 可能与最初在 Git 2.18(2018 年第二季度)中引入提交图不兼容(祖先遍历所需的预计算信息在单独的文件中优化图行走)

Ævar Arnfjörð Bjarmason describes inthis thread the error messages you would see: Ævar Arnfjörð Bjarmason 在此线程中描述了您将看到的错误消息:

$ git status
    error: graph version 2 does not match version 1
$ ~/g/git/git --exec-path=$PWD status
    error: commit-graph version 2 does not match version 1
    On branch master
    [...]

With Git 2.31 (Q1 2021), the commit-graph learned to use corrected commit dates instead of the generation number to help topological revision traversal, in order to differentiate itself from protocol v1.在 Git 2.31(2021 年第一季度)中,提交图学会了使用更正的提交日期而不是代号来帮助拓扑修订遍历,以便将自己与协议 v1 区分开来。

See commit 5a3b130 , commit 8d00d7c , commit 1fdc383 , commit e8b6300 , commit c1a0911 , commit d7f9278 , commit 72a2bfc , commit c0ef139 , commit f90fca6 , commit 2f9bbb6 , commit e30c5ee (16 Jan 2021) by Abhishek Kumar ( abhishekkumar2718 ) .提交5a3b130提交8d00d7c提交1fdc383提交e8b6300提交c1a0911提交d7f9278提交72a2bfc提交c0ef139提交f90fca6提交2f9bbb6提交e30c5ee (2021年1月16日)由阿布舍克·库马尔( abhishekkumar2718
(Merged by Junio C Hamano -- gitster -- in commit 8b4701a , 17 Feb 2021) (由Junio C gitster合并-- gitster -- in commit 8b4701a ,2021 年 2 月 17 日)

commit-graph : implement generation data chunk commit-graph : 实现生成数据块

Signed-off-by: Abhishek Kumar签字人:Abhishek Kumar
Reviewed-by: Taylor Blau审核人:Taylor Blau
Reviewed-by: Derrick Stolee评论人:德里克·斯托利

As discovered by Ævar, we cannot increment graph version to distinguish between generation numbers v1 and v2.正如 Ævar 发现的那样,我们无法通过增加图版本来区分代号 v1 和 v2。
Thus, one of pre-requistes before implementing generation number v2 was to distinguish between graph versions in a backwards compatible manner.因此,在实现第 v2 代之前的先决条件之一是以向后兼容的方式区分图形版本。

We are going to introduce a new chunk called Generation DATa chunk (or GDAT).我们将引入一个名为 Generation DATA 块(或 GDAT)的新块。
GDAT will store corrected committer date offsets whereas CDAT will still store topological level. GDAT 将存储更正的提交者日期偏移,而 CDAT 仍将存储拓扑级别。

Old Git does not understand GDAT chunk and would ignore it, reading topological levels from CDAT.旧 Git 不理解 GDAT 块,会忽略它,从 CDAT 读取拓扑级别。
New Git can parse GDAT and take advantage of newer generation numbers, falling back to topological levels when GDAT chunk is missing (as it would happen with a commit-graph written by old Git).新 Git 可以解析 GDAT 并利用较新的代数,当 GDAT 块丢失时回退到拓扑级别(就像旧 Git 编写的提交图一样)。

To minimize the space required to store corrected commit date, Git stores corrected commit date offsets into the commit-graph file, instead of corrected commit dates.为了最小化存储更正提交日期所需的空间,Git 将更正提交日期偏移量存储到提交图文件中,而不是更正提交日期。
This saves us 4 bytes per commit, decreasing the GDAT chunk size by half, but it's possible for the offset to overflow the 4-bytes allocated for storage.这为我们每次提交节省了 4 个字节,将 GDAT 块大小减少了一半,但偏移量可能会溢出分配给存储的 4 个字节。
As such overflows are and should be exceedingly rare, we use the following overflow management scheme:由于此类溢出非常罕见,因此我们使用以下溢出管理方案:

We introduce a new commit-graph chunk , Generation Data OVerflow (' GDOV ') to store corrected commit dates for commits with offsets greater than GENERATION_NUMBER_V2_OFFSET_MAX .我们引入了一个新的提交图块Generation Data Overflow (' GDOV ') 来存储偏移量大于GENERATION_NUMBER_V2_OFFSET_MAX提交的更正提交日期。

If the offset is greater than GENERATION_NUMBER_V2_OFFSET_MAX, we set the MSB of the offset and the other bits store the position of corrected commit date in GDOV chunk, similar to how Extra Edge List is maintained.如果偏移量大于GENERATION_NUMBER_V2_OFFSET_MAX,我们设置偏移量的MSB,其他位存储GDOV块中更正提交日期的位置,类似于额外边缘列表的维护方式。

We test the overflow-related code with the following repo history:我们使用以下 repo 历史记录测试与溢出相关的代码:

 F - N - U / \\ U - N - UN \\ / N - F - N

Where:在哪里:

  • the commits denoted by U have committer date of zero seconds since Unix epoch,由 U 表示的提交自 Unix 纪元以来的提交日期为零秒,
  • the commits denoted by N have committer date of 1112354055 (default committer date for the test suite) seconds since Unix epoch and自 Unix 纪元以来,由 N 表示的提交的提交日期为 1112354055(测试套件的默认提交日期)秒,并且
  • the commits denoted by F have committer date of (2 ^ 31 - 2) seconds since Unix epoch.自 Unix 纪元以来,由 F 表示的提交的提交日期为 (2 ^ 31 - 2) 秒。

The largest offset observed is 2 ^ 31, just large enough to overflow.观察到的最大偏移量为 2 ^ 31,刚好足以溢出。

This is backward compatible with v1 because:这与 v1 向后兼容,因为:

commit-graph : use generation v2 only if entire chain does commit-graph :仅当整个链都执行时才使用第 2 代

Signed-off-by: Derrick Stolee签字人:德里克·斯托利
Signed-off-by: Abhishek Kumar签字人:Abhishek Kumar
Reviewed-by: Taylor Blau审核人:Taylor Blau
Reviewed-by: Derrick Stolee评论人:德里克·斯托利

Since there are released versions of Git that understand generation numbers in the commit-graph's CDAT chunk but do not understand the GDAT chunk, the following scenario is possible:由于有些已发布的 Git 版本可以理解提交图的 CDAT 块中的代号但不理解 GDAT 块,因此可能出现以下情况:

  1. "New" Git writes a commit-graph with the GDAT chunk. “新”Git 使用 GDAT 块编写提交图。
  2. "Old" Git writes a split commit-graph on top without a GDAT chunk. “旧”Git 在没有 GDAT 块的情况下在顶部编写了一个拆分提交图。

If each layer of split commit-graph is treated independently, as it was the case before this commit, with Git inspecting only the current layer for chunk_generation_data pointer, commits in the lower layer (one with GDAT) whould have corrected commit date as their generation number, while commits in the upper layer would have topological levels as their generation.如果拆分提交图的每一层都是独立处理的,就像这次提交之前的情况一样,Git 只检查当前层的chunk_generation_data指针,在较低层(带有 GDAT 的层)中的提交应该将提交日期更正为它们的生成编号,而上层的提交将具有拓扑级别作为其生成。
Corrected commit dates usually have much larger values than topological levels.更正的提交日期通常具有比拓扑级别大得多的值。
This means that if we take two commits, one from the upper layer, and one reachable from it in the lower layer, then the expectation that the generation of a parent is smaller than the generation of a child would be violated.这意味着,如果我们进行两次提交,一次来自上层,另一次可从下层到达,那么将违反父代小于子代的期望。

It is difficult to expose this issue in a test.在测试中很难暴露这个问题。
Since we start with artificially low generation numbers, any commit walk that prioritizes generation numbers will walk all of the commits with high generation number before walking the commits with low generation number.由于我们人为的低代号开始,任何优先考虑代号的提交遍历都会先遍历所有具有高代号的提交,然后再遍历低代号的提交。
In all the cases I tried, the commit-graph layers themselves "protect" any incorrect behavior since none of the commits in the lower layer can reach the commits in the upper layer.在我尝试的所有情况下,提交图层本身“保护”了任何不正确的行为,因为下层中的任何提交都无法到达上层中的提交。

This issue would manifest itself as a performance problem in this case, especially with something like " git log --graph " ( man ) since the low generation numbers would cause the in-degree queue to walk all of the commits in the lower layer before allowing the topo-order queue to write anything to output (depending on the size of the upper layer).在这种情况下,这个问题会表现为一个性能问题,特别是像“ git log --graphman )这样的东西,因为低代数会导致入度队列在之前遍历低层中的所有提交允许拓扑顺序队列向输出写入任何内容(取决于上层的大小)。

Therefore, When writing the new layer in split commit-graph, we write a GDAT chunk only if the topmost layer has a GDAT chunk.因此,当在 split commit-graph 中写入新层时,只有当最顶层有 GDAT 块时,我们才写入 GDAT 块。
This guarantees that if a layer has GDAT chunk, all lower layers must have a GDAT chunk as well.这保证了如果一个层有 GDAT 块,那么所有较低的层也必须有一个 GDAT 块。

Rewriting layers follows similar approach: if the topmost layer below the set of layers being rewritten (in the split commit-graph chain) exists, and it does not contain GDAT chunk, then the result of rewrite does not have GDAT chunks either.重写层遵循类似的方法:如果被重写的层集(在拆分提交图链中)下面的最顶层存在,并且它不包含 GDAT 块,那么重写的结果也没有 GDAT 块。

What is a " corrected commit date "?什么是“更正的提交日期”?

commit-graph : implement corrected commit date commit-graph : 实现更正的提交日期

Signed-off-by: Abhishek Kumar签字人:Abhishek Kumar
Reviewed-by: Taylor Blau审核人:Taylor Blau
Reviewed-by: Derrick Stolee评论人:德里克·斯托利

With most of preparations done, let's implement corrected commit date.完成大部分准备工作后,让我们实现更正的提交日期。

The corrected commit date for a commit is defined as :提交更正提交日期定义为

  • A commit with no parents (a root commit) has corrected commit date equal to its committer date.没有父项的提交(根提交)已更正提交日期等于其提交者日期。
  • A commit with at least one parent has corrected commit date equal to the maximum of its commit date and one more than the largest corrected commit date among its parents.具有至少一个父项的提交的更正提交日期等于其提交日期的最大值,并且比其父项中最大的更正提交日期多一个。

As a special case, a root commit with timestamp of zero (01.01.1970 00:00:00Z) has corrected commit date of one, to be able to distinguish from GENERATION_NUMBER_ZERO (that is, an uncomputed corrected commit date).作为一种特殊情况,时间戳为零 (01.01.1970 00:00:00Z) 的根提交已更正提交日期为 1,以便能够与GENERATION_NUMBER_ZERO (即未计算的更正提交日期)区分开来。

To minimize the space required to store corrected commit date, Git stores corrected commit date offsets into the commit-graph file.为了最小化存储更正提交日期所需的空间,Git 将更正提交日期偏移量存储到提交图文件中。
The corrected commit date offset for a commit is defined as the difference between its corrected commit date and actual commit date.提交的更正提交日期偏移量定义为其更正提交日期与实际提交日期之间的差异。

Storing corrected commit date requires sizeof(timestamp_t) bytes, which in most cases is 64 bits (uintmax_t) .存储更正的提交日期需要sizeof(timestamp_t)字节,在大多数情况下是 64 位(uintmax_t)
However, corrected commit date offsets can be safely stored using only 32-bits.但是,可以仅使用 32 位安全地存储更正的提交日期偏移量。
This halves the size of GDAT chunk, which is a reduction of around 6% in the size of commit-graph file.这将 GDAT 块的大小减半,即提交图文件的大小减少了约 6%。

However, using offsets be problematic if a commit is malformed but valid and has committer date of 0 Unix time, as the offset would be the same as corrected commit date and thus require 64-bits to be stored properly.但是,如果提交格式错误但有效并且提交者日期为 0 Unix 时间,则使用偏移量是有问题的,因为偏移量将与更正的提交日期相同,因此需要正确存储 64 位。

While Git does not write out offsets at this stage, Git stores the corrected commit dates in member generation of struct commit_graph_data .虽然 Git 在此阶段不会写出偏移量,但 Git 将更正的提交日期存储在 struct commit_graph_data成员生成中。
It will begin writing commit date offsets with the introduction of generation data chunk.随着生成数据块的引入,它将开始写入提交日期偏移量。

And that improves performances:这提高了性能:

commit-reach : use corrected commit dates in paint_down_to_common() commit-reach :在paint_down_to_common()使用更正的提交日期

Signed-off-by: Abhishek Kumar签字人:Abhishek Kumar
Reviewed-by: Taylor Blau审核人:Taylor Blau
Reviewed-by: Derrick Stolee评论人:德里克·斯托利

091f4cf (" commit : don't use generation numbers if not needed", 2018-08-30, Git v2.19.0-rc2 -- merge ) changed paint_down_to_common() to use commit dates instead of generation numbers v1 (topological levels) as the performance regressed on certain topologies. 091f4cf (" commit : don't use generation numbers if not needed", 2018-08-30, Git v2.19.0-rc2 -- merge ) 将paint_down_to_common()更改为使用提交日期而不是paint_down_to_common() v1(拓扑级别)作为性能在某些拓扑上有所下降。
With generation number v2 (corrected commit dates) implemented, we no longer have to rely on commit dates and can use generation numbers.随着代号 v2(更正的提交日期)的实施,我们不再需要依赖提交日期并且可以使用代号。

For example, the command git merge-base ( man ) v4.8 v4.9 on the Linux repository walks 167468 commits, taking 0.135s for committer date and 167496 commits, taking 0.157s for corrected committer date respectively.例如,Linux 存储库上的命令git merge-base ( man ) v4.8 v4.9 走 167468 次提交,提交者日期为 0.135 秒,提交者日期为 167496 次,修正后的提交者日期分别为 0.157 秒。

While using corrected commit dates, Git walks nearly the same number of commits as commit date, the process is slower as for each comparision we have to access a commit-slab (for corrected committer date) instead of accessing struct member (for committer date).在使用更正的提交日期时,Git 执行的提交次数与提交日期几乎相同,该过程较慢,因为对于每次比较,我们必须访问提交板(用于更正的提交者日期)而不是访问结构成员(用于提交者日期) .

As this has already causes problems (as noted in 859fdc0 ( commit-graph : define GIT_TEST_COMMIT_GRAPH , 2018-08-29, Git v2.20.0-rc0 -- merge listed in batch #1 ), we disable commit graph within t6404-recursive-merge.由于这已经导致问题(如859fdc0 中所述commit-graph :定义GIT_TEST_COMMIT_GRAPH ,2018 年 8 月 29 日,Git v2.20.0-rc0 -- 合并批次 #1 中列出),我们在 t6404-recursive- 中禁用提交图合并。


Then, still with Git 2.31 (Q1 2021), fix incremental update of commit-graph file around corrected commit date data.然后,仍然使用 Git 2.31(2021 年第一季度),围绕更正的提交日期数据修复提交图文件的增量更新。

See commit bc50d6c , commit fde55b0 , commit 9c2c0a8 , commit 448a39e (02 Feb 2021), and commit 90cb1c4 , commit c4cc083 (01 Feb 2021) by Derrick Stolee ( derrickstolee ) .提交bc50d6c提交fde55b0提交9c2c0a8提交448a39e (2021年2月2日),并提交90cb1c4提交c4cc083 (2021年2月1日),由德里克Stolee( derrickstolee
(Merged by Junio C Hamano -- gitster -- in commit 5bd0b21 , 17 Feb 2021) (由Junio C gitster合并-- gitster -- in commit 5bd0b21 ,2021 年 2 月 17 日)

commit-graph : compute generations separately commit-graph :分别计算代

Signed-off-by: Derrick Stolee签字人:德里克·斯托利
Reviewed-by: Taylor Blau审核人:Taylor Blau

The compute_generation_numbers() method was introduced by 3258c66 (" commit-graph : compute generation numbers", 2018-05-01, Git v2.19.0-rc0 -- merge listed in batch #1 ) to compute what is now known as " topological levels ".所述compute_generation_numbers()方法通过引入3258c66 (“ commit-graph :计算生成号”,2018年5月1日,GIT中v2.19.0-RC0 - 合并中列出批次#1 )来计算什么现在被称为“拓扑水平”。
These are still stored in the commit-graph file for compatibility sake while c1a0911 (" commit-graph : implement corrected commit date", 2021-01-16, Git v2.31.0 -- merge listed in batch #9 ) updated the method to also compute the new version of generation numbers: corrected commit date .出于兼容性考虑,这些仍存储在提交图文件中,而c1a0911 (“ commit-graph :实现更正的提交日期”,2021-01-16,Git v2.31.0 -- 合并第 9 批中列出)将方法更新为还计算新版本的代号:更正的提交日期

It makes sense why these are grouped.为什么将这些分组是有道理的。
They perform very similar walks of the necessary commits and compute similar maximums over each parent.他们对必要的提交执行非常相似的遍历,并在每个父节点上计算相似的最大值。
However, having these two together conflates them in subtle ways that is hard to separate.然而,将这两者放在一起以难以区分的微妙方式将它们混为一谈。

In particular, the topo_level slab is used to store the topological levels in all cases, but the commit_graph_data_at(c)->generation member stores different values depending on the state of the existing commit-graph file.特别是, topo_level板用于存储所有情况下的拓扑级别,但commit_graph_data_at(c)->generation成员根据现有提交图文件的状态存储不同的值。 * If the existing commit-graph file has a "GDAT" chunk, then these values represent corrected commit dates. * 如果现有的提交图文件有一个“GDAT”块,那么这些值代表更正的提交日期。 * If the existing commit-graph file doesn't have a "GDAT" chunk, then these values are actually the topological levels. * 如果现有的提交图文件没有“GDAT”块,那么这些值实际上是拓扑级别。

This issue only occurs only when upgrading an existing commit-graph file into one that has the "GDAT" chunk.仅当将现有提交图文件升级为具有“GDAT”块的文件时,才会出现此问题。
The current change does not resolve this upgrade problem, but splitting the implementation into two pieces here helps with that process, which will follow in the next change.当前的更改并没有解决这个升级问题,但是在这里将实现分成两部分有助于该过程,这将在下一个更改中进行。

The important thing this helps with is the case where the num_generation_data_overflows was being incremented incorrectly, triggering a write of the overflow chunk.这有帮助的重要一点是num_generation_data_overflows被错误地增加,触发了溢出块的写入。

And:和:

commit-graph : be extra careful about mixed generations commit-graph : 对混合世代要格外小心

Signed-off-by: Derrick Stolee签字人:德里克·斯托利
Reviewed-by: Taylor Blau审核人:Taylor Blau

When upgrading to a commit-graph with corrected commit dates from one without, there are a few things that need to be considered.当升级到具有更正提交日期的提交图时,需要考虑一些事项。

When computing generation numbers for the new commit-graph file that expects to add the generation_data chunk with corrected commit dates, we need to ensure that the 'generation' member of the commit_graph_data struct is set to zero for these commits.当计算新的提交图文件的commit_graph_data ,该文件希望添加具有更正提交日期的generation_data块,我们需要确保这些提交的commit_graph_data结构的“generation”成员设置为零。

Unfortunately, the fallback to use topological level for generation number when corrected commit dates are not available are causing us harm here: parsing commits notices that read_generation_data is false and populates 'generation' with the topological level.不幸的是,当更正的提交日期不可用时,使用拓扑级别作为代号的回退在这里给我们造成了伤害:解析提交通知read_generation_data是假的,并用拓扑级别填充“代”。

The solution is to iterate through the commits, parse the commits to populate initial values, then reset the generation values to zero to trigger recalculation.解决方案是遍历提交,解析提交以填充初始值,然后将生成值重置为零以触发重新计算。
This loop only occurs when the existing commit-graph data has no corrected commit dates.此循环仅在现有提交图数据没有更正的提交日期时发生。


And also:并且:

With Git 2.32 (Q2 2021), over-the-wire protocol learns a new request type to ask for object sizes given a list of object names .在 Git 2.32(2021 年第二季度)中,在线协议学习了一种新的请求类型,以在给定对象名称列表的情况下询问对象大小

See commit a2ba162 (20 Apr 2021) by Bruno Albuquerque ( brunoga2 ) .请参阅Bruno Albuquerque ( brunoga2 ) 提交的 a2ba162 (2021 年 4 月 20 日
(Merged by Junio C Hamano -- gitster -- in commit eede711 , 14 May 2021) (由Junio C gitster -- gitster --eede711 提交中合并,2021 年 5 月 14 日)

object-info : support for retrieving object info object-info : 支持检索对​​象信息

Signed-off-by: Bruno Albuquerque签字人:布鲁诺·阿尔伯克基

Sometimes it is useful to get information of an object without having to download it completely.有时无需完全下载即可获取对象的信息很有用。

Add the "object-info" capability that lets the client ask for object-related information with their full hexadecimal object names.添加“object-info”功能,让客户端使用完整的十六进制对象名称询问与对象相关的信息。

Only sizes are returned for now.目前只返回尺寸。

technical/protocol-v2 now includes in its man page : technical/protocol-v2现在包含在其手册页中

object-info

object-info is the command to retrieve information about one or more objects. object-info是检索有关一个或多个object-info的命令。 Its main purpose is to allow a client to make decisions based on this information without having to fully fetch objects.其主要目的是允许客户端根据此信息做出决策,而无需完全获取对象。 Object size is the only information that is currently supported.对象大小是目前唯一支持的信息。

An object-info request takes the following arguments: object-info请求采用以下参数:

  • size
    Requests size information to be returned for each listed object id.请求为每个列出的对象 ID 返回大小信息。

  • oid <oid>
    Indicates to the server an object which the client wants to obtain information for.向服务器指示客户端想要为其获取信息的对象。

The response of object-info is a list of the the requested object ids and associated requested information, each separated by a single space. object-info的响应是请求的对象 ID 和相关请求信息的列表,每个 ID 由单个空格分隔。

 output = info flush-pkt info = PKT-LINE(attrs) LF) *PKT-LINE(obj-info LF) attrs = attr | attrs SP attrs attr = "size" obj-info = obj-id SP obj-size

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM