.git 目录中有什么?

news/2024/4/23 20:11:14/

好吧,我想你们中的大多数人每天都或多或少地使用 git,但是您是否研究过 git 创建的 .git 文件夹中的内容?本文[1]我们将一起探索一下,了解里面到底发生了什么。

git 在基本层面上只是一堆通过文件名相互链接的文本文件。

init

众所周知,我们从 git init 开始我们的 git 之旅。这给出了我们现在可能已经习惯的信息,特别是如果你开始并放弃了很多副项目。

Initialized empty Git repository in /home/meain/dev/src/git-talk/.git/

让我们看看目前 .git 存储库中有什么。

$ tree .git

.git
├── config
├── HEAD
├── hooks
│   └── prepare-commit-msg.msample
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

它似乎创建了一堆文件和文件夹。这些都是什么?让我们一一回顾一下。

  • config 是一个文本文件,其中包含当前存储库的 git 配置。如果你仔细研究它,你会看到你的存储库的一些基本设置,如作者、文件模式等。
  • HEAD 包含存储库的当前头。根据您设置的“默认”分支,它将是 refs/heads/master 或 refs/heads/main 或您设置的任何其他分支。正如您可能已经猜到的,这指向您可以在下面看到的 refs/heads 文件夹,并指向一个名为 master 的文件,该文件目前还不存在。该文件主文件仅在您第一次提交后才会显示。
  • hooks 包含可以在 git 执行任何操作之前/之后运行的任何脚本。
  • objects包含 git 对象,即存储库中有关文件、提交等的数据。
  • refs 存储引用(指针)。 refs/heads 包含指向分支的指针,refs/tags 包含指向标签的。

add

现在您已经了解 .git 中的初始文件集是什么,让我们执行第一个操作,将某些内容添加到 .git 目录中。让我们创建一个文件并添加它(我们还没有提交它)。

echo 'meain.io' > file
git add file

这会执行以下操作:

--- init       2024-07-02 15:14:00.584674816 +0530
+++ add        2023-07-02 15:13:53.869525054 +0530
@@ -3,7 +3,10 @@
 ├── HEAD
 ├── hooks
 │   └── prepare-commit-msg.msample
+├── index
 ├── objects
+│   ├── 4c
+│   │   └── 5b58f323d7b459664b5d3fb9587048bb0296de
 │   ├── info
 │   └── pack
 └── refs

如您所见,这会导致两个主要变化。它修改的第一件事是索引文件。索引存储有关当前暂存内容的信息。这用于表示名为 file 的文件已添加到索引中。

第二个也是更重要的变化是在其中添加了一个新文件夹objects/4c和一个文件5b58f323d7b459664b5d3fb9587048bb0296de。

文件里有什么?

这是我们详细了解 git 如何存储内容的地方。让我们首先看看其中存在哪些类型的数据。

$ file .git/objects/5c/5b58f323d7b459664b5d3fb9587048bb0296de
.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de: zlib compressed data

嗯,但是 zlib 压缩数据是什么?

$ zlib-flate -uncompress <.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de
blob 9\0meain.io

看起来它包含我们执行 git add 的名为 file 的文件的类型、大小和数据。在本例中,数据表明它是一个大小为 9 的 blob,内容是 meain.io。

文件名是什么?

嗯,好问题。它来自于内容的sha1。如果您获取 zlib 压缩数据并通过 sha1sum 进行管道传输,您将获得文件名。

$ zlib-flate -uncompress <.git/objects/4c/5b58f323d7b459664b5d3fb9587048bb0296de|sha1sum
4c5b58f323d7b459664b5d3fb9587048bb0296de

git 获取要写入的内容的 sha1,获取前两个字符(在本例中为 4c),创建一个文件夹,然后使用其余部分作为文件名。 git 从前两个字符创建文件夹,以确保单个对象文件夹下没有太多文件。

向 git cat 文件问好

事实上,由于这是 git 中比较重要的部分之一,因此 git 还有一个管道命令来查看对象的内容。您可以使用 git cat-file,其中 -t 表示类型,-s 表示大小,-p 表示内容。

$ git cat-file -t 4c5b58f323d7b459664b5d3fb9587048bb0296de
blob

$ git cat-file -s 4c5b58f323d7b459664b5d3fb9587048bb0296de
9

$ git cat-file -p 4c5b58f323d7b459664b5d3fb9587048bb0296de
meain.io

commit

现在我们知道添加文件时会发生什么变化,让我们通过提交将其提升到一个新的水平。

$ git commit -m 'Initial commit'
[master (root-commit) 4c201df] Initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 file

以下是发生的变化:

--- init        2024-07-02 15:14:00.584674816 +0530
+++ commit      2023-07-02 15:33:28.536144046 +0530
@@ -1,11 +1,25 @@
 .git
+├── COMMIT_EDITMSG
 ├── config
 ├── HEAD
 ├── hooks
 │   └── prepare-commit-msg.msample
 ├── index
+├── logs
+│   ├── HEAD
+│   └── refs
+│       └── heads
+│           └── master
 ├── objects
+│   ├── 3c
+│   │   └── 201df6a1c4d4c87177e30e93be1df8bfe2fe19
 │   ├── 4c
 │   │   └── 5b58f323d7b459664b5d3fb9587048bb0296de
+│   ├── 62
+│   │   └── 901ec0eca9faceb8fe0a9870b9b6cde75a9545
 │   ├── info
 │   └── pack
 └── refs
     ├── heads
+    │   └── master
     └── tags

哇,看来有很多变化。让我们一一浏览它们。第一个是新文件 COMMIT_EDITMSG。顾名思义,它包含(最后的)提交消息。

如果您在不带 -m 标志的情况下运行 git commit 命令,那么 git 获取提交消息的方式是使用 COMMIT_EDITMSG 文件打开编辑器,让用户编辑提交消息,一旦用户更新并退出编辑器,git 使用文件的内容作为提交消息。

它还添加了一个全新的文件夹日志。这是 git 记录存储库中所有提交更改的一种方式。您将能够在此处看到所有引用和 HEAD 的提交更改。

对象目录也进行了一些更改,但我希望您首先查看 refs/heads 目录,其中我们现在有文件 master.txt。您可能已经猜到这是对 master 分支的引用。让我们看看里面有什么。

$ cat refs/heads/master
3c201df6a1c4d4c87177e30e93be1df8bfe2fe19

看起来它指向新对象之一。我们知道如何观察物体,让我们这样做吧。

$ git cat-file -t 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
commit

$ git cat-file -p 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
tree 62902ec0eca9faceb8fe0a9870b9b6cde75a9545
author Abin Simon <mail@meain.io> 1688292123 +0530
committer Abin Simon <mail@meain.io> 1688292123 +0530

Initial commit

你也可以这样做 git cat-file -t refs/heads/master

嗯,看起来那是一种新的对象。这似乎是一个提交对象。提交对象的内容告诉我们,它包含一个哈希值为 62902ec0eca9faceb8fe0a9870b9b6cde75a9545 的树对象,它看起来像我们提交时添加的另一个对象。提交对象还包含有关作者和提交者是谁的信息,在本例中都是我。最后还显示了此提交的提交消息是什么。

现在让我们看看树对象包含什么。

$ git cat-file -t 62902ec0eca9faceb8fe0a9870b9b6cde75a9545
tree

$ git cat-file -p 62901ec0eca9faceb8fe0a9870b9b6cde75a9545
100644 blob 4c5b58f323d7b459664b5d3fb9587048bb0296de    file

树对象将以其他树和 blob 对象的形式包含工作目录的状态。在本例中,由于我们只有一个名为 file 的文件,因此您只会看到一个对象。如果您看到的话,该文件指向我们执行 git add 文件时添加的原始对象。

这是更成熟的仓库的树的样子。更多的树对象用于从提交对象链接的树对象内部来表示文件夹。

$ git cat-file -p 2e5e84c3ee1f7e4cb3f709ff5ca0ddfc259a8d04
100644 blob 3cf56579491f151d82b384c211cf1971c300fbf8    .dockerignore
100644 blob 02c348c202dd41f90e66cfeb36ebbd928677cff6    .gitattributes
040000 tree ab2ba080c4c3e4f2bc643ae29d5040f85aca2551    .github
100644 blob bdda0724b18c16e69b800e5e887ed2a8a210c936    .gitignore
100644 blob 3a592bc0200af2fd5e3e9d2790038845f3a5cf9b    CHANGELOG.md
100644 blob 71a7a8c5aacbcaccf56740ce16a6c5544783d095    CODE_OF_CONDUCT.md
100644 blob f433b1a53f5b830a205fd2df78e2b34974656c7b    LICENSE
100644 blob 413072d502db332006536e1af3fad0dce570e727    README.md
100644 blob 1dd7ed99019efd6d872d5f6764115a86b5121ae9    SECURITY.md
040000 tree 918756f1a4e5d648ae273801359c440c951555f9    build
040000 tree 219a6e58af53f2e53b14b710a2dd8cbe9fea15f5    design
040000 tree 5810c119dd4d9a1c033c38c12fae781aeffeafc1    docker
040000 tree f09c5708676cdca6562f10e1f36c9cfd7ee45e07    src
040000 tree e6e1595f412599d0627a9e634007fcb2e32b62e5    website

