git submodule
文章目录
- 1.简介
- 2.格式
- 3.选项
- 4.示例
- 5.小结
- 参考文献
1.简介
git submodule 用于管理子模块。
有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。
Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
2.格式
git submodule [--quiet] [--cached]
git submodule [--quiet] add [<options>] [--] <repository> [<path>]
git submodule [--quiet] status [--cached] [--recursive] [--] [<path>…]
git submodule [--quiet] init [--] [<path>…]
git submodule [--quiet] deinit [-f|--force] (--all|[--] <path>…)
git submodule [--quiet] update [<options>] [--] [<path>…]
git submodule [--quiet] set-branch [<options>] [--] <path>
git submodule [--quiet] set-url [--] <path> <newurl>
git submodule [--quiet] summary [<options>] [--] [<path>…]
git submodule [--quiet] foreach [--recursive] <command>
git submodule [--quiet] sync [--recursive] [--] [<path>…]
git submodule [--quiet] absorbgitdirs [--] [<path>…]
3.选项
-q, --quiet
只打印错误信息
-b, --branch <branch>
要添加为子模块的仓库分支。分支的名称记录在 .gitmodules 文件中的 submodule.<name>.branch,用于 update --remote。特殊值 . 用于指示子模块的分支名称应与当前仓库的当前分支名称相同。如果未指定该选项,则默认为远程 HEAD。
<path>…
子模块的路径。当指定时,这将限制命令只操作指定路径上找到的子模块。(此参数对于add是必填的)。
4.示例
(1)查看子模块。
git submodule
(2)添加子模块。
git submodule add <repository-url> <path>
该命令会将一个远程仓库添加为子模块,并将其克隆到指定的目录。同时会在主仓库中生成一个 .gitmodules 文件来记录子模块的信息。
(3)克隆包含子模块的仓库。
如果第一次使用 git clone 下载主仓库,建议使用如下命令把主仓库和子模块一次性下载下来:
git clone --recurse-submodules <project-url>
如果只是 git clone 去下载主仓库的内容,没有使用 --recurse-submodules
那么你会发现子模块的文件夹是空的!
此时我们可以初始化子模块,如果不指定子模块路径,则初始化所有子模块。
git submodule init [<path>...]
当你克隆一个包含子模块的仓库时,子模块的相关信息(如 URL 和路径)会被保存在 .gitmodules 文件中。执行 git submodule init 后,Git 会根据这个文件中的配置信息,准备好子模块的本地配置。
初始化完子模块后,然后更新子模块,则会根据子模块的配置信息,拉取子模块的代码为主项目里指定的 commit id。
git submodule update [<options>] [--] [<path>...]
或者直接初始化和更新子模块。
git submodule update --init
这个命令会下载子模块的内容到指定的路径。其中 --init
用于初始化子模块。
(4)拉取子模块的远端更新。
如果子模块在远端发生了版本变更,有多种方法可以获取子模块最新版本。
方法一:cd submodule 后 git pull。
在 submodule 中,所有 Git 操作就当作一个普通的 Git 仓库就行,你可以切换分支、提交代码、拉取更新等。
这个方法,你可以拉取到 submodule 的最新代码。但是如果这时候的 commit id 跟主项目里记录的 submodule 的 commit id 不一致,你会在主项目仓库看到 diff,你可能需要提交主项目更新。
方法二:使用如下命令,这相当于在每个子模块中执行 git pull。
git submodule update --remote [<path>...]
如果你不带参数子模块路径,就会更新所有子模块。
当我们更新子项目后,相当于把主项目记录的 submodule 的 commit id 给更新了,需要提交下主项目的变更。
(5)推送子模块的变更到远端。
如果在本地修改了子模块,需要推送子模块到远端仓库。此时在主项目中使用 git status 能够看到关于子模块尚未暂存以备提交的变更,但是于主项目而言是无能为力的,使用 git add/commit 对其不会产生影响。
在此情景下,通常需要进入子模块文件夹,按照子模块内部的版本控制提交代码。
注意,当在子模块做 commit 后,此时主项目中所记录的子模块的 commit id 也会更新,需要提交下主项目的变更。
(6)删除子模块。
git submodule deinit [-f|--force] (--all|[--] <path>…)
如果加上参数 -f|–force,则子模块工作区内即使有本地的修改,也会被移除。
执行完上面的命令,会自动在 .git/config 中删除子模块的配置信息。然后我们还需要使用 git rm 删除子模块目录。
git rm <path>...
5.小结
虽然 Git 提供的子模块功能已足够方便好用,但不建议使用。
请在为主仓库项目添加子模块之前确保这是非常必要的。毕竟有很多编程语言提供了类似的依赖包管理工具,如 Go Modules、Node.js npm 和 Ruby’s rubygemsor 等,可以更好地完成类似的功能。
主项目的合作者并不会自动地看到子模块仓库的更新通知,所以,更新子模块后一定要记得提醒一下主项目的合作者执行 git submodule update --remote
。
参考文献
git submodule