深入剖析 Git 对象底层原理

一、引言

在我们日常使用 Git 时,通常的操作是:

  • 在写完一段代码后,执行 git add命令,将这段代码添加到暂存区中
  • 然后再执行 git commitgit push 命令,将 本地 Git 版本库中的提交同步到服务器中的版本库中

Git 在中间做了什么,它如何存储不同的文件和内容,以及如何区分不同分支下的文件版本呢?日常操作对这些自动的操作都是无感的。
但是如果哪天一旦上述操作中出现了错误,需要找回自己的代码时,如果不懂 Git 其内部存储原理,是没法找回的,因此为了避免这种情况,就有必要去了解其内部的存储——Git 对象的原理。

二、Git 对象

2.1. Git 对象概述

我们知道,Git 是一个内容寻址文件系统,其核心部分是一个键值对数据库。
当我们向 Git 仓库中插入任意类型的内容时,它会返回一个唯一的键。我们可以通过该键在任意时刻再次取回插入的内容。
比如我们初始化 GitDemo ,发现 Git 对 objects 目录进行了初始化,并创建了 pack 和 info 子目录,但均为空:

$ git init GitDemo
Initialized empty Git repository in D:/GitDemo/.git/
$ find .git/objects
.git/objects
.git/objects/info
.git/objects/pack
$ find .git/objects -type f

然后创建一个 readme.txt 文本,执行 git add后会发现在 .git/objects 中新增了一个文件夹 89 和文件 dab47ae90ebdfee4e6cb3d64708cd73e9c5472

$ echo 'read me please' > readme.txt
$ git add readme.txt
$ find .git/objects -type f
.git/objects/89/dab47ae90ebdfee4e6cb3d64708cd73e9c5472

查看其文件内容,类型和大小:

$ git cat-file -p 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
read me please
$ git cat-file -t 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
blob
$ git cat-file -s 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
15

这个键值为 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472的对象就是 Git 对象中的 blob 对象。而且 Git 中所有的对象都存储在 .git/objects目录(也叫做对象库)中。
这个键值是一个 SHA-1 的哈希值,由 40 个十六进制的数字组成。它是通过一个将待存储的数据外加一个头部信息一起做 SHA 算法运算而得到的校验和。40 个十六进制数字就相当于 160 比特,当用 SHA-1 对不同对象进行区分和识别时,冲突的概率就会极低,不用存储文件的具体类型,用 blob 和 SHA-1 就足以分辨不同文件内容了。
下面来看看 Git 对象的类型:

2.2. Git 对象类型

2.2.1. Blob 对象

1. Blob 对象的定义和作用

Blob(Binary Large Object,二进制大对象)是Git中的一种对象类型,用来指代某些可以包含任意数据的变量或文件。它是Git对文件内容的一种抽象表示。每个文件在Git仓库中都被表示为一个独立的Blob对象。Blob对象保存了文件的原始二进制数据,无论文件是文本文件还是二进制文件,Git都以Blob对象的形式存储它们。
比如在上一节中的 readme.txt 文本,在 Git 中就是以 blob 对象存储的:

$ git cat-file -t 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
blob
$ git cat-file -p 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
read me please
  • **当在Git仓库中添加、修改或删除某个文件时,Git会创建一个新的Blob对象来存储这个文件的内容。**这样就可以跟踪文件的变化历史,并且可以在需要时恢复到特定的文件版本。

比如我们修改 readme.txt 文本,会发现有两个 blob 对象存储 readme.txt 的两个版本:

//新增一行文本: reading
$ vi readme.txt
$ git add readme.txt
//原来版本的readme.txt内容还存在:
$ git cat-file -p 89dab47ae90ebdfee4e6cb3d64708cd73e9c5472
//新版本的readme.txt内容
$ git cat-file -p b0530c9
read me please
reading
  • 因为在修改内容后创建了新的 Blob 对象,因此 Git 可以使用 Blob 对象来进行文件比较操作。通过比较两个Blob对象的哈希值,Git可以快速确定文件内容是否发生了变化,从而进行版本控制和合并操作。
