Git是如何工作的

news2024/12/22 16:05:55

Git 是一个分布式的版本控制系统,这意味着它使用多个本地存储库,包括一个集中式存储库和服务器,它在从前端工作中抽象出底层机制方面做得非常出色。虽然 Git 已经演变成一个成熟的版本控制管理系统,但这并不是作者最初的意图,但并不影响它成为最为世界上最为出色、优雅的工具之一。Git 的好处在于,我们可以在整个职业生涯中都不知道 Git 内部是如何工作的,但依然可以和它相处得很好。但当我们了解了 Git 如何管理自己的存储库将有助于打开咱的思维方式,并让咱更深入地了解 Git。

Git 的特性

区别

  • SVN 是集中式版本控制系统,它的版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,只有一台服务器来维护和控制代码,所以首先要从中央服务器那里得到最新的版本,干完活后需要把自己做完的活推送到中央服务器。
  • Git 是分布式版本控制系统,它没有中央服务器,每一台主机都当成一台服务器。

优势

  • Git 和其他版本控制系统的主要差别在于,Git 只关心文件数据的整体是否发生变化,而大多数其他系统则关心文件内容的具体差异。
  • Git 并不保存这些前后变化的差异数据。实际上,Git 更像是把变化的文件作快照后,记录在一个微型的文件系统中。每次提交更新时,它会纵览一遍所有文件的指纹信息并对文件做快照,然后保存一个指向这次快照的索引。为提高性能,若文件没有变化,Git 不会再次保存,而是直接引用上次保存的快照链接。
  • Git 近乎所有操作都是本地执行,它的绝大多数操作都只需要访问本地文件和资源,不用连网。但如果用 CVCS (集中式版本控制系统)的话,差不多所有操作都需要连接网络。且因为 Git 在本地磁盘上就保存着所有当前项目的历史更新,所以处理起来速度飞快。

Git 实际上是如何工作的

当我们要去探究 Git 是如何工作的时候我们该从何处下手呢?我们知道 Git 近乎所有操作都是本地执行的,在本地的文件中我们能找到他执行的记录,这就需要我们聚焦本地文件的 Git 文件 —— .git 文件,那么接下来就来看看 Git 的本地文件都有些什么。

Git 对象

.git 文件作为一个隐藏文件并不经常出现在我们的目录中,现在我们打开一个从代码仓库拉取的项目,打开终端程序并导航到存储库的主目录,再导航到存储库的 .git 目录:

cd .git

拉出 .git 的目录列表,那么你至少能看到以下几个目录:

FETCH_HEAD/             
HEAD/
config/
objects/
refs/

现阶段我们需要聚焦的是objects目录,在objects中,我们最常见的对象是以下三种(具体的下文会详细说明这三者):

  • Commits: 这将树对象链接在一起以形成历史,保存有关您的提交的元数据的结构,以及指向父提交和下面文件的指针。

  • Tree: 这相当于一个目录,记录着目录树内容及其中各个文件对应 blob 对象索引。

  • Blobs: 这是文件的内容,用于表示文件快照内容。

Commits 对象

直接进入 object 对象:

cd objects
ls

控制台展示:

// 每个人的项目都不同,文件自然也不同,此处以笔者的一个项目为例
0c      57      85      b3       
1b      60      94      c4      
2a      67      98      cb      
2c      6c      9a      info      
3c      73      a9      pack      
49      82      af      
52      83      b1

小朋友你是否有很多问号?在第一眼看到这么多两位字符的文件夹名时完全不知道这些是啥。那么我们就需要转头来解释一下 Git 的数据存储结构 了。

当 Git 存储对象(也就是我们提交的记录)时,它不会将它们全部转储到一个目录中,因为这样会使得目录在不断的迭代提交后变得笨拙,所以它会将它们整齐地构造成一棵树—— Git 将对象哈希的前 2 个字符用作目录名称,然后将剩余的 38 个字符用作对象标识符。当我们将以上的二位字符命名的文件夹展开时,我们就会得到这样一个树形结构的目录:

objects
├── 0c
│   ├── 8867d7e175f46d4bcd66698ac13f4ca00cf592
│   └── c8002da0403724dfaa6792885eaa97faa71bcf
├── 1b
│   └── 716fafdd3aeb3636222a0026d1d4971078db05
├── 2a
│   └── 14f7db6a6748cc98862960ff5d0e9b1d4a2f17
├── 2c
│   ├── 14f7db6a6748cc98862960ff5d0e9b1d4a2f17
├── 3c
│   ├── 121291ffc25ce6792f9350883b77cea2633048
.
.
.

为了验证上述 Git 存储对象的结构,我们可以查看当前最新的4次提交,并取第一条记录去提交记录的结构树中匹配:

command: git log -4 --oneline

9a5bf36 (HEAD -> master) feat: third commit
2c5331f feat: second commit
60814e1 feat: first commit
49942f3 Initial commit

我们能看到最近的4次提交,并且每次提交都会有一个 7 位长的哈希值以及提交时的描述。以 9a5bf36 这次提交为例,我们可能会有个疑问:这只有 7 位似乎跟我们说的不太一样呀。别急!我们需要转换一下,将他转换成完整的长哈希值,因为在树结构中是以长哈希值构建生成的。

git rev-parse 9a5bf36

Git 以等效的长哈希值响应:9a5bf367f10390c64a3f7b3e738b78bd78a3d781.

将其分解为目录名称和对象标识符:

  • 目录9a
  • 对象标识符5bf367f10390c64a3f7b3e738b78bd78a3d781

我们很容易就能看到找到:

objects
├── 0c
│   ├── 8867d7e175f46d4bcd66698ac13f4ca00cf592
│   └── c8002da0403724dfaa6792885eaa97faa71bcf
├── 1b
│   └── 716fafdd3aeb3636222a0026d1d4971078db05
.
.
.
├── 98
│   ├── ed6b3f02409778bc864d8897bc230c90cae445
├── 9a
│   ├── 5bf367f10390c64a3f7b3e738b78bd78a3d781   //====>在这
.
.

既然我们知道了它的存储结构,那么我们自然就应该打开这个文件查看文件的内容,但是我们不能直接查看此对象,因为 Git 中的对象是经过压缩的。如果您尝试使用 cat 5bf367f10390c64a3f7b3e738b78bd78a3d781 或类似方式查看它,您可能会看到一堆像这样的乱码,以及计算机尝试从二进制对象读取控制字符时发出的咔呲声:

6?$?(?E9?z??nUmV?Em]?p??3?`??????q?Ţqjw????VR?O? q?.r???e|lN?p??Gq?)?????#???85V?W6?????
)|Wc*??8?1a?b?=?f*??pSvx3??;??3??^??O?S}??Z4?/?%J?
xu?Ko?0??̯?51??Ԯ
yB
    ??f?y?cBɯo?{ݝ?|ҌFL?:?@??_?0Td5?D2Br?D$??f?B??b?5W?HÁ?H*?&??(fbꒉdC!DV%?????D@?(???u0??8{?w
    ????0?IULC1????@(<?s '
mO????????ƶe?S????>?K8                  89_vxm(#?jxOs?u?b?5m????=w\l?
%?O??[V?t]?^??????G6.n?Mu?%
                           ?̉?X??֖X
                          v??x?EX???:sys???G2?y??={X?Ռe?X?4u???????4o'G??^"qݠ???$?Ccu?ml???vB_)?I?
`??*ގF?of??O

我们可以使用命令:

git cat-file -p 9a5bf36
sanqius-MacBook-Pro:3c zcy$ git cat-file -p 9a5bf36
tree 85b9416a23f8fb018181f96e5c01ba4bd923b965
parent 2c5331fd7046e561aad8fdde3e3f21375a17549c
author 三秋 <sanqiu@***.com> 1665729807 +0800
committer 三秋 <sanqiu@***.com> 1665729807 +0800

feat: third commit

我们看到的这个文件内部的这些内容其实就是一个对象,一个包含了 tree、parent、author… 等数据的对象,这个对象就是 Commits 了。

Commits 对象是以键值对的形式展示的,这个 Commits 指向一个 Hash 值为 2c5331fd7046e561aad8fdde3e3f21375a17549c 的 parent ,其实这个 parent 同样是一个 Commits 对象,这很好理解。但是这个 Commits 还有一个 Hash 值为 85b9416a23f8fb018181f96e5c01ba4bd923b965 的 tree 属性,也就是我们上面所说的第二个常用对象 Tree 。接下来我们需要聚焦的是 Commits 对象中的 Tree。

