Git Submodule 使用

Git Submodule 使用,第1张

git 的 submodule 作为一个独立的 repo , 其拥有普通 repo 全部的功能, 我们可以完全按照普通的 repo 管理命令来进入 submodule 中进行手动管理. 不过如果存在多个 submodule 位于同一 superproject 下时, 掌握一些 git submodule ... 命令就变得尤为重要了.

本文列出了常用的一些 git submodule 管理命令, 并举出实际应用中遇到的问题及解决方案.

在 git 仓库 superproject 的目录中使用 git submodule add https://github/HanleyLee/C 即可将 https://github/HanleyLee/C 作为一个 submodule 被 superproject 依赖与管理.

当 submodule 被修改时我们可以在 superproject 中得到通知:

在 repo Test 作为 submodule 被 superproject 管理后:

添加 git submodule 的方法很简单, 使用 git submodule add <repo url> 即可. 添加完之后, 在 superproject 的目录下会产生一个 .gitmodule 文件, 文件的结构如下:

可以看到, .gitmodule 文件中标记了每一个 submodule 的 path 与 url .

然后我们进入 ./C :

我们发现 ./C/.git 竟然是一个文件 (常规 git 目录中的 .git 是文件夹), 然后其内容指向了另一个文件夹 (类似于指针), 我们再去到那个文件夹:

我们发现这个文件夹才是 submodule 的真实 .git 文件夹, 我们对于 submodule 的所做的 commit 信息也都保存在这里.

默认情况下, git pull 命令会递归地抓取子模块的更改 (fetch), 然而, 它不会将 submodule merge 到所跟踪的分支上. 因此我们还需要执行 git submodule update .

如果我们想一句话解决, 那么可以使用 git pull --recurse-submodule , 这个可以在拉取完 submodule 后再将其 merge 到所跟踪的分支上.

如果我们想让 Git 总是以 --recurse-submodules 拉取, 可以将配置选项 submodule.recurse 设置为 true . 具体命令为 git config --global submodule.recurse true . 此选项会让 Git 为所有支持 --recurse-submodules 的命令使用该选项 (除 clone 以外).

如果我们在主项目中提交并推送但并不推送子模块上的改动, 其他尝试检出我们修改的人会遇到麻烦, 因为他们无法得到依赖的子模块改动. 那些改动只存在于我们本地的拷贝中.

为了确保这不会发生, 我们可以让 Git 在推送到主项目前检查所有 submodule 是否已推送. git push 命令接受可以设置为 check 或 on-demand 的 --recurse-submodules 参数. 如果任何提交的 submodule 改动没有推送那么 check 选项会直接使 push *** 作失败.(此外还有 demand , while , no 选项, 参考前节命令列表进行理解)

为了以后方便, 我们可以设置默认检查 git config --global push.recurseSubmodules check

很多人用了 git submodule 后, 都发现每次 update 之后, submodule 中的 HEAD 都是 detached 状态的, 即使本次 git checkout master 后, 下次更新仍然恢复原样, 难道就没有办法使其固定在某个 branch 上吗? 经过研究, 参考 stackoverflow 的答案, 我发现是可以解决的.

问题的关键在于 .gitmodule 的配置:

我们需要添加 update = rebase 这行, 根据 git official 的说明

submodule 的 update 有多种选择, 默认情况下是 checkout , 其会根据 superproject 所记录的 submodule 的 commit 进行 checkout. 类似于 git checkout 4eda5fgrd , 这必然导致 submodule 的 HEAD 处于 detached 状态. 解决办法就是使用 rebase ( merge 也可以), 这样当我们对 submodule 设置了一个初始的 branch 后, 其以后都只会在这个 branch 上对远程的最新 commit 进行 rebase , 不会导致 detached 状态的产生.

以 submodule 的目录为 ./C/ 为例. 具体的解决步骤如下:

此时, 以后再使用 git submodule update 就不会有 detached 状态的产生了

添加后会多一个 .gitmodules 文件,文件的内容只是保存submodule的引用信息,包括路径和repo地址

添加完后需要在主项目 git commit 提交新增子项目文件夹以及 .gitmodules 文件的修改

