温故而知新(一)— 执行git操作时,git到底做了什么?

开发人员每天都在使用git,但git原理是什么?.git文件夹下到底记录了哪些内容?git命令执行后,git到底做了些什么?今天来一起梳理下吧。

一、Git是什么

聊聊Git,git我们在项目开发中,几乎每天都能接触到,它是一个分布式的版本控制系统,优点如下:

  1. 引入快照概念:当git提交信息时,会对当前提交的全部文件、包括目录结构创建快照,并保留快照的索引;而并非记录单个文件的更改信息。
  2. 基本所有操作都在本地执行:git提供的工作区,使开发者能够在本地对代码进行修改,而不需要依赖网络环境。
  3. 完整性:git通过SHA-1散列算法,对git的文件目录和文件统一计算hash值,在每次提交存储前,git都会对该hash值进行比对,如果文件有丢失,git很容易发现。
  4. git提供了工作区、暂存区、仓库的概念,通常从仓库拉取分支到本地工作区,工作区操作文件后,将文件提交到暂存区,暂存区的内容会批量性的提交到远程仓库。分别对应的状态为已修改、已暂存、已提交。

二、模拟git文件变化

2.1 文件变化时,.git文件里记录了什么

  • git init git init命令,在当前项目根目录下创建.git文件夹,用于保存版本信息,该文件夹下。文件夹的结构如下图所示
  • git hash-object -w 文件名

在项目中创建一个mainPage.vue的文件,同时对该文件使用hash-object命令,此时可查看,该文件内容已被压缩成为二进制文件,该压缩后的文件,保存在.git/objects下,称为Git对象 ;计算的hash值前两位,作为目录名称,其他作为文件名。

  • git cat-file -p 二进制编码

查看二进制文件内容,使用cat-file命令,其中文件名称是计算出的完整hash码。

当我们更改mainPage.vue的内容之后,再次对该文件执行git hash-object命令,可看到新的Git对象已生成,让我们查看.git/objects文件夹下的目录变化,可发现,新的文件目录和文件已生成。

2.2 变化的文件,如何在暂存区记录

  • git update-index --add mainPage.vue
  • git ls-files --stage

当前暂存区保存的是第二次变化的文件,可以根据该命令查找到要提交的Git对象文件。当前的mainPage.vue文件对应的二进制文件名称,可以在.git/objects/a2/文件夹下找到