Tree 对象

这个提交的文章目录里面有什么?我们使用相同的命令打开这个哈希值指向的文件:

git cat-file -p 85b9416a23f8fb018181f96e5c01ba4bd923b965
100644 blob 0cc8002da0403724dfaa6792885eaa97faa71bcf    README.md
040000 tree 3c121291ffc25ce6792f9350883b77cea2633048    src

我们发现这个 Tree 对象下有两个,一个是 Blob 类型的 README.md 文件和 Tree 类型的 src 的文件夹,可以看出 Tree 是可以嵌套的,并且这个结构似乎有点眼熟,没错这就是我们项目的目录结构,这也就能解释为什么说 Commits 对象下的 Tree 就是对应着这个代码版本的文件快照了。(100644 代表它是一个普通的文件,100755 表示一个可执行文件,120000 仅仅是一符号链接)。

Blobs 对象

接上文,现在这个 Tree 文件类型已经出现我们的第三类对象 Blob 了,打破砂锅问到底,继续看看这个Blob 是啥:

git cat-file -p 0cc8002da0403724dfaa6792885eaa97faa71bcf
MIT License

Copyright (c) 2019

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell...
<snip>

我们可以看到其实这就是我们在这个代码版本下的文件内容,这也就意味着 Blob 其实就是存放文件的内容

总结

放一张图用来总结一下 Commits、Tree、Blob 三者之间的关系:

在这里插入图片描述

分支创建与合并

在上文中,我们不难知道每一次提交记录其实就是向代码仓库提交一次 Commits 对象,还记得 Commits 对象中的 Parent 属性吗, Parent 属性指向的是当前基变的原型版本。那么当有多个 Commits 提交后,我们能得到这样一个结构的 Commits 流:

在这里插入图片描述

用过图形化 Git 工具的同学有没有觉得这个很眼熟,没错,图形化工具就是将 Commits 关系视图化,就得到我们常用的 SourceTree 、GitKraken 这些常用的图像化 Git 工具,当然这些软件肯定没这么简单,但基本原理还是一样的。

现在来谈分支,Git 中的分支,其实本质上仅仅是个指向 Commit 对象的可变指针。Git 会使用 Master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 Master 分支,它在每次提交的时候都会自动向前移动。

在这里插入图片描述

当我们创建一个新的分支时,其实就是在当前 Commit 对象上新建一个分支指针。这也就是为什么当我们新建一个分支的时候会如此迅速。

在这里插入图片描述

那么 Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针。在 Git 中,它是一个指向你正在工作中的本地分支的指针。所以当我们切换分支的时候就是切换 HEAD 指针的指向,这和大多数版本控制系统形成了鲜明对比,它们管理分支大多采取备份所有项目文件到特定目录的方式,所以根据项目文件数量和大小不同,花费的时间也会有很大的差别,快则几秒,慢则数分钟。而 Git 的实现与项目复杂度无关,它永远可以在几毫秒的时间内完成分支的创建和切换。

在这里插入图片描述

当我们分别在 Master、testing 分支分别进行了一些修改,并将代码提交,那么我们就会得到这样结构的分支关系,当前 Master、testing 分支最新的代码的父级记录指向的都是同一个。

在这里插入图片描述

读到这我们可以总结出分支的本质:

  1. 当我们切换到一个命名分支,其实只是切换一个引用提交哈希的标签。
  2. Git 是通过哈希值来找到该提交对象,然后从提交对象中获取树哈希。
  3. 然后 Git 沿树对象递归,找到哈希对应的快照文件对象,然后解压缩文件对象。
  4. 您的工作目录现在代表该分支的状态,因为它存储在存储库中。

代码合并与冲突

当我们继续在 testing 分支进行开发,且 Master 与 testing 分支的开发是在两个不同文件中,那么当我们要将 testing 分支合并到 Master 分支中去时,Git实际上会将两个分支的末端(A5 和 A7)以及它们的共同祖先(A3)进行一次简单的三方合并计算。

在这里插入图片描述

这次,Git 没有简单地把分支指针右移,而是对三方合并后的结果重新做一个新的快照,并自动创建一个指向它的提交对象( A8 )。这个提交对象比较特殊,它有两个祖先( A5 和 A7 )。

在这里插入图片描述