2. Blob 对象的存储方式

Blob对象在Git中的存储方式是使用对象哈希值来进行索引和存储。具体的存储方式如下:

  1. 当在 Git 仓库中添加文件并执行 git add时,Git 就会提取该内容,然后将内容进行 SHA-1 哈希计算,得到一个40个十六进制字符的哈希值。这个哈希值就是Blob对象的唯一标识符,也就是我们上节提到的键。
  2. 而后如果Blob对象是新的,Git会将它以哈希值(上面由 SHA-1 哈希计算得到的标识符)为文件名存储在对象数据库中(也就是 .git/objects 目录下)。
  3. 存储时,Git将Blob对象的内容写入一个临时文件,并将该文件的路径与哈希值相关联。(一般来说取前两位作为文件目录,剩下的 38 位作为文件名。比如 readme.txt 文件:目录是 89,文件名为 dab47ae90ebdfee4e6cb3d64708cd73e9c5472。)
  4. 此外如果 blob 对象过大,Git会对存储的Blob对象进行压缩,并将压缩后的数据写入真正的对象文件中。这些压缩的文件存储在 .git/objects/pack

2.2.2. Tree 对象

1. Tree 对象的定义和作用

Tree 对象是Git中的一种对象类型,用于表示文件和目录的组织结构。每当向Git仓库中添加一个目录时,Git会创建一个新的Tree对象来表示该目录的结构。Tree对象包含了目录中的文件和子目录的元数据,以及它们对应的Blob或Tree对象的哈希值。
比如我们接着在 GitDemo 仓库中添加目录 lib和文件 readme2.txt 并提交后,当前目录为:

│  readme.txt
│
└─libreadme2.txt

在 git 中的存储如下:

$ git cat-file -p master^{tree}
040000 tree dbff68a947c7cc60653ff64260b372a405939ae2    lib
100644 blob b0530c9b7360a8cea0e4af86475cac70a2985138    readme.txt

master^{tree} 语法表示 master 分支上最新的提交所指向的树对象。lib 子目录(所对应的那条树对象记录)并不是一个数据对象,而是一个指针,其指向的是另一个树对象:
image.png

$ git cat-file -p dbff68a947c7cc
//模式  对象类型   对象的SHA-1值                          文件名
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    readme2.txt

从上面可以发现,一个 Tree 对象包含一条或多条树对象记录。每条记录含有一个指向数据对象或者子目录对象的 SHA-1 指针,以及相应的模式、类型、对象名(SHA-1 值)、文件名信息:
image.png

  1. 模式(Mode):模式表示文件或目录的类型和权限。它是一个八进制数字,通常以4位表示。常见的模式包括:
  • 100644:表示普通文件,即Blob对象。
  • 100755:表示可执行文件,即Blob对象。
  • 040000:表示目录,即Tree对象。
  1. 类型(Type):类型表示列表项所指向的对象类型,即是Blob对象还是Tree对象。
  2. 对象名(Object Name):对象名是对应的Blob或Tree对象的哈希值。它是一个40个十六进制字符的字符串,用于唯一标识对象。
  3. 文件名或目录名(File/Directory Name):文件名或目录名是列表项所代表的文件或目录的名称。

如果记录中的类型为 Blob,表示该项是一个文件;如果该类型为 Tree,表示该项是一个子目录。

2. Tree 对象的存储方式

