在探索Git内部工作的过程中,我进入了我的git项目的refs/remotes/origin目录并运行了ls命令.这就是我所看到的.
$ ls
HEAD sp2013dev
Run Code Online (Sandbox Code Playgroud)
然后我跑了cat HEAD,这是打印的.
$ cat HEAD
ref: refs/remotes/origin/master
Run Code Online (Sandbox Code Playgroud)
但是,refs/remotes/origin目录中没有master名称的文件或目录.这个目录只有'HEAD'和'sp2013dev'
我在这里错过了什么吗?为什么HEAD指的是某些东西(顺便说一下,'参考'这个'某事'的正确术语?)哪个不存在?
只是为了强调:你在git的内部徘徊; 你找到了一个名为的目录.git/refs/remotes/origin,它包含两个文件,HEAD和sp2013dev.内容.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与你的SHA-1哈希配对.git/packed-refs.
注意:ref可能同时出现在packed-refs文件和.git/refs子目录中的文件中.在这种情况下,第二个版本会覆盖第一个版本.这允许git pack-refs(调用者git gc)打包所有引用,然后让refs在更新时根据需要变为"解压缩".(但这是一个实现细节,你不应该假设这一点;在脚本中,使用git update-ref和git symbolic-ref读取和更新引用,并让这些程序强制执行更新规则.)
目前,似乎没有符号引用的打包格式,所以那些现在都存在于"真实文件"中.
当您克隆另一个存储库时 - 或者就此而言,在您运行的任何时候,git fetch或者git push,尽管那些不处理refs/remotes/origin/HEAD- 涉及两个存储库,两个规则由两个不同的Gits控制这两个存储库强制执行.除了命令git remote set-head,它只是git clone创造了origin/HEAD第一个位置,所以我们可以专注于git clone自己.
由于有两个存储库,让我们给它们命名.我们可以调用您的本地存储库L和存储库origin,您正在进行克隆,O.由于O 是 Git存储库,因此它有自己的存储库HEAD.这HEAD通常是一个象征性的参考:HEAD -> master例如.然而,它命名的分支是O的本地:它是O的本地分支.如果您要登录托管存储库O的计算机,并查看其文件,它将包含.Git on O正在强制执行此规则,该规则始终命名本地(本地到O)分支.refs/heads/branch.git/HEADref: refs/heads/branchHEAD
现在,你自己的Git,您的系统上本地运行,正在努力创建资源库大号.你的G上的L想要创建L一个全名为的远程跟踪分支refs/remotes/origin/HEAD.这将是一个象征性的参考,它将指向.但有两个并发症:refs/remotes/origin/branch
HEAD.在我们的例子中它是(他们的).refs/heads/branchrefs/remotes/origin/branch.git/packed-refsrefs/remotes/origin/HEADrefs/remotes/origin/branch在这两点中的任何一点都可能出错.git clone -b otherbranch --single-branch例如,如果您使用,步骤2将失败.你告诉你的Git L根本不应该,但只是.但是如果第2步失败了,你的Git根本就不会创建.这样,你就不必在大号,一个指向不存在的远程跟踪分支.refs/remotes/origin/branchrefs/remotes/origin/otherbranchrefs/remotes/origin/HEADrefs/remotes/origin/HEAD
第1步"失败"(在某种程度上),如果您的Git,L楼或Git,为您的Git 服务O,太老了.在这些互联网连接"电话呼叫"期间,有一个用于查找引用名称的定义协议,用于复制提交(git fetch,git push)和查看分支和标记名称(git ls-remote)等.该clone命令使用相同的定义协议.在连接的早期,您的Git和他们的Git协商使用的协议选项.旧版GITS有用于表达和解析符号引用任何选项,因此,如果任一GIT中不支持的选项,ö只是声称Ö的HEAD是一些特定的SHA-1的ID.构建克隆L的Git 必须猜测哪个分支实际上HEAD在O上.它通过扫描O获得的其余分支名称来实现.如果Ø的是,这里面的一个分支,也是,好,那一定是在那里他们的分!HEAD12345671234567HEAD
这可能是错误的,即你的Git可能猜错了.但如果是这样,你的Git只会继续错误的假设并继续担心第2步.
如果它们(O ')HEAD被分离,则步骤1可能会完全不同.在这种情况下,可能没有匹配的分支.如果是这样,你的Git不会猜错,它只会知道在存储库O中没有检出分支.如果你的Git和他们的Git都不是太老了,你的Git会协商正确的协议选项,你的Git会确定O是否有一个分离的HEAD,如果不是,那么在O中检查哪个分支.
这很容易使第2步失败故意:只是一些克隆库,其HEAD你知道指的是某些特定的分支(如master同时使用两者)--single-branch,并-b让你的克隆大号 避免分支.有意识地使第1步失败有点困难,但你可以通过登录导出O并分离O的HEAD的系统来实现.
如果你这样做,不过,在自己的系统中使用,然后回git clone做大号,你只需找到你的克隆大号有没有 origin/HEAD.这维持了正常的规则,包括这三个(如果还有更多的话我不确定):
HEAD通常(但不总是)符号,仅包含对本地分支的引用,即refs/heads/名称空间中的名称.特殊情况例外是特殊引用名称HEAD 可能包含尚未实际存在的本地分支的名称.这个(称为"未出生的分支"或"孤儿分支")是如何master在一个新的,空的存储库中产生的:尽管尚不存在但仍HEAD指向它.在此状态下进行的提交会导致分支开始存在,指向刚才提交的提交; 刚刚提交的提交没有父级,即是root提交.mastermaster
你可能认为你可以使用破坏这些规则git remote set-head,但事实上,它不会让你:
用于 显式
<branch>设置symbolic-refrefs/remotes/<name>/HEAD.例如,"git remote set-head origin master"将symbolic-ref设置refs/remotes/origin/HEAD为refs/remotes/origin/master.这只有在refs/remotes/origin/master已存在的情况下才有效 ; 如果不是,它必须先取出.
(强调我的).欲了解更多有关git remote set-head,请参阅该git remote文档.
您可以使用直接访问.git目录或使用来破坏这些规则git symbolic-ref.显然,如果你在里面逛逛.git,你可以把事情弄得很好,:-)所以这需要小心.锋利的边缘git symbolic-ref有点令人惊讶,但现在你知道你也一定要小心.
| 归档时间: |
|
| 查看次数: |
4988 次 |
| 最近记录: |