此时我们知道了代码的合并是如何进行的,但当我们在两个分支都同时修改了同一处代码时,那么当你合并代码的时候碰到这样的提示时,就意味着我们在进行代码合并时出现了代码冲突。

// 代码合并冲突提示
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

当我们打开冲突的文件,你会看到类似于这种

<<<<<<< HEAD
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
  please contact us at support@github.com
</div>
>>>>>>> iss53

可以看到 ======= 隔开的上半部分,是 HEAD(即 Master 分支,在运行 Merge 命令时所切换到的分支)中的内容,下半部分是在 testing 分支中的内容。解决冲突的办法无非是二者选其一或者由你手动整合到一起。但是 Git 是如何进行 Diff 的呢?

代码合并算法(Myers)

Git 的 Diff 是基于 Myers 算法进行的,那么先来了解一下 Myers 算法。Myers 算法由 Eugene W.Myers 在 1986 年发表的一篇论文中提出,是一个能在大部分情况产生”最短的直观的“diff的一个算法。

differ

Diff 就是寻找目标文本和源文本之间的区别,也就是将源文本变成目标文本所需要的操作。举一个 Myers 算法中最常用的例子,A1 = ABCABBA,A2 = CBABAC,那么通过怎样的操作才能使得由 A1 转变成 A2 呢。

例如:
1.  - A       2.  - A       3.  + C
    - B           + C           - A
      C             B             B
    - A           - C           - C
      B             A             A
    + A             B             B
      B           - B           - B
      A             A             A
    + C           + C           + C

这三种都是有效的变动方式,其实这种转化过程有很多种,那么那种转换过程才是最高效的呢?我们在变动时有这么一个共识:

  • 删除后新增,比新增后删除要好
  • 当修改一块代码时,整块的删除然后新增,比删除新增交叉在一起要好

面对这个问题我们可以将这个问题抽象成一个数学问题,生成“直观”的 Diff 算法。抽象的结果是:寻找 Diff 的过程可以被表示为图搜索

图搜索

还是以两个字符串,A1 = ABCABBA ,A2 = CBABAC 为例,根据这两个字符串我们可以构造下面一张图,横轴是 A1 内容,纵轴是 A2 内容,要想从 A1 变换成为 A2抽象的数学问题就是求一条从左上角到右下角的路径。图中每一条从左上角到右下角的路径,都表示一个 Diff。向右表示“删除”,向下表示”新增“,对角线则表示“原内容保持不动“。

在这里插入图片描述

将上述的共识再次进行数学抽象化就对应为:

  • 路径长度最短(对角线不算长度)
  • 先向右,再向下(先删除,后新增)

就像走迷宫一样,我们就可以摸索得到这么一条路径:

.  (0, 0) -> (1, 0) -> (2, 0).  (2, 0) -> (3, 1).  (3, 1) -> (3, 2).  (3, 2) -> (4, 3) -> (5, 4).  (5, 4) -> (6, 4).  (6, 4) -> (7, 5).  (7, 5) -> (7, 6)

在这里插入图片描述

这条路径代表的 diff 的操作为:

- A
- B
  C
+ B
  A
  B
- B
  A
+ C

代码 diff

我们以上文中的几次提交中的任意两次 2c5331f 60814e1 提交进行 diff:

command: git diff 2c5331f 60814e1

2c5331f60814e1 表示两个文件的 Hash,相当于它们的 HashID,这个 HashID 就代表了一个文件对象的特定版本,最后的一串数字代表了一个文件的模式。

在这里插入图片描述

Git 会告诉你哪些行存在差异,它们被显示在两个 “@@” 符号之前,以上图示例中所表示的含义为:

  • 来自文件 a (标记为 “-”),从第 1 行开始之后的 15 行代码。
  • 来自文件 b (标记为 “+”),从第 1 行开始之后的 15 行代码。
@@ -1,15 +1,5 @@
-  console.log('watch')
-
-  const add = (a,c) => {
-    return a+c
-  }
-  const reduce=(a)=>{
-    if (a<0){
-      return  "第一位不能为负数"
-    }else {
-      return a-b
-    }
+  const add = (a,b) => {
+    return a+b
   }
   add(4,8)
-  console.log(reduce(-2,-9))
-  console.log(new Date().getDate(),'第二次提交')

而”@@”后面的紧跟着的部分就是其上下文信息,在每一个被改动过的代码行之前都会前置一个 “+” 或是 “-” 符号。这些符号可以帮助你准确了解版本 a 和版本 b ,例如前置了 “-” 符号的行就代表来自版本 a ,反之带有符号 “+” 的行就代表来自于版本 b 。

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

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

相关文章

网络硬盘录像机NVR程序源码和NVR模组展示及设备开机配置和主界面使用介绍

NVR软硬一体机支持录像设置&#xff0c;还具有录像回放、录像备份和报警设置等多种功能。接下来&#xff0c;我们首先看一下硬件连接&#xff0c;并开机后的基础配置操作。 NVR的优势&#xff08;包括不限于&#xff09;&#xff1a; 1.支持录像回放 支持设置冗余录像&#…

Java开发中使用腾讯云OCR进行身份证识别与COS云存储实践

文章目录 完整代码代码讲解总结 在Java开发中&#xff0c;处理身份证识别和云存储是一项常见的需求&#xff0c;尤其是在需要用户身份验证的应用场景中。今天&#xff0c;我想和大家分享一个实际的案例&#xff0c;展示如何利用腾讯云的OCR服务进行身份证识别&#xff0c;并将识…

记一次:Datawhale AI夏令营-第四期-魔搭-AIGC-Task03

前言&#xff1a;书接上回&#xff0c;前面说了AIGC的了解和精读baseline&#xff0c;那么我们可以再次的抽丝拔茧&#xff0c;开始了解GUI部分和微调部分。 一、ComfyUI应用部分 1、什么是GUI&#xff1f; 2、什么是ComfyUI&#xff1f; 3、ComfyUI核心模块 4、ComfyUI图片生…

搭建高可用OpenStack(Queen版)集群(七)之部署dashbord(Horizon)控制节点集群

一、搭建高可用OpenStack&#xff08;Queen版&#xff09;集群之部署dashbord&#xff08;Horizon&#xff09;控制节点集群 一、Dashboard(horizon)简介 Dashboard(horizon)是一个web接口&#xff0c;使得云平台管理员以及用户可以管理不同的openstack资源及服务。 二、部署da…

AAAI Reproducibility Checklist Latex 模板

官网介绍 AAAI-25 Reproducibility Checklist - AAAI This paper: Includes a conceptual outline and/or pseudocode description of AI methods introduced (yes/partial/no/NA)Clearly delineates statements that are opinions, hypothesis, and speculation from object…

Science Robotics封面 | 当机器人学会用‘快照‘导航,轻重量小内存实现‘长途跋涉‘

一个仅重56克的微型无人机实现了自主视觉导航&#xff0c;这听起来似乎不可思议。 然而&#xff0c;荷兰代尔夫特理工大学的研究人员通过向大自然学习&#xff0c;成功让这样一个轻如鸿毛的小家伙完成了长达100米的自主视觉路径跟随。 这一突破性成果不仅为微型机器人的自主导…

【Vue3】高颜值后台管理模板推荐

ELP - 权限管理系统 基于Vue 3框架与PrimeVue UI组件库技术精心构建的高颜值后台权限管理系统模板。该模板系统已成功实现基于RBAC&#xff08;Role-Based Access Control&#xff09;模型的权限管理系统和字典数据管理模块&#xff0c;后端则使用了Spring Boot框架&#xff0…

008 | 基于RNN和LSTM的贵州茅台股票开盘价预测

&#x1f449;&#x1f449;&#x1f449; 《玩转Python金融量化专栏》&#x1f448;&#x1f448;&#x1f448; 订阅本专栏的可以下载对应的代码和数据集 &#x1f680; 上一篇&#x1f31f; 下一篇⬅️ 007 期权定价与布莱克-斯科尔斯计算009 上证50ETF基金数据分析及预测…

WebRTC音视频开发读书笔记(一)

一、基本概念 WebRTC(Web Real-Time Communication&#xff0c;网页即时通信)于2011年6月1日开源&#xff0c;并被纳入万维网联盟的W3C推荐标准&#xff0c;它通过简单API为浏览器和移动应用提供实时通信RTC功能。 1、特点 跨平台&#xff1a;可以在Web&#xff0c;Android、…

Unity扩展 Text 彩虹文本

本文章用于原生组件 Text 的扩展 TextRainbow&#xff0c;对于新版TextMeshPro不适用。 一、效果预览图&#xff1a; 默认&#xff1a; 随机&#xff1a; 循环&#xff1a; 二、原理 通过强制刷新顶点数据&#xff0c;来修改颜色。 通过Unity中自带的 BaseMeshEffect 抽…

五、OpenCVSharp 中的图像滤波与平滑

文章目录 简介一、均值滤波1. 原理和数学公式2. 不同大小的滤波核效果对比3. 边界处理方式二、高斯滤波1. 高斯核的生成2. 标准差对滤波效果的影响3. 高斯滤波的应用场景(如去除高斯噪声)三、中值滤波1. 中值的计算方法2. 中值滤波对椒盐噪声的处理效果3. 中值滤波的性能分析…

AWS Lambda 十年回顾:功能总览、更新记录与入门指南

这次&#xff0c;我为2014年11月发布的AWS Lambda创建了一个历史时间表。AWS Lambda 是一项无服务器、全托管的代码执行服务&#xff0c;今年2024年11月将迎来其宣布发布的十周年纪念。虽然提前了一些&#xff0c;但为了提前庆祝这一重要时刻&#xff0c;我写了这篇文章。 文章…

空间间隔组(Spacers)-Qt-思维导图-学习笔记

空间间隔组&#xff08;Spacers&#xff09; 空间间隔组&#xff08;Spacers&#xff09; &#xff08;1&#xff09;Horizontal Spacer:水平间隔 &#xff08;2&#xff09;Vertical Spacer:垂直间隔 QSpacerItem 控件简介 继承关系&#xff1a;QSpacerItem 继承自 QLayou…

面试必备之——TCP/UDP(二)

TCP流量控制 让发送方发送的速率不要太快&#xff0c;要让接收方开的及接收&#xff0c;防止发送方发送太快&#xff0c;导致接收方来不及接收。是端到端之间的控制 滑动窗口是实现流量控制的方法之一 TCP流量控制-滑动窗口 滑动窗口是传输层进行流控的一种措施&#xff0c;…

电脑版视频剪辑软件哪个好?适合新手使用的剪辑软件!

电脑版视频剪辑软件哪个好&#xff1f;在电脑版视频剪辑软件的选择上&#xff0c;每位用户都有其独特的偏好和需求。对于初学者而言&#xff0c;寻找一款操作简便、功能齐全的软件至关重要。为大家推荐几款常用的视频剪辑软件&#xff1a; 1、福昕视频剪辑 2、HitFilm 3、DaVin…

天了噜,IDEA竟然还有这种坑!

问题描述 IDEA 编辑器 idea Cannot resolve symbol 鼠标聚焦时&#xff0c;错误信息为&#xff1a;” idea Cannot resolve symbol “ IDEA自动修复功能 提示信息如下&#xff0c;然而并没有什么卵用。 问题梳理&#xff1a; IDEA 这个目录下的包都引入不了 import org.s…

Redis的分布式部署方案-哨兵

Redis 的主从复制模式下&#xff0c;⼀旦主节点由于故障不能提供服务&#xff0c;需要⼈⼯进⾏主从切换&#xff0c;同时⼤量 的客⼾端需要被通知切换到新的主节点上&#xff0c;对于上了⼀定规模的应⽤来说&#xff0c;这种⽅案是⽆法接受的&#xff0c; 于是 Redis 从 2.8 开…

uniapp加载第三方字体方案对比(附原生微信小程序方案)

文章目录 官方文档uniapp文档微信小程序文档 下载字体包引入方案限制微信小程序限制uniapp的限制 方案对比方案1&#xff1a;CSS本地加载方案2&#xff1a;CSS远程加载方案3&#xff1a;转换为base64&#xff0c;然后通过css引入方案4&#xff1a;使用uni.loadFontFace() 页面使…

手撕初阶数据结构之---排序

1.排序概念及运用 排序&#xff1a;所谓排序&#xff0c;就是使⼀串记录&#xff0c;按照其中的某个或某些关键字的⼤⼩&#xff0c;递增或递减的排列起来的操作。 常见的排序算法 直接插入排序的时间复杂度是O(N^2) 这个是最差的情况下&#xff0c;就是大的在前面&#xff…