父模块git submodule update和子模块git pull区别

当你在子模块内部执行 git pull 时,你是在直接从子模块的远端仓库拉取最新的提交。这个操作仅影响子模块本身,不会对父模块产生任何影响。如果子模块有新的更新,父模块不会知道这一点,除非你明确地告诉父模块更新子模块的引用。

git submodule update 命令则是从父模块的视角来更新子模块。当你执行这个命令时,Git会检查父模块记录的子模块提交SHA-1值,并尝试将子模块的本地工作目录更新到这个特定的提交。这个操作会考虑父模块中 .gitmodules 文件和 .git/config 文件里记录的子模块的URL和分支。如果子模块有更新,并且父模块已经更新了子模块的引用(通常通过 git submodule update --remote 或者手动编辑 .gitmodules 文件),那么 git submodule update 会拉取这些更新。

简而言之,两者的主要区别在于

git pull 在子模块内部执行,仅更新子模块的内容,而不影响父模块。
git submodule update 在父模块中执行,根据父模块记录的子模块提交SHA-1值来更新子模块。
通常,如果你想要更新子模块到其远端仓库的最新状态,你需要在子模块中执行 git pull,然后将子模块的新提交SHA-1值更新到父模块中(通过 git addgit commit),最后在父模块中执行 git submodule update 来确保所有使用父模块的人都能获取到更新后的子模块状态。

举个栗子

假设我们有一个父模块 SuperProject 和一个子模块 SubProject

以下是操作步骤:

初始化子模块在父模块中,我们首先添加子模块:

1
git submodule add https://example.com/SubProject.git

这会在父模块中创建一个名为 SubProject 的子目录,并在其中初始化一个 Git 仓库,指向子模块的远端仓库。
提交更改我们提交这次更改:

1
git commit -m "Add SubProject as a submodule"

克隆父模块现在另一个人克隆了父模块:

1
git clone https://example.com/SuperProject.git

这时会包含子模块的目录,但目录为空。他们需要初始化并更新子模块:

1
git submodule update --init --recursive

这会拉取子模块的最新提交,并检出父模块记录的子模块提交SHA-1值。
使用 git pull 更新子模块
假设子模块的远端仓库有新的提交。在子模块目录中,我们执行:

1
2
cd SubProject
git pull origin main

这会拉取远端仓库的最新提交,并更新子模块的本地工作目录。

使用 git submodule update 更新子模块
现在,我们回到父模块的目录,并执行:

1
git submodule update

这个命令会根据父模块记录的子模块提交SHA-1值来更新子模块。但由于我们没有更新父模块记录的子模块提交SHA-1值,子模块将不会更新到最新的提交。

为了更新父模块记录的子模块提交SHA-1值,我们需要执行:

1
git submodule update --remote

或者直接在子模块目录中手动更新到最新提交,然后回到父模块提交更改:

1
2
3
4
cd SubProject
git pull origin master
cd ..
git commit -a -m "Update SubProject to the latest commit"

这样,当我们执行 git submodule update 时,子模块就会更新到最新的提交。

总结一下,git pull 在子模块内部执行,仅更新子模块的内容。而 git submodule update 在父模块中执行,根据父模块记录的子模块提交SHA-1值来更新子模块。要确保子模块更新到最新状态,我们需要在子模块中执行 git pull,然后更新父模块记录的子模块提交SHA-1值,最后在父模块中执行 git submodule update