git submodule的使用
1. submodule简介
submodule是一种git特性,用以将一部分公共代码从主项目中抽离出来成为一个独立的git工程,并以submodule的形式被主项目使用,submodule和主项目(作为区分,本文叫主模块)充分解耦,这样做的好处是作为submodule的公共代码可以被多个主项目工程使用,减少了开发量和版本控制负担。同时,submodule作为独立的git工程,也使得权限管理、代码修改更加灵活。
举个例子,多个互相通信的项目,可以将通信协议部分独立出来作为submodule,所有项目维护同一套通信协议。类似于一个maven中的依赖,但不同的是maven依赖基本上使用者不会去修改依赖的库,但submodule通常需要被使用者修改。
2. submodule使用
我们举例说明submodule的使用方式,有A和B两个开发者协作开发一套系统,其中需要使用一个submodule,我们以时间轴的顺序看看会发生什么情形,以及对应的处理方式。
day1:开发者A为主模块添加submodule
上面代码中, submodule_url是子模块远程仓库地址,submodule_dir是要创建的文件夹名,用来放submodule的代码 。执行后,submodule_dir被创建,但是空的,因为还没有拉取子模块的代码。.gitmodules文件记录子模块的信息。打开.gitmodules文件,可以看到:
对于submodule_dir,git在提交时不是当作一个普通的子目录提交,只是记录子模块commit信息,本地子模块目录里的文件不会被push到远程仓库,clone主项目时也只会获取submodule_dir空目录而已。
day2:开发者B克隆主模块到本地,同时初始化子模块
注意,git submodule update拉取的代码是父项目中记录的那个submodule版本,但不一定是submoudle远程仓库里最新的版本。要充分理解这个概念。
可以注意下git submodule update执行后屏幕上打印的信息,最后一句是下面这样:
当我们运行 git submodule update 从子模块仓库中抓取修改时, Git 将会获得这些改动并更新子目录中的文件,但是会将子仓库留在一个称作“detached HEAD”的状态,或者叫游离态。如果我们进入子模块目录执行git branch,可以看到当前HEAD不在任何分支:
如果进入游离态,那么意味着没有分支去跟踪我们的更改,即使子模块代码被我们本地修改了,下次update的时候可能就丢失了。如果出现这个情况,我们需要checkout回我们的工作分支:
关于游离态的问题,后面具体情形遇到时再细说。
day3:开发者B拉取远程更新(包括主模块和子模块)
注意:
1,在主模块目录pull会更新主模块,但是对于子模块,只会获取子模块的更新记录,但不会去更新子模块文件。
2,子模块submodule update方式更新,需要加–remote和–merge,其中–remote表示将子模块远程仓库的更新合并到本地(否则还是主模块里记录的最后commit的那个submodule版本,而不一定是子模块远程最新版本),–merge表示将更新合并到本地子模块(也可以–rebase)。如果有多个子模块,全部都会更新。
3,子模块也是一个独立的git工程,因此可以直接进入子模块目录,按普通git工程的方式更新。如果多个子模块,需要一个一个更新。如果子模块不是很多,个人推荐这种方式,避免出现detached问题。
day4:开发者B修改子模块并提交到远程
注意:
push的前提是当前submodule不在detached游离状态,如果在游离态,需要checkout回工作分支(比如master分支)。这里就有3种情况:
1,修改子模块和commit之前,子模块已经处于或者已经从游离态checkout回到工作分支,那么就正常add commit push操作即可;
2,修改了子模块但还没有commit,突然想起来当前处于detached状态,这个时候因为有未提交的修改,checkout会报错,那么你可以git stash先把修改缓存起来,然后checkout回工作分支,再用git stash pop把缓存的修改应用到工作分支上来,或者你想直接丢弃掉修改,那就不pop就好。
3,修改了子模块且commit了,突然想起来当前处于detached状态,这个时候可以checkout回工作分支,但是你commit的修改也就丢失了,这个时候如果需要把这个修改应用到工作分支上,可以把detached HEAD合并到当前工作分支。举例,下面model_training是主项目,odl_config是一个submodule,我们在detached状态下新建一个test.txt文件:
上面我们看到,切换回master分支后,test.txt文件并没有出现在master分支,因为上次修改commit到detached状态上了,commit后到版本号是b6fa872,如果需要把修改同步到当前工作分支,可以执行下面命令:
至此,你完成了修改submodule代码并提交远程,学会了处理detached状态。如果pull时出现conflict,按照git正常处理confilct流程处理就好。
day5: 子模块远程仓库url被修改(不常见的情形)
一种不常见的情形:上游仓库中将子模块的URL做了修改,比如换了域名,远程仓库主模块的.gitmodule文件里子模块的URL会改变,但本地主模块里关于submodule的commit记录还是旧的,这个时候执行submodule update操作时会失败。针对这种情况,需要使用git submodule sync命令:
__EOF__

本文链接:https://www.cnblogs.com/amgulen/p/16740702.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY