gpt4 book ai didi

git - 为什么我的 refs/remotes/origin 没有 ref to master?

转载 作者:行者123 更新时间:2023-12-02 23:19:40 34 4
gpt4 key购买 nike

在探索Git内部工作的过程中,我进入了我的git项目的refs/remotes/origin目录,运行了ls命令。这是我所看到的。

$ ls
HEAD sp2013dev

然后我跑了 cat HEAD这是打印出来的。
$ cat HEAD
ref: refs/remotes/origin/master

但是,在 refs/remotes/origin 目录中没有以 master 名称命名的文件或目录。该目录只有“HEAD”和“sp2013dev”

我在这里错过了什么吗?为什么 HEAD 指的是不存在的东西(顺便说一句,“ref”是这个“东西”的正确术语吗?)?

最佳答案

只是为了强调:您正在 git 内部四处闲逛;您已经找到了一个名为 .git/refs/remotes/origin 的目录,它包含两个文件, HEADsp2013dev.git/refs/remotes/origin/HEAD 的内容是 ref: refs/remotes/origin/master

由文字字符串 ref: 后跟另一个引用名称组成的引用在 git 术语中是“符号”引用。它的意思是“虽然这是一个有效的名称,但通过读取另一个引用可以找到这个引用解析到的 SHA-1。”但是,正如您所注意到的,master 目录中没有名为 .git/refs/remotes/origin 的文件,所以您想知道它是如何工作的。

答案是并非所有引用都必须在文件中。引用可以并且已经“打包”。目前,打包引用位于 .git/packed-refs 中,它是一个纯文本文件。您自己的 Git 将有一个 refs/remotes/origin/master.git/packed-refs 中的 SHA-1 哈希配对。

注意:ref 可能出现在 packed-refs 文件和 .git/refs 子目录中的文件中。在这种情况下,第二个版本会覆盖第一个版本。这允许 git pack-refs (由 git gc 调用)打包所有引用,然后在更新时根据需要让引用“解包”。 (但这是一个实现细节,您不应该假设这一点;在脚本中,使用 git update-refgit symbolic-ref 来读取和更新引用,并让这些程序强制执行更新规则。)

目前,似乎没有符号引用的打包格式,所以现在这些都存在于“真实文件”中。

顺便说一句:这一切是如何运作的(仅当足够好奇时才阅读)

当你克隆另一个存储库时——或者,就此而言,任何时候你运行 git fetchgit push ,尽管它们不处理 refs/remotes/origin/HEAD —— 涉及两个存储库,两组规则由控制这两个存储库的两个不同 Git 强制执行。除了命令 git remote set-head 之外,首先只有 git clone 创建了 origin/HEAD,所以我们可以专注于 git clone 本身。

由于有两个存储库,让我们为它们命名。我们可以将您的本地存储库称为 L 和位于 origin 的存储库,您正在克隆 Ojit_code 。由于 O 是一个 Git 存储库,因此它有自己的 HEAD 。这个 HEAD 通常是一个符号引用:例如 HEAD -> master。但是,无论它命名为哪个分支,都是 O 本地的:它是 refs/heads/branch ,它是 O 上的本地分支。如果您要登录托管存储库 O 的机器,并查看其 .git/HEAD 文件,它将包含 ref: refs/heads/branch 。 O 上的 Git 正在执行这个规则,即 HEAD 总是命名一个本地(local-to-O 即)分支。

