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

Cur*_*ous 12 git

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

例如,当我这样做

git submodule update --init --recursive
Run Code Online (Sandbox Code Playgroud)

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

注意具有该--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
Run Code Online (Sandbox Code Playgroud)

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

tor*_*rek 6

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

浅克隆和浅子模块

很长的答案,让你可以得到你想要的东西,从一个技术说明开始:你没有用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 只能使用名称:例如,您可以通过检出特定分支来启动新克隆,或者通过签出(作为分离的HEAD)特定标记来启动新克隆.尽管如此"检查特定分支或标记",但克隆默认克隆远程提供的所有名称,并进行全深度(即非浅)克隆.git clone -b branch urlgit clone -b tag url

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

其次,由于存在浅的克隆,也存在浅的子模块. 浅子模块只是一个克隆的子模块--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)存储它你自己.这也就意味着,你不必担心你的浅克隆是浅薄:你刚得到一个缓慢的完整克隆,然后引用的挫折感出来的所有其他克隆,它走的快. 使用引用克隆可以缩短克隆几个大GitHub存储库的时间,例如从一小时以上到几十秒.


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

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


Von*_*onC 5

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

然后,结合了git archive中的boost一个浅表副本设置为你的子模块回购:

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

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

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

git archive --format=tar HEAD
Run Code Online (Sandbox Code Playgroud)

如果您没有本地克隆,但是增强仓库在GitHub上(例如,像boostorg/boost),那么您可以通过简单的卷曲获得当前HEAD的压缩图像(不需要git archive).


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

但是,这似乎不完整:

git submodule add --depth 1 https://github.com/boostorg/boost
Run Code Online (Sandbox Code Playgroud)

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

git submodule add -b master --depth 1 https://github.com/boostorg/boost
Run Code Online (Sandbox Code Playgroud)

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

请参阅" Git子模块:指定分支/标记 ".