Git Submodules:如何知道子模块的commit/tag

Git Submodules: how to know the commit/tag of the submodule

由于公司政策,我们工具带中的工具很少。我一直坚持使用 Git 来处理一些 其他工具 会做得更好、更快的事情。

我的项目中需要一个特定的 dll,最快的获取方法是添加第二个存储库作为子模块。我在测试部门,所以我不需要最新的dll,也不需要dll的稳定分支。我需要所述 dll 的特定版本,并且需要对其进行精细控制。

幸运的是,我可以使用标签导航到特定版本。通过 git checkout <tag> 我将子模块发送到分离的头中,我可以通过提交超级项目来冻结信息。 运行 git status 没有明确告诉我子模块的位置。

如何从超级项目中明确获取有关子模块在分离头内对齐的标签的信息?理想情况下,我希望以纯文本形式存储此信息,例如 .gitsubmodules 文件。我想确定子模块与给定标签对齐(或者如果标签不可用则提交)并且我希望自动测试这个。

让我们注意一些基本事实:

  1. 子模块 一个 Git 存储库(因此它有自己的分支名称、标签名称和提交对象)。
  2. 超级项目是一个 Git 存储库,其中超级项目 Git 进入子模块 Git 并执行 git 签出 <em>hash</em>(或git switch --detach <em>hash</em>),通过哈希ID , 在子模块 Git 存储库中获取分离的 HEAD。用于此操作的哈希 ID 是记录在超级项目中的提交中的哈希 ID。 (这是您通过提交冻结的哈希 ID。)

换句话说,Git实际上使用标签来实现这一点,即使你确实使用了标签 以获取您随后冻结为提交的状态。所以...

How can I explicitly get the information regarding tag the submodule is aligned within the detached head from the superproject?

...有两种不同的处理方法:

  • 一种方法是在超级项目中记录——在Git本身不会使用的东西中,因为Git将在提交中使用哈希 ID——标签名称。

  • 另一种方法是无论如何都使用哈希ID,然后进入子模块,看看是否有一些标签对应于该哈希ID。

这是两个总体策略。如果有人选择做技术上可行但建议反对的事情,它们会产生不同的后果。特别是,假设控制子模块存储库的人 以某种方式更改了标签 。像 v2.1 这样的标签过去命名为提交 a123456,但现在命名为提交 b789abc。也许 a123456 现在有一个标签 2.1alpha 来代替。那么:

  • 询问子模块 你有什么标签 a123456 得到了一个新的不同的答案(2.1alpha),但是你——或者更确切地说,你的超级项目 Git,当你执行 git submodule update 时——仍然会签出并因此使用 a123456(你之前通过提交冻结的哈希 ID)。

  • 询问子模块 你有什么哈希 ID v2.1 得到了一个新的不同的答案,b789abc

如果没有人做这种不受欢迎的事情,问题就不会出现在首位。但是如果您认为它可能会发生,您必须自己决定如何处理它。

现在,至于在 .gitmodules 中记录项目, 一种方法。问题是 Git 将记录的不是 tag 名称,而是 branch 名称:

git submodule set-branch -b <name> submodule

将添加:

branch = <name>

.gitmodules 文件中的条目。您在这里使用的 name 不一定实际存在!例如,我刚刚做了:

git submodule set-branch -b v1.0 scripts

在我添加了一个子模块的临时测试仓库中。实际子模块中的任何地方都没有 v1.0,既不是分支也不是标记。 Git 完全忽略此名称 除非 你 运行 特定品种的 git submodule update。我不会详细介绍所有这些,但例如,考虑一下:

$ git submodule update --remote
fatal: Needed a single revision
Unable to find current origin/v1.0 revision in submodule path 'scripts'

注意这里Git 假设 v1.0是一个分支的名字,并且添加了origin/ 在它的前面;没有办法告诉它不要做这个假设。

.gitmodules 文件只是一个 Git 配置文件,因此可以由 git config 直接操作。您可以阅读或写入 branch 条目,或创建您自己的条目。自己发明有一点危险:Git 的某些未来版本可能会发明同样的东西,但会以不同的方式使用它。不过,让我们看看它的作用:

$ git config -f .gitmodules submodule.scripts.tag v1.0
$ git diff
diff --git a/.gitmodules b/.gitmodules
index 32170c2..f8cb154 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,5 @@
 [submodule "scripts"]
        path = scripts
        url = ssh://git@github.com/chris3torek/scripts
+       branch = v1.0
+       tag = v1.0

branch = 是我之前的 git submodule 命令遗留下来的——让我们现在删除它,只是为了清理一下:

$ git submodule set-branch --default scripts
$ git diff
diff --git a/.gitmodules b/.gitmodules
index 32170c2..71dcdd2 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,4 @@
 [submodule "scripts"]
        path = scripts
        url = ssh://git@github.com/chris3torek/scripts
+       tag = v1.0

您现在可以使用 git config -f .gitmodules --get 检索此标签:

$ git config -f .gitmodules --get submodule.scripts.tag
v1.0

git config命令非常适合脚本;咨询 the documentation for more. See also git submodule foreach in the git submodule documentation 以获取为每个子模块自动 运行 命令的方法。

(当然,您不必将此标签信息直接存储在 .gitmodules 中;任何文件都可以,并且可以使您免受未来潜在的 Git 更改的影响。)

要将哈希 ID 转换为标签名称,请考虑使用 git tag --points-at(假设您的 Git 版本至少为 1.7.10):

git tag --points-at <hash>

将打印 select 该特定提交的标签的名称。注意你必须运行 this Git command in the submodule, after using the superproject to find the hash ID. 1

最后,要自动检查子模块,请考虑 git submodule status and/or git submodule summary 命令,这些命令也在 git submodule 文档中进行了描述。


1使用超级项目查找子模块的哈希 ID 的一种方法是让 Git 运行 git checkout / git switch 在子模块中,通过 运行ning git submodule update 在超级项目中。但是,如果您只想 读取 正确的哈希 ID,请使用 git rev-parse。子模块哈希 ID 作为 gitlink 条目存储在每个提交中,然后在检出时复制到 Git 的索引超级项目提交。例如,您可以使用:

git rev-parse <commit>:path/to/submodule

在超级项目中查看给定提交中的哈希 ID,或者:

git rev-parse :path/to/submodule

查看当前存储在超级项目Git索引中的哈希ID。