现在,您自己的 Git 在您的系统上本地运行,正在努力创建存储库 L。您在 L 上的 Git 想要在 L 上创建一个远程跟踪分支,其全名是 refs/remotes/origin/HEAD 。这将是一个符号引用,它将指向 refs/remotes/origin/branch 。但是有两个并发症:

  • 你的 Git,在 L 上,必须找到或找出他们的 Git(在 O 上)符号 HEAD 。在我们的例子中,它是(他们的) refs/heads/branch
  • L 上的 Git 然后必须创建 refs/remotes/origin/branch 作为远程跟踪分支。 (您的 Git 会将其存储在您的 .git/packed-refs 文件中。)然后您的 Git 创建 L 的 refs/remotes/origin/HEAD 作为对 refs/remotes/origin/branch 的符号引用。

  • 在这两点中的任何一个都可能出错。例如,如果您使用 git clone -b otherbranch --single-branch ,则第 2 步将失败。你告诉你的 Git L 根本不应该有 refs/remotes/origin/branch ,而应该只有 refs/remotes/origin/otherbranch 。但是如果第 2 步像这样失败,您的 Git 根本不会创建 refs/remotes/origin/HEAD。这样你就不会在 L 中拥有指向不存在的远程跟踪分支的 refs/remotes/origin/HEAD

    如果您的 Git、构建 L 或他们的 Git(为您的 Git 提供 O 服务)太旧,则第 1 步“失败”(在某种程度上)。在复制提交( git fetchgit push )和查看分支和标记名称( git ls-remote )等的 Internet 连接“电话调用”期间,有一个已定义的协议(protocol)用于查找引用名称。 clone 命令使用相同的定义协议(protocol)。在连接的早期,您的 Git 和他们的 Git 协商要使用的协议(protocol)选项。较旧的 Git 没有表达和解析符号引用的选项,因此如果任一 Git 不支持该选项,O 只会声称 O 的 HEAD 是某个特定的 SHA-1 ID。构建克隆 L 的 Git 必须猜测哪个分支实际上是 O 上的 HEAD。它通过扫描它为 O 获得的其余分支名称来做到这一点。如果 O 的 HEAD1234567 ,并且有一个分支也是 1234567 ,那么,那一定是他们的 HEAD 指向的地方!

    这可能是错误的,即您的 Git 可能猜错了。但如果是这样,您的 Git 只会继续进行错误的假设并继续担心第 2 步。

    如果他们的 (O's) HEAD 被分离,步骤 1 可能会以完全不同的方式失败。在这种情况下,可能没有匹配的分支。如果是这样,您的 Git 不会猜错,它只会知道在存储库 O 中没有 check out 分支。 如果您的 Git 和他们的 Git 都不太旧,您的 Git 将协商正确的协议(protocol)选项,您的 Git 会知道确定 O 是否有分离的 HEAD,如果没有,在 O 中 check out 哪个分支。

    故意使第 2 步失败很容易:只需克隆一些存储库,您知道其 HEAD 指的是某个特定分支(例如 master ),同时使用 --single-branch-b 使您的克隆 L 避开该分支。故意让步骤1失败有点困难,但是你可以通过登录导出O的系统并分离O的HEAD来做到这一点。

    但是,如果你这样做,那么——回到你自己的系统——使用 git clone 来生成 L,你只会发现你的克隆 L 没有 origin/HEAD 。这保持了正常规则,其中包括这三个(我不确定是否有更多):
  • 所有普通(非符号)引用都包含有效的哈希 ID。
  • 所有符号引用(下面详述的一种特殊情况除外)都包含现有引用的名称。
  • 特殊引用 HEAD ,通常(但不总是)符号化,仅包含对本地分支的引用,即 refs/heads/ namespace 中的名称。

  • 特殊情况的异常(exception)是特殊引用名称 HEAD 可能包含实际尚不存在的本地分支的名称。这(称为“未出生分支”或“孤立分支”)是 master 在新的空存储库中的形成方式: HEAD 指向 master,即使 master 尚不存在。在此状态下进行的提交会导致分支开始存在,指向刚刚进行的提交;并且刚刚进行的提交没有 parent ,即是根提交。

    您可能认为使用 git remote set-head 可以打破这些规则,但实际上,它不会让您:

    Use <branch> to set the symbolic-ref refs/remotes/<name>/HEAD explicitly. e.g., "git remote set-head origin master" will set the symbolic-ref refs/remotes/origin/HEAD to refs/remotes/origin/master. This will only work if refs/remotes/origin/master already exists; if not it must be fetched first.



    (强调我的)。有关 git remote set-head 的更多信息,请参阅 the git remote documentation

    您可以使用直接访问 .git 目录或使用 git symbolic-ref 来打破这些规则。显然,如果你在 .git 内部四处闲逛,你可以 mess things up pretty good , :-) 所以这需要小心。 git symbolic-ref 的锐利边缘有点令人惊讶,但现在您知道您也必须小心谨慎。

    关于git - 为什么我的 refs/remotes/origin 没有 ref to master?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22855567/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com