有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。
我们举一个例子。 假设你正在开发一个网站然后创建了 Atom 订阅。 你决定使用一个库,而不是写自己的 Atom 生成代码。 你可能不得不通过 CPAN 安装或 Ruby gem 来包含共享库中的代码,或者将源代码直接拷贝到自己的项目中。 如果将这个库包含进来,那么无论用何种方式都很难定制它,部署则更加困难,因为你必须确保每一个客户端都包含该库。 如果将代码复制到自己的项目中,那么你做的任何自定义修改都会使合并上游的改动变得困难。
Git 通过子模块来解决这个问题。 子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
我们假设这样一种情况,本地的测试项目结构如下:
其中 LearnLocal 是主项目,对应的远程项目路径为:ssh://[ssh]/learn.git
LearnSubLocal是子项目,对应的远程项目路径为:ssh://[ssh]/learnSub.git
如果我们直接在 LearnLocal 文件夹下执行:git add LearnSubLocal/ 会发生什么?
$ git add LearnSubLocal/ warning: adding embedded git repository: LearnSubLocal hint: You've added another git repository inside your current repository. hint: Clones of the outer repository will not contain the contents of hint: the embedded repository and will not know how to obtain it. hint: If you meant to add a submodule, use: hint: hint: git submodule add <url> LearnSubLocal hint: hint: If you added this path by mistake, you can remove it from the hint: index with: hint: hint: git rm --cached LearnSubLocal hint: hint: See "git help submodule" for more information.
在终端里多了许多平常没见到的提示,比如:
warning: adding embedded git repository: LearnSubLocal
(警告:正在添加嵌入的git项目:LearnSubLocal)
这是因为 LearnSubLocal 实际上关联了另一个 git 工作区,我们可以在这个文件夹下看到 .git 文件夹,代表这是一个git工作区。
现在我们暂且不关心这个警告,直接继续提交,并且推送到远端,会发生什么呢?
git commit -m "Add LearnSubLocal" git push origin master
在远程网页看到,工程已经提交上去了
但是会发现这个文件夹点击不了,也就是说在远程没办法看到子项目的内容。
我们尝试性在本地clone这个仓库,得到的结果是:
发现LearnSubLocal仍旧是空的,也就是说在已有的git工作区提交另一个子git工作区失效,只能提交这个文件夹,内容却提交不了。
如果想要提交这个文件夹及其里面的内容,有如下三种办法
2. 如果想要保留 .git 文件夹,一种取巧的办法是将其压缩为 zip文件,再上传(还是要删除.git文件夹)
3. submodule 功能(今天的主角)
现在我们创建一个只有主模块的文件夹:Learn.git
这个文件夹下面只有 README.md 文件
执行指令:
$ git submodule add ssh://[ssh]/learnsub.git
将learnsub.git注册和添加为Learn.git的模块
这个指令会在运行 git 命令的文件夹下新建一个同名文件夹,如果你想命名到自定义路径可以按照这样的指令结构修改:git submodule url path
指令执行的结果是:添加了learnsub文件夹,以及添加了.gitmodules
learnsub我们知道是什么,.gitmodules呢?
看看便知:
$ vim .gitmodules
这个文件建立了子模块文件夹和url的映射关系,如果你添加了多个自模块,这里会有多个映射关系。
查看下当前工作环境
$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: .gitmodules new file: learnsub
再次提交:
$ git add ./ $ git commit -m "Add submodule" [master 2f86134] Add submodule 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 learnsub $ git push origin master
看看远程仓库变成什么样了?
这时候点击 learnsub 文件夹,他会根据.gitmodules的映射关系跳转到对应的子模块仓库。
现在推送到远端的操作完成了,主模块也建立了子模块文件夹与url的映射关系。
接着我们来试试从远端clone:
$ git clone ssh://[ssh]/learn.git
看起来一切安好
点进learnsub里面看看:
诶,为什么文件夹里面是空的?
根据官网的介绍,你必须运行两个命令:
git submodule init 用来初始化本地配置文件, git submodule update 则从该项目中抓取所有数据并检出父项目中列出的合适的提交。
也可以用下面的指令一步到位:
git submodule update --init --recursive
用用看:
$ git submodule init Submodule 'learnsub' (ssh://[ssh]/learnsub.git) registered for path 'learnsub' $ git submodule update Cloning into 'C:/Users/[path]/learn/learnsub'... Submodule path 'learnsub': checked out 'fb2971eb3355cef677448d93xxxxxxxxcc1'
搞定了!!!
恭喜你,可以接着愉快的开发了(秃头了)。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!