Git Submodule
一. 什么是Git Submodule
在实际工程中,使用别人的代码模块是一件很常见的事情,比如我有一个git项目,名为A,GitHub上有一个项目B可以作为我的子模块,传统的思路可能是,把别人的项目BClone到自己的本地仓库,然后一起作为自己的仓库内容进行提交,但是这样有很多不方便的地方,比如:
- 如果项目B更新了,那么自己还得手动Clone复制粘贴再上传
- 如果模块很多时,每次拉取工程,都要拉取整个项目A,包括子项目B、C、D等
- 可能会造成版权问题(我猜的)
Git Submodule允许在自己的Github仓库里加入别人的github仓库,作为自己仓库的子仓库(即submodule),有了Git的Submodule功能,就可以解决上述问题,git submodule允许在git仓库里存放别人仓库的url,作为自己的子模块,其核心内容是在Git仓库里面加入一个.gitmodules
文件,如下图所示:
.gitmodules
只是一个文本文件,用来记录仓库里的submodule的url和相对于仓库的路径,举个例子,一共有三个submodule,很简单的记录了各个submodule的名字、路径和对应的地址url:
[submodule "Hazel/vendor/spdlog"]
path = Hazel/vendor/spdlog
url = https://github.com/gabime/spdlog.git
[submodule "Hazel/vendor/GLFW"]
path = Hazel/vendor/GLFW
url = https://github.com/TheCherno/glfw.git
[submodule "Hazel/vendor/imgui"]
path = Hazel/vendor/imgui
url = https://github.com/hwx0000/imgui.git
简单来说,git submodule的核心就是这个.gitmodules
文件,下面介绍常用的相关git命令,看看具体怎么操作。
二. 添加submodule
直接在自己的git的cmd或者bash界面,输入git submodule add 要拉取的子模块的url 想要存放的相对路径,就可以在自己的git仓库里添加别的仓库作为submodule了:
git submodule add url path
举个例子,添加Github上的imgui库作为我的submodule,放到我工程的imgui文件夹中:
git submodule add https://github.com/hwx0000/imgui.git imgui
然后等待git去下载就好了,不过如果网不好,很容易失败,下载完成后,工程根目录应该会自动出现一个.gitmodules文件,然后可以把它提交,push到github就可以了。
三. Git Clone带有submodule的仓库
前面提到了怎么直接从自己的仓库添加submodule,下面介绍如何Clone一个带有submodule的git仓库。
如果要从其他电脑clone仓库,仅仅输入git clone url
只会拉取submodule对应的文件夹,里面的内容是空的,要想拉取里面的内容,有以下做法。
Clone仓库,同时Clone仓库里所有的submodule
在命令行输入git clone --recursive url
,url是实际的仓库地址,就可以了,仅仅加了个--recursive
,recursive也就是递归的意思,这种命令下,就算里面的submodule里还有自己的submodule(套娃),也应该是可以clone到的(不过我没有具体测试过)
Clone仓库,同时Clone仓库里指定的submodule
这种情况应该也很常见,比如别人的仓库里一堆submodule,但是我并不需要用到那么多,所以我只想Clone对应的几个submodule,这个时候,就需要使用git submodule init
和git submodule update
指令了。如下图所示,比如原仓库有四个submodule,都是存放了lib文件的文件夹:
.gitmodules的内容如下:
[submodule "lib1"]
path = lib1
url = https://example.com/demo/lib1
[submodule "lib2"]
path = lib2
url = https://example.com/demo/lib2
[submodule "lib3"]
path = lib3
url = https://example.com/demo/lib3
[submodule "lib4"]
path = lib4
url = https://example.com/demo/lib4
比如我要运行code1.js文件,这个文件只使用了lib1和lib2里的.lib文件,所以我只需要拉lib1和lib2的submodule,那么可以输入这两行代码:
git submodule init lib1 lib2
git submodule update//会update所有被init过的submodule
也就是说,git默认的submodule是不会被clone的,除非你使用了git submodule init submodulename
的指令,git submodule init具体做了什么,可以参考: https://stackoverflow.com/questions/44366417/what-is-the-point-of-git-submodule-init。
git clone忘了带–recursive
如果忘了带–recursive,或者是由于网络原因clone失败,可以输入:
git submodule update --init
相当于为所有的submodule进行git submodule init
,然后执行git submodule update
四. 更新submodule
更新到最新版本的submodule
比如我的项目A引用了submodule项目B,然后别人最近在项目B上有了新的更改,那么输入下面命令即可:
git submodule update --remote
这行命令应该会拉取所有被git submodule init
的submodule,如果只想更新特定的submodule,那么可以输入:
git submodule update --remote <path to the submodule>
五. Git移除submodule
看到网上说的步骤如下:
To remove a submodule you need to:
- Delete the relevant section from the .gitmodules file.
- Stage the .gitmodules changes git add .gitmodules
- Delete the relevant section from .git/config.
- Run git rm --cached path_to_submodule (no trailing slash).
- Run rm -rf .git/modules/path_to_submodule (no trailing slash).
- Commit git commit -m "Removed submodule "
- Delete the now untracked submodule files rm -rf path_to_submodule
但实际上我是把Git加入到cmd的命令行里,用cmd环境做的,所以上面的Linux命令不适用,不过做法还是大同小异:
- .gitsubmodules文件里手动删除对应路径
- 用git add保存文件改动
- 手动删除.git/config文件里面对应的内容
- cmd里运行git rm --cached path_to_submodule (no trailing slash),不过我是带斜杠的,我写的是git rm --cached Hazel/vendor/imgui
- 手动找到.git文件夹下的modules文件夹,删除里面的submodule的内容
- 最后commit,再push就可以了
- 然后别忘了删除自己的本地的submodule内容
更正式和详细的做法参考https://stackoverflow.com/questions/1260748/how-do-i-remove-a-submodule,这里就不多研究了
六. 查看submodule状态
查看当前仓库的submodule状态,可以得到各个submobule对应的commit和commit对应的哈希值,指令如下:
git submodule status
查看当前仓库的submodule状态,包括submodule的submodule状态(if you want to show nested submodules.):
git submodule status --recursive
七. 更改submodule的版本
我一开始直接用的git submodule update --remote path-to-submodule
的指令,cmd界面上成功走完了,没报错,但是我进去我的submodule里,发现文件内容并没有改变,所以我想,应该是更新了对应的commits,但是我的submodule仓库的HEAD指针指向的版本没有修改。
所以我做了接下来的尝试,首先cd到submodule对应的文件夹里面,输入git status,发现显示的哈希值与我在Github上的版本哈希值一模一样,为了改变版本,我找到原submodule上对应我想要版本的哈希值,再进行了git reset --hard 哈希值
的操作,结果本地文件是改过来了。
接下来的问题就是提交了,我把路径回退到主仓库,进入cmd,输入下列指令,如下图所示:
就可以看到我在github上仓库的哈希值更改到了我想要的commit对应的哈希值,(虽然GitHub上的Commits里显示不到具体的修改),如下图所示:
八. 常见问题
下载到一半退出了
如下图所示,这里的Cloning into,由于外网的下载很慢,也没有进度条,所以这里应该耐心等待,我之前就是直接关掉了,然后再用git submodule update,就会报错fatal: could not get a repository handle for submodule ....
这个时候我去把对应submodule路径的.git
文件删掉,再重新git submodule update,clone之后等等就可以了
在git submodule里添加东西并提交
由于实际需求,尝试过从当前仓库在submodule中添加东西,后来发现这样是不对的,因为submodule本身就是一个整体,不应该自己在里面加东西。如果要使用别人的东西,正确做法是使用GitHub的Fork功能,Fork后自己Clone对应的工程,然后直接修改submodule后上传,再在自己的仓库里调用git submodule update --remote
就可以了
直接pull仓库发现不会pull仓库里面submodule的内容
参见上面的git submodule update
,使用submodule应该不存在pull和push指令,自己应该是无权改动的。
参考链接:https://stackoverflow.com/questions/1030169/easy-way-to-pull-latest-of-all-git-submodules
Git Submodule变更
这个稍微麻烦一点,可以参考:https://stackoverflow.com/questions/913701/how-to-change-the-remote-repository-for-a-git-submodule
git submodule sync
https://stackoverflow.com/questions/16727110/forked-git-submodule-and-changed-source-url-but-clone-still-pulls-old-source-u
Submodule点进去发现404
用git clone --recursive的时候报错Fetched in submodule path ‘Hazel/vendor/imgui’, but it did not contain babcc121b86274e4e920fede44a407cd5b96df4b. Direct fetching of that commit failed.然后进我的Github仓库,点进去对应的submodule,发现Github显示404
这是因为我之前改动了submodule,而且进行了commit,但是没有push到remotes上,所以需要回去对应的submodule,用git reset --hard 回到特定的版本,重新加上对应的内容,再重新add、commit和push,然后再去submodule的父项目,重新add和commit对应submodule的内容
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本