和 blob 对象的存储方式类似,Tree对象在Git中的存储方式是使用对象哈希值来进行索引和存储。当执行 git add 时 Git 内部的操作有:

  1. 构建树对象:当你在Git仓库中添加、修改或删除文件时,Git会根据当前目录结构构建一个Tree对象。该Tree对象包含了目录中的文件和子目录的元数据,以及它们对应的Blob或Tree对象的哈希值。
  2. 哈希计算:Git会对Tree对象的内容进行哈希计算,生成一个40个十六进制字符的哈希值。这个哈希值就是Tree对象的唯一标识符。
  3. 检查存储:Git会检查对象数据库中是否已存在具有相同哈希值的Tree对象。如果存在,则直接引用已有的对象;如果不存在,则进行存储。
  4. 存储对象:如果Tree对象是新的,Git会将它以哈希值为文件名存储在对象数据库中。对象数据库通常位于".git/objects"目录下。存储时,Git将Tree对象的内容以特定的格式写入一个临时文件,并将该文件的路径与哈希值相关联。
  5. 压缩和索引:Git会对存储的Tree对象进行压缩,并将压缩后的数据写入真正的对象文件中。同时,Git会更新索引文件,将Tree对象的哈希值与文件路径进行映射。

2.2.3. Commit 对象

1. Commit 对象的定义和作用

Commit对象是Git中的一种对象类型,用于记录代码仓库中的提交操作(也就是执行 git commit命令)。每个Commit对象代表一个特定的提交操作,包含了提交的元数据和指向代码快照的引用。通过Commit对象,Git能够跟踪代码修改的历史,并实现版本控制和代码回溯等功能。
如下图所示,每个 Commit 对象就是一个 version 版本,Commit 对象通过指向代码快照(也就是一个 Tree 对象)的引用,记录了代码仓库在某个特定时间点的状态。

我们再次引用上面 Tree 对象中的 GitDemo 仓库案例,此时仓库中有如下文件和目录:

│  readme.txt
│
└─libreadme2.txt

可以通过 git cat-file master命令查看此时的 commit 对象:

//master就是一个指向commit对象的指针, 其内部存储Commit对象的SHA-1值
$ cat .git/refs/heads/master
2b2af66549827bd6a466fe43081f406c2a12900b
$ git cat-file -p 2b2af665498
tree 2503e9e0c4f774fc5ce298f4972f0e6d3a800d6f
parent 7b34a1e750918570ed610ee1f228e83b43a1192e
author wangJw <wangJw@163.com> 1705458723 +0800
committer wangJw <wangJw@163.com> 1705458723 +0800second commit

从上面可知,一个 commit 对象由这样几个部分组成:

  1. 指向代码快照的引用(tree):Commit对象包含一个指向代码快照的引用,通常是指向一个Tree对象。该Tree对象记录了提交时代码仓库中文件和目录的状态。
  2. 父提交(parent):Commit对象可以有一个或多个父提交,指向前一个或多个Commit对象。这构成了提交历史的链式结构。通常,一个Commit对象的父提交是它之前的一个Commit对象,除非进行了分支合并等操作。
  3. 作者(author):Commit对象记录了提交的作者信息,包括姓名和电子邮件。作者是指实际进行代码更改的人。
  4. 提交者(Committer):Commit对象还包含了提交者信息,通常与作者相同。提交者是指将更改提交到代码仓库的人。
  5. 提交消息(Commit Message):也就是 second commit 中的内容, Commit对象包含了提交时附加的可选消息,用于描述提交的目的、更改的内容、修复的问题等。提交消息可以提供其他开发者和团队成员了解提交的背景和目的。
  6. Commit对象的哈希值(SHA-1 值):每个Commit对象都有一个唯一的哈希值,用于标识该对象。

加上 commit 对象和 master 指针,可以完善在 tree 对象中的图:
image.png

2. Commit 对象的存储方式

