git submodule
子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
比如我们想抽象出一个组件库供多个项目使用
git submodule add <子模块git地址> <存放的文件名>
会生成: .gitmodules 和 子模块文件夹
-
.gitmodules
文件保存了项目 URL 与已经拉取的本地目录之间的映射,这样就能知道子模块在哪获取。如果有多个子模块,该文件中就会有多条记录。 -
子模块文件夹只存子项目的
commit id
,就能指定到对于的git header
上, 父项目的git并不会记录Submodule
的文件变动,它是按照commitid
指定Submodule
的git header
当你不在那个目录中时,Git 并不会跟踪它的内容, 而是将它看作子模块仓库中的某个具体的提交。
注意的是,这两个文件也像 .gitignore
文件一样受到(通过)版本控制。 它会和该项目的其他部分一同被拉取推送。
克隆含有子模块的项目
克隆一个含有子模块的项目时,默认会包含该子模块目录,但其中还没有任何文件,是空目录。 必须运行:
-
git submodule init
用来初始化本地配置文件 -
git submodule update
则从该项目中抓取所有数据并检出父项目中列出的合适的提交。
合成一步就是: git submodule update --init
如果还要初始化、抓取并检出任何嵌套的子模块:git submodule update --init --recursive
或者在克隆的时候加上参数: git clone --recurse-submodules
它就会自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。
修改submodule
进入submodule目录里修改后add 、commit 、push到远程服务器,然后要回到父目录,提交submodule在父项目中的改动(submodule commit id 会更新),再push
坑:子模块的分支默认不是master,也不会切到任何branch
当我们运行
git submodule update
从子模块仓库中抓取修改时, Git 将会获得这些改动并更新子目录中的文件,但是会将子仓库留在一个称作“游离的 HEAD”的状态。 这意味着没有本地工作分支(例如 “master” )跟踪改动。 如果没有工作分支跟踪更改,也就意味着即便你将更改提交到了子模块,这些更改也很可能会在下次运行git submodule update
时丢失。
因此,在修改前先进入子模块,然后切换到需要的分支(eg. git checkout master),然后再对子模块做修改、提交。
更新submodule (未完待续)
from : git 官方文档
1、从子模块的远端拉取上游修改
方法一:手动抓取并合并
进入到子目录中运行 git fetch
与 git merge
( = git pull
),合并上游分支来更新本地代码。
方法二:交给Git抓取更新
git submodule update --remote
,Git 将会进入子模块然后抓取并更新,Git 默认会尝试更新 所有 子模块, 所以如果有很多子模块的话,你可以传递想要更新的子模块的名字。
2、从项目远端拉取上游更改
默认情况下,git pull
命令会递归地抓取子模块的更改。 然而,它不会 更新 子模块。 为了完成更新,你需要运行 git submodule update
。
注意,为安全起见,如果主项目提交了你刚拉取的新子模块,那么应该在 git submodule update
后面添加 --init
选项,如果子模块有嵌套的子模块,则应使用 --recursive
选项。
如果你想自动化此过程,那么可以为 git pull
命令添加 --recurse-submodules
选项(从 Git 2.14 开始)
坑 ( from: 唐巧-Git submodule的坑 )
如果你的同事更新了 submodule,然后更新了父项目中依赖的版本号。你需要在 git pull 之后,调用 git submodule update 来更新 submodule 信息。
这儿的坑在于,如果你 git pull 之后,忘记了调用 git submodule update,那么你极有可能再次把旧的 submodule 依赖信息提交上去。
如果你不慎忘记切换到 master 分支,又做了提交,可以用 cherry-pick 命令挽救。具体做法如下:
- 用
git checkout master
将 HEAD 从游离状态切换到 master 分支 , 这时候,git 会报 Warning 说有一个提交没有在 branch 上,记住这个提交的 change-id(假如 change-id 为 aaaa) - 用
git cherry-pick aaaa
来将刚刚的提交作用在 master 分支上 - 用
git push
将更新提交到远程版本库中
当子模块的URL改变时
# 将新的 URL 复制到本地配置中
$ git submodule sync --recursive
# 从新 URL 更新子模块
$ git submodule update --init --recursive
实谈
在实际项目中,在子项目我们的分支上做好修改后,要将分支合并到子项目仓库。同时,不要忘了主项目上的分支也要合并(毕竟我就忘了Orz)!!否则主项目保存的子项目的引用还是旧的版本,同事拉取时如果没有进入到子项目中去更新,就得不到新的代码,那么在他修改推送后很可能又将之前自己做的修改覆盖了。
以上很多内容来自官方文档。看的有点懵。但其实主要的命令就是那几条,拉取时不要忘记更新子项目,推送时不要忘记更改主项目中引用的子项目commitid。