git clone --shared 和 --reference 有什么区别?

42
阅读文档后,我仍然不太明白--shared--reference <repo>之间的区别。它们看起来非常相似。
1. --shared--reference <repo>选项之间有什么区别? 2. 它们可用于在制作另一个本地克隆的多个本地克隆时节省驱动器空间吗? 3. 每个本地克隆可以检出不同的分支吗?
注意:我知道我可以使用git clone --depth <depth>使用多个浅克隆截断历史记录,但每个克隆仍然必须至少复制一些历史记录才能这样做,所以我认为这可能不是保存驱动器空间的最佳方式(尽管比没有好)。
背景:有时我喜欢在存储库中拥有我的工作副本的多个检出,因此我创建多个克隆,每个克隆都有自己的检出。

然而,我并不需要每个克隆版本的完整历史记录,只需要最新版本的分支,所以通过让每个克隆使用原始本地克隆的标签、提交、树和 blob 对象(例如通过符号链接)来节省大量驱动器空间是可能的。

git clone 文档

我查看了 git clone 文档,看看有没有可以用的东西。

--shared

我发现有一个 --shared 选项:

当要克隆的存储库位于本地机器上时,自动设置 .git/objects/info/alternates 以共享对象与源存储库。生成的存储库开始时没有任何自己的对象。

这似乎可能对我有用,帮助我在具有不同检出的多个克隆中节省驱动器空间,因为每个克隆与原始本地克隆共享对象。

--reference <repository>

如果参考仓库在本地机器上,自动设置.git/objects/info/alternates以从参考仓库获取对象。将已存在的仓库用作备选项将需要从正在克隆的仓库复制较少的对象,从而减少网络和本地存储成本。

注意:请参阅--shared选项的注意事项。

这意味着它将减少本地存储成本,因此这也可能很有用。


@user3348022 很酷,我在谷歌搜索中看到了这个链接(http://lists-archives.com/git/505518-clarify-git-clone-local-shared-reference.html),但是我无法找到前几个回复,因为那个界面过于古老。如果你能总结其中相关的部分并将其添加为答案,你可能会获得一些史诗级的赞和声望!`:D` - user456814
@user3348022,另外,你提供的那封电子邮件仍然没有为我澄清为什么我要使用“--shared”而不是“--reference”。唯一的区别是当你使用“--shared”时,源是被克隆的本地存储库,而使用“--reference”时,源是被克隆的远程存储库吗? - user456814
@John - 我有点困惑。你提供的答案说 --reference 意味着 --shared。但是 DoubleWord 的答案说 --shared 不会复制对象,而 --reference 会复制对象。这似乎并不像一个 "意味着" 的关系。这也使得 --reference 看起来比 --shared 更安全。你能否澄清一下? - Sean
1
“lists-archives.com” 的链接引导我进入了点击诱饵的网站,而这个 narkive 链接还是好的:https://git.vger.kernel.narkive.com/TxZNFARz/clarify-clone-local-shared-reference,我建议阅读一下,因为在使用这些选项时有一些有趣的交互作用。 - qneill
3个回答

15

两个选项都会更新.git/objects/info/alternates指向源代码库,这可能是危险的,因此警告注释在文档中两个选项上都存在。

--shared选项不会复制对象到克隆体中,这是主要区别。

--reference使用一个额外的存储库参数。在克隆期间,使用--reference仍然将对象复制到目标中,但您正在指定从现有源复制对象,当这些对象已经在参考存储库中可用时。通过传递到本地更快/本地设备上的存储库的路径,可以减少来自源存储库的网络时间和IO。

亲自试试

创建--shared克隆和--reference克隆。使用git count-objects -v计算每个克隆体中的对象数。您会注意到共享克隆没有对象,而参考克隆具有与源相同数量的对象。此外,请注意您的文件系统中每个克隆体的大小差异。如果您移动源并在共享和参考存储库中测试git log,则共享克隆中的日志不可用,但参考克隆正常工作。


那么使用“--reference”和普通的“git clone”有什么区别呢? - Yahya Uddin
1
@YahyaUddin:当克隆非本地存储库时,差异会发生。如果没有使用--reference,则会通过网络下载所有对象。如果使用了--reference,则会通过网络获取对象ID,然后检查这些对象ID是否在本地可用。如果它们在本地可用,则跳过下载步骤。如果它们在本地不可用,则像通常一样进行下载。最终结果是git clone --reference更快(速度取决于本地引用的更新程度)。 (但也请参见--dissociate。) - torek
“--shared” 选项通常只能在克隆本地仓库时使用;而“--reference”选项则主要用于克隆远程网络仓库,对于这些仓库,我们已经在本地仓库中有一些对象可用。因此,使用情况不同,我认为这个答案是误导性的。 - YoungFrog

8

你问题评论中的链接提供了更清晰的答案:--reference意味着--shared--reference的目的是在克隆远程存储库时优化网络I/O。

与上面的答案相反,我发现来自同一来源的--shared--reference存储库的大小相同,并且都没有任何对象。当然,如果您对基于共同源的其他存储库使用--reference,则大小和对象将反映存储库之间的差异。 请注意,在这两种情况下,我们并没有节省工作树中的空间,只有.git/objects中的空间。

要维护此设置,需要一些技巧 - 请阅读线程以获取更多详细信息。基本上,两者应被视为公共存储库,并需注意重写历史记录时重新打包/修剪/垃圾回收的情况。

在初始克隆后维护最佳磁盘空间利用率的工作流程似乎是:

  1. 拉取源代码
  2. 重新打包源代码
  3. 拉取次要存储库
  4. 在次要存储库中运行git gc

最好阅读该线程中的讨论。

您可以通过将源代码的绝对路径放入secondary/.git/objects/info/alternates中并运行git gc(许多人使用git repack -a -d -l,这是由git gc完成的)来向现有存储库添加备用项。

您可以通过在次要存储库中运行git repack -a -d(没有-l),然后从alternates文件中删除该行来删除替代项。如线程所述,可以拥有多个替代项。

我自己没有使用过这个功能,因此不知道管理是否容易出错。


--shared 的危险性也在以下链接中提到:https://dev59.com/43E95IYBdhLWcg3wWMdQ - Ciro Santilli OurBigBook.com

3

您的问题中评论中的链接已经失效。

https://www.oreilly.com/library/view/git-pocket-guide/9781449327507/ch06.html上有一些关于这个主题的很棒的信息。以下是其中的一些内容:

首先,我们创建一个远程仓库的裸克隆,作为本地参考仓库(因此命名为“refrep”):
$ git clone --bare http://foo/bar.git refrep
然后,我们再次克隆远程仓库,但这一次以refrep作为参考:
$ git clone --reference refrep http://foo/bar.git
这与--shared选项的关键区别在于,您仍在跟踪远程仓库,而不是refrep克隆。当您拉取时,仍会联系http://foo/,但您不需要等待它发送已在refrep中本地存储的任何对象;当您推送时,直接更新foo仓库的分支和其他引用。
当然,一旦您和其他人开始推送新提交,参考仓库将变得过时,您将开始失去一些好处。定期地,您可以在refrep中运行git fetch --all来拉取任何新对象。单个参考仓库可以成为任意数量其他仓库对象的缓存;只需将它们作为远程添加到参考中:
$ git remote add zeus http://olympus/zeus.git
$ git fetch --all zeus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接