当执行 git commit命令提交代码时,commit 对象随之创建,Git 的内部操作有:

  1. 内容提取:执行git commit命令提交代码时,Git会提取提交的相关信息,包括作者、提交者、提交时间、提交消息和父提交等。
  2. 创建对象:Git会将提交信息和父提交的引用等数据组合成一个Commit对象。
  3. 哈希计算:Git会对Commit对象的内容进行SHA-1哈希计算,得到一个40个十六进制字符的哈希值。这个哈希值就是Commit对象的唯一标识符。
  4. 检查存储:Git会检查对象数据库中是否已存在具有相同哈希值的Commit对象。如果存在,则直接引用已有的对象;如果不存在,则进行存储。
  5. 存储对象:如果Commit对象是新的,Git会将它以哈希值为文件名存储在对象数据库中。对象数据库通常位于 .git/objects 目录下。存储时,Git将Commit对象的内容写入一个临时文件,并将该文件的路径与哈希值相关联。
  6. 压缩和索引:Git会对存储的Commit对象进行压缩,并将压缩后的数据写入真正的对象文件中。同时,Git会更新索引文件,将Commit对象的哈希值与文件路径进行映射。

2.2.4. Tag 对象

1. Tag 对象的定义和作用

Tag对象是Git中的一种对象类型,用于给特定的提交打上标记。Tag对象的主要作用是标记代码仓库中的特定提交或里程碑。它可以用于记录发布版本、重要的里程碑、稳定的代码快照等。git 标签分为两种类型:轻量标签和附注标签。

轻量标签

轻量标签是指向提交对象的引用:

//创建轻量级标签
$ git tag firstTag
//查看标签:
$ git tag
firstTag

当创建了 firstTag 后,会在.git/refs/tags 目录下创建一个名为 firstTag 的文件,其内容指向当前的 commit 对象的 SHA-1 值

$ cat .git/refs/tags/firstTag
2b2af66549827bd6a466fe43081f406c2a12900b
//轻量标签指向提交对象的引用
$ git cat-file -t firstTag
commit
$ git cat-file -p firstTag
tree 2503e9e0c4f774fc5ce298f4972f0e6d3a800d6f
parent 7b34a1e750918570ed610ee1f228e83b43a1192e
author wangJw <wangJw@163.com> 1705458723 +0800
committer wangJw <wangJw@163.com> 1705458723 +0800second commit

我们发现,轻量标签 firstTag 中的内容只有一个指向提交对象的 SHA-1 值。没有其他内容,因此无法知道何人,什么时间创建的标签。在团队开发中很容易发生混淆,因此可以用另外一种打标签的方式:附注标签

附注标签

附注标签则是仓库中的一个独立对象,使用带参数 -a-m <msg>git tag 命令:

//创建一个空提交:
$ git commit --allow-empty -m "empty commit for tagTest"
[master 8a4678f] empty commit for tagTest
//创建一个附注标签
$ git tag -m "secondTag" secondTag
//查看所有标签
$ git tag
firstTag
secondTag

这个时候再来看看 .git/refs/tags中的 secondTag 标签内容:

//查看该标签的类型
$ git cat-file -t secondTag
tag
//再来看看secondTag标签的内容
$ git cat-file -p secondTag
object 8a4678fae181c16c6f4ff0e6a618991128d86da2
type commit
tag secondTag
tagger wangJw <wangJw@163.com> 1705480524 +0800secondTag

主要由这样几个部分组成:

  1. 标签指向的提交对象(object):附注标签对象中包含一个指向特定提交的引用。此处 object 中的值为我上面的提交对象的 SHA-1 值
  2. 标签指向对象类型(type):指向的提交对象的类型
  3. 标签名称(tag):附注标签对象包含一个唯一的标签名称,用于标识和引用该标签。
  4. 标签作者(tagger):附注标签对象记录了标签的作者信息,包括姓名和电子邮件地址。作者是指创建该标签的人。
  5. 标签消息(Tag Message):其中的 "secondTag"内容,附注标签对象包含一个可选的标签消息,用于描述标签的目的、里程碑或其他相关信息。标签消息可以提供其他开发者和团队成员了解标签的背景和用途。

我们再来看看 Tag 对象的存储方式

2. Tag 对象的存储方式

