当前位置: 首页 > news >正文

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

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/sub091559e..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教程】(九)版本标签 —— 创建、查看标签,标签的散列值,将标签添加到日志输出中,判断标签是否包含特定的提交 ~》

继续阅读下一篇(点击跳转)
《【Git教程】(十一)一些技巧 —— 引用日志、忽略临时性的本地修改、检查对文本文件的修改、Git 命令别名、为临时指向的提交创建分支、将提交移动到另一分支 ~》

相关文章:

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

Git教程 版本库之间的依赖 1️⃣ 与子模块之间的依赖2️⃣ 与子树之间的依赖🌾 总结 在 Git 中,版本库是发行单位,代表的是一个版本,而分支或标签则只能被创建在版本库这个整体中。如果一个项目中包含了若干个子项目,…...

最新版IntelliJ IDEA 2024.1安装和配置教程 详细图文解说版安装教程

IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版 文章目录 IntelliJ IDEA 2024.1 最新版如何快速入门体验?IntelliJ IDEA 2024.1 安装和配置教程 图文解说版前言 第一步: IntelliJ IDEA 2024.1安装教程第 0 步&…...

JVM常用参数一

jvm启动参数 JVM(Java虚拟机)的启动参数是在启动JVM时可以设置的一些命令行参数。这些参数用于指定JVM的运行环境、内存分配、垃圾回收器以及其他选项。以下是一些常见的JVM启动参数: -Xms:设置JVM的初始堆大小。 -Xmx&#xff1…...

分布式锁-redission可重入锁原理

5.3 分布式锁-redission可重入锁原理 在Lock锁中,他是借助于底层的一个voaltile的一个state变量来记录重入的状态的,比如当前没有人持有这把锁,那么state0,假如有人持有这把锁,那么state1,如果持有这把锁的…...

Android Gradle开发与应用 (八) :Kotlin DSL

1. 前言 本文介绍了Gradle Kotlin DSL相关的一些知识点 2. DSL是什么 DSL是为特定领域设计的专门的语言,也就是设计了一门语言,然后解决某个特定的领域的特定问题。 2.1 举例说明 以下的这些都可以称之为DSL 正则表达式 :用于文本处理的特定语言SQ…...

phpstorm 快捷键

PHPstorm最常用的快捷键,提高开发效率 - 知乎 (zhihu.com) 四年精华PHP技术文章整理合集——PHP框架篇 (qq.com) 四年精华PHP技术文合集——微服务架构篇 (qq.com) Vue3 打印票据 预览的库:vue3打印解决方案:Vue-Plugin-HiPrint - 掘金 (j…...

浦大喜奔APP8.0智能升级,发力数字金融深化五大金融篇章服务

1. 浦大喜奔立足科技赋能持续迭代升级,筑牢用户体验护城河 浦发信用卡中心坚持数字科技与客户体验双轮驱动,以科技赋能发展,优化整体系统性能,全方位支撑浦大喜奔 APP提高线上客户服务能力与体验,积极服务民生消费&a…...

自然语言处理、大语言模型相关名词整理

自然语言处理相关名词整理 零样本学习(zero-shot learning)词嵌入(Embedding)为什么 Embedding 搜索比基于词频搜索效果好? Word2VecTransformer检索增强生成(RAG)幻觉采样温度Top-kTop-p奖励模…...

移动开发避坑指南——内存泄漏

在日常编写代码时难免会遇到各种各样的问题和坑,这些问题可能会影响我们的开发效率和代码质量,因此我们需要不断总结和学习,以避免这些问题的出现。接下来我们将围绕移动开发中常见问题做出总结,以提高大家的开发质量。本系列文章…...

太好玩了,我用 Python 做了一个 ChatGPT 机器人

毫无疑问,ChatGPT 已经是当下编程圈最火的话题之一,它不仅能够回答各类问题,甚至还能执行代码! 或者是变成一只猫 因为它实在是太好玩,我使用Python将ChatGPT改造,可以实现在命令行或者Python代码中调用。…...

STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡

STM32存储左右互搏 SDIO总线读写SD/MicroSD/TF卡 SD/MicroSD/TF卡是基于FLASH的一种常见非易失存储单元,由接口协议电路和FLASH构成。市面上由不同尺寸和不同容量的卡,手机领域用的TF卡实际就是MicroSD卡,尺寸比SD卡小,而电路和协…...

累积分布函数图(CDF)的介绍、matlab的CDF图绘制方法(附源代码)

在对比如下两个误差的时候,怎么直观地分辨出来谁的误差更低一点?: 通过这种误差时序图往往不容易看出来。 但是如果使用CDF图像,以误差绝对值作为横轴,以横轴所示误差对应的累积概率为纵轴,绘制曲线图&am…...

代码随想录算法训练营第四十一天|343.整数拆分、96不同的二叉搜索树

文档链接:https://programmercarl.com/ LeetCode343.整数拆分 题目链接:https://leetcode.cn/problems/integer-break/ 思路: j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘…...

全量知识系统 程序详细设计之 统一资产模型(QA-SmartChat)

Q1. 下面我们聊聊整个全知系统的设计 的矩阵和函数,矩阵表示的是“活物”,分别 类似 一个基因的活性、一个实体的辨识度和某种特征的可区分度。 函数的可微、可积和可导性 则表示 运动的控制方式 在全知系统设计中,矩阵和函数是两个核心的组…...

已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法,亲测有效!!!

已解决org.springframework.web.client.HttpClientErrorException: 400异常的正确解决方法,亲测有效!!! 文章目录 问题分析 报错原因 解决思路 解决方法 总结 在日常开发过程中,通过Spring框架提供的RestTemplat…...

内网渗透-Windows内网渗透

内网渗透-Windows内网渗透 文章目录 内网渗透-Windows内网渗透前言一、信息收集 1.1、SPN1.2、端口连接1.3、配置文件1.4、用户信息1.6、会话收集1.7、凭据收集 navicat:SecureCRT:Xshell:WinSCP:VNC: 1.8、DPAPI1.9、域信任1.10、…...

机器人方向控制中应用的磁阻角度传感芯片

磁阻传感器提供的输出信号几乎不受磁场变动、磁温度系数、磁传感器距离与位置变动影响,可以达到高准确度与高效能,因此相当适合各种要求严格的车用电子与工业控制的应用。所以它远比采用其它传感方法的器件更具有优势。 机器人的应用日渐广泛&#xff0…...

如何在树莓派安装Nginx并实现固定公网域名访问本地静态站点

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx(发音为“engine-x”)可以将您的树莓派变成一个强大的 Web 服务器,可以用于托管网站或 Web 应用程序。相比其他 Web 服务器,Ngi…...

Ubuntu与主机windows共享文件夹

一、创建共享文件夹: 虚拟机->设置->选项->共享文件夹->总是启用->选择本地的共享文件夹(如E:\Share)->确定。 二、设置挂载: 首先赋予/etc/fstab文件可编辑的权限; sudo chmod 777 /…...

(四)C++自制植物大战僵尸游戏启动流程

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/ErelL 一、启动方式 鼠标左键单机VS2022上方工具栏中绿色三角按钮(本地Windows调试器)进行项目启动。第一次启动项目需要编译项目中所有代码文件,编译生成需要一定的时间。不同性能的电…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

【JavaEE】-- HTTP

1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...