来说说坑爹的 git submodule

11,509 阅读4分钟

git submoduleGit自带的子模块管理命令,作为一个写了5年代码的low b,之前完全没有用过这个东东,现在的项目中有位同志使用来了这个神奇的命令。然后,我修改了子模块库的代码,却不知道怎么提交。

一、首先我来说我遇到的问题以及解决过程:

1.首先我惯常的采用git commit -am "xxxx"进行提交,结果,并没有卵用。然后,查阅资料之后,我知道了,嗯,因为主模块是不会自动帮你管理子模块的,所以,子模块的修改,你需要到子模块仓库操作,于是,我切换到子模块目录进行操作,git comit -am "sssss", 添加成功,然后git push,阿哈!报错了,detached HEAD,我真是日了狗!查阅资料后我了解到,git submodule update之后,子模块会自动切换到一个detached branch!这tmd都是什么玩意儿。。。于是,我狗怂的chekcout子模块的master分支,然后cherry-pick我的修改,合并到master,然后再来,git commit -am "ssss" && git push,好了,世界安静了,我装逼的以为一切都好了。于是,切换到主仓库,git push --recurse-submodules=on-demand && git submodule update
2.然后,悲剧发生了!子模块的修改全没有了!我浑身颤抖,切换到子模块仓库,想着实在不行,我还有reflog,但是,我常识性的git status看了下,发现,我又tmd回到了Detached HEAD上,然后我切换到master分支,git log查看,发现我的提交记录是有的,master接收了我的推送。那么,问题来了,为什么git submodule udpate 就会更新到一个detached branch,并且,修改都不见了呢?我再次查阅资料,发现了一件事情:Git默认是将主模块跟子模块分开管理的!子模块就算是提交了更新,主模块也不会自动更新, 主模块记录了上次提交的submodule的SHA值,也就是,主模块已经把子模块记录在提交过的某次更新状态了,主模块需要添加子模块的更新,重新提交,这次的子模块更新才会被主模块记录。我在主模块git status,果然,显示子模块的目录有更新,然后我git diff, tmd居然不显示任何差异!!!我只能又去查资料了。。。大神说,主模块会把子模块当作是一个相当于binary文件的东西,只记录更改,没办法显示更新内容,所以,git diff不显示任何信息,这就对了!我重新 git commit -am "xxxx" ./submoduleDir && git push, 显示推送成功!然后我再 git submodule update 好了,一切都正常了!

二、总结一下:

1.喜欢使用git commit -am "xxxxx" && git push 的玩家可以下线了,友情提示:子模块的更新会丢!你得把子模块当作单独的仓库!虽然你可以git push --recurse-submodules=on-demand在推送代码的时候让Git同时推送子模块的修改。但是,但是啊!主模块不会给你递归添加修改和提交!所以,你要先去子模块下 git commit -am "ssss", 先提交你的修改到子模块的跟踪远程分支!然后,我觉得,既然你都提交了,为啥不自己推送一下啊!所以,我觉得,git push --recurse-submodules 很鸡肋!很鸡肋!
2.子模块修改提交之后,一定要回去主项目添加子模块的修改,其实,就是告诉主项目使用更新后的子模块,然后再将修改提交到远程。这样,主项目中对子模块的引用才会更新,要不然,你会神奇的发现,你主项目只要git submodule update就会回到没有修改的版本。

综上,记住两点:子模块是另一个仓库!子模块是另一个仓库!子模块是另一个仓库!重要的话说三遍。 更新子模块不会自动更新主模块的引用!更新子模块不会自动更新主模块的引用!更新子模块不会自动更新主模块的引用!重要的话同样说三遍!

其实,git submodule 在一些更复杂的情况下,更让你崩溃,比如冲突合并。到目前为止,笔者还没有进过这种坑。

关于submodule更多坑的介绍,请阅读此链接 submodule的坑 另外这个链接有很多关于填坑的讨论 submodule问题解决