9.1 克隆包含子模块的 Git 仓库

当你克隆使用子模块的仓库时,需要初始化并更新这些子模块。

$ git clone --recursive <url id="cumojpmf2kq15kc4oe7g" type="url" status="parsed" title="Build software better, together" wc="719">https://github.com/username/repo.git</url>

这将克隆引用的子模块,并将它们放置在适当的文件夹中(包括子模块内的子模块)。这等同于在克隆完成后立即运行 git submodule update --init --recursive。

9.2 更新子模块

子模块引用另一个仓库中的特定提交。要检出所有子模块引用的确切状态,运行:

git submodule update --recursive

有时,你可能不希望使用引用的状态,而是想将本地检出更新到该子模块在远程的最新状态。要使用单个命令将所有子模块检出到远程的最新状态,可以使用:

git submodule foreach git pull <remote> <branch>

或者使用默认的 git pull 参数:

git submodule foreach git pull

请注意,这只会更新你的本地工作副本。运行 git status 会列出子模块目录,因为此命令导致了更改。要更新你的仓库以引用新的状态,你需要提交更改:

git add <submodule_directory>
git commit

在使用 git pull 时,可能会有一些更改会导致合并冲突,因此你可以使用 git pull --rebase 将你的更改回滚到顶部,大多数情况下可以减少冲突的可能性。它还会将所有分支拉取到本地。

git submodule foreach git pull --rebase

要检出特定子模块的最新状态,可以使用:

git submodule update --remote <submodule_directory>

9.3 添加子模块

你可以将另一个 Git 仓库作为文件夹包含在你的项目中,并由 Git 进行跟踪:

$ git submodule add <url id="cumojpmf2kq15kc4oe80" type="url" status="parsed" title="GitHub - jquery/jquery: jQuery JavaScript Library" wc="14274">https://github.com/jquery/jquery.git</url>

你应该添加并提交新的 .gitmodules 文件;这告诉 Git 在运行 git submodule update 时应该克隆哪些子模块。

9.4 设置子模块跟踪分支

子模块始终在特定的提交哈希(“gitlink”,父仓库索引中的特殊条目)处检出。

但你可以请求更新该子模块,以跟踪子模块远程仓库中的最新提交。

而不是进入每个子模块,执行 git checkout abranch --track origin/abranch,git pull,你可以简单地从父仓库执行以下操作:

git submodule update --remote --recursive

由于子模块的 SHA1 会更改,你仍然需要跟上:

git add .
git commit -m "update submodules"

这假设子模块是:

  • 添加时带有要跟踪的分支:
git submodule -b abranch -- /url/of/submodule/repo
  • 或者配置(对于现有子模块)以跟踪分支:
cd /path/to/parent/repo
git config -f .gitmodules submodule.asubmodule.branch abranch

9.5 移动子模块

版本 > 1.8

运行:

$ git mv /path/to/module new/path/to/module

版本 ≤ 1.8

  1. 编辑 .gitmodules 文件,适当更改子模块的路径,并使用 git add .gitmodules 将其放入索引中。
  2. 如果需要,创建新位置的子模块的父目录(mkdir -p /path/to)。
  3. 将所有内容从旧目录移动到新目录(mv -vi /path/to/module new/path/to/submodule)。
  4. 确保 Git 跟踪此目录(git add /path/to)。
  5. 使用 git rm --cached /path/to/module 删除旧目录。
  6. 将 .git/modules//path/to/module 目录及其所有内容移动到 .git/modules//path/to/module。
  7. 编辑 .git/modules//path/to/config 文件,确保 worktree 项指向新位置,例如 worktree = ../../../../..//path/to/module。通常这里应该有两个更多的 ..。 编辑 /path/to/module/.git 文件,确保路径指向主项目 .git 文件夹中的正确新位置,例如 gitdir: ../../../.git/modules//path/to/module。
  8. 最后,提交更改。

此示例来自 Stack Overflow,作者为 Axel Beckert。

git status 输出如下:

# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: .gitmodules
# renamed: old/path/to/submodule -> new/path/to/submodule
#

9.6 删除子模块

版本 > 1.8

你可以通过以下命令删除子模块(例如 the_submodule):

$ git submodule deinit the_submodule
$ git rm the_submodule
  • git submodule deinit the_submodule 删除 .git/config 中的 the_submodule 条目。这会将 the_submodule 从 git submodule update、git submodule sync 和 git submodule foreach 调用中排除,并删除其本地内容(源)。此外,这不会在你的父仓库中显示为更改。
  • git rm the_submodule 会从工作树中删除子模块。子模块的条目也会从 .gitmodules 文件中删除(源)。如果仅运行 git rm the_submodule(没有先运行 git submodule deinit the_submodule),子模块的条目将保留在 .git/config 文件中。

版本 < 1.8

  1. 从 .gitmodules 文件中删除相关部分。
  2. 将 .gitmodules 的更改放入暂存区 git add .gitmodules。
  3. 从 .git/config 中删除相关部分。
  4. 运行 git rm --cached path_to_submodule(路径末尾不要加斜杠)。
  5. 运行 rm -rf .git/modules/path_to_submodule。
  6. 提交更改 git commit -m "Removed submodule <name>"。
  7. 删除现在未跟踪的子模块文件。
  8. rm -rf path_to_submodule