当执行带有 -a-m <msg>git tag命令时,Git 就会由如下操作:

  1. 创建对象:当你执行创建标签的操作(如git tag命令)时,Git会创建一个Tag对象。
  2. 内容提取:Tag对象包含标签的名称、类型、标签指向的提交、标签作者、标签创建时间、标签消息等信息。
  3. 哈希计算:Git会对Tag对象的内容进行SHA-1哈希计算,得到一个40个十六进制字符的哈希值。这个哈希值就是Tag对象的唯一标识符。
  4. 检查存储:Git会检查对象数据库中是否已存在具有相同哈希值的Tag对象。如果存在,则直接引用已有的对象;如果不存在,则进行存储。
  5. 存储对象:如果Tag对象是新的,Git会将它以哈希值为文件名存储在对象数据库中。对象数据库通常位于 .git/objects 目录下。存储时,Git将Tag对象的内容写入一个临时文件,并将该文件的路径与哈希值相关联。
  6. 压缩和索引:Git会对存储的Tag对象进行压缩,并将压缩后的数据写入真正的对象文件中。同时,Git会更新索引文件,将Tag对象的哈希值与文件路径进行映射。

三. Git 对象的存储

3.1 SHA-1 算法如何生成哈希值

SHA-1(Secure Hash Algorithm 1)是一种用于生成哈希值的加密算法。该算法将任意长度的输入经过散列运算转换为固定长度的输出。这个固定长度的输出就叫做对应输入内容的数字摘要或者哈希值。
那么对于 Git 对象中的 SHA-1 哈希值是如何生成的?
在 《Pro Git 2nd》这本书提到,SHA-1 哈希值是通过将待存储的数据+一个头部信息(header)一起做 SHA-1 校验运算而得到的。
而在头部信息由这些部分组成:

  • 对象类型字符串,比如"blob", “tree”, “commit”, “tag”
  • 空格
  • 数组内容的字节数
  • 空字节(null byte)

Git 会将上述的头部信息和文件原始数据拼接,来计算出 SHA-1 校验和。在 Linux 中有 sha1sum 命令可以生成 SHA1 哈希值,下面来验证一下我们生成的 SHA1 哈希值和 Git 是不是相同的:

//当前目录结构
│  a.txt
│
└─bc.txt

3.1.1. blob 对象的 SHA1 哈希值

先来看看 blob 对象,也就是 a.txt 对应的文件内容的 SHA1 哈希值生成过程,

//a.txt中的内容为:
$ cat a.txt
123
//字符数为3
$ git cat-file blob HEAD:a.txt | wc -c
3

其头部信息为 blob 3\000
在文件内容上加上头部信息,然后对新文件内容执行 SHA-1 哈希算法:

$ (printf "blob 3\000"; git cat-file blob HEAD:a.txt) | sha1sum
d800886d9c86731ae5c4a62b0b77c437015e00d2 *-

查看在 Git 仓库中是否找到该 SHA-1 值对应的 blob 对象

$ git cat-file -p d80088
123

说明执行 sha1 算法和 Git 操作算法得到的结果一致,验证了 Git 中 SHA-1 哈希值的生成过程

3.1.2. commit 对象的 SHA1 哈希值

此时在提交链最末端的 commit 对象内容是:

$ git cat-file commit master
tree 46bda27c4834d428a388841808fdaa7ca15a7bc1
parent 61b04b17412e1d9639db2a6b1b4e83319473a14a
author wangJW <1w@163.com> 1679818066 +0800
committer wangJW <1w@163.com> 1679818066 +0800second commit

根据头部信息的组成,需要知道 commit 中的字符数:

$ git cat-file commit HEAD | wc -c
218

然后加上空格以及空字符串:commit 218\000,然后与 commit 对象内容拼接,将拼接后的内容计算 SHA1 校验和:

$ (printf "commit 218\000"; git cat-file commit HEAD) | sha1sum
2514fb61430ad5beea4f80e2548f1fbdfd97d74d *-

再来看看 HEAD 文件中对应的 Commit 对象以及其内容是不是与上面的 SHA1 相符:

$ cat .git/HEAD
2514fb61430ad5beea4f80e2548f1fbdfd97d74d
$ git cat-file -p 2514fb6
tree b79d07773ea2d47125f1e7078bbc8113a74a2fa7
parent 61b04b17412e1d9639db2a6b1b4e83319473a14a
author wangJW <1w@163.com> 1705493204 +0800
committer wangJW <1w@163.com> 1705493204 +0800second commit

从结果可知,说明 Git 内部就是采用头部信息+内容利用 SHA1 算法得到的哈希值。
再来看看 tree 对象

3.1.3 tree 对象的 SHA1 哈希值

直接拿上面 commit 对象中的 tree 对象来做实验,首先查看 tree 对象中的内容和其中的字节数

$ git cat-file -p b79d0777
100644 blob d800886d9c86731ae5c4a62b0b77c437015e00d2    a.txt
040000 tree ceb3bfbba0a2f151a88628549113aa5c1be65bf5    b
//此时就是对应HEAD指针指向的树
$ git cat-file tree HEAD^{tree} | wc -c
61

然后根据头部信息+tree 对象内容信息计算 SHA-1 值:

$ (printf "tree 61\000"; git cat-file tree HEAD^{tree}) | sha1sum
b79d07773ea2d47125f1e7078bbc8113a74a2fa7 *-

发现此时计算出的 SHA-1 值和 commit 对象所指向的值完全相同,再次验证 SHA-1 生成方式。最后再来看看 tag 对象

3.1.4 tag 对象的 SHA1 哈希值

首先创建一个 tag 对象:

$ git tag -m "firstTag" firstTag
//创建成功
$ git tag
firstTag

获取这个 tag 对象的字节数,并执行 SHA1 哈希算法

$ git cat-file tag firstTag | wc -c
136$ (printf "tag 136\000"; git cat-file tag firstTag) | sha1sum
d0c8f7e57f23b368152094bf3e57e70b3569cb13 *-

从 tag 对象的执行结果说明,SHA1 哈希值生成方式正确。

3.2 Git 对象的存储位置

从前面查看 blob 对象内容时提到过,在 Git 中的对象存储在 Git 仓库的 .git/objects 目录下。
在下列情况中,会触发 Git 存储对象的操作:

  1. git add:在执行 git add 命令暂存某个文件 时,Git 将会将文件的内容转换为一个 Blob 对象,并将该对象存储在本地对象数据库中。这个操作将文件添加到暂存区(Staging Area),为接下来的提交做准备。
  2. git commit:执行 git commit 命令时,Git 首先会创建一个新的 Commit 对象。这个 Commit 对象包含了提交的元数据信息,如作者、提交时间、提交信息等。同时,Git 会创建一个对应的根目录的 Tree 对象,记录了当前提交时仓库中所有文件的快照。最后,Git 将这个 Commit 对象存储在本地对象数据库中,并将当前分支指向该 Commit 对象,表示当前的工作状态。
  3. git tag:执行创建附注标注命令时,Git 会创建一个 Tag 对象,该对象包含标签的元数据信息,并指向一个特定的 Commit 对象。这个 Tag 对象会被存储在本地对象数据库中,以便后续引用。
  4. git merge:执行 git merge 命令时,Git 会创建一个新的 Commit 对象,该对象包含合并的元数据信息,并引用两个或多个合并的分支的 Commit 对象。Git 会将这个新的 Commit 对象存储在本地对象数据库中,并将当前分支指向该新的 Commit 对象。

四、 总结

本文通过 .git 目录角度解析 Git对象

  1. Git 对象主要有以下四种类型:Blob存储文件内容,Tree记录文件结构,Commit记录历史,Tag添加标签。
  2. Git 通过提取对象内容加头信息,使用 SHA-1 算法生成哈希值作为唯一 ID
  3. Git 对象存储于 .git/objects目录下,其中对象 ID 值前两位作为目录名,后 38 位作为文件名
  4. 在在执行暂存(add)、提交(commit)、合并(merge)、打标签(tag)等操作时都会触发 Git 对象的存储

参考资料

