跳转至

Git Submodule: Data & Code Repository Separate

导言

原本是不期望使用submodule的,但是PTA要用,还是需要学习一下。

Git 子模块入门教程

Git Submodule在下载zip包时是无法运行的

由于子模块信息会保留在.git 信息,和.gitmodules文件里。zip下载没有。

需要删除.gitmodules文件,并且重复git add来重新添加。

在 Git 中,子模块(submodule)允许将一个 Git 仓库作为另一个 Git 仓库的子目录,从而管理不同的 Git 项目作为一个整体。这在需要将外部项目作为依赖或嵌入到你的项目中时非常有用。子模块的管理有时比较复杂,特别是当项目中有大量子模块时。

如果你觉得子模块不好用,也可以选择使用 .gitignore 或者 ln -s 来替代。


1. 添加子模块

要将子模块添加到你的 Git 仓库中,首先进入你的主仓库根目录,然后执行以下命令:

git submodule add <repository_url> <submodule_path>
  • <repository_url> 是你想要添加的子模块仓库的 URL。
  • <submodule_path> 是你希望将子模块放置在主项目中的相对路径。

  • 这个命令会在主仓库中创建对子模块的引用,允许你将子模块与主项目一起管理。

  • 相关信息会保留在.git 信息,和.gitmodules文件里。

2. 更新和初始化子模块

添加子模块后,你需要初始化并更新子模块的内容。运行以下命令:

git submodule update --init --recursive --depth=1
  • --init 用于初始化子模块。
  • --recursive 确保子模块中的其他子模块也被初始化。

这将会下载并初始化子模块的内容,使其成为主仓库的一部分。

3. 配置 .gitignore 文件

如果你不希望将子模块的内容提交到主仓库中,你可以在主仓库的 .gitignore 文件中忽略子模块的路径。例如,如果你的子模块位于 submodule_folder 目录下,可以在 .gitignore 文件中添加如下内容:

submodule_folder/

这样,Git 就不会把子模块的内容包含在版本控制中,但子模块的引用信息(即它指向的 commit)仍然会被记录在主仓库中。

4. 使用子模块

当你在其他机器上克隆这个主仓库时,或者将仓库分享给其他开发者时,他们需要运行以下命令来初始化并获取子模块的内容:

git submodule update --init --recursive --depth=1

对子模块进行修改

如果你需要对子模块做修改,可以进入子模块目录并像普通 Git 仓库一样进行工作。修改并提交后,不要忘记将子模块的更新推送到子模块的远程仓库。然后,再回到主仓库,提交更新后的子模块引用。

# 在子模块目录中进行修改和提交
cd third_party/op-plugin
git commit -m "Update submodule"
git push origin master

# 回到主仓库并提交子模块引用的更新
cd ..
git add third_party/op-plugin
git commit -m "Update submodule reference"
git push

更新子模块

如果你需要将子模块更新到最新的版本,可以进入子模块目录并运行以下命令:

cd third_party/op-plugin
git pull origin master

然后,回到主仓库提交更新后的子模块引用:

cd ..
git add third_party/op-plugin
git commit -m "Update submodule reference"
git push

子模块的独立版本控制

记住,子模块有自己独立的版本控制系统,因此你需要单独管理子模块的版本。子模块提供了一种将外部项目整合到你的主项目中的方式,同时保持它们独立的开发和版本控制。

替代方案

虽然 Git 子模块提供了强大的功能,但在一些场景下,它可能会显得比较复杂或不适用。如果你觉得子模块难以管理,可以考虑以下替代方案:

  • 使用 .gitignore:如果你不想管理子模块的内容,直接将其添加到 .gitignore 文件中。
  • 使用符号链接 (ln -s):通过在主仓库中使用符号链接,将外部项目作为文件夹包含进来,而不直接嵌套它们为 Git 子模块。

这两种方法可以简化一些场景,但会失去 Git 对子模块的自动管理和版本控制支持。


总结

Git 子模块是将外部仓库引入到你的主仓库中的强大工具,适用于有外部依赖的项目。尽管它们有独立的版本控制,需要管理多个仓库,但它们提供了更灵活和独立的版本控制方式。子模块的使用需要一些配置和理解,但一旦掌握,就能有效地组织和管理多个 Git 仓库。

必要性存疑
  1. parent repository ignore the sub directory in .gitignore
  2. Normal git usage in child repository, eg. init commit push
  3. submodule for what?
    1. for auto upload and init multi-subgit to target git commit

常见问题

合并冲突

父项目为空

PS C:\Users\94364\github\pytorch_without_subgit> git submodule status
66b781b70b1d095d107786d6b6a1bdfef7aa3e18 third_party/Tensorpipe (66b781b)
58d77fa8070e8cec2dc1ed015d66b454c8d78850 third_party/googletest (release-1.8.0-2986-g58d77fa8)
U0000000000000000000000000000000000000000 third_party/op-plugin
114e06a0b131d4055da3688d915bac4bbd29eb4f third_party/torchair/torchair (114e06a0)

使用git add third_party/op-plugin即可更新

submodule 有git, 但是没文件

说明是git clone时中断了,可以直接git reset --hard origin/master

合并submodule commit冲突

这个错误是因为 Git 在处理子模块的冲突时发现 third_party/op-plugin 子模块未被正确初始化或未检出其对应的 commit。以下是解决该问题的步骤:


  1. 初始化和更新子模块 确保子模块已被初始化并更新到正确的版本:
git submodule update --init --recursive --depth=1

如果子模块没有被初始化,这将下载并检出子模块内容。如果子模块已经存在但未被更新,这个命令会同步它到当前父项目的正确版本。


  1. 手动解决子模块冲突 子模块冲突需要手动解决,按照以下步骤操作:

(1) 进入子模块目录 进入冲突的子模块目录 third_party/op-plugin

cd third_party/op-plugin

(2) 检查冲突状态 在子模块中运行以下命令查看冲突情况:

git status

(3) 解决冲突 解决子模块内的冲突问题,可以选择:

  • 回退到指定版本:如果你知道父项目期望的子模块版本,直接检出该版本:
    git checkout <expected_commit>
    
  • 合并冲突:如果子模块的冲突是由于不同分支的内容合并导致的,运行:
    git merge <conflicting_commit_or_branch>
    

(4) 提交子模块的修改 子模块冲突解决后,提交子模块的变更:

git add .
git commit -m "Resolve conflict in third_party/op-plugin"

然后返回到父项目目录。


  1. 更新父项目状态 在父项目中,标记子模块冲突已解决:
git add third_party/op-plugin

然后继续变基过程:

git rebase --continue

参考文献

上面回答部分来自ChatGPT-3.5,没有进行正确性的交叉校验。