change

让我们对文件进行更改,看看它是如何工作的。

echo 'blog.meain.io' > file
$ git commit -am 'Use blog link'
[master 68ed5aa] Use blog link
 1 file changed, 1 insertion(+), 1 deletion(-)

它的作用如下:

--- commit      2024-07-02 15:33:28.536144046 +0530
+++ update      2023-07-02 15:47:20.841154907 +0530
@@ -17,6 +17,12 @@
 │   │   └── 5b58f323d7b459664b5d3fb9587048bb0296de
 │   ├── 62
 │   │   └── 901ec0eca9faceb8fe0a9870b9b6cde75a9545
+│   ├── 67
+│   │   └── ed5aa2372445cf2249d85573ade1c0cbb312b1
+│   ├── 8a
+│   │   └── b377e2f9acd9eaca12e750a7d3cb345065049e
+│   ├── e5
+│   │   └── ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
 │   ├── info
 │   └── pack
 └── refs

好吧,我们添加了 3 个新对象。其中之一是包含文件新内容的 blob 对象,一个是树对象,最后一个是提交对象。

让我们从 HEAD 或 refs/heads/master 再次追踪它们。

$ git cat-file -p refs/heads/master
tree 9ab377e2f9acd9eaca12e750a7d3cb345065049e
parent 3c201df6a1c4d4c87177e30e93be1df8bfe2fe19
author Abin Simon <mail@meain.io> 1688292975 +0530
committer Abin Simon <mail@meain.io> 1688292975 +0530

Use blog link

$ git cat-file -p 9ab377e2f9acd9eaca12e750a7d3cb345065049e
100644 blob e5ec63cd761e6ab9d11e7dc2c4c2752d682b36e2    file

$ git cat-file -p e6ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
blog.meain.io

那些关注的人可能已经注意到,提交对象现在有一个名为parent的附加键,它链接到先前的提交,因为此提交是在先前的提交之上创建的。

branch

我们是时候创建一个分支了。让我们使用 git branch fix-url 来做到这一点。

--- update      2024-07-02 15:47:20.841154907 +0530
+++ branch      2023-07-02 15:55:25.165204941 +0530
@@ -27,5 +28,6 @@│   └── pack└── refs├── heads
+    │   ├── fix-url│   └── master└── tags

这会在 refs/heads 文件夹下添加一个新文件,其中文件作为分支名称,内容作为最新提交的 id。

$ cat .git/refs/heads/fix-url
68ed5aa2372445cf2249d85573ade1c0cbb312b1

这几乎就是创建分支的全部内容。 git 中的分支确实很便宜。标签的行为方式也相同,只不过它们是在 refs/tags 下创建的。

在logs目录下也添加了一个文件,用于存储类似于master分支的提交历史数据。

检查分支

在 git 中签出是指 git 获取提交的树对象并更新工作树中的文件以匹配其中记录的状态。在这种情况下,由于我们从 master 切换到 fix-url,两者都指向相同的提交和底层树对象,因此 git 在工作树中没有任何事情可做。

git checkout fix-url

当您在 .git 中进行签出时发生的唯一变化是 .git/HEAD 文件现在将指向 fix-url。

$ cat .git/HEAD
ref: refs/heads/fix-url

如果我们在这里,做出commit。我需要这个来展示稍后合并的作用。

echo 'https://blog.meain.io'>file
$ git commit -am 'Fix url'

合并

主要有3种合并方式。

  1. 最简单也是最容易的就是快进合并。在这种情况下,您只需更新一个分支指向另一个分支指向的提交。这几乎涉及将 refs/heads/fix-url 中的哈希复制到 refs/heads/master。
  2. 第二个是变基合并。在这种情况下,我们首先将更改应用到 main 当前一次指向一个提交的内容之上,然后执行类似于快进合并的操作。
  3. 最后一种是使用单独的合并提交来合并两个分支。这有点不同,因为它的提交对象中有两个父条目。我们将在最后进一步讨论这一点。

首先让我们看看合并之前的图表是什么样子的。

git log --graph --oneline --all
* 42c6318 (fix-url) Fix url
* 67ed5aa (HEAD -> master) Use blog link
* 3c201df Initial commit

现在执行合并:

$ git merge fix-url # updates refs/heads/master to the hash in refs/heads/fix-url

$ git log --graph --oneline --all
* 42c6318 (HEAD -> master) (fix-url) Fix url
* 67ed5aa Use blog link
* 3c201df Initial commit

push

