为什么我的refs / remotes / origin没有掌握参考?

时间:2014-04-04 06:50:27

标签: git

在探索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指的是某些东西(顺便说一句,是'参考'这个正确的术语'某些东西'?)哪些不存在?

1 个答案:

答案 0 :(得分:7)

只是为了强调:你在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与{1}}中的SHA-1哈希配对。

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

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

长期搁置:这一切是如何运作的(只有充分好奇才能阅读)

当您克隆另一个存储库时 - 或者就此而言,只要您运行git symbolic-refgit fetch,但是那些不处理git push - 就会有两个< / em>涉及的存储库,两个规则由两个控制这两个存储库的不同Git强制执行。除了命令refs/remotes/origin/HEAD之外,它只是git remote set-head首先创建git clone,因此我们可以专注于origin/HEAD本身。

由于有两个存储库,让我们给它们命名。我们可以在git clone调用您的本地存储库 L 和存储库,您正在进行克隆, O 。由于 O Git存储库,因此它有自己的origin。这个HEAD通常是一个符号引用:例如HEAD。但是,它所命名的分支是 O 的本地:它是HEAD -> master,它是 O 上的本地分支。如果您要登录计算机托管存储库 O ,并查看其refs/heads/branch文件,则它将包含.git/HEAD O 上的Git正在执行此规则,ref: refs/heads/branch始终将本地(本地到 O )分支命名。

现在,您自己的Git(在您的系统上本地运行)正在创建存储库 L L 上的Git想要在HEAD上创建一个全名为L的远程跟踪分支。这将是一个象征性的参考,它将指向refs/remotes/origin/HEAD。但有两个并发症:

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

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

    步骤1&#34;失败&#34; (在某种程度上)如果您的Git,构建 L 或他们的Git,为您的Git提供 O ,则太旧了。在这些互联网连接期间,有一个用于查找参考名称的已定义协议&#34;电话呼叫&#34;该副本提交(refs/remotes/origin/HEADgit fetch)并查看分支和标记名称(git push)等。 git ls-remote命令使用相同的定义协议。在连接的早期,您的Git和他们的Git协商使用的协议选项。较旧的Gits没有表达和解析符号引用的选项,因此如果Git不支持该选项, O 只声称​​ O &#39; s {{1是一些特殊的SHA-1 ID。构建克隆 L 的Git必须猜测 O 上的哪个分支实际上是clone。它是通过扫描 O 获取的分支名称的 rest 来实现的。如果 O HEADHEAD,并且还有一个分支也是HEAD,那么,那一定是他们的1234567点!

    这可能错误,即您的Git可能猜错了。但如果是这样,那么你的Git就会采用错误的假设继续担心第2步。

    如果他们( O &#39; s)1234567被分离,步骤1可能会完全失败。在这种情况下,可能没有匹配的分支。如果是这样,你的Git不会猜错,它只会知道在存储库 O 中没有检出分支。如果你的Git和他们的Git都没有太老,你的Git会协商正确的协议选项,你的Git会确定 O 是否有一个分离的HEAD,如果没有,那么检查哪个分支在 O

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

    如果您这样做,然后在您自己的系统上使用--single-branch来制作 L ,您只需找到您的克隆 L -b。这维持了正常的规则,其中包括这三个(如果还有更多,我不确定副手):

    1. 所有普通(非符号)引用都包含有效的哈希ID。
    2. 所有符号引用(下面详细说明一个特例)都包含现有引用的名称。
    3. 特殊参考git clone,通常(但不总是)符号,仅包含对本地分支的引用,即origin/HEAD名称中的名称-space。
    4. 特殊情况例外是特殊引用名称HEAD 可能包含尚未实际存在的本地分支的名称。这个(称之为&#34;未出生的分支&#34;或者#34;孤儿分支&#34;)是refs/heads/在一个新的空库中出现的方式:HEAD即使master尚不存在,也指向HEAD。在此状态下进行的提交会导致分支开始存在,指向刚才提交的提交;刚刚提交的提交有 no 父项,即是root提交。

      您可能认为可以使用master破坏这些规则,但事实上,它不会让您:

        

      使用master设置symbolic-ref git remote set-head    明确。例如,&#34; git remote set-head origin master&#34;将设置    symbolic-ref <branch> to    refs/remotes/<name>/HEAD这只适用于    refs/remotes/origin/HEAD已经存在;如果不是必须的话    首先取得。

      (强调我的)。有关refs/remotes/origin/master的更多信息,请参阅the git remote documentation

      可以使用直接访问refs/remotes/origin/master目录或使用git remote set-head来破坏这些规则。显然,如果你在.git里面徘徊,你可以mess things up pretty good,:-)所以这需要小心。 git symbolic-ref的尖锐边缘有点令人惊讶,但现在你知道你也一定要小心。