在子项目加入到项目的时候,其实做了这样三件事:

所以在当前项目push到remote repository的时候,只是更新了引用的 commit id ,那么在其他人clone项目的时候,就可以获取子项目的 commit id ,然后在 git submodule update 的时候获取子项目 commit id 所表示的commit

查看子模块的commit id,如果子模块没有被checkout,前面会有 - ,那么就需要 git submodule init , git submodule update

clone带有submodule的项目的两种方法:

其实相当于

注意,在clone之后, cd submodule/ ,然后 git status ,你会看到这样的状态

也就是说,现在是 detached HEAD ,使用 git branch 就可以查看到

所以需要 git checkout master 到master分支,然后在master分支上修改

为什么呢?因为父项目不记录子模块的修改,只记录commit id,所以clone的时候只获取到对应的commit,而不在任何分支上,但是master分支的commit id和HEAD保持一致,所以只要 git checkout master ,而不需要新建分支

注意: 只有子项目内容更新,就需要更新父项目引用的子项目的commit id

其实子项目和父项目只是独立的git项目,所以其他 *** 作和一般git项目一样,在子项目修改,需要

其实普通的git项目一样 *** 作,然后需要在父项目更新引用的子项目commit id,有 两 一种方法:

为什么这种方法不行呢,其实是个坑!就是你 git submodule update 之后,你的子项目会恢复到你父项目引用的那个commit,也就是不是最新的commit,此时 git status 是干净的,就像第一次 git clone 项目然后 git submodule init , git submodule update 一样,子项目指向的是父项目引用的那个commit,所以此时把子项目 git checkout master 之后,再切回到父项目,使用 git status ,你会发现提示子项目有新的commit,所以还是需要父项目更新引用的子项目的commit id

注意: 如果更新submodule的时候有新的commit id产生,需要在父项目产生一个提交,用来更新对子项目commit id的引用

两种方法:

子项目一旦产生变动,有新的commit id,父项目必需产生一个提交,更新对子项目commit id的引用

Git Submodule使用完整教程

使用Git Submodule管理子模块

Git submodule的坑

有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。 也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。这种情况就可以使用Git子模块。

clone地址: https://github.com/xxx/parent.git

clone地址: https://github.com/xxx/child.git

注: 创建仓库的时候勾选README.md,保证不是空仓库

在父目录下,执行 git submodule add https://github.com/xxx/child.git

这时运行 git status

会出现

此时执行

如果单纯的使用git clone命令,当你在克隆这样的项目时,默认会包含该子模块目录,但其中还没有任何文件。解决办法:

git submodule update --remote Git 默认会尝试更新 所有 子模块, 所以如果有很多子模块的话,你可以传递想要更新的子模块的名字。例: git submodule update --remote submoduleName

此命令默认会假定你想要更新并检出子模块仓库的 master 分支,不过你也可以设置为想要的其他分支,那么既可以在 .gitmodules 文件中设置 (这样其他人也可以跟踪它),也可以只在本地的 .git/config 文件中设置。

git config -f .gitmodules submodule.submoduleName.branch develop

如果你想自动化此过程,那么可以为 git pull 命令添加 --recurse-submodules 选项(从 Git 2.14 开始)。

你想让 Git 总是以 --recurse-submodules 拉取,可以将配置选项 submodule.recurse 设置为 true (从 Git 2.15 开始可用于 git pull)。此选项会让 Git 为所有支持 --recurse-submodules 的命令使用该选项(除 clone 以外)。

步骤如下:

rm -rf 子模块目录 删除子模块目录及源码

vi .gitmodules 删除项目目录下.gitmodules文件中子模块相关条目

vi .git/config 删除配置项中子模块相关条目

rm .git/module/* 删除模块下的子模块目录,每个子模块对应一个目录,注意只删除对应的子模块目录即可

执行完成后,再执行添加子模块命令即可,如果仍然报错,执行如下:

git rm -f --cached 子模块名称

完成删除后,提交到仓库即可。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/7906879.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-11
下一篇2023-04-11

发表评论

登录后才能评论

评论列表(0条)

    保存