现在我们已经使用本地 git 存储库一段时间了,让我们看看推送它时会发生什么。什么正在发送到另一端的 git 存储库?

为了展示这一点,首先让我创建另一个 git 存储库,它可以用作此存储库的远程。

$ mkdir git-talk-2
cd git-talk-2 && git init --bare

cd ../git-talk && git remote add origin ../git-talk-2

现在push

$ git push origin master

让我们看看我们的仓库发生了什么变化。

--- branch 2023-07-02 15:55:25.165204941 +0530
+++ remote 2023-07-02 17:41:05.170923141 +0530
@@ -22,12 +29,18 @@
 │   ├── e5
 │   │   └── ec63cd761e6ab9d11e7dc2c4c2752d682b36e2
 │   ├── info
 │   └── pack
 ├── ORIG_HEAD
 └── refs
     ├── heads
     │   ├── fix-url
     │   └── master
+    ├── remotes
+    │   └── origin
+    │       └── master
     └── tags

它添加了一个新的 refs/remotes 来存储有关不同remote中所有可用内容的信息。

但是什么会被发送到另一个 git 存储库呢?它是对象中和引用下的所有内容。这就是其他 git 实例获取整个 git 历史记录所需的全部内容。

Reference

[1]

Source: https://blog.meain.io/2023/what-is-in-dot-git/

本文由 mdnice 多平台发布


http://www.ppmy.cn/news/1164139.html

相关文章

《数据结构、算法与应用C++语言描述》使用C++语言实现链表队列

《数据结构、算法与应用C语言描述》使用C语言实现链表队列 定义 队列的定义 队列&#xff08;queue&#xff09;是一个线性表&#xff0c;其插入和删除操作分别在表的不同端进行。插入元素的那一端称为队尾&#xff08;back或rear&#xff09;&#xff0c;删除元素的那一端称…

记录一个奇怪bug

一开始Weapon脚本是继承Monobehavior的&#xff0c;实例化后挂在gameObject上跟着角色。后来改成了不继承mono的&#xff0c;也不实例化。过程都是顺利的&#xff0c;运行也没问题&#xff0c;脚本编辑器也没有错误。 但偶尔有一次报了一些错误&#xff0c;大概是说Weapon (1)…

acwing算法基础之数据结构--KMP算法

目录 1 知识点2 模板 1 知识点 KMP算法已经集成到string类型的find()方法了&#xff0c; 但这里我们不用这个&#xff0c;我们自己来实现这个方法。 KMP算法的关键步骤&#xff1a; p[N]表示输入模式串&#xff0c;求取该模式串的ne[]数组。ne[i]表示前缀等于后缀的长度&…

openGauss学习笔记-103 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书生成

文章目录 openGauss学习笔记-103 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书生成103.1 操作场景103.2 前提条件103.3 自认证证书生成过程 openGauss学习笔记-103 openGauss 数据库管理-管理数据库安全-客户端接入之SSL证书管理-证书生成 openGauss默认…

【pytorch 中 torch.max 和 torch.argmax 的区别】

torch.max 和 torch.argmax 的区别 1.torch.max torch.max(input, dim, maxNone, max_indicesNone, keepdimFalse) -->> (Tensor, LongTensor) 作用&#xff1a;找出给定tensor的指定维度dim上的上的最大值&#xff0c;并返回最大值在该维度上的值和位置索引。 应用举…

this指向详解

目录 一&#xff1a;严格模式与非严格模式 1.严格模式的开启 2.this指向的一些情况&#xff1a; 二&#xff1a;如何指定this的值&#xff1f; 1.在调用时指定this的值 2.在创建时指定this的值 ​编辑三&#xff1a; 结尾 一&#xff1a;严格模式与非严格模式 在非严格模…

https证书配置(nginx)

HTTPS 是什么 HTTPS 是一种应用层协议&#xff0c;是一种透过计算机网络进行安全通信的传输协议&#xff0c;HTTPS 经由 HTTP 进行通信&#xff0c;但是在 HTTP 的基础上引入了一个加密层&#xff0c;使用 SSL/TLS 来加密数据包&#xff0c;HTTPS 开发的主要目的&#xff0c;是…

【Leetcode每日一题 1726】「组合|哈希表」同积元组

2023.10.19 本题重点&#xff1a; 1.题目的理解&#xff0c;如何转化成一种组合问题 2.哈希表的使用 题目介绍&#xff1a; 给你一个由 不同 正整数组成的数组 nums &#xff0c;请你返回满足 a * b c * d 的元组 (a, b, c, d) 的数量。其中 a、b、c 和 d 都是 nums 中的元…

