'git submodule init' 的作用是什么?

135

背景

为了填充存储库的子模块,通常需要调用以下命令:git submodule update

git submodule init
git submodule update
在这种用法中,git submodule init 看起来只做了一件事:向 .git/config 中填充已经在 .gitmodules 中的信息。
那有什么意义吗?
不能git submodule update 直接使用 .gitmodules 中的信息吗?这将避免两种情况:
- 不必要的命令(git submodule init); - 数据的不必要重复(.gitmodules 的内容复制到 .git/config 中)。
问题:
要么:
- 我不知道 git submodule init 的用例(如果是这样,请给我解释!);或者 - git submodule init 是 Git 中可以被弃用的东西,而不会带来任何危害。
这两种说法哪一个是正确的?

我在仓库中看到的命令是反向的 git submodule update && git submodule init,这样做的目的是什么? - Charlie Parker
3个回答

119

假设仓库中有 10 个子模块,你只对其中两个子模块感兴趣。在这种情况下,你可能只想不时从远程仓库获取这两个子模块的更新。使用 git init 可以很好地解决这个问题,因为一旦你对这两个子模块执行了 git init 命令,git submodule update --remote 就只会针对它们应用。


新增了两个工作流示例。

工作流1:子模块是多个项目共同使用的库。

我认为这是最常见的用例之一。

你只是克隆了 "my-project"。

git clone https://example.com/demo/my-project

它的结构表面如下图所示。

在此输入图片描述

.gitmodules的内容

[submodule "lib1"]
    path = lib1
    url = https://example.com/demo/lib1
[submodule "lib2"]
    path = lib2
    url = https://example.com/demo/lib2
[submodule "lib3"]
    path = lib3
    url = https://example.com/demo/lib3
[submodule "lib4"]
    path = lib4
    url = https://example.com/demo/lib4

你想重构代码code1.js,它引用了lib1和lib2,这意味着你不需要克隆和检出lib3和lib4。所以你只需运行以下命令。

git submodule init lib1 lib2

现在让我们来看看.git/config的内容。

...
[submodule "lib1"]
    active = true
    url = https://example.com/demo/lib1
[submodule "lib2"]
    active = true
    url = https://example.com/demo/lib2
这意味着类似于“准备从example.com/demo更新lib1和lib2”。此时,lib1和lib2目录为空。您可以使用一个命令克隆和检出lib1和lib2:
git submodule update

现在,您可以重构code1.js而不会出现导入错误。

子模块只是指向特定提交的引用。因此,当您想将库更新到新版本时,您必须更新这些引用。您可以通过以下命令来完成。

git submodule update --remote

现在你可以看到只初始化所需的子模块是多么有用。

工作流2:每个子模块都是一个项目,一个大型顶级项目包含它们。

我喜欢这个。

您克隆“main-project”。

git clone https://example.com/demo/main-project

它的结构表面如下所示。

图片描述

你可以看到一个名为“shared”的目录。在这个工作流中有一条规则:如果你想在你的项目中使用主项目的共享代码,你必须将项目创建为主项目的子模块。

我喜欢把实体类放在像下面这样的共享目录中。

图片描述

回到子模块工作流,.gitmodules文件的内容如下所示。

[submodule "sub-project1"]
    path = sub-project1
    url = https://example.com/demo/sub-project1
[submodule "sub-project2"]
    path = sub-project2
    url = https://example.com/demo/sub-project2
[submodule "sub-project3"]
    path = sub-project3
    url = https://example.com/demo/sub-project3
[submodule "sub-project4"]
    path = sub-project4
    url = https://example.com/demo/sub-project4

这次你想要重构主项目中共享目录的一些代码,你知道只有 sub-project1 和 sub-project2 引用了共享代码,这意味着你不需要克隆和检出 sub-project3 和 sub-project4。所以你只需运行下面的命令。

git submodule init sub-project1 sub-project2

就像我在workflow1中提到的那样,您需要运行以下命令来克隆和检出它们。

git submodule update

在这种情况下,我需要执行 git submodule update --remote 吗?或者说,我是否必须初始化并更新子模块以重构共享目录中的代码?是的,因为在重构共享代码后,您必须运行子模块中的测试,如果在您重构时提交并推送了任何子模块的更新到远程存储库,那么您需要使用 git submodule update --remote 命令来获取它们。


1
感谢您指出在这种情况下 git submodule init 可能会有帮助。我还没有尝试过,但是因为您让我更广泛地思考了 git 子模块工作流程,所以我已经为您的答案点赞了 :) 您介绍的工作流程是否可以添加一个代码块来说明呢?我认为这将使得答案对社区更有价值。再次感谢 :) - user82216
1
谢谢您纠正我的英语。我添加了两个工作流程。但我不确定这是否对某人有所帮助。 - Nigiri
如果您有其他子模块,只想init并更新一些特定的子模块,则工作流程变为:[git submodule init -- ./lib1 ./lib2]和[git submodule update --remote --recursive -- ./lib1 ./lib2]。您还可以在更新命令中使用[--merge]或[--rebase],但是请先了解它们的功能,因为它们可以避免在更新期间检出分离头,但可能会破坏历史记录。目前,您可以使用[git submodule foreach "git checkout master && git pull"]修复分离的头状态(子模块很有趣且易于使用xD)。 - FocusedWolf
我在仓库中看到的命令是反向的 git submodule update && git submodule init,这样做的目的是什么? - Charlie Parker

35

阅读git submodule的文档,似乎有一个使用案例可以证明git submodule init作为独立命令存在的必要性。

如果克隆了一个存储库的用户希望为子模块使用与上游存储库指定的不同URL,则该用户可以执行以下操作:

git submodule init
vim .git/config # Alter submodule URL as desired, without changing .gitmodules
                # or polluting history.
git submodule update

3
例如,当子模块很大并且您已经因其他原因将其保存在本地时。git config -f .gitmodules submodule.biglib.url=/path/to/it 比编辑文件更容易,而 git submodule update --init 在您满意默认设置时比两步骤更容易。 - jthill
我在仓库中看到的命令是反向的 git submodule update && git submodule init,这样做的目的是什么? - Charlie Parker

0

据我所知,这就是命令的作用和所需顺序:

# - git submodule init initializes your local configuration file to track the submodules your repository uses, it just sets up the configuration so that you can use the git submodule update command to clone and update the submodules.
git submodule init
# - git submodule update --init initializes your local configuration file and clones the submodules for you, using the commit specified in the main repository.
#   note, command bellow will not pull the right branch -- even if it's in your .gitmodules file, for that you need remote. Likely because it looks at the origin (pointer to remote) in github for the available branches.
#   note, bellow pulls the submodules if you didn't specify them when cloning parent project, ref: https://youtu.be/wTGIDDg0tK8?t=119
git submodule update --init
# - The --remote option tells Git to update the submodule to the commit specified in the upstream repository, rather than the commit specified in the main repository.
#git submodule update --init --remote
git submodule update --init --recursive --remote meta-dataset

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接