《Git 权威指南》

《Git Pro》

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

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

相关文章

vscode 格式化代码

在 Visual Studio Code 中&#xff0c;你可以使用以下步骤来格式化代码&#xff1a; 打开你的代码文件。选择你要格式化的代码部分或按 CtrlA 来全选。按下 ShiftAltF&#xff0c;这会触发 "格式化文档" 的命令。 如果你的键盘布局没有 "Alt" 键&#xf…

Three.js 学习笔记之模型(学习中1.17更新)

文章目录 模型 几何体 材质模型点模型Points - 用于显示点线模型Line | LineLoop | LineSegments网格模型mesh - 三角形 几何体BufferGeometry缓冲类型几何体BufferGeometry - 没有任何形状的空几何体创建几何体的方式BufferAttribute Types定义顶点法线 geometry.attributes…

Maven工程 — 继承与聚合 相关知识点详解

简介&#xff1a;这篇帖子主要讲解Maven工程中的继承与聚合的相关知识点&#xff0c;用简洁的语言和小编自己的理解&#xff0c;深入浅出的说明Maven工程的继承与聚合。 目录 1、继承 1.1 继承关系的实现 1.2 版本锁定 2、聚合 2.1 聚合方法 3、总结 1、继承 图 1-1 继承…

2018年认证杯SPSSPRO杯数学建模C题(第一阶段)机械零件加工过程中的位置识别全过程文档及程序

2018年认证杯SPSSPRO杯数学建模 基于轮廓特征的机械零件位置识别研究 C题 机械零件加工过程中的位置识别 原题再现&#xff1a; 在工业制造自动生产线中&#xff0c;在装夹、包装等工序中需要根据图像处理利用计算机自动智能识别零件位置&#xff0c;并由机械手将零件自动搬…

[go语言]输入输出

目录 知识结构 输入 1.Scan ​编辑 2.Scanf 3.Scanln 4.os.Stdin --标准输入&#xff0c;从键盘输入 输出 1.Print 2.Printf 3.Println 知识结构 输入 为了展示集中输入的区别&#xff0c;将直接进行代码演示。 三者区别的结论&#xff1a;Scanf格式化输入&#x…

【Ubuntu】使用NFS共享挂载硬盘

在Ubuntu系统上使用NFS&#xff08;Network File System&#xff09;将某个硬盘挂载并在另一个Ubuntu系统上进行挂载的过程可以分为两个步骤&#xff1a;一是将硬盘挂载到服务器上&#xff0c;二是在客户端上挂载这个共享。 以下是详细步骤&#xff1a; 在服务器上挂载硬盘并…

Python中re模块search和findall函数的使用

1.search函数&#xff1a; re.search(pattern,string,flags0) 用于整个字符串中搜索第一个匹配的值&#xff0c;如果匹配成功&#xff0c;结果为Match对象&#xff0c;否则结果位None。 import re pattern\d\.\d sI study Python3.11 every day Python2.7 I love you matchr…

ElasticSearch(1):Elastic Stack简介

1 简介 ELK是一个免费开源的日志分析架构技术栈总称&#xff0c;官网https://www.elastic.co/cn。包含三大基础组件&#xff0c;分别是Elasticsearch、Logstash、Kibana。但实际上ELK不仅仅适用于日志分析&#xff0c;它还可以支持其它任何数据搜索、分析和收集的场景&#xf…

MongoDB面试系列-02

1. MongoDB 中必须调用 getLastError 来确保写操作生效吗&#xff1f; MongoDB中不管有没有调用getLastError&#xff08;又称为Safe Mode&#xff09;&#xff0c;服务器执行的操作都会一样。 而调用getLastError只是为了确认写操作是否成功提交&#xff0c;但是写操作的安全…

MySQL中根据出生日期计算年龄