Hive insert插入数据与with子查询

1. insert into 与 insert overwrite区别 insert into 与 insert overwrite 都可以向hive表中插入数据&#xff0c;但是insert into直接追加到表中数据的尾部&#xff0c;而insert overwrite会重写数据&#xff0c;既先进行删除&#xff0c;再写入 注意&#xff1a;如果存在分…

大同小异!如何在苹果不同类型设备上更改AirDrop的名称

你可以更改你的AirDrop ID&#xff0c;让其他人看到你名字之外的东西。本文介绍了如何在iPhone、iPad和Mac上更改AirDrop名称。 如何在iPhone上更改AirDrop名称 在iPhone上更改AirDrop名称涉及到你可能不想做的更改。幸运的是&#xff0c;这在iPad和Mac上不是真的&#xff0c…

Spring Security认证流程分析(6)

1、认证流程分析 Spring Security中默认的一套登录流程是非常完善并且严谨的。但是项目需求非常多样化, 很多时候&#xff0c;我们可能还需要对Spring Secinity登录流程进行定制&#xff0c;定制的前提是开发者先深刻理解Spring Security登录流程&#xff0c;然后在此基础之上…

Python——案例

题一&#xff1a;利用装饰器来计算函数的执行时间 代码&#xff1a; import timedef decorated(fn):def inner():a time.time() # func开始的时间 time.time记录时间fn()b time.time() # func结束的时间print(f"{fn.__name__}程序运行的总数时间:{b - a}秒"…

利用反射将class A 属性赋值给class B

利用反射将classA 赋值给classB&#xff0c;其中a b属性名一样&#xff0c;属性类型不一样 a属性是json串&#xff0c;b里的属性是list 方法&#xff1a; private static List<CompareResultTemplate> exportDataIterationComparisonResult(List<ByteDanceOrderCompa…

Python使用scapy库监听指定的网卡数据并转发

监听指定网卡中的数据&#xff08;UDP&#xff09;数据转发 具体实现代码如下&#xff1a; from scapy.all import * from scapy.layers.inet import UDP, IP from scapy.layers.l2 import Etherdef Callback(packet):# 目的IPdst_ip packet[IP].dst# 源IPsrc_ip packet[IP]…

linux环境下文件传输与环境命令

1、基础命令简介 01 ls list 查看当前文件夹下的内容 02 pwd print work directory 查看当前所在文件夹 03 cd[目录名] changge directory 切换文件夹 04 touch[文件名] touch 如果文件不存在&#xff0c;新建文件 05 mkdir[目录名] …

Ubuntu18.04安装QGC报错 `GLIBC_2.29‘ not found

按照官网教程&#xff0c;最后运行时出错。 /tmp/.mount_QGroun2NOhPP/QGroundControl: /lib/x86_64-linux-gnu/libm.so.6: version GLIBC_2.29 not found (required by /tmp/.mount_QGroun2NOhPP/QGroundControl) /tmp/.mount_QGroun2NOhPP/QGroundControl: /usr/lib/x86_64-…

P3396 题解

P3396 哈希冲突 题目背景 众所周知&#xff0c;模数的 hash 会产生冲突。例如&#xff0c;如果模的数 p 7 p7 p7&#xff0c;那么 4 4 4 和 11 11 11 便冲突了。 题目描述 B 君对 hash 冲突很感兴趣。他会给出一个正整数序列 value \text{value} value。 自然&#x…

Elasticsearch介绍及插件head和kibana下载

目录标题 一、Elasticsearch介绍二、Elasticsearch下载三、Elasticsearch-head四、Elasticsearch-kibana 一、Elasticsearch介绍 Elasticsearch是什么? Elasticsearch 是一个基于Lucene的分布式搜索和分析引擎&#xff0c;ES是elaticsearch简写&#xff0c;Elasticsearch是一…

Linux操作系统从BIOS到bootloader是如何运行的

操作系统一般都会在安装在硬盘上&#xff0c;在 BIOS 的界面上。你会看到一个启动盘的选项。启动盘有什么特点呢&#xff1f;它一般在第一个扇区&#xff0c;占 512 字节&#xff0c;而且以 0xAA55 结束。这是一个约定&#xff0c;当满足这个条件的时候&#xff0c;就说明这是一…

postgresql字符串处理的函数

1. SPLIT_PART SPLIT_PART() 函数通过指定分隔符分割字符串&#xff0c;并返回第N个子串。语法&#xff1a; SPLIT_PART(string, delimiter, position) string : 待分割的字符串 delimiter&#xff1a;指定分割字符串 position&#xff1a;返回第几个字串&#xff0c;从1开始&…