2.3 暂存区文件,如何生成一个commit对象

  • git write-tree 保存当前文件的目录结构,即记录文件所在目录关系。这里会为当前文件所在的每个目录都生成一个Git对象,同样保存在.git/objects目录下。mainPage.vue保存在src/views文件下,执行完当前命令后,可查看.objects下生成了三个目录。分别为(1e,2a,93

查看每个文件夹对应的文件内容

到目前为止,git就为我们保存了一个目录结构,该目录结构上保存了当前文件夹地下的文件二进制对象,当前的目录结构和目录中的文件对象也就称作文件快照。这个目录结构在git中生成的对象是一个树结构对象

现在,我们需要将目录树对象写入到版本历史,在这一步,会生成一个commit对象。可以看到,目前在objects目录下,多生成了一个d5的文件夹,让我们来查看下d5下包含了哪些内容。

可以看到,当前目录中包含了上一次提交的tree对象信息,还有作者、提交者和提交说明信息。

好了,到目前为止,可以为我们前面这块工作做一个总结了。

  1. 当执行git add时,git主要完成两个步骤,1、保存对象,对变化的文件生成一个git对象。同时将它保存在objects目录下。2、将文件写入/更新暂存区,以通知git哪些文件需要提交,即执行git add时,objects目录下生成了当前文件的hashcode值。
  2. 当执行git commit时,git主要完成,1、为文件目录结构和文件生成一棵树,git将该树生成一个git对象,保存在objects中。2、生成一个commit对象,该commit对象记录了树对象的值,以及提交信息。

那么快照是什么:

个人理解,在git执行commit时,会对暂存区内的内容进行一次备份,该内容可以理解为生成的commit对象,该对象中包含了文件的目录结构、文件原始快照信息,以及文件的提交信息。对应上面的分析,应该就是.git目录下的d5文件夹下的二进制内容。可以看出,git在备份时,保留的是文件的完整信息,而非某个文件的差异信息,在提交时,暂存区的内容也不会随着提交而消失,因此可以使用git log命令,查看历史提交内容,暂存区的内容更像是保存了当前待提交文件的状态。

三、与远程仓库关联,发生了什么?

3.1 关联远程仓库

目前在本地创建的文件都保存在了暂存区,下一步需要推送到远程分支,推送到远程分支前,需要创建远程仓库,同时对将本地git与远程仓库进行管理。 使用命令

git remote add origin https://gitlab.**.**.cn/test3/monorop.git

3.2 同步远程仓库信息

关联之后,需要将远程分支生成的内容同步到本地,我们执行 git pull origin master操作,这步执行完后,可观察到我们的objects文件中,同时多了三个文件夹,分别记录了文件远程分支的文件blob信息、远程分支的目录结构、远程分支的commit对象信息。

查看各个文件夹目录下的内容,可看到其记录的都是远程分支上的信息。

3.3 提交文件到远程仓库

紧接着,将当前本地变更,提交到远程分支上。执行git commit操作,看下发生了什么。 可以看到objects中增加了两个文件夹,一个文件夹记录了本地与远程分支的tree对象信息,查看其记录数据,可分析出来,每次在更改代码时,git会为我们保存一次git object对象,以便记录最新的变更。

而另一个文件夹中,则记录的是当前指针指向的commit对象,该commit对象中除了记录当前的tree对象指针和提交作者人员信息之外,还记录了一个指向上次提交对象(父对象)的指针,该父对象指针,记录了完整的上一次快照信息,因此git通过这种模式,记录了完整的信息变化,而不仅仅是当前变化文件的信息,因此不会存在丢失数据问题。

当有信息变更时,commit对象上保存的什么:

当git分支上有内容变更时,会生成一个最新的commit对象,该commit对象中,除了保存本次修改的tree对象信息、提交信息之外,还记录了上一次的parent对象信息。这个parent对象信息,记录了完整的上一次操作,因此git生成的commit对象,通常都是完整的历史记录信息。

四、git分支

我们在项目中,经常会让创建新的分支,那分分支的具体是什么呢?分支其实指的就是指向commit对象的指针,分支名称也叫做当前的指针名。比如上面示例中的master初始分支,其实代表的就是指向最新commit对象的指针名为master。

4.1 创建新分支

我们基于某个分支创建新分支时,如基于master分支创建了feature-xyl分支,可在本地使用命令git branch feature-xyl。执行完成,git会为当前所在的commit对象创建一个叫做feature-xyl的指针,指向当前commit对象。

4.2 记录分支

当创建的分支越来越多时,git如何知道当前在哪个分支上呢,git提供了一个名叫HEAD 的指针,它总是指向当前所在的本地分支 ,比如我们创建了feature-xyl分支,但没切换到这个分支上时,此时head指向的还是master分支。 使用命令git log --oneline --decorate可查看。下图有两层含义,第一表明了head目前指向的当前所在本地分支。第二表明master、origin/master、feature-xyl都指向同一个commit对象。

4.3 修改分支内容,查看HEAD指针情况

当我们在本地分支上,比如feature-xyl分支上修改了内容,提交之后,查看当前的HEAD指针指向,可以看到当前HEAD指针,指向的feature-xyl上最新的commit对象上。根据回溯,可以发现当前的提交内容,正好是修改内容。

切换回master分支,可以看到HEAD指向的是master分支上最新的commit对象。

HEAD指向:

HEAD是git提供的一个特殊指针,总是指向当前本地分支的最新commit对象,并会随着分支的切换,自动变化。其保存在.git/refs/heads/目录下。由于每个分支指向的最新commit对象不同,因此我们在切换分支时对应的内容通常也是不一样的。

这篇文章主要记录了git中,文件blob对象、tree对象、commit对象的生成方式及在.git文件夹下的表示形式,同时通过和远程仓库关联,演示了分支不同变化下,上述三个对象分别有哪些变化,最后介绍了HEAD指针的指向形式,相信通过这篇文章,会给大家提供一个很清晰的视角去理解git命令后的内容。下篇文章,会继续围绕这篇内容,讲解其他命令后的故事。

相关推荐
AlienZHOU5 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
Captaincc8 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
拼图2098 小时前
Git常用语法
分布式·git·学习
计算机魔术师9 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen10 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒10 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow11 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林81811 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang8007811 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明11 小时前
第 6 章 组件进阶
前端·vue.js