创建student表 mysql> create table student( -> sid int primary key comment 学生号, -> sname varchar(20) comm…

「实战应用」如何用DHTMLX Gantt构建类似JIRA式的项目路线图(二)

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的所有需求&#xff0c;是最完善的甘特图图表库。 在web项目中使用DHTMLX Gantt时&#xff0c;开发人员经常需要满足与UI外观相关的各种需求。因此他们必须确定JavaScript甘特图库的…

Android Studio由于开启代理无法下载依赖,一直在Build model

一、问题描述 正常打开AS项目&#xff0c;一直显示Build model就是不下载依赖 二、问题解决 1、首先选择No Proxy&#xff0c;可以看到这位同学之前是使用的代理。 2、打开下面文件&#xff0c;然后删除某尾的4行。 3、面对提示框&#xff0c;直接点击OK。 4、然后停…

IIS 缓存, 更新后前端资源不能更新问题

解决办法: 通常只需要index.html 不缓存即可, 其他文件都是根据index.html 中的引用去加载; 正确的做法是在 站点下增加 web.config 文件, 内容如下: 我这个是因为目录下有个config.js 配置文件, 也不能缓存, 所以加了两个 <?xml version"1.0" encoding&quo…

基于Python flask的猫眼电影票房数据分析可视化系统,可以定制可视化

技术方案 猫眼电影票房数据分析可视化系统是基于Python Flask框架开发的一款用于分析和展示猫眼电影票房数据的Web应用程序。该系统利用Flask提供了一个简单而强大的后端框架&#xff0c;结合Request库进行网络爬虫获取猫眼电影票房数据&#xff0c;并使用Pyecharts进行可视化…

消息中间件面试题

目录 一.为什么使用消息队列 二.RabbitMQ 1.RabbitMQ如何保证消息不丢失 2.RabbitMQ消息的重复消费问题 3.RabbitMQ延迟队列 4.RabbitMQ消息堆积 5.RabbitMQ高可用机制 三.Kafka 1.Kafka如何保证消息不丢失 2.Kafka如何保证消费消息的顺序性 3.Kafka高可用机制 4.Ka…

运维笔记之linux运维管理基础

课程链接 001_课程介绍_哔哩哔哩_bilibili 编辑器vi/vim 在 CentOS 上使用 Vim 编辑器时&#xff0c;可以进行更多操作&#xff0c;包括复制、粘贴、删除、查找等。以下是一些常用的 Vim 操作命令&#xff1a; 复制光标所在行&#xff1a;按下 yy 键。剪切光标所在行&#…

MongoDB聚合:$set

聚合$set阶段可以为文档添加新的字段。$set输出的文档包含输入文档中的所有现有字段和新添加的字段。$set是$addFields的别名&#xff0c;从MongoDB4.2开始支持。$set和$addFields等价于$project阶段&#xff0c;这两个阶段都等同于 $project 阶段&#xff0c;后者明确指定输入…

黑马程序员——javase基础——day05——面向对象基础

目录&#xff1a; 面向对象 面向对象介绍为什么要用面向对象编程面向对象.重点学习什么?类和对象 什么是类什么是对象对象的属性和行为类的定义对象的使用学生类的定义和使用对象内存图 Java内存分配单个对象多个对象思考&#xff1a;多个引用指向相同成员变量和局部变量的区…

未来能源转型之路:2023年第十三届中国国际储能大会启示录

在2023年第十三届中国国际储能大会上&#xff0c;全球各地的能源专家、学者和企业代表齐聚一堂&#xff0c;共同探讨了储能技术在推动能源转型中的重要作用。对于我们普通人来说&#xff0c;从这场大会中可以学到什么呢&#xff1f; 一、储能技术是未来能源发展的关键 随着可再…

《剑指 Offer》专项突破版 - 面试题 15 : 字符串中的所有变位词(C++ 实现)

题目链接&#xff1a;LCR 015. 找到字符串中所有字母异位词 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 输入字符串 s1 和 s2&#xff0c;如何找出字符串 s2 的所有变位词在字符串 s1 中的起始下标&#xff1f;假设两个字符串中只包含英文小写字母。例如&…