Git 子仓(Git Submodule)学习

Git 子仓学习

Git 子仓(Submodule)是 Git 提供的一种功能,用于在一个 Git 仓库(称为主仓库或 superproject)中嵌入另一个 Git 仓库(称为子仓或 submodule)。这种功能在管理大型项目或依赖关系较多的项目时非常有用。

Git 子仓的特点和用途

  1. 模块化管理:可以将项目中的某些部分独立成一个子仓库进行独立管理,这样可以保持代码的模块化和独立性。
  2. 版本一致性:每个子仓都有独立的版本控制,可以锁定在某个特定的提交或版本,从而保证主项目中使用的子仓版本的稳定性。
  3. 复用代码:子仓可以在多个项目中复用,避免代码重复和版本不一致的问题。

添加已有的子仓

使用 git submodule add 命令可以将一个已存在的 Git 仓库添加为子仓。

$ git submodule add https://github.com/chaconinc/DbConnector
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.

默认情况下,子仓会将子项目放到一个与仓库同名的目录中,本例中是 “DbConnector”。 如果你想要放到其他地方,那么可以在命令结尾添加一个不同的路径。

可以注意到新的 .gitmodules 文件。 该配置文件保存了项目 URL 与已经拉取的本地目录之间的映射:

[submodule "DbConnector"]path = DbConnectorurl = https://github.com/chaconinc/DbConnector

如果有多个子仓,该文件中就会有多条记录。 要重点注意的是, 该文件也像 .gitignore 文件一样受到(通过)版本控制。 它会和该项目的其他部分一同被拉取推送 。 这就是克隆该项目的人知道去哪获得子仓的原因。

克隆含有子仓的项目

当克隆一个含有子仓的项目时,默认会包含该子仓目录,但其中还没有任何文件:

$ git clone https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
$ cd MainProject/DbConnector/
$ ls
$ 

其中有 DbConnector 目录,不过并不会直接拉取,目录为空。

主仓克隆后手动初始化子仓

为了解决直接克隆无法初始化的问题,必须运行两个命令:

  • git submodule init: 用来初始化本地配置文件
  • git submodule update: 从该项目中抓取所有数据并检出父项目中列出的合适的提交。
$ git submodule init
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
$ git submodule update
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'

其实也有更简单的方法,可以将 git submodule initgit submodule update 合并运行,可以使用命令:

  • git submodule update --init:初始化并拉取当前提交。
  • git submodule update --init --recursive初始化、拉取并检出任何嵌套的子仓

主仓克隆时自动初始化子仓

除了上述方法,还有一种更简单的方式:

  • git clone --recurse-submodules自动初始化并同时更新仓库中的每一个子仓, 包括可能存在的嵌套子仓
$ git clone --recurse-submodules https://github.com/chaconinc/MainProject
Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'DbConnector' (https://github.com/chaconinc/DbConnector) registered for path 'DbConnector'
Cloning into 'DbConnector'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'DbConnector': checked out 'c3f01dc8862123d317dd46284b05b6892c7b29bc'

子仓更新

在子仓直接更新

这是子仓更新最简单的方法,可以进入到子仓目录中运行 git fetchgit merge,合并上游分支来更新本地代码。

$ git fetch
From https://github.com/chaconinc/DbConnectorc3f01dc..d0354fc  master     -> origin/master
$ git merge origin/master
Updating c3f01dc..d0354fc
Fast-forwardscripts/connect.sh | 1 +src/db.c           | 1 +2 files changed, 2 insertions(+)

从主仓拉取子仓更新

作为协作者,当有自己的 MainProject 主仓的本地克隆, 只是执行 git pull 获取你新提交的更改还不够:

$ git pull
From https://github.com/chaconinc/MainProjectfb9093c..0a24cfc  master     -> origin/master
Fetching submodule DbConnector
From https://github.com/chaconinc/DbConnectorc3f01dc..c87d55d  stable     -> origin/stable
Updating fb9093c..0a24cfc
Fast-forward.gitmodules         | 2 +-DbConnector         | 2 +-2 files changed, 2 insertions(+), 2 deletions(-)$ git statusOn branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git checkout -- <file>..." to discard changes in working directory)modified:   DbConnector (new commits)Submodules changed but not updated:* DbConnector c87d55d...c3f01dc (4):< catch non-null terminated lines< more robust error handling< more efficient db routine< better connection routineno changes added to commit (use "git add" and/or "git commit -a")

默认情况下,git pull 命令会递归地抓取子仓的更改,如上面第一个命令的输出所示。

然而,它不会 更新 子仓 。这点可通过 git status 命令看到,它会显示子仓“已修改”,且“有新的提交”。

此外,左边的尖括号(<)指出了新的提交, 表示这些提交已在 MainProject 中记录,但尚未在本地的 DbConnector 中检出

手动拉取单个子仓

由于git pull 不能直接更新子仓,为了完成子仓的更新,还需要在 git pull 后运行 git submodule update

运行 git submodule update --remote 子仓名,Git 将会进入对应子仓然后抓取并更新。

$ git submodule update --remote DbConnector
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector3f19983..d0354fc  master     -> origin/master
Submodule path 'DbConnector': checked out 'd0354fc054692d3906c85c3af05ddce39a1c0644'
手动拉取所有子仓

如果希望一次性直接更新所有子仓,可以使用 git submodule update --init --recursive 直接递归拉取所有子仓:

$ git submodule update --init --recursive
Submodule path 'vendor/plugins/demo': checked out '48679c6302815f6c76f1fe30625d795d9e55fc56'$ git statusOn branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
自动拉取所有子仓

如果想自动化前述过程,直接和主仓的拉取命令结合。那么 可以在主仓的 git pull 命令添加 --recurse-submodules 选项 (从 Git 2.14 开始)。 这会让 Git 在拉取后运行 git submodule update,将子仓置为正确的状态。

$ git pull --recurse-submodules

如果想让 Git 总是以 --recurse-submodules 拉取,可以通过 git config submodule.recurse true 设置 submodule.recurse 选项, 告诉 Git(>=2.14)总是使用 --recurse-submodules

$ git config submodule.recurse true
$ git pull

如上所述,这也会让 Git 为每个拥有 --recurse-submodules 选项的命令(除了 git clone) 总是递归地在子仓中执行。

这样就可以直接在运行 git pull 拉取主仓的时候,同步更新子仓。

子仓检出分支

上述 git submodule update --remote命令默认会假定你想要更新并检出子仓仓库的 master 分支, 不过你也可以设置为想要的其他分支。

例如,你想要 DbConnector 子仓跟踪仓库的 “stable” 分支,那么既可以在 .gitmodules 文件中设置 (这样其他人也可以跟踪它),也可以只在本地的 .git/config 文件中设置。 让我们在 .gitmodules 文件中设置它:

$ git config -f .gitmodules submodule.DbConnector.branch stable$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector27cf5d3..c87d55d  stable -> origin/stable
Submodule path 'DbConnector': checked out 'c87d55d4c6d4b05ee34fbc8cb6f7bf4585ae6687'

如果不用 -f .gitmodules 选项,那么它只会为你做修改。但是在仓库中保留跟踪信息更有意义一些,因为其他人也可以得到同样的效果。

在子仓修改代码

更新子仓

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

为了将子仓设置得更容易进入并修改,首先需要做两件事来更新代码:

  1. 进入每个子仓并检出其相应的工作分支。
  2. 运行 git submodule update --remote 拉取最新的代码。
$ cd DbConnector/
$ git checkout stable
Switched to branch 'stable'
$ cd ..
$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 2), reused 4 (delta 2)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnectorc87d55d..92c7337  stable     -> origin/stable
Updating c87d55d..92c7337
Fast-forwardsrc/main.c | 1 +1 file changed, 1 insertion(+)
Submodule path 'DbConnector': merged in '92c7337b30ef9e0893e758dac2459d07362ab5ea'

如果我们进入 DbConnector 目录,可以发现新的改动已经合并入本地 stable 分支。

将修改代码与远端合并/变基

接着, 可以运行 git submodule update --remote --merge 或者 git submodule update --remote --rebase ,将远端代码合并或者变基到本地提交的代码上。

$ cd DbConnector/
# 修改代码并提交
$ vim src/db.c
$ git commit -am 'unicode support'
[stable f906e16] unicode support1 file changed, 1 insertion(+)
$ cd ..
# 更新子仓
$ git submodule update --remote --rebase
First, rewinding head to replay your work on top of it...
Applying: unicode support
Submodule path 'DbConnector': rebased into '5d60ef9bbebf5a0c1c1050f242ceeb54ad58da94'

如果我们现在更新子仓,就会看到当我们在本地做了更改时上游也有一个改动,我们需要将它并入本地。

如果 忘记 --rebase--merge ,Git 会将子仓更新为服务器上的状态, 并且会将项目重置为一个游离的 HEAD 状态

即便这真的发生了也不要紧,你只需回到目录中 再次检出你的分支(即还包含着你的工作的分支),然后手动地合并或变基 origin/stable(或任何一个你想要的远程分支) 就行了。

本地合并失败的情况

如果没有提交子仓的改动,那么更新子仓也不会成功,此时 Git 会只抓取更改而并不会覆盖子仓目录中未保存的工作:

$ git submodule update --remote
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 4 (delta 0)
Unpacking objects: 100% (4/4), done.
From https://github.com/chaconinc/DbConnector5d60ef9..c75e92a  stable     -> origin/stable
error: Your local changes to the following files would be overwritten by checkout:scripts/setup.sh
Please, commit your changes or stash them before you can switch branches.
Aborting
Unable to checkout 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'

如果改动与远端改动冲突,当运行更新时 Git 也会让你知道:

$ git submodule update --remote --merge
Auto-merging scripts/setup.sh
CONFLICT (content): Merge conflict in scripts/setup.sh
Recorded preimage for 'scripts/setup.sh'
Automatic merge failed; fix conflicts and then commit the result.
Unable to merge 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'DbConnector'

发布子仓改动

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

为了确保这不会发生,可以让 Git 在推送到主仓前检查所有子仓是否已推送。 git push 命令接受可以设置为 “check” 或 “on-demand” 的 --recurse-submodules 参数

子仓推送检查

如果任何提交的子仓改动没有推送,那么 check 选项会直接使 push 操作失败。

$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:DbConnectorPlease trygit push --recurse-submodules=on-demandor cd to the path and usegit pushto push them to a remote.

如你所见,它也给我们了一些有用的建议,指导接下来该如何做。 最简单的选项是进入每一个子仓中然后手动推送到远程仓库,确保它们能被外部访问到,之后再次尝试这次推送。

如果你想要对所有推送都执行检查,那么可以通过设置 git config push.recurseSubmodules check 让它成为默认行为

子仓自动推送

另一个选项是使用 on-demand 值, 会自动检查并推送任何引用了新提交的子仓 。这可以确保主仓库和其子仓之间的引用关系是一致且完整的。

$ git push --recurse-submodules=on-demand
Pushing submodule 'DbConnector'
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 3), reused 0 (delta 0)
To https://github.com/chaconinc/DbConnectorc75e92a..82d2ad3  stable -> stable
Counting objects: 2, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 266 bytes | 0 bytes/s, done.
Total 2 (delta 1), reused 0 (delta 0)
To https://github.com/chaconinc/MainProject3d6d338..9a377d1  master -> master

如你所见,Git 进入到 DbConnector 模块中然后在推送主项目前推送了它。 如果那个子仓因为某些原因推送失败,主项目也会推送失败。

你也可以通过 设置 git config push.recurseSubmodules on-demand 让它成为默认行为

更新子仓远端仓库

.gitmodules 文件中记录的子仓的 URL 发生了改变。此时,若父级项目引用的子仓提交不在仓库中本地配置的子仓远端上,那么执行 git pull --recurse-submodulesgit submodule update 就会失败。

为了补救,需要借助 git submodule sync 命令:

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

子仓技巧

子仓遍历

使用 git submodule foreach 子仓命令,它能在每一个子仓中运行任意命令。

例如,可以创建一个新分支,并将所有子仓都切换过去。

$ git submodule foreach 'git checkout -b featureA'
Entering 'CryptoLibrary'
Switched to a new branch 'featureA'
Entering 'DbConnector'
Switched to a new branch 'featureA'

子仓别名

你可能想为其中一些命令设置别名,因为它们可能会非常长而你又不能设置选项作为它们的默认选项。 我们在 Git 别名 介绍了设置 Git 别名, 但是如果你计划在 Git 中大量使用子仓的话,这里有一些例子。

$ git config alias.sdiff '!'"git diff && git submodule foreach 'git diff'"
$ git config alias.spush 'push --recurse-submodules=on-demand'
$ git config alias.supdate 'submodule update --remote --merge'

这样当你想要更新子仓时可以简单地运行 git supdate,或 git spush 检查子仓依赖后推送。

参考文献

  1. Git - 子仓


部分图片来源网络,如有侵权请联系我删除。
如有疑问或错误,欢迎和我私信交流指正。
版权所有,未经授权,请勿转载!
Copyright © 2024.07 by Mr.Idleman. All rights reserved.


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876009.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CeoMax总裁主题最新3.8.1破解免授权版/WordPress付费资源素材下载主题

CeoMax总裁主题最新3.8.1破解免授权版&#xff0c;一套WordPress付费资源素材下载的主题&#xff0c;感觉这是做资源站唯一一个可以和ripro媲美甚至超越的模板&#xff0c;UI很美&#xff0c;功能也很强大&#xff0c;有想学习的可下载搭建学习一下&#xff0c;仅供学习研究借鉴…

仿学校网页

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width,initial-scale1.0"><title>学校网页</title> <style>.WebTop{backg…

誉天网络安全课程怎么样

学员服务质量保障讲师团队&#xff1a;平均5年课程交付经验&#xff0c;授课质量有保障辅导团队&#xff1a;实验论述辅导讲师&#xff0c;实验备考环境复刻&#xff0c;备考资料完善&#xff0c;及时更新就业服务&#xff1a;简历制作培训&#xff0c;面试技巧培训&#xff0c…

昇思MindSpore学习入门-轻量化数据处理

在资源条件允许的情况下&#xff0c;为了追求更高的性能&#xff0c;一般使用Pipeline模式执行数据变换Transforms。 基于Pipeline模式执行的最大特点是需要使用map方法&#xff0c;如下图中将Resize、Crop、HWC2CHW交由map调度&#xff0c;由其负责启动和执行给定的Transform…

R语言统计分析——控制流

参考资料&#xff1a;R语言实战【第2版】 语句&#xff08;statement&#xff09;是一条单独的R语言或一组复合语言&#xff08;包含在花括号{}中的一组R语言&#xff0c;使用分号分隔&#xff09; 条件&#xff08;cond&#xff09;是一条最终被解析为真&#xff08;TRUE&…

python黑马笔记

运算符&#xff1a; 算术运算符&#xff1a; 加 - 减 * 乘 / 除 // 整除 % 取余 ** 求平方 除法计算得出的结果都是小数 赋值运算符&#xff1a; 标准赋值&#xff1a; 复合赋值&#xff1a; 、 - 、 * 、 / 、// 、 ** 字符串&#xff1a; 字符串拓展内容&#xf…

护网紧急情况应对指南:Linux 应急响应手册

继上一篇&#xff1a;护网紧急情况应对指南&#xff1a;Windows版v1.2全新升级版 之后 收到小伙伴后台要Linux应急手册&#xff0c;今天给大家安排上。 《Linux应急手册》是一本为Linux系统管理员和运维工程师量身打造的实用指南&#xff0c;旨在帮助他们快速应对各种突发状况…

基于FFMPEG和SDL的音视频解码播放的实现过程与相关细节

目录 1、视频播放器原理 2、FFMPEG解码 2.1 FFMPEG库 2.2、数据类型 2.3、解码 2.3.1、接口函数 2.3.2、解码流程 3、SDL播放 3.1、接口函数 3.2、视频播放 3.3、音频播放 4、音视频的同步 4.1、获取音频的播放时间戳 4.2、获取当前视频帧时间戳 4.3、获取视…

MATLAB仿真:数字信号处理用FFT对信号分析

目录 1.实验目的 2 实验原理 3.实验仪器及设备 4.实验步骤及内容 (1)对以下序列进行谱分析。 (2)对以下周期序列进行谱分析。 (3)对模拟周期信号进行谱分析 1.实验目的 学习用 FFT 对连续信号和时域离散信号进行谱分析的方法,了解可能出现的分析误差及其原因,…

CAS算法

CAS算法 1. CAS简介 CAS叫做CompareAndSwap&#xff0c;比较并交换&#xff0c;主要是通过处理器的指令来保证操作的原子性。 CAS基本概念 内存位置 (V)&#xff1a;需要进行CAS操作的内存地址。预期原值 (A)&#xff1a;期望该内存位置上的旧值。新值 (B)&#xff1a;如果旧…

The Llama 3 Herd of Models.Llama 3 模型论文全文

现代人工智能(AI)系统是由基础模型驱动的。本文提出了一套新的基础模型,称为Llama 3。它是一组语言模型,支持多语言、编码、推理和工具使用。我们最大的模型是一个密集的Transformer,具有405B个参数和多达128K个tokens的上下文窗口。本文对Llama 3进行了广泛的实证评价。我们…

DNS 污染/毒化——华为ensp

实验原理:1&#xff0c;用户正常访问 Web页面&#xff0c;会查询本地DNS服务器&#xff0c;一般情况下&#xff0c;本地DNS服务器会设置为 网关地址。2&#xff0c; 攻击者在 用户和网关之间&#xff0c;开启ARP攻击即可&#xff0c;这样&#xff0c;就可以让 用户访问本地DNS服…

【Ant Design Pro】快速上手

初始化 初始化脚手架&#xff1a;快速开始 官方默认使用 umi4&#xff0c;这里文档还没有及时更新&#xff08;不能像文档一样选择 umi 的版本&#xff09;&#xff0c;之后我选择 simple。 然后安装依赖。 在 package.json 中&#xff1a; "start": "cross-e…

卷积的意义及其派生(一)

1.卷积的意义 1.1从LTI的角度看 卷积最开始其实是信号处理中用来描述线性移不变系统Linear time-invariant systems的。线性&#xff0c;表明可以叠加&#xff0c;信号可以拆分成脉冲的响应&#xff1b;时不变&#xff0c;指信号不随着时间的迁移改变&#xff0c;意味着能量守…

【iOS】——通知机制及底层原理

通知传值概要 通知传值可以跨越多个界面进行传值&#xff0c;一般用于后一个界面向前一个界面传值。 通知传值支持多个接收者&#xff0c;多个对象可以同时接收同一个通知并进行处理。这样可以实现一对多的通信&#xff0c;方便跨多个对象进行值传递。 使用步骤 1.在发送者中…

Latent Factor Analysis via Dynamical Systems:LFADS (Nature methods 2018)

Nature Methods&#xff1a;https://www.nature.com/articles/s41592-018-0109-9 LFADS Run Manager for Matlab&#xff1a;https://lfads.github.io/lfads-run-manager/ 目录 Single session:假设&#xff1a;方法&#xff1a;结果&#xff1a; Multi-sessions:假设&#xff…

【C++】位运算:两整数之和

1.题目 2.算法思路 本题不能只用 -&#xff0c;那大概率用到位运算符。 异或的作用是无进位相加&#xff0c;所以需要通过异或运算&#xff08;^&#xff09;来替代加法运算&#xff0c;但是我们无法确定进位的信息。所以需要与运算&#xff08;&&#xff09;来得到进位的…

【Android】Activity生命周期与五种启动模式

文章目录 生命周期返回栈Activity状态生命周期方法 启动模式standard模式singleTask模式singleTop模式singleInstance模式singleInstancePerTask模式配置方式 生命周期 返回栈 每个Activity的状态由它在Activity栈&#xff08;又叫“回退栈back stack”&#xff09;中的位置决…

MySQL高性能读写分离实战

介绍 我的上一篇文章实现了mysql的主从复制结构&#xff0c;今天这篇继续将如何实现读写分离。 读写分离是指&#xff1a;针对数据库的写操作&#xff08;插入、更新、删除等&#xff09;访问主数据库&#xff0c;读操作访问从数据库。 因为一般网站的读请求的数量是远远大于…

《数据结构:顺序实现二叉树》

文章目录 一、树1、树的结构与概念2、树相关术语 二、二叉树1、概念与结构2、满二叉树3、完全二叉树 三、顺序二叉树存储结构四、实现顺序结构二叉树1、堆的概念与结构2、堆的实现3、堆的排序 一、树 1、树的结构与概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff…