今天上午在 tg 频道看到一则消息:

中国最著名的公共 CDN 服务 BootCDN 昨日停止服务。

cdn.bootcss.com 解析到一台境外服务器,且 www.bootcdn.cn 上所有文件链接已经指向 cdnjs.cloudflare.com

突然想起,昨天晚上本来想打开博客查一个笔记的,结果打不开(当然我是常年挂梯子的。。
开始以为是什么偶然的连通性问题,没多太在意,没有那么敏锐的察觉能力。
然后马上去开了下博客,打不开,看请求,果然是有个js用了bootcdn:

1
http://cdn.bootcss.com/node-waves/0.7.4/waves.min.js

这样,只需要是博客主题包的源文件中,找到这行代码,改为可用的cdn地址即可,比如说

1
https://cdnjs.cloudflare.com/ajax/libs/node-waves/0.7.6/waves.min.js

但是之前迁移博客源码仓库的时候,太 过 唐 突
直接把博客主题 git clone 进项目的,然后加上 gitignore 忽略掉,这样不是优雅的做法。
ps: 我博客的仓库里面是md文件和一些配置文件的;主题的代码我也做了写调整和魔改,比如菜单栏的机器人icon是新版的图标库才有的,所以单独存了个仓库。
所以本文其实要说的是:
如果一个程序(仓库)依赖与另一个程序(仓库),但是又需要同时开发,分开存储版本迭代信息,如何优雅的解决这个问题?答案就是submodule。

添加 Submodule

submodule 是git的二级命令,从字面意思上看,就是子模块。
将仓库添加到当前目录,目录相对仓库的路径为current directory

1
git submodule add https://github.com/username/module

运行完后,repository仓库最新的commit会被checkout到当前目录,在网页上可以看到目录名为module@<commit-id>是一个6位数的crc32 id。
并且会添加一个.gitmodules的文件到仓库的根目录,内容为:

1
2
3
[submodule "current directory"]
path = current directory
url = https://github.com/username/module

然后 commit,push,主仓库就会有子模块的引用信息。

clone 包含 submodule 的仓库

比如以上面例子的仓库名为repo。

  1. 递归式 clone 这个repo:
    1
    git clone --recursive https://github.com/username/repo

它就会自动初始化并更新仓库中的每一个子模块。

  1. 传统方式是:
    1
    git clone https://github.com/username/repo

这个时候进入仓库目录,submodule的子目录下面是空的,因为默认不会把submodule一同checkout出来。
接着执行两条命令,初始化子模块

1
2
git submodule init
git submodule update

这个时候submodule子目录就有文件了。

如果你更改了子模块,比如更新了主题的相关文件,像平常一样 add-commit-push.
这里需要注意,子模块的分支默认不是master.
我们可以到子模块的目录下

1
2
3
4
git checkout master
cd ..
git submodule foreach git pull
cd ..

即可更新
似乎是这样(逃

submodule的更多详细用法可以参考git官方文档:https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97