git pull --recurse-submodule 真的会在子模块中提取最新提交吗?

时间:2021-07-26 10:56:10

标签: git git-submodules

此线程的 (Easy way to pull latest of all git submodules) 回答指出运行时:

$ git pull --recurse-submodules

将拉取子模块中的最新提交。但是试了一下,好像不行。

我有一个演示存储库,其中包含一个名为“tinyXml”的演示子模块(这不是真正的 tinyXml,只是一个演示)。看看下面的shell交互:

PS D:\DemoProject> cd .\tinyXml
PS D:\DemoProject\tinyXml> git status 
HEAD detached at 9101c63
nothing to commit, working tree clean
PS D:\DemoProject\tinyXml> cd ..     
PS D:\DemoProject> git pull --recurse-submodules                  
Fetching submodule tinyXml
Already up to date.
PS D:\DemoProject> cd .\tinyXml\
PS D:\DemoProject\tinyXml> git status      
HEAD detached at 9101c63
nothing to commit, working tree clean
PS D:\DemoProject\tinyXml> cd ..
PS D:\DemoProject> git submodule update --remote      
Submodule path 'tinyXml': checked out 'e249788ed10afbdff043f758f46add75b81d522a'

所以您看到 git submodule update --remote 有效,但 git pull --recurse-submodules 没有提取子模块中的最新提交。

我的 git 版本 - 2.32.0

2 个答案:

答案 0 :(得分:0)

正如您从日志中看到的,您的一些子模块不在分支上,而是处于分离状态。

您应该进入每个子模块并检查正确的分支,然后返回并再次发出 public function courseDelete($courseId) { dd($courseId); } 命令。

答案 1 :(得分:0)

简短的回答是否定的。那是因为子模块不应该使用最新的提交

子模块的意图superproject 存储库指定要在子模块中使用的提交。超级项目存储库没有列出子模块中要使用的分支名称;这不可靠。因此,超级项目存储库会列出要在子模块中使用的原始哈希 ID,因为它可靠。

子模块因此被检出为“分离的 HEAD”。这是设计使然。

请记住,每个子模块都是一个单独的 Git 存储库。它不是超级项目的一部分。超级项目存储库只列出用于克隆子模块的 URL,以便 Git 可以运行 git clone,加上路径(以便超级项目知道在哪里放置子模块)和正确的哈希 ID(以便超级项目知道将哪个提交用作分离的 HEAD)。

你想要什么

现在,有一种方法,可以从超级项目存储库中请求超级项目 Git 在子模块中做一些不同的事情。这种方式不能运行git pull。相反,您需要带有特定标志git submodule update。您想要的特定标志包括但不一定限于 --remote

我上面说过,超级项目没有为每个子模块列出一个分支。这只是部分正确。超级项目可以为每个子模块列出一个分支名称。但请记住这一点:分支名称只是一种表示“获得某些特定提交”的方式。哪个特定的提交?嗯,这是棘手的部分,因为每个 Git 存储库都有自己的分支名称。您的超级项目 Git 有自己的分支名称,您克隆的每个子模块都有自己的分支名称,每个存储库从中克隆的存储库都有自己的分支姓名等。

这很令人困惑,因为此时这里涉及的 Git 存储库绝对最少四个

  • 您拥有自己的超级项目克隆,作为您的存储库 R
  • 您的 R 有一个 origin,您可以从中获得提交。
  • 您的 R 有一些子模块 S,这是您的 Git 通过运行 git clone 创建的。
  • 您的 S 有一个 originit 从中获得提交。

当您克隆某个 Git 存储库时,您会获得他们的所有提交,而没有他们的分支。然后您的 Git 在您自己的本地存储库中创建一个分支。您的 Git 获取它们的分支名称并更改,将它们转换为您自己的 Git 的远程跟踪名称:它们的 main 或 {例如,{1}} 成为您的 masterorigin/main

对于您的每个子模块也是如此。当您的超级项目 Git 运行 origin/master 来克隆一些 other 存储库作为 git clone url path/to/submodule 中的子模块时,那个 submodule Git此 path/to/submodule 命令复制的存储库......好吧,这就像任何其他 git clone 一样。 Git 会从该 URL 复制他们的所有提交,而没有复制任何分支。所以 branch 名称在这里实际上没有用。您的超级项目存储库 R 允许(但不是必需)为子模块 S 存储的“分支名称”根本不是您的 分支名称— 因为那没有用 — 而是 Sgit clone 中的分支名称

您的超级项目 Git 将在 R 中运行,实际上:

origin

这将使您的 Git-that-c​​ontrols-S 使用 (cd path/to/S; git fetch) Sgit fetch 获取提交。这将更新 S远程跟踪名称,例如 Soriginorigin/main

如果 RS 应该使用“分支功能”,这实际上意味着在 R 中运行的 Git 应该运行:

origin/feature

紧随其后:

(cd path/to/S; git fetch)

S 中运行的这个 (cd path/to/S; git rev-parse origin/feature) 将获得在 S 中找到的 git rev-parse 的提交哈希 ID,它刚刚由 { {1}} 您的 Git S 中运行,以获取原始哈希 ID。

这就是origin/feature中的git fetch的意思:在子模块中运行--remote后,使用存储在R中的分支名称来构造远程-将在 S 中找到的跟踪名称,以获取提交哈希 ID,以便在 S 中查找。

git submodule update --remote 命令的 rest 决定了用这个哈希 ID 做什么。使用 git fetch,处理这个哈希 ID 的操作是使用该哈希 ID 的分离 HEAD 的 git submodule update

因此:

--checkout

将进入您的存储库 R 的每个子模块 S 并运行 git checkoutgit submodule update --recurse --checkout --remote 并执行分离的 HEAD 检出 S 视情况 将在 S 内部递归以更新 S 具有的任何子模块。

不过,您可能不想要 git fetch。您做什么要取决于太多因素,无法真正进入这里。我要注意的一件事是,一旦子模块处于您希望它们进行的提交上,您需要进行新的 superproject 提交以记录这些哈希 ID超级项目。这也可能很痛苦。

这太复杂了。为什么 Git 这么难?

是的,是的。我无法回答“为什么”,只能说明这从根本上来说是一个难题

这不是我想做的。为什么 Git 不能做 _____ 呢?

现在可能有人正在做这件事。有一些项目正在进行中以改进子模块。这……很难。

这就是今天的情况。不要使用git rev-parse;这不适合工作。即便是 --checkout 也可能无法胜任你的工作,无论那是什么。