最近在作一个上传的客户端,上传的部分由后端同窗以 SDK 的方式提供,所以该 SDK 是在一个独立的仓库,那么对于客户端该如何方便的集成该 SDK 呢?每次 SDK 更新把代码拷贝到客户端仓库?把 SDK 发布到 npm?这就能够考虑用 git 的 submodule。git
submodule 是一个多项目管理工具,它容许将子项目以独立的 git 项目添加到主项目,而主项目以 submodule 的形式拥有子项目。子项目拥有本身的 commit、push、pull,而与主项目互不干扰。主项目只须要记录子项目的地址和所须要的 commit id,经过地址和 commit id 就可以获得对应的子项目。github
一般状况下,咱们都有一个主项目(MainProject),在 MainProject 文件夹下执行以下命令,便可添加 submodule。npm
/*
url: 子项目远程地址或本地地址
path: 子项目路径,可省略
*/
$ git submodule add [url] [path]
例: git add submodule git@github.com:fengyueran/UploaderSDK.git ./src/UploaderSDK
复制代码
git status 能够看到以下信息后端
On branch master
Changes to be committed:
new file: .gitmodules
new file: UploaderSDK
复制代码
能够看到多了两个文件: .gitmodules 和 UploaderSDK。 cat .gitmodules 看到.gitmodules 储存了 submodule 的路径及远程地址。缓存
[submodule "src/uploaderSDK"]
path = src/uploaderSDK
url = git@github.com:fengyueran/UploaderSDK.git
复制代码
UploaderSDK 的内容为 submodule 的 commit id。bash
Subproject commit 6b53e1840b27ca1587b96c1eb9dd5f4ff0866089
复制代码
不难想象经过.gitmodules 和 UploaderSDK 的信息就能够拿到 submodule 的内容了,所以咱们须要提交这个两个文件。工具
git add .
git commit -m "add submodule"
复制代码
主要有两个方式测试
1. 采用先克隆后更新的方式ui
和想象中的不同,直接 clone 主项目,submodule 并不会跟着 clone 下来,而只有包含 submodule 名的空文件夹。url
1)$ git clone git@github.com:fengyueran/MainProject.git
复制代码
需再执行以下命令
2)$ git submodule init
复制代码
输出以下,能够看到该命令给子项目注册了路径,即在主项目中的位置。此时,uploaderSDK 文件夹仍未空。
Submodule 'src/uploaderSDK' (git@github.com:fengyueran/UploaderSDK.git) registered for path 'src/uploaderSDK'
复制代码
再执行
//该命令并非直接更新到最新的submodule commit,而是更新至主项目所存储存的commit(有多是较旧的commit)。
3)$ git submodule update
复制代码
输出以下,能够看到 sumodule 获得更新,更新到主项目存储的 submodule commit,是一个游离的 git header。
Cloning into '/Work/test/MainProject/tmp/MainProject/src/uploaderSDK'...
Submodule path 'src/uploaderSDK': checked out '6b53e1840b27ca1587b96c1eb9dd5f4ff0866089'
复制代码
2. 采用递归参数--recursive
git clone git@github.com:fengyueran/MainProject.git --recursive
复制代码
输出以下,能够看到主项目包括 submodule 都被 clone 下来了。
Cloning into 'MainProject'...
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (4/4), done.
Receiving objects: 100% (7/7), done.
remote: Total 7 (delta 0), reused 4 (delta 0), pack-reused 0
Submodule 'src/uploaderSDK' (git@github.com:fengyueran/UploaderSDK.git) registered for path 'src/uploaderSDK'
Cloning into '/Work/test/MainProject/tmp/MainProject/tmp/MainProject/src/uploaderSDK'...
Submodule path 'src/uploaderSDK': checked out '6b53e1840b27ca1587b96c1eb9dd5f4ff0866089'
复制代码
主要有两种状况
1. 直接在主项目中的 submodule 下修改
如上例,直接在 MainProject 下的 src/uploaderSDK 中修改,uploaderSDK 切换到工做分支,修改并提交后,能够 checkout 到最新的 commit,也能够不切,反正都在当前最新的 commit 上(若是想测试其余 commit 也能够切换到相应 commit 上),此时 MainProject 中咱们能够看到 src/uploaderSDK 的 commit 有以下变化
-Subproject commit 6b53e1840b27ca1587b96c1eb9dd5f4ff0866089
+Subproject commit a4d6dc0457673a275b1f6cbeda6f8ff23293b9de
复制代码
a4d6 为修改的提交,须要注意的地方是此时 submodule 已经在最新的 commit 上了,不要再在 MainProject 中 git submodule update 进行更新了,若是进行此操做 submodule 又会回到原来的 commit(带有减号的 commit),只须要在 MainProject 提交,并在必要的时候 push 到远程仓库。这种方法,非 submodule 的开发人员就不用关心 submodule 是否更新了,只须要在 MainProject 下 pull 代码发现 submodule 有更改时执行 git submodule update(更新为带减号 commit)进行更新,前提是其余开发人员提交了正确的 submodule commit。
2. 在 submodule 本身独立的仓库进行修改
在工做目录克隆下 submodule 的仓库,切换到工做分支进行修改提交并 push 到远程仓库。这种方法须要 submodule 开发人员告诉 MainProject 的开发人员 submodule 有更新或主动查看是否有更新,有更新时就在 MainProject 的 src/uploaderSDK 下 pull 远程代码(须要知道 submodule 的工做分支),快速合并后,uploaderSDK 的 commit 有以下变化,此时同 1 不要 git submodule update,而只是在 MainProject 下提交这个更改。
-Subproject commit f4573cc1bb50000779202c7f56a640b1ffc075cb
+Subproject commit 64ae6d149c0f6e3b06b8cea262c6126a7bc0887f
复制代码
执行以下命令
逆初始化模块,submodule为子模块目录,执行后可发现子模块目录被清空
$ git submodule deinit [submodule_name]
-> Cleared directory 'test2sub'
Submodule 'test2sub' (git@github.com:fengyueran/test2sub.git) unregistered for path 'test2sub'
//执行以下命令还能看到子项目信息
$ git submodule
-> -dab52c62f52353d9967619625c28e28dc4320aef test2sub
复制代码
--
cached [submodule_name]// 删除.gitmodules中记录的模块信息(--cached选项清除.git/modules中的缓存)
git rm --cached test2sub
//执行以下命令已看看不到删除的子项目信息了
$ git submodule
复制代码
git commit -m "remove submodule"
复制代码