繁体   English   中英

如何只在git子模块中提取最新的提交

[英]How to only pull latest commit in a git submodule

有没有办法我只能在git子模块中提取最新的提交? 我试图将boost作为git子模块放在一些项目中,但由于包含所有内容的boost repo非常重量级,我只想将子模块更新为最新的提交而不是拉出所有提交。 这可能吗?

例如,当我这样做

git submodule update --init --recursive

所有提升子模块都会被提交所有提交。 我是否只能要求子模块镜像最新的提交而不是拉动所有更改?

注意带有--depth标志的浅克隆不起作用,因为它只提取最新提交,并且最新提交仅包含在该提交中所做的更改,因此存储库未处于正确状态。

注意当我尝试以下命令序列时, git archive (如下面的答案所示)似乎不起作用

mkdir temp-git-test
cd temp-git-test
git init
git submodule add --depth 1 https://github.com/boostorg/boost
cd boost
git archive --format=tar HEAD --output ../boost.tar.gz
cd ..
tar -xzvf boost.tar.gz

解压缩仓库的输出与子模块相同。 难道我做错了什么?

最简洁的答案是不。 答案可能很长,但考虑另一种方式。

浅克隆和浅子模块

很长的答案,让你可以得到你想要的东西,从一个技术说明开始:你没有用Git术语拉动 在Git中,“pull”表示“fetch,then merge-or-rebase”,你不会在这里进行merge-or-rebase。 事实上,当你“初始化”时,你通常会制作初始克隆。

每个子模块实际上都是它自己的存储库。 1 Git迟早会在每个存储库中执行git checkout ,要求它检出,而不是分支 ,而是一个特定的提交 ,这通常不是最新的提交。 考虑到Git存储库和软件开发的本质,以及子模块首先是对第三方存储库的引用的想法,即一个你没有 也无法控制的存储库,你能做的最好就是说:“我知道我的软件适用于他们软件的一个特定版本 ,而该版本是<填空>。” 因此,您的存储库会从其存储库中列出您想要的特定版本。

现在我们了解问题的核心。 当您git clone存储库或使用git fetch更新现有克隆时,您可以通过询问特定的分支和/或标记名称而不是特定的提交ID来实现。 获取特定ID有一些(非常有限的)支持,但必须在另一个存储库中启用它,我们刚刚说过你没有并且无法控制的存储库。 对于他们来说启用fetch-by-ID在计算上是昂贵的 - 无论他们是谁,控制另一个存储库的人 - 而不是你可以做的事情,也不是要求,也不是默认启用。 这意味着一般来说它不可用。

在任何情况下, git clone 只能使用名称:例如,你可以git clone -b branch url ,通过检查特定的分支来启动你的新克隆,或者git clone -b tag url使你的新克隆开始于签出(作为独立的HEAD)特定标签。 尽管如此“检查特定分支或标记”,但克隆默认克隆远程提供的所有名称,并进行全深度(即非浅)克隆。

所有这些都意味着重要的事情。 首先, 存在浅克隆。 浅层克隆是使用--depth参数创建的。 它可以通过另一个--depthgit fetch加深。 “深度”是在克隆或获取期间使用的名称所标识的提交“超出”提交的提交数,具有一些相当复杂的规则。 (这些规则的细节在这里并不重要。)

其次,由于存在浅的克隆, 也存在浅的子模块。 浅子模块只是一个用--depth克隆的子模块。 但是存在一个问题: 没有简单或明显的方法来确定需要什么样的深度。 你可以将一个--depth参数传递给git submodule addgit submodule update ,但是你应该知道它有多深。

这是问题所在:您的子模块可能会被分支或标记名称克隆,但是您的子模块将被告知签出一个特定的提交 (通过其原始哈希ID)。 这个提交会在克隆中吗? 什么深度保证它会? 如果您是通过标签名称克隆和标记名称总是正确提交,你可以使用--depth 1 (因此你可以使用--shallow-submodules的初始期间git clone为好),但如果只有工作,好吧,见上文。


1这些子存储库的特殊之处在于它们是:

  1. 列在外部存储库中(在.gitmodules文件中);
  2. 一般保持“独立HEAD”模式;
  3. 并在其ID存储在外部存储库中的提交中分离。

模块文件列出了各个子模块的名称和URL。 “初始化”子模块相当于将.gitmodules中的内容复制到包含超级项目的配置文件中,“更新”子模块通常相当于克隆或获取。 要分离子模块的提交在超级项目的存储库中记录为树对象中的“gitlink”条目。

在现代版本的Git中,子模块支持变得相当复杂,所以现在在执行更新步骤时可以做更多的事情。


参考克隆

对于许多情况,有一个更好,更通用的解决方案。 您可以将Git指向参考克隆,而不是使用浅层克隆。 引用克隆是您尝试克隆的存储库的任何克隆。 2理想情况下,它是您正在克隆的存储库的最新且合理的最新克隆,但任何克隆都可以。

Git对引用克隆的作用有点复杂(详见文档 ),但简短版本是克隆某些存储库时,而不是从某个远程服务器通过网络获取所有对象(这可能很慢和/或者速率限制的),你的Git会向远程服务器询问它需要什么对象,然后查看你的本地 3参考克隆,看看它是否已经有了这些对象。 如果是这样,它将从参考克隆“借用”它们。

这使您可以在使用非常少的网络和存储资源的同时获得完整,完整,最新的克隆,因为您不再需要(大部分或全部)数据,也不需要(除非--detach -ing )自己存储。 这也就意味着,你不必担心你的浅克隆是太浅 :你只会得到一个缓慢的完整克隆,然后引用的挫折感出来的所有其他克隆,它走的快。 使用引用克隆可以缩短克隆几个大GitHub存储库的时间,例如从一小时以上到几十秒。


2从技术上讲,引用可以是任何存储库。 但是,与您正在克隆的存储库实际上没有相关的存储库将会成为一个糟糕的引用:它将没有您需要的任何对象,并且根本不提供加速。 (它甚至可能有下对象的名称错误的数据,虽然这个机会是微乎其微。如果参考正确的,因为对象名称不能被这种方式重用这是不可能发生的。)

3对于速度,参考应该是“尽可能本地”,但实际上并非必须在您的机器上,只是可访问 如果引用并不总是存在,您可能需要添加--dissociate ,以便将对象从引用克隆复制到新克隆中。 当然,这会占用更多的磁盘空间。

注意带有--depth标志的浅克隆不起作用,因为它只提取最新提交,并且最新提交仅包含在该提交中所做的更改,因此存储库未处于正确状态。

然后将boost repo的git archive与子模块的浅克隆设置结合使用:

  • 你的子模块仍然很浅
  • 但是你用同一个git archive的一个(完整的) git archive图像覆盖它的不完整内容,使得工作树成为远程仓库SHA1的精确副本。

从那里,每次刷新(浅)将补充完整的内容,并将保持最新。

git archive在repo的本地克隆中完成:

git archive --format=tar HEAD

如果你没有本地克隆,但是增强boostorg/boost在GitHub上(比如,例如, boostorg/boost ),那么你可以通过一个简单的curl获得当前HEAD的压缩图像(不需要git archive然后)。


如注释中所示,添加存档的内容是没有用的,因为它表示提交的相同内容。

但是,这似乎不完整:

git submodule add --depth 1 https://github.com/boostorg/boost

对于子模块更新 - 远程工作(即获取最后一次提交,而不是保持初始SHA1检出),您需要:

git submodule add -b master --depth 1 https://github.com/boostorg/boost

然后git submodule update --init --recursive --remote将获取最后一次提交。

请参阅“ Git子模块:指定分支/标记 ”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM