【Git教程】(十)版本库之间的依赖 —— 项目与子模块之间的依赖、与子树之间的依赖 ~

news2024/11/24 3:22:06

Git教程 · 版本库之间的依赖

  • 1️⃣ 与子模块之间的依赖
  • 2️⃣ 与子树之间的依赖
  • 🌾 总结

在这里插入图片描述

在 Git 中,版本库是发行单位,代表的是一个版本,而分支或标签则只能被创建在版本库这个整体中。如果一个项目中包含了若干个子项目,它们有各自的发布周期和属于自己的版本,那我们就必须要为每个子项目建立对应的版本库了。

对于主项目和子项目之间的关系,我们可以通过Git 中的 submodulesubtree 命令来实现。
请注意,subtree 命令是在1.7.11这一版本中首先被正式纳入Git 的。但该命令只是 contrib 目录下的一个可选组件。有些 Git 的安装包会自动包含的subtree 命令,而另一些则需要我们去手动安装。

子模块和子树这两个概念之间的主要区别在于:带子模块的主版本库只能发布模块版本库,而模块版本库的内容中带有子树的话,该模块版本库就被导入了主版本库中。


1️⃣ 与子模块之间的依赖

对于子模块来说,其模块版本库可以被嵌入到主版本库中去。为了实现这一点,模块版本库中的提交会以目录的形式被链接到主版本库中。

下面,我们通过下图来看看其基本结构。该图中有main 和 sub 两个版本库。在主版本库中,sub 目录将会与模块版本库相链接。这样,主版本库工作区的 sub 目录下就有了一个 完整的模块版本库。但事实上主版本库其实只是引用了模块版本库。为了实现这一目标,我们就得有一个名为 .gitmodules 的文件,以便用来定义各模块版本库所在的绝对路径。

[submodule "sub"]
path=sub
url=/project/sub

在这里插入图片描述

除了.gitmodules 文件之外,子模块的引用信息还会被被保存在 .git/config 文件中。该文件会在我们调用 submodule init 命令时完成存储,届时该命令会将从 .gitmodules 文件中读取的信息写入到 .git/config文件中。有了这样的间接配置,我们就可以在 git/config 文件对模块版本库的路径进行本地化调整了。

[core]
repositoryformatversion=0
filemode=true
bare=false
logallrefupdates=true
ignorecase=true
[submodule "sub"]
url=/project/sub

凭借上述信息,我们是不可能为主版本库中的每次提交都重现相应模块版本库的版本的。 也正因为如此,模块版本库中的提交才仍会被需要。这些都将会被存储在主版本库的对象树 中。下面我们来看看该对象树。其第三项 sub就是一个子模块,它可以被识别成 commit类型,随后的散列值引用的就是模块版本库中的提交 。

100644 blob le2bld1d51392717a479eaaaa79c82df1c35d442    .gitmodules
100644 tree 19102815663d23f8b75a47e7a01965dcdc96468c   src
160000 commit 7fa7elclbd6c920ba71bd791f35969425d28b91b sub

在这里,我们要将一个现有 Git 项目以子模块的形式嵌入到一个不同的项目中

  1. 链接目录
    如果我们想要纳入某个子模块,就必须调用 submodule add 命令,并指定该模块版本库的绝对路径与该模块所在的目录名:
    > git submodule add /global-path-to/sub sub
    这样一来,模块版本库就会被完整地克隆到指定目录中(并且它也会创建属于它自己 的.git 目录)。此外,主版本库中的.gitmodules 文件也将被同步创建或更新。
  2. 在 config 文件在注册子模块
    除此之外,新的子模块还需要被注册到.gitconfig 文件中。我们可以通过 submodule init 命令来完成这件事。
    > git submodule init
  3. 选择子模块的版本
    该模块版本库的工作空间最初会被设置为默认分支的 HEAD。如果我们想要子模块中 的另一提交,就需要用checkout 命令来选择一下相应的版本。
    > cd sub
    > git checkout v1.0
  4. 将该 gitmodules 文件和子目录添加到提交中
    当我们添加一个子模块时,主版本库中的.gitmodules 文件就会随之被创建或更新。然
    后,我们就必须要将其添加到提交中去。此外,子模块所在的新目录自然也要添加。
    > cd
    > git add .gitmodules
    > git add sub
  5. 做一次提交
    最后,我们需要在主版本库中做一次提交。
    > git commit -m "Submodule added"

如果我们克隆了一个带子模块的版本库,就必须调用一下 submodule init 命令。该命令 会将.git/config 文件中各子模块的 URL 传送过来。之后,我们就可以调用 submodule update 命令来克隆模块版本库所在的目录了。

克隆一个带子模块的项目
当我们克隆一个带子模块的版本库时,最初在工作区中创建的只有主版本库。其子模块必须要进行显式的初始化和更新。

  1. 初始化子模块
    首先,我们必须要用submodule init命令来完成子模块的注册。
    > git submodule init
  2. 更新子模块
    待该子模块在完成Git 的初始化配置之后,我们就可以通过 submodule update 命令来下载完整的子模块了。
    > git submodule update

我们可以用 submodule status 命令查看子模块中被引用提交的散列值。其中如果存在标签的话,也会以括号的形式显示在输出的结尾处。

> git submodule status
091559ec65c0ded42556714c3e6936c3bla90422 sub(v1.0)

在这里,Git 往往引用了模块版本库中的一次提交。而与此同时,该提交对象的散列值也是主版本库中每次提交的一个部分。模块版本库中随后的新提交并不会自动被记录在主版本库中。这种操作必须要显式执行,以便我们在主版本库中恢复某一项目版本时可以获取与之相匹配的、模块版本库中的项目版本。

使用子模块中的新版本
在发现子模块中有新版本可用了,我们要怎么做呢?

  1. 更新子模块
    首先,我们需要将子模块的本地工作区调整到理想的状态。通常情况下,我们应该执行一次fetch 命令,以获取模块版本库中的最新提交。
    > cd sub
    > git fetch
    接下来,我们要用checkout 命令指定自己所需要的提交。
    > git checkout v2.0
  2. 使用新版本
    最后,将该新提交预备到模块目录中,并提交它。
    > cd ..
    > git add sub
    > git commit -m "New version of the submodule"

如果我们想在主版本库中使用模块版本库的某一新版本,就必须要对其进行显式修改。如果我们同时在主版本库与模块版本库中工作,就必须要将修改同时提交到两个版本库中。如果你还有一个中央版本库,那么这两个版本库都必须分别执行 push 命令,各自单独完成传送。

与子模块相关的工作
在工作区中,主版本库与模块版本库中的文件都已经被修改了。随后,主版本库应该要指向模块版本库中的新提交。

  1. 提交并推送模块版本库中的修改
    首先,我们要对模块版本库中的修改完成一次提交,并在可能的情况下将其用 push 命令传送给中央版本库。
    > cd sub
    > git add foo.txt
    > git commit -m "Changed submodule"
    > git push
  2. 提交并推送主版本库中的修改
    接下来,我们要将主版本库中的修改,其中包括对模块版本库的引用提交,并在必要 的情况执行传输。
    > cd ..
    > git add bar.txt
    > git add sub
    > git commit -m "New version of submodule"

每次在对包含子模块的工作区执行更新之后后,我们应该随之调用 submodule update 命令来获得各子模块的正确版本。
如果这次是添加了一个全新的子模块,那么在执行submodule update 命令之前,我们还应该先调用一下 submodule init 命令。
另外作为开发者,如果我们在每次更新工作区内容(包括签出、合并、变基、重置、拉取等操作)之后都要执行一次初始化-更新命令序列,就说明事情做得不够好。

更新子模块
如果某子模块的新版本是由别的开发者所记录,那么我们就应该更新自己本地的克隆版本库和工作区。

 > git submodule init
 > git submodule update
From /project/sub
	091559e..4722848   master  -> origin/master
★[new tag]  v1.0  -> v1.0
★[new tag]  v2.0  -> v2.0
Submodule path  'sub':
checked out  '472284843ce4c0b0bb503bc4921ab7...le51'

当然,只有在当前工作区中没有相应的模块项的时候, submodule init 命令才会将 .gitmodules 文件中的信息传送给.git/config 文件。这样一来,我们就可以对模块版本库的路径进行本地化调整了。但如果这时有另一个开发者已经修改了.gitmodules 文件中的正式路径, 我们的修改就不会被接受。这就必须要通过 submodule sync 命令来完成此任务了。该命令会更新.git/config 文件中的路径并覆盖掉所有的本地修改。


2️⃣ 与子树之间的依赖

利用子树的概念,我们可以将一些模块版本库嵌入到某一个 Git 版本库中。为了实现这一点,我们必须要将该版本库中的某一目录与模块版本库中的某一提交、标签或分支关联起来。但与子模块不同的是,这回是一个被嵌入的模块版本库,其全部内容是被导入主版本库,而不在仅仅是引用了。这使得主目录中的工作相对更为自给自足了。

下面,我们通过下图来看一下子树处理的基本结构。在该图中,我们有 main 和 sub 两个版本库:我们(通过subtree add命令) 将主目录中的sub 目录与模块目录链接了起来。
而在主版本库的 sub 目录下,我们看到了来自模块版本库中某一版本的文件。

在这里插入图片描述

从技术上来说, subtree add 命令会将模块版本库中所有的提交都导入到主版本库中(即 提交 S1 和 S2) 。然后,主版本库的当前分支就被链接到了模块版本库的特定提交上(即合并提交 G3) 。 在内部, Git 用到了它的子树合并策略(-strategy=subtree )。这样一来就在特定的目录里出现了一次合并,将模块版本库中的内容载入到了sub 目录下。

嵌入一个子树
如果想要嵌入一个模块版本库,我们就要通过 subtree add 命令将它添加到主版本库中(只需要调用一次 subtree add即可)。在这种情况下,你可以通过 -prefix 选项来指定目录。
此外,目标模块库及其标签或分支的URL 也必须要指定。
> git subtree add --prefix=sub /global-path-to/sub v2.0
如果模块版本库的历史记录无需与主版本库相关,你也可以用--squash 选项限制其只 获取特定提交的内容。
> git 'subtree add --squash --prefix=sub /global-path-to/sub master
该命令会产生一个新的合并提交,并会以注释的形式添加它的散列值,这可以使得我们在下次更新时获取正确的模块提交。

与子模块不同的是,当某一带子树的版本库被克隆时,我们通常并不会观察到什么特殊情况。 一般情况下, clone 命令都会去捡取整个主版本库以及它所包含的所有模块版本库。

> git clone /path-to/main

使用子树中的新版本
以下操作的前提是被嵌入的子树中已经有别的版本正在使用。我们可以用subtree pull 命令来更新一个已被嵌入的子树。只要是可用于 subtree add 的 参数都可用于 subtree pull 命令。如果你在使用添加命令时使用了一个标签,必须用一个新的标签来代替。如果已经使用了一个分支,也可以指定是同一分支还是不同分支。如果该 分支上没有任何修改,subtree pull 命令就不会做任何事。
> git subtree pull --prefix=sub /global-path-to/sub v2.1
此外,通过在拉取操作中使用--squash 选项,我们可以跳过模块版本库的历史记录。 在这种情况下,没有中间提交会被涉及到,只有那个被指定的提交。当然,我们也可以用 --squash 选项返回到模块版本库的某一个旧版本上,例如,从2.0版回到1.5版。
> git subtree pull --squash --prefix=sub /global-path-to/sub master

另外通过子树,我们才有可能直接在嵌入式模块的目录中做某些修改。在这里,如果我 们并没有什么特别需求的话。只需调用一般性的commit 命令就可以了。当然,我们也可以将主版本库中的相关修改或者某一提交中一个或多个模块目录版本化。
只有在重发各版本库中对模块所所做的修改时,我们才需要采取一些预防性措施。

扩散模块版本库中的修改
在这里,我们要将在模块目录中所做的修改传送相应的模块版本库中去。

  1. 分离模块目录中的修改
    首先,我们要用 subtree split 命令将模块目录中所发生的修改从其他修改中分离出来。 该命令会基于目前已知模块版本库的提交来生成一个新的提交,该新提交中将包含各提交中那些被修改的了模块文件。该命令执行完后,我们会得到一个指向这个新提交的本地分支(例如 sub/master)。如果你在调用subtree addsubtree pull 命令时没有使用 --squash 选项,在这里可以使用 --rejoin 选项。这可以简化对sqlit 的反复调用。
    > git subtree split --rejoin --prefix sub --branch sub/master
  2. 合并模块版本库中的修改
    模块版本库中的本地修改必须要跟远端的修改进行合并。因此,我们先要激活新建的分支,并检索出目标分支中的最新版本。然后,我们就必须要合并这两个分支。
    > git checkout sub/master
    > git fetch /global-path-to/sub master
    > git merge FETCH_HEAD
    请注意,上面带URL的那个获取操作会创建一个临时引用 FETCH_HEAD, 该引用会指向其获取分支中的最新提交。如果你此刻正在某个远程分支上工作,理所当然可以使用其远程名称而不是URL。在这之后,目标分支将就可直接使用了,并不非得是 FETCH_HEAD。
  3. 将修改传送到模块版本库中,并删除临时分支
    临时分支中的本地修改必须要被推送到远程模块版本库中。在推送完成之后,我们可以切换回主版本库的分支,并删除该临时分支。
    > git push /global-path-to/sub HEAD:master
    > git checkout master
    > git branch -d sub/master

从上述内容,我们可以清楚地看到,大部分子树操作都要比那些相应的子模块简单一些,两者只有在提取修改方面的复杂度是差不多的。
但在多数情况下,我们是不会用到提取操作的,因为我们是在主版本库上工作,而不是 模块目录中。

🌾 总结

  • 嵌入子模块:我们可以通过submodule addsubmodule init 命令来嵌入一个子模块。
  • 克隆包含子模块的项目:我们可以在克隆该项目后,对其调用 submodule initsubmodule update 命令。
  • 选择子模块中的某个新版本:首先,我们要(通过 checkout 命令来看) 选择在子模块目录中的新提交。然后,在主版本库中对其做一次提交。
  • 同时处理模块版本库与主版本库:我们必须要先在模块版本库中执行提交,然后才能在主版本库中执行提交。另外,两个版本库的推送操作也必须要各自执行 push 命令。
  • 嵌入子树:我们可以通过subtree add 命令来嵌入子树。
  • 选择子树中的某个新版本:我们可以通过subtree pull命令来将模块目录更新到所需的分支或标签上。
  • 提取模块目录中的修改:我们可以通过subtree split 命令创建一个单独的分支,用于 包含模块目录在的修改。然后再使用 merge 命令将这些修改与其他修改合并,并用 push 命令完成推送操作。


温习回顾上一篇(点击跳转)
《【Git教程】(九)版本标签 —— 创建、查看标签,标签的散列值,将标签添加到日志输出中,判断标签是否包含特定的提交 ~》

继续阅读下一篇(点击跳转)
《》

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

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

相关文章

学习赚钱两不误--全自动挂机软件(网心云)

1、简介 程序员的工作环境程序员的工作环境最多的就是网络资源,所以我们工作中有很多的闲置网络资源,不白嫖有点浪费哈。下面就给大家介绍一下免费分享上行带宽赚钱的平台--网心云 优点: (1)平台大、靠谱、稳定 &a…

四川易点慧电子商务抖音小店可靠购物

在当下这个信息爆炸的时代,电子商务的崛起不仅改变了人们的购物习惯,也催生了众多新兴的电商平台。四川易点慧电子商务抖音小店便是其中的佼佼者,以其独特的魅力和可靠性,赢得了广大消费者的青睐。 一、平台背景实力雄厚 四川易点…

3、最大池化maxinmum pooling

了解有关最大池化特征提取的更多信息。 简介 在第二课中,我们开始讨论卷积神经网络(convnet)的基础如何进行特征提取。我们了解了这个过程中的前两个操作是在带有 relu 激活的 Conv2D 层中进行的。 在这一课中,我们将看一下这个序列中的第三个(也是最后一个)操作:通过…

(一)基于IDEA的JAVA基础12

一维数组 为什么使用数组: 当我们需要存储一系列数据的时候,就需要用到数组,如果不使用数组,我们就要需要一个一个的去声明变量,这样浪费内存空间,同时效率低下。 什么是数组: 数组本身就是一个变量,只…

蓝桥杯-【二分】分巧克力,跳石头

代码及解析: #include<bits/stdc.h> using namespace std; int n,k; const int N100010; int h[N],w[N]; bool check(int d){int num0;for(int i0;i<n;i) num (h[i]/d)*(w[i]/d);if(num>k) return true; //够分else return false; //不够分 } in…

Linux: 工具: tshark 抓到了收方向的ESP明文包?

根据这个描述&#xff0c;看着是正常的&#xff0c; 抓到包之后&#xff0c;可以方便的分析问题&#xff0c;省去在wireshark里解码的问题。 经过调查发现是内核将ESP解开之后&#xff0c;如果是tunnel模式&#xff0c;内核又重新将skb丢给了interface去做处理。这样tshark/tcp…

LightDB24.1 ecpg支持exec sql for :i update(or insert)语法

背景 oracle 在适配过程中&#xff0c;发现pro*c支持exec sql for :i update(or insert)语法&#xff0c;其功能是取代 for(;;) {update(or insert)语法; }其中i决定循环执行的次数&#xff0c;update(or insert)表示循环执行的次数。 我们在oracle环境下测试得到如下经验&a…

diffusion model(十五) : IP-Adapter技术小结

infopaperhttps://arxiv.org/pdf/2308.06721.pdfcodehttps://github.com/tencent-ailab/IP-Adapterorg.Tencent AI Lab个人博客地址http://myhz0606.com/article/ip_adapter 1 Motivation 为了对文生图diffusion model进行特定概念的定制&#xff0c;常用LoRA[1]、textual in…

国内超声波清洗机排名!洗眼镜超声波清洗机推荐

眼镜是我们日常生活中不可或缺的用具&#xff0c;但随着使用时间的增长&#xff0c;眼镜上的灰尘和污垢也会逐渐积累&#xff0c;传统的清洗方法往往难以彻底清洁。为了解决这一难题&#xff0c;超声波清洗机出现了&#xff01;它利用超声波振动原理&#xff0c;可以轻松、快速…

使用Docker部署jar包

vi DockerfileDockerfile内容 FROM java:8 ADD chery5G-admin.jar chery5G-admin.jar ENTRYPOINT ["java","-jar","chery5G-admin.jar"]上传jar包到Dockerfile文件同级目录 使用Dockerfile文件&#xff0c;将jar包制作为镜像 docker build -t…

2024/4/5—力扣—在排序数组中查找元素的第一个和最后一个位置

代码实现&#xff1a; 思路&#xff1a;二分法 方法一&#xff1a;分别查找左右侧边界 /*** Note: The returned array must be malloced, assume caller calls free().*/ int GetTargetFirstPosition(int *nums, int numsSize, int target) {int l 0, r numsSize - 1;while …

JAVA面试八股文之Redis相关

Redis相关 Redis6.0为什么要用多线程&#xff1f;在Redis中存一个list集合怎么实现排序&#xff1f;Redis的5大基本类型的底层原理&#xff1f;缓存穿透&#xff1f;缓存击穿&#xff1f;缓存雪崩&#xff1f;redis做为缓存怎么保持和mysql数据进行同步&#xff1f;&#xff08…

物证管理系统|DW-S404实现物证全生命周期管理

物证管理系统|DW-S404实现物证全生命周期管理 一、项目背景 随着社会的进步和科技的发展&#xff0c;信息化和数字化已经成为各个行业的必然趋势。在众多领域中&#xff0c;物证管理系统逐渐受到广泛的关注和应用。 物证是公安机关处理案件的关键凭证&#xff0c;针对过去物证管…

如何给MySQL数据库的所有表统一加上字段

在开发过程中&#xff0c;有时候慢慢的建了很多数据库表&#xff0c;但是后来发现需要统一增加某些字段的时候&#xff0c;可以通过alter语句 ALTER TABLE 表名 ADD 列名 数据类型;比如我要给t_user表增加gmt_create与gmt_modified字段&#xff0c;用作记录新增记录时间与更新…

U盘格式化数据恢复,3个妙计助你快速恢复!

“我的u盘由于中病毒了&#xff0c;我不得已将它格式化了&#xff0c;现在想进行u盘数据的恢复&#xff0c;不知道应该怎么操作&#xff0c;大家有什么方法推荐吗&#xff1f;” U盘作为我们日常生活中常见的存储设备&#xff0c;经常用于存储各种重要数据。但是在日常使用u盘的…

华火电火灶:人间烟火味,最抚凡人心

厨房&#xff0c;一直是家的核心&#xff0c;那里不仅有妈妈的味道&#xff0c;更有生活的味道。当炊烟袅袅&#xff0c;炉火旺盛&#xff0c;家的温馨与幸福便油然而生。华火电火灶以其独特的魅力&#xff0c;不仅成为了现代厨房中的一道亮丽风景线&#xff0c;更成为了家人的…

Digicert 证书

一、简介 在当今数字化时代&#xff0c;网络安全已成为全球关注的焦点。随着网络攻击和数据泄露事件的频发&#xff0c;企业和组织越来越重视保护自己的网络环境。在这种背景下&#xff0c;数字证书成为了确保网络通信安全的关键工具。作为数字证书行业的领导者&#xff0c;Di…

yolov8草莓及病害检测项目开发(python开发,带有训练模型,可以重新训练,并有Pyqt5界面可视化)

本次检测系统&#xff0c;可以通过图片、视频或摄像头三种形式检测&#xff0c;检测出开花、结果、熟果、草莓叶子健康、叶子缺钙、灰叶斑病等八大类别。基于最新的YOLO-v8模型&#xff0c;下载后即可重新运行训练脚本&#xff0c;&#xff0c;也可以直接运行检测脚本&#xff…

嘉轩智能工业科技诚邀您参观2024第13届生物发酵展

参展企业介绍 自2005年成立以来&#xff0c;嘉轩一直致力于工业智能永磁滚筒的研发、制造及销售&#xff0c;具有十多年的从业经验&#xff0c;公司主营产品包括工业智能永磁滚筒、机电智能诊断、工业智能电机等&#xff0c;高效智能自驱动永磁滚筒为我公司目前主导产品&#x…

考PMP一定要培训吗?PMP备考可不是说着玩的

想要考项目管理认证一定要培训吗&#xff1f;其实这是必要的也是必须的啦&#xff0c;不仅仅是因为自学的难度大&#xff0c;个人自学很难总结学习技巧&#xff0c;另一个原因就是考试前还必须要有授权培训机构提供的35学时培训证明&#xff0c;没有这个培训证明也就直接意味着…