【问题标题】:What's the difference between Git protocol v1 and v0,v2?Git 协议 v1 和 v0,v2 有什么区别?
【发布时间】:2021-06-18 22:10:13
【问题描述】:

如果我使用协议 v0 和 v2 克隆一个 repo,一切正常。 但如果我将协议更改为 v1,我得到了这个:

$GIT_TRACE_PACKET=1  git clone -c protocol.version=1 https://gitee.com/yomorun/yomo.git out
Cloning into 'out'...
16:57:10.089707 pkt-line.c:80           packet:          git< version 1
fatal: invalid server response; got 'version 1'

错误信息来自check_smart_http()方法,我知道协议v2和v0都是智能协议,但是v1智能协议不一样吗?

这里贴一个Git的源代码sn-p:

static void check_smart_http(struct discovery *d, const char *service,
                 struct strbuf *type)
{
    const char *p;
    struct packet_reader reader;
    warning("    remote-curl.c call [check_smart_http]");

    /*
     * If we don't see x-$service-advertisement, then it's not smart-http.
     * But once we do, we commit to it and assume any other protocol
     * violations are hard errors.
     */
    if (!skip_prefix(type->buf, "application/x-", &p) ||
        !skip_prefix(p, service, &p) ||
        strcmp(p, "-advertisement"))
        return;

    packet_reader_init(&reader, -1, d->buf, d->len,
               PACKET_READ_CHOMP_NEWLINE |
               PACKET_READ_DIE_ON_ERR_PACKET);
    if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
        die(_("invalid server response; expected service, got flush packet"));

    if (skip_prefix(reader.line, "# service=", &p) && !strcmp(p, service)) {
        /*
         * The header can include additional metadata lines, up
         * until a packet flush marker.  Ignore these now, but
         * in the future we might start to scan them.
         */
        for (;;) {
            packet_reader_read(&reader);
            if (reader.pktlen <= 0) {
                break;
            }
        }

        /*
         * v0 smart http; callers expect us to soak up the
         * service and header packets
         */
        d->buf = reader.src_buffer;
        d->len = reader.src_len;
        d->proto_git = 1;

    } else if (!strcmp(reader.line, "version 2")) {
        /*
         * v2 smart http; do not consume version packet, which will
         * be handled elsewhere.
         */
        d->proto_git = 1;

    } else {
        die(_("invalid server response; got '%s'"), reader.line);
    }
}

我不明白为什么它忽略了版本 1。

【问题讨论】:

    标签: git network-protocols


    【解决方案1】:

    commit aa9bab2(Gti 2.16.0,2017 年 10 月)中引入了“protocol v1”

    协议版本 1 只是原始和当前协议(我是 调用版本 0) 并添加了一条数据包行,其中 在 ref 通告之前,表明协议版本是 口语。

    由于 v2 对 v1 进行了改进,因此不再直接支持 v1:它是 v0 或 v2。

    关于 v2,在 Git 2.34(2021 年第四季度)中,http-backend 已更新,可在对方请求时自动启用协议 v2,从而利用 CGI 接口。

    参见Jeff King (peff)commit 1b421e7commit 2834a72commit 295d81bcommit ff6a37ccommit 2614698(2021 年 9 月 10 日)。
    (由Junio C Hamano -- gitster -- 合并到commit cabb41d, 2021 年 9 月 23 日)

    docs/http-backend:提到v2协议

    签字人:杰夫·金

    从历史上看,为了让客户端的 v2 协议探测到 Git,需要在网络服务器级别进行一些配置。
    但是当我们引入 v2 协议时,我们从未记录过这些。

    截至上一次提交,这应该大部分开箱即用,无需任何显式配置。
    但值得记录这一点,以明确我们期望它如何工作,尤其是面对不通过 CGI 接口提供所有标头的网络服务器。
    或者任何浏览过本文档但拥有旧版本 Git 的人(或使用拥有旧版本,并想知道为什么他们的 Apache 配置中仍然有 SetEnvIf 行以及是否仍然有必要)。

    git http-backend 现在包含在其man page 中:

    利用CGI接口,同时支持Git的 如果配置得当,更高效的“v2”协议;

    git http-backend 现在包含在其man page 中:

    # This is not strictly necessary using Apache and a modern version of
    # git-http-backend, as the webserver will pass along the header in the
    # environment as HTTP_GIT_PROTOCOL, and http-backend will copy that into
    # GIT_PROTOCOL. But you may need this line (or something similar if you
    # are using a different webserver), or if you want to support older Git
    # versions that did not do that copying.
    #
    # Having the webserver set up GIT_PROTOCOL is perfectly fine even with
    # modern versions (and will take precedence over HTTP_GIT_PROTOCOL,
    # which means it can be used to override the client's request).
    SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
    

    git http-backend 现在包含在其man page 中:

    客户端可以探测可选的协议功能(如 v2 协议)使用Git-Protocol HTTP 标头。为了支持 这些,该标题的内容必须出现在GIT_PROTOCOL 环境变量。大多数网络服务器会将此标头传递给 CGI 通过HTTP_GIT_PROTOCOL 变量,git-http-backend 将 自动将其复制到GIT_PROTOCOL。但是,一些网络服务器可能 对他们将通过哪些标头更有选择性,在这种情况下,他们 需要显式配置(参见Git-Protocol 中的提及 前面的示例部分中的 Apache 配置)。


    git -c protocol.version=1 clone... 曾经在t/interop/i5700-protocol-transition.sh 工作,但仅适用于 Got 2.0.0,而不是之后。
    那是因为它是一个互操作测试:

    这个目录有 git 的互操作性测试。
    每个脚本都是 类似于t/ 中的普通测试脚本,但增加了一些扭曲 git 的两个特殊版本“git.a”和“git.b”在 PATH.
    然后单独的测试可以检查两个版本之间的交互。

    所以protocol.version=1 只在 Git 2.0.0 中工作。不是之前也不是之后。

    【讨论】:

    • 感谢您的耐心和详细解答。
    【解决方案2】:

    没有“Git 协议 v1”。版本为零,这是第一个版本(如果需要,您可以调用“v1”,但 Git 不会);然后是版本 2,即第二个版本。所以有效的选择是 v0 和 v2。

    【讨论】:

    • 如果它是真的,似乎一切都有意义。但是我确实发现了很多关于“protocol v1”的线索,如果你愿意,你可以找到一个名为t5700-protocol-v1.sh的测试脚本,它通过将protocol.version指定为1来测试git wire协议。
    • 查看该测试的前几行,其中设置了TEST_NO_CREATE_REPO=1 和(导出的)GIT_TEST_PROTOCOL_VERSION=0。测试只是确保-c protocol.version=1 指令被发送到服务器,而不是任何实际的克隆或其他工作发生。这是因为当客户端确实请求版本 1 时,数据包跟踪会显示该请求,但服务器本身并不处理该请求。注意this comment in builtin/receive-pack.c.
    • 它看起来确实像指定protoco.version=1意味着 工作,即使它并没有真正做任何特别的事情。显然t5700-protocol-v1.sh 的测试是不够的。
    • 非常感谢,您的回答对我理解Git协议很有帮助。
    • 这意味着在实践中,当我们克隆一个 repo 时,将 protocol.version 指定为 1 没有任何意义,对吗?我希望有一个警告通知客户端这种配置是无效的,因为v1只是带有版本字符串的原始协议,而不仅仅是告诉客户端它得到了无效的服务器响应。
    【解决方案3】:

    版本 Git Protocol v1 和版本 2 的区别是,

    本文档介绍了 Git 有线协议第 2 版的规范。协议 v2 将通过以下方式对 v1 进行改进:

    一个服务将支持多个命令,而不是多个服务名称

    易于扩展,因为功能被移动到协议的自己的部分,不再隐藏在 NUL 字节后面,也不受 pkt 行大小的限制

    分离出隐藏在 NUL 字节后面的其他信息(例如,代理字符串作为一种能力,可以使用 ls-refs 请求 symrefs)

    除非明确要求,否则参考广告将被省略

    ls-refs 命令显式请求一些参考

    在设计时考虑了 http 和 stateless-rpc。通过明确的刷新语义,http 远程助手可以简单地充当代理

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

    Git 文档中有关 Protocol v2 的更多信息, https://git-scm.com/docs/protocol-v2

    【讨论】:

    • 感谢您的回复!但这似乎不能解释为什么我在使用协议 v1 时得到无效的服务器响应
    猜你喜欢
    • 1970-01-01
    • 2020-05-16
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 2018-11-29
    • 2017-04-20
    • 1970-01-01
    相关资源
    最近更新 更多