# Submodule 子模块 https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97#_git_submodules ## 新增 * 添加子模块 ```bash git submodule add <子模块地址> [指定路径(可选)] # 此时 .gitmodules .git/config .git/modules 会添加子模块的信息 # 子模块目录也会下载,不为空 # 1. 未初始化: 指定分支 git submodule add -b main [URL to Git repo] # 2. 已初始化: 修改分支 git config -f .gitmodules submodule.DbConnector.branch main # 这里的 DbConnector 是子模块的名称,stable 是分支的名称 # 或者修改.gitmodules [submodule "path/to/submodule"] path = path/to/submodule url = https://github.com/example/repo.git branch = main # 更新 git add path/to/submodule git commit -m "Update submodule to use specific branch" git submodule update --recursive --remote ``` * 查看 ```bash git status # 发现只列出 submodule 目录而不是里面所有的文件 # 对于模块外的项目来说,把子模块整个文件夹当成一个文件 ``` * 提交 ```bash git add . git commmit -m 'git add submodule' ``` ## 克隆 如果是克隆已经添加了子模块的项目 ```bash # 拉完主项目,此时子模块的目录是空的 git submodule init # 初始化本地配置文件 git submodule update # 拉取对应的提交 # 或者 git submodule update --init --recursive # 或者在拉取的时候添加参数 git clone <地址> --recurse-submodules # 子模块不一定是最新的,版本是在主项目里记录的版本 ``` ## 更新 * 情况1: 子模块的上游更新了, 本地还是旧的 ```bash # 子模块是一个独立的git项目,它并不需要知道自己被谁用 cd <子模块目录> git pull # 和第一次添加一样, 并不会在status里显示模块里面的文件更新 # submodule的版本控制在于submodule git 的 commit id, 所以要提交这些更新记录 cd <仓库目录> git add . git commit -m 'submodule update' # 或者 git submodule update --remote --recursive # 递归更新子模块 git add . git commit -m 'submodule update' ``` 当项目的子模块很多的时候,可以一个命令更新所有的模块 ```bash git submodule foreach 'git pull origin master' ``` * 情况2: 远程仓库**主项目**的子模块信息更新了, 本地的子模块还是旧的 ```bash # 先更新主项目 git pull origin master # 再根据主项目里的记录更新本地子模块 git submodule init git submodule update ``` * 情况3: 对本地的子模块作了个人的修改 不能提交到子模块的仓库, 要自己fork一份再修改 * 情况4: 使用远程仓库覆盖本地的子模块 ```sh cd 子模块的目录 git reset --hard origin/main ``` ## 修改模块 如果有子模块的修改权,那么把子模块当成单独的项目修改提交 ## 删除模块 ```bash # 不要去手动修改 .gitmodules .git/config .git/modules cached # 先卸载 git submodule deinit <子模块目录> # 添加 --force 参数,则子模块内有本地修改,也会被移除 git submodule deinit --force static/platform # 删除文件夹 git rm <子模块目录> git commit -m "delete submodule" ``` ## 拆分已有文件为子模块 ```bash # 建立新分支 git checkout -b test # 建立单独的仓库 cd git init git add . git commit -m "version 1.0 of sub-module" git remote add origin git push -u origin master # 把文件夹从暂存区和工作区删除 cd ../ git rm -r git commit -m "remove sub-module directory" rm -rf # 注册为子模块 git submodule add git commit -m "add submodule version 1.0" ``` * 存在问题点:如果要回到拆分前没有子模块的分支,结果发现提示报错 ```bash error: The following untracked working tree files would be overwritten by checkout: sub/a.txt Please move or remove them before you switch branches. # 可以强制切换, 注意强制切换前保存修改 git checkout -f master # 再回到test分支,发现子模块文件夹空了 cd # 找回 git checkout . ```