首页 > 解决方案 > 设置复杂的 git 子模块依赖项

问题描述

我有一个 git 存储库,它有多个子模块,这些子模块也有子模块。在我的依赖关系图中,我有这样的子图:

在此处输入图像描述

我希望所有存储库共享公共父文件夹,即如果我的存储库名为 A、B、C 等...,那么 A 在 C:/dev/folderA 中,B 在 C:/dev/folderB 中, C 在 C:/dev/folderC 等...

这样的设置可能吗?如果是这样,如何创建它。

标签: windowsgitgit-submodules

解决方案


我不认为你可以从 Git 中得到你想要的东西,但我不确定你想要什么(也不知道你为什么想要它)。

以下是子模块在 Git 中的实际工作方式。

假设 R 是一些充当超级项目的存储库。这意味着 R 至少有一个子模块 S。R 中的子模块 S 包括:

  • 向 Git 说明git clone从哪里开始。这些存储在.gitmodulesR 中每个提交中出现的文件中,并.git/config在您要求 Git 这样做时从那里复制到 R 中。子模块“foo”的.gitmodules条目至少有以下两个子字段:

    [submodule "foo"]
        path = path/to/foo
        url = https://github.com/owner/foo.git
    

    (子模块名称通常是“path/to/foo”,但我故意在这里作弊来说明它们是如何分开的。)

  • 每个提交中的gitlink条目,在给定的路径下。

每个 gitlink 都包含一个“文件”(实际上是伪文件),其mode160000,其存储的哈希 ID 是子模块存储库中提交的哈希 ID。提交后,该文件的路径名出现在 Git 的索引中git checkout。在上面的示例中,子模块“foo”将出现在名称下的索引中path/to/foo1 这里的哈希 IDgit submodule updategit checkout是 S 中的哈希 ID,通过执行:

(cd path/to/foo; git checkout $hash)

$hash这个哈希 ID在哪里。

现在,子模块 S 本身就是一个 Git 存储库。在过去, beforegit submodule absorbgitdirs最终path/to/foo会包含一个名为的目录.git,它是实际的存储库本身。其余的path/to/foo——一个目录——将简单地包含这个存储库的工作树。

随着对 的更改git submodule absorbgitdirs,S 的存储库现在驻留在 R 的存储库之下,即.git/其本身。在这里您将找到一个modules/子目录:.git/modules/foo将包含S的存储库path/to/foo。该目录将包含一个名为的文件.git,该文件包含此存储库的路径,以及当前签出提交的所有文件,即工作-存储库 S 的树。

现在假设 S 本身作为一个超级项目,带有子模块 T。这意味着,在 S 的工作树(位于 中path/to/foo)中,有一个工作树.gitmodules;提交S有一个提交的、冻结的 this 副本.gitmodules;这.gitmodules列出了子模块 T 的名称和相对于path/to/foo的路径。如果该子模块已命名bar并位于 中path = bar,则 R 的工作树的相对路径为path/to/foo/bar

R 中的这个相对路径包含 T 的工作树。T 的存储库位于以下两个位置之一,具体取决于您的 Git 年份:

  • pre-absorb-Git-dirs: path/to/foo/bar/.git; 或者
  • 吸收后:.git/modules/foo/modules/bar

请注意,兄弟子模块可能是相邻的:如果 R 具有路径为path/to/s1和的子模块 S1 和 S2 path/to/s2,则存储库本身和两个工作树在 R 的工作树内是相邻的。但是,子模块的子模块具有的工作树必须在子模块的工作树中更深。

还要注意,如果 R 有 S 和 T 作为子模块,并且 S 有 T 作为子模块,那么您将获得存储库T 的两个副本,一个在.git/modules/T,一个在.git/modules/S/modules/T(假设新吸收的布局)。您还将获得两个单独的工作树,但这显然是必要的,因为这两个可能有两个不同的提交被签出。如果吸收代码很聪明并发现存储库 T 的重复,那就太好了,但事实并非如此。


1请记住,在索引中,每个提交的文件都由一个包含四个条目的元组表示:

  • name:文件的路径名,包括斜杠,例如path/to/foopath/file.ext
  • 模式:通常100644(常规文件)或100755(可执行文件)。您还可以在支持它的系统上拥有一个符号链接,存储为 mode 120000,当然还有 gitlinks , mode 160000
  • 暂存槽号:通常为零;非零数字表示您处于冲突合并中。
  • 哈希 ID:Git blob 对象的哈希 ID,在所有情况下,除了 gitlink,这是子模块中提交的哈希 ID。

推荐阅读