【发布时间】:2014-11-25 22:20:09
【问题描述】:
鉴于recent question on SO,我想知道为什么git clone 中没有一个选项,这样新创建的分支的HEAD 指针将指向指定的提交?在上面所说的问题中,OP 正在尝试提供有关他的用户应该克隆的特定提交的说明。
请注意,这个问题与How To Clone To A Particular Version 使用reset 无关;但是关于为什么不存在?
【问题讨论】:
鉴于recent question on SO,我想知道为什么git clone 中没有一个选项,这样新创建的分支的HEAD 指针将指向指定的提交?在上面所说的问题中,OP 正在尝试提供有关他的用户应该克隆的特定提交的说明。
请注意,这个问题与How To Clone To A Particular Version 使用reset 无关;但是关于为什么不存在?
【问题讨论】:
到目前为止,有两个答案(在我写这篇文章的时候,现在还有更多)他们所说的都是正确的,但并没有真正回答“为什么”的问题。当然,“为什么”这个问题真的很难回答,除了 Git 的各个部分的作者(即便如此,如果两个 Git 频繁的贡献者给出了两个不同的答案怎么办?)。
尽管如此,考虑到 Git 的“哲学”,一般来说,各种传输协议都是通过命名 reference 来工作的。如果他们提供 SHA-1,则它是该引用的 SHA-1。对于尚未直接(例如,命令行)访问存储库的人,没有1 的内置命令允许通过 ID 引用提交。我能找到的最接近原因的事情——实际上是一个很好的理由2——是the git upload-archive documentation中的这一点:
安全
为了保护已删除对象的隐私 历史但可能尚未被修剪,git-upload-archive 避免 为无法从 存储库的参考。然而,因为计算对象可达性是 计算成本高, git-upload-archive 实现了更严格但 更易于检查的规则集 ...
但是,它继续说:
如果配置选项
uploadArchive.allowUnreachable为真,则这些 规则被忽略,客户端可以使用任意 sha1 表达式。这 如果您不关心无法访问的对象的隐私,这很有用, 或者,如果您的对象数据库已经可以通过以下方式公开访问 非智能http。
这特别有趣,因为git clone 首先获取所有可访问的对象,之后您的本地克隆可以通过 SHA-1 ID 轻松检查提交(如果需要,可以创建一个指向该 ID 的本地分支名称,或者只是让你的克隆处于“分离 HEAD”模式)。
鉴于这两个交叉流,我认为“为什么”的真正答案,在这一点上,是“没有人足够关心添加它”。 :-) 隐私参数是有效的,但没有理由git clone 在克隆后无法通过 ID 签出提交,就像可以告诉它签出 master3 与git clone -b ...。允许 -b <em>sha1</em> 的唯一缺点是 Git 无法预先(在克隆过程开始之前)检查是否会收到 sha1。它可以检查引用名称,因为这些是预先传输的(连同它们的分支提示或其他 SHA-1 值),所以git clone -b nonexistentbranch ssh://... 会快速终止并且不会创建副本:
fatal: Remote branch nonexistentbranch not found in upstream origin
fatal: The remote end hung up unexpectedly
如果-b 允许一个 ID,你会得到整个克隆,然后它必须告诉你:“哦,天哪,对不起,不能检查那个 ID,我会把你留在 master 上”管他呢。 (这或多或少是现在与破坏的子模块发生的情况。)
1虽然git upload-archive 现在 强制执行此“隐私”规则,但情况并非总是如此(它是在版本 1.7.8.1 中引入的);许多(大多数?) git-web 服务器,包括与 Git 本身一起分发的服务器,允许通过任意 ID 进行查看。这可能就是为什么 allowUnreachable 在添加“仅按引用名称”代码几年后添加到 upload-archive 的原因(但请注意,1.7.8 和 2.0.0 之前的 Git 版本无法放松规则)。因此,虽然“安全”的想法是有效的,但有一段时间(1.7.8.1 之前)它没有被强制执行。
2有多种方法可以将表面上的私有数据“泄露”出 Git 存储库。一个新文件Documentation/transfer-data-leaks 即将出现在 Git 2.11.1 中,而 Git 2.11.0 添加了一些内部功能(请参阅commit 722ff7f87 等)以立即删除已推送但未接受的对象。这样的对象最终会被垃圾回收,但这会使它们在持续时间内暴露出来。
3实际上,默认情况下,git clone 会在本地签出它认为与远程的 HEAD 引用相关的分支。不过,通常那是master。
【讨论】:
allowUnreachable 业务似乎相当新(Git 2.0+):github.com/git/git/commit/…
正如其他答案所说,这通常不是什么大问题,但他们没有说明为什么您不能克隆特定的提交。答案是安全。
如果你不小心推送了机密信息,然后强制推送了一个固定的历史,带有机密信息的提交仍然会存储在服务器上,直到服务器的 Git 的垃圾收集器发现不再需要它。如果哈希是已知的(例如它可能在日志中可用),恶意用户可能会请求不应该推送的特定提交,即使您能够验证当您强制推送固定历史时,没有人已经获取了这些提交。
确保您只能从 ref 进行克隆,确保只有“可访问”的提交才会发送给客户端。
【讨论】:
克隆 repo 是与 checkout 不同的操作。您不会“克隆特定的提交”。为方便起见,您可以克隆然后同时签出特定的预先存在的分支,因为这是大多数人想要的。如果这不能满足您的需求(您想要的特定 SHA 没有分支),只需使用或别名某种形式的
git clone -n <some repo> && cd <some repo> && git checkout SHA
【讨论】:
如果您的特定提交被分支引用,您可以这样做:
git clone -b yourBranch /url/of/the/repo
克隆的 repo 将直接位于该分支引用的提交处。
【讨论】:
master 中的特定(较旧)提交相关联。
git branch clone_me OLD_SHA