git submodule 的使用

https://git-scm.com/book/zh/v2/Git-工具-子模块

0. 添加子模块

git submodule add [https://github.com/JwwwL/hexo-theme-matery.git](https://github.com/JwwwL/hexo-theme-matery.git) themes/hexo-theme-matery
git status
git commit -am 'added DbConnector module'
git push origin master

1. 克隆含有子模块的项目

尚未克隆主项目时:

git clone --recurse-submodules https://github.com/chaconinc/MainProject

已经克隆主项目,但未处理子模块时:

git submodule update --init --recursive

2. 在包含子模块的项目上工作

2.1. 从子模块的远端拉取上游修改

在项目中使用子模块的最简模型,就是只使用子项目并不时地获取更新,而并不在你的检出中进行任何更改。

方法1(在主项目中执行):

git submodule update --remote

Git 将会进入子模块然后抓取并更新。此命令默认会假定你想要更新并检出子模块仓库的 master 分支。 不过你也可以设置为想要的其他分支,在 .gitmodules 文件中设置它:git config -f .gitmodules submodule.DbConnector.branch stable,然后 git submodule update --remote,注意修改子模块名和分支名。查看当前分支:进入子模块目录,git status

方法2(进入子模块目录执行):

# 正常使用项目管理的拉取更新方法
git pull
# or
git pull --rebase

2.2. 从主项目的远端拉取上游更改

git pull
git submodule update --init --recursive

当 .gitmodules 文件中记录的子模块的 URL 发生了改变时,第二步会失败,这时需要:

# 将新的 URL 复制到本地配置中
$ git submodule sync --recursive
# 从新 URL 更新子模块
$ git submodule update --init --recursive

2.3. 在子模块上工作

你很有可能正在使用子模块,因为你确实想在子模块中编写代码的同时,还想在主项目上编写代码(或者跨子模块工作)。 否则你大概只能用简单的依赖管理系统(如 Maven 或 Rubygems)来替代了。

到目前为止,当我们运行 git submodule update 从子模块仓库中抓取修改时, Git 将会获得这些改动并更新子目录中的文件,但是会将子仓库留在一个称作“游离的 HEAD”的状态。 这意味着没有本地工作分支(例如 “master” )跟踪改动。 如果没有工作分支跟踪更改,也就意味着即便你将更改提交到了子模块,这些更改也很可能会在下次运行 git submodule update 时丢失。如果你想要在子模块中跟踪这些修改,还需要一些额外的步骤。

为了将子模块设置得更容易进入并修改,你需要做两件事。 首先,进入每个子模块并检出其相应的工作分支。 接着,若你做了更改就需要告诉 Git 它该做什么,然后运行 git submodule update --remote 和参数来从上游拉取新工作。 你可以选择将它们合并到你的本地工作中,也可以尝试将你的工作变基到新的更改上。合并或变基中如果有冲突,像正常平时那样解决就行。

方法1(在主项目中执行):

# 进入子模块目录,检出分支
# pro git 中要求这个,但是实际操作似乎不需要,有分支在不用检出
cd DbConnector/
git checkout stable

# 方法1 -------------------------------------
# 使用 merge 同步远端修改
cd ..
git submodule update --remote --merge
# 进入子模块目录做自己的工作,然后提交
cd DbConnector/
vim src/db.c
git commit -am 'unicode support'

# 方法2 -------------------------------------
# 使用 rebase 同步远端修改
cd ..
git submodule update --remote --rebase
cd DbConnector/
vim src/db.c
git commit -am 'unicode support'

方法2(进入子模块目录执行):

# 进入子模块目录
cd DbConnector/

git pull
# 或者
git pull --rebase

2.4. 发布整个项目 (包括子模块) 的改动

# 在主项目目录中执行,一起推送主项目和所有子模块
git push --recurse-submodules=on-demand

# 或者手动进入每个子模块目录,手动推送每个子模块

2.5. 合并子模块改动

【本小节为阅读《Pro Git》后的理解笔记,尚未实操验证,仅参考】

【详见《Pro Git》7.11】

可能发生在 2.2. 的 git pull 中,当自己改了本地子模块内容,远程库中的子模块也有修改时。

当在主项目中试图合并两个分支时,如果这两个分支中的子模块是不同的,不过一个提交是另一个的直接祖先(一个快进式合并),那么 Git 会简单地选择之后的提交来合并,这样没什么问题。

当在主项目中试图合并两个分支时,如果这两个分支中的子模块是不同的且是分叉的。例如,两个主项目分支,一个中的子模块的提交把a改成了b,另一个中的子模块的提交把a改成了c。即,子模块如果不是子模块,当作普通项目合并时,会有冲突的情况,这个情况现在被包含在了一个父项目的合并内。

解决方法是在主项目查看要合并的分支的提交的 SHA-1,进入子模块目录根据 SHA-1 手动合并,并解决冲突,然后返回主项目目录,add 修改,commit。其实就是普通 merge 中,需要解决的冲突出现在子模块内,导致需要进入子模块手动 merge 解决冲突,然后回到主项目进行冲突解决完成后的步骤。

git pull

git diff
cd DbConnector
git rev-parse HEAD
git branch try-merge c771610
git merge try-merge
vim src/main.c
git add src/main.c
git commit -am 'merged our changes'

cd ..
git diff
git add DbConnector
git commit -m "Merge Tom's Changes"

或者当这种情况发生时,git submodule update --remote --mergegit submodule update --remote --rebase 先更新子模块并解决其中的冲突,再重新 git pull 就行了。

3. 删除子模块

删除子模块比较麻烦,需要手动删除相关的文件,否则在添加子模块时有可能出现错误,以删除assets子模块为例

  1. 删除子模块文件夹
git rm --cached assets
rm -rf assets
  1. 删除.gitmodules文件中相关子模块信息
[submodule "assets"]
  path = assets
  url = https://github.com/maonx/vimwiki-assets.git
  1. 删除.git/config中的相关子模块信息
[submodule "assets"]
  url = https://github.com/maonx/vimwiki-assets.git
  1. 删除.git文件夹中的相关子模块文件
rm -rf .git/modules/assets

4. 杂项

git 目录下再有 git clone 仓库时,用 submodule。

如果子仓库不是自己的仓库且需要修改其中内容时,fork 到自己账号再 clone、添加 submodule。

进入子模块,当作正常仓库 pull、work、add、commit、push。然后进入主项目,当作正常仓库 pull、work、add、commit、push。

两种路线。全在主项目中操作,用好多 git submodule 命令;手动切换父子,基本是普通 git 操作,只有涉及父子交互才需要 git submodule,例如主项目中 .gitmodules 文件中引用子模块发生变化时。

分支中添加了子模块之后,切换到其他没有该子模块的分支时,在工作区中该子模块仍会显示,只是 untracked 状态,要注意不要在此时(没有添加该子模块的分支)修改其中的内容,会丢失。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2019-2021 Jarvis Li
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信