Ken*_*ton 8 git http github smart-http
我正在尝试实现一个模拟 Git 远程的网络服务器。用户应该能够从我的服务器克隆或拉取、编辑文件、提交和推送(需要身份验证)\xe2\x80\x94 使用 Git 执行的正常操作。然而,在服务器端并不是一个裸露的 Git 存储库或任何东西;数据以其他格式存储,并且仅在请求时进行转换。
\n我花了很多时间试图了解 Git Smart HTTP 协议是如何工作的,这是我目前所知道的。
\n从http-protocol 上的 Git 文档,我知道这GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.1
应该引发以下(示例)响应:
HTTP/1.1 200 OK<CRLF>\nContent-Type: application/x-git-upload-pack-advertisement<CRLF>\nCache-Control: no-cache<CRLF>\n<CRLF>\n001e# service=git-upload-pack<LF>\n0000<no LF>\n004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint<NUL>multi_ack<LF>\n003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master<LF>\n003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0<LF>\n003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}<LF>\n0000\n
Run Code Online (Sandbox Code Playgroud)\n从我自己对我的 repo 进行的实验来看,提交很少,看来 GitHub 到目前为止完全在文档中描述的协议限制内:
\nHTTP/1.1 200 OK<CRLF>\nServer: GitHub Babel 2.0<CRLF>\nContent-Type: application/x-git-upload-pack-advertisement<CRLF>\nContent-Security-Policy: default-src \'none\'; sandbox<CRLF>\nTransfer-Encoding: chunked<CRLF>\nexpires: Fri, 01 Jan 1980 00:00:00 GMT<CRLF>\npragma: no-cache<CRLF>\nCache-Control: no-cache, max-age=0, must-revalidate<CRLF>\nVary: Accept-Encoding<CRLF>\nX-Frame-Options: DENY<CRLF>\nX-GitHub-Request-Id: [redacted]<CRLF>\n<CRLF>\n001e# service=git-upload-pack<LF>\n0000<no LF>0156feee8d0aeff172f5b39e3175175d027f3fd5ecc1 HEAD<NUL>multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed allow-tip-sha1-in-want allow-reachable-sha1-in-want no-done symref=HEAD:refs/heads/master filter object-format=sha1 agent=git/github-g69d6dd5d35d8<LF>\n003ffeee8d0aeff172f5b39e3175175d027f3fd5ecc1 refs/heads/master<LF>\n0000\n
Run Code Online (Sandbox Code Playgroud)\n然而,这就是简单部分的结束。如果我想实际获取提交数据怎么办?有关此事的 Git 文档给出了要发送的 POST 请求的示例以及一些语法,然后说“ TODO:进一步记录这一点”。???????
\n我尝试按照我在文档中看到的格式对 GitHub 进行 CURL 尝试。
\n(cwd)>curl https://github.com/Kenny2github/ConvoSplit.git/git-upload-pack -o - -i -X POST -d @-\n0032want feee8d0aeff172f5b39e3175175d027f3fd5ecc1\n0032have 941ea62275547bcbfb78fd97d29be18d09a78190\n0009done\n0000\n^Z\nHTTP/1.1 200 OK\nServer: GitHub Babel 2.0\nContent-Type: application/x-git-upload-pack-result\nContent-Security-Policy: default-src \'none\'; sandbox\nTransfer-Encoding: chunked\nexpires: Fri, 01 Jan 1980 00:00:00 GMT\npragma: no-cache\nCache-Control: no-cache, max-age=0, must-revalidate\nVary: Accept-Encoding\nX-GitHub-Request-Id: [redacted]\nX-Frame-Options: DENY\n\ncurl: (18) transfer closed with outstanding read data remaining\n
Run Code Online (Sandbox Code Playgroud)\n什么?
\n我尝试使用Python:
\nHTTP/1.1 200 OK<CRLF>\nContent-Type: application/x-git-upload-pack-advertisement<CRLF>\nCache-Control: no-cache<CRLF>\n<CRLF>\n001e# service=git-upload-pack<LF>\n0000<no LF>\n004895dcfa3633004da0049d3d0fa03f80589cbcaf31 refs/heads/maint<NUL>multi_ack<LF>\n003fd049f6c27a2244e12041955e262a404c7faba355 refs/heads/master<LF>\n003c2cb58b79488a98d2721cea644875a8dd0026b115 refs/tags/v1.0<LF>\n003fa3c2e2402b99163d1d59756e5f207ae21cccba4c refs/tags/v1.0^{}<LF>\n0000\n
Run Code Online (Sandbox Code Playgroud)\n其余的 http 协议文档没有帮助 - 出现了另外 6 个 TODO。包协议文档至少让我了解我应该接收什么,但没有说明如何接收。
\n传输协议文档没有告诉我任何新内容,然后说“看看 Git 源代码”。我尝试过,但它是核心 C,我必须基本上了解 Git 本身的整个基础结构。(我可能还会尝试这样做,但现在还不是时候。)
\n我确实设法收集了所git upload-pack
涉及的内容,并且运行git upload-pack --stateless-rpc --advertise-refs .git
确实给了我像以前一样的 /info/refs 列表。然而,从其中获取实际包的尝试失败了,而且它们不仅失败了,而且在平台之间失败的情况不一致。
在 Windows 上:
\nHTTP/1.1 200 OK<CRLF>\nServer: GitHub Babel 2.0<CRLF>\nContent-Type: application/x-git-upload-pack-advertisement<CRLF>\nContent-Security-Policy: default-src \'none\'; sandbox<CRLF>\nTransfer-Encoding: chunked<CRLF>\nexpires: Fri, 01 Jan 1980 00:00:00 GMT<CRLF>\npragma: no-cache<CRLF>\nCache-Control: no-cache, max-age=0, must-revalidate<CRLF>\nVary: Accept-Encoding<CRLF>\nX-Frame-Options: DENY<CRLF>\nX-GitHub-Request-Id: [redacted]<CRLF>\n<CRLF>\n001e# service=git-upload-pack<LF>\n0000<no LF>0156feee8d0aeff172f5b39e3175175d027f3fd5ecc1 HEAD<NUL>multi_ack thin-pack side-band side-band-64k ofs-delta shallow deepen-since deepen-not deepen-relative no-progress include-tag multi_ack_detailed allow-tip-sha1-in-want allow-reachable-sha1-in-want no-done symref=HEAD:refs/heads/master filter object-format=sha1 agent=git/github-g69d6dd5d35d8<LF>\n003ffeee8d0aeff172f5b39e3175175d027f3fd5ecc1 refs/heads/master<LF>\n0000\n
Run Code Online (Sandbox Code Playgroud)\n怀疑是回车引起问题,我尝试了WSL:
\n(cwd)>curl https://github.com/Kenny2github/ConvoSplit.git/git-upload-pack -o - -i -X POST -d @-\n0032want feee8d0aeff172f5b39e3175175d027f3fd5ecc1\n0032have 941ea62275547bcbfb78fd97d29be18d09a78190\n0009done\n0000\n^Z\nHTTP/1.1 200 OK\nServer: GitHub Babel 2.0\nContent-Type: application/x-git-upload-pack-result\nContent-Security-Policy: default-src \'none\'; sandbox\nTransfer-Encoding: chunked\nexpires: Fri, 01 Jan 1980 00:00:00 GMT\npragma: no-cache\nCache-Control: no-cache, max-age=0, must-revalidate\nVary: Accept-Encoding\nX-GitHub-Request-Id: [redacted]\nX-Frame-Options: DENY\n\ncurl: (18) transfer closed with outstanding read data remaining\n
Run Code Online (Sandbox Code Playgroud)\n我究竟做错了什么?我怎样才能让 GitHub/git-upload-pack 尊重我?
\n首先,不可能在 StackOverflow 的答案中解释整个协议;解释太长了。不过,我会尝试指出一些需要注意的事项。
首先,当你讲协议时,你需要非常准确;在这种情况下,不能容忍行结束差异和额外字节。因此,如果您要合成数据以传递到远程,则应该使用printf(1)
编程语言来完成。不要在 shell 上输入内容。
Git 使用 pkt-line 格式,这意味着每行或数据块都以四个十六进制字符序列作为前缀,表示数据的长度和前缀。如果序列为 0000,则这是一个刷新数据包,它指示该数据块的结尾。如果序列为 0001,则这是一个分隔符数据包,它在协议 v2 中用于分隔该数据块的各个部分。否则,十六进制序列的值不能超过 65519。
在您发送want
和have
线路的情况下,您需要进行多次迭代,直到服务器向您发送包。在 HTTP 中,这是多个请求。服务器将向您发送对have
您指定的参数的确认。服务器期望找到从每个want
指令到双方都有的对象的路径(否则,客户端什么都没有,在这种情况下存储库为空)。
请注意,这项任务实际上非常复杂。现在有一个 v2 协议(旧的协议是 v0,还有一个 v1,它是相同的,但带有版本标头)用于提取。您还应该期望能够支持 SHA-256 存储库,该存储库当前不与 SHA-1 存储库互操作,但以其他方式受支持。Git 还提供了大量您实际上想要支持的扩展,例如边带功能,如果您想向用户提供有关您这边正在做什么的输出,则需要使用边带功能。
文档主要位于Documentation/technical
Git 存储库中。它在某些地方不完整,但您应该能够通过一些阅读和测试来辨别它。