【QA】Git的底层原理

2024-04-27 06:52
文章标签 原理 底层 git qa

本文主要是介绍【QA】Git的底层原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

本文通过一个简单的示例,来理解Git的底层原理。

示例

1、新建本地仓库并上传第一个文件

相关步骤

  • 新建仓库及创建文件
  • 查看文件状态
  • 将文件添加到暂存区
  • 将文件提交到本地仓库
HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1
$ git init  	# 初始化一个空的仓库
Initialized empty Git repository in D:/GSF_Data/Github/Java/Git/git-test-1/.git/HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git status	# 查看当前状态
On branch masterNo commits yetnothing to commit (create/copy files and use "git add" to track)HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ touch a.txt	# 创建文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ vi a.txt		# 编辑文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ cat a.txt		# 查看文件内容
创建a.txt,并提交到本地仓库HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git status	# 查看当前状态,工作区有文件更改,但是没有添加到暂存区
On branch masterNo commits yetUntracked files:(use "git add <file>..." to include in what will be committed)a.txtnothing added to commit but untracked files present (use "git add" to track)HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git add .		# 将文件添加到暂存区,警告可以不用管
warning: in the working copy of 'a.txt', LF will be replaced by CRLF the next time Git touches itHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$git status		# 查看当前状态,追踪到文件在暂存区,但是还没有提交到本地仓库
On branch masterNo commits yetChanges to be committed:(use "git rm --cached <file>..." to unstage)new file:   a.txtHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git commit -m "创建a.txt文件" .		# 将所有文件提交到本地仓库,并添加注释
warning: in the working copy of 'a.txt', LF will be replaced by CRLF the next time Git touches it
[master (root-commit) 30d0542] 创建a.txt文件1 file changed, 1 insertion(+)create mode 100644 a.txtHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git status		# 查看当前状态
On branch master
nothing to commit, working tree cleanHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ 

概念介绍 | 版本号

版本号组成

  • 常规的版本号可能是:v1、v2…v10。
  • Git的版本号通过SHA-1算法,生成40位的十六进制数字。40位数字中,分成2+38:前两位用来定位文件夹,后38位用来定位文件。

Git为什么要这样选择版本号

  • 因为Git是一个分布式的版本控制软件,通过这样算法生成的版本号,可以大概率避免文件重复。

Git命令查询版本号

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git log	# 查看历史记录
commit 30d0542a85b3f3248e5a363b491978251e631978 (HEAD -> master)	# 版本号(从HEAD指向主分支master)
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 17:52:28 2024 +0800创建a.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ 

查看文件在本地仓库中的位置:.git/objects

image-20240104180845595

查看版本号对应的文件内容

常规编辑器无法查看,需要使用Git命令查看文件内容

相关Git命令

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git log
commit 30d0542a85b3f3248e5a363b491978251e631978 (HEAD -> master)	# 第一次提交的版本号
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 17:52:28 2024 +0800创建a.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 30d0542a85b3f3248e5a363b491978251e631978		# 查看第一次提交的版本号的内容
tree 30ed07b83fcd3a42970483553d54f44481630250			# 是一个状态信息,对应一个新的版本号
author hmteen <sfguo1@126.com> 1704361948 +0800
committer hmteen <sfguo1@126.com> 1704361948 +0800创建a.txt文件		# commit时候的信息HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 30ed07b83fcd3a42970483553d54f44481630250		# 查看状态信息
100644 blob 04b3abdeac873dcf8d7d9fafe35ecaac711abe45    a.txt	# 普通文件 blob对象 文件内容对应的版本号 文件名字HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 04b3abdeac873dcf8d7d9fafe35ecaac711abe45		# 查看文件内容
创建a.txt,并提交到本地仓库HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$

总结:

  • 可以看到Git在提交一个文件到本地仓库后,创建了三个版本号:提交信息的版本号、文件状态的版本号、文件内容的版本号

  • 三个版本号有明显的单向传递特点

2、依次对一个文件完成新增、修改、删除操作

在初次提交a.txt文件到本地仓库后,依次进行b.txt文件的:增、改、删操作,然后追溯版本号,理解Git的版本控制原理

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ vi b.txt		# 创建并编辑b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ cat b.txt		# 查看b.txt文件内容
新增b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git add .		# 文件送到暂存区
warning: in the working copy of 'b.txt', LF will be replaced by CRLF the next time Git touches itHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git commit -m "新增b.txt文件" .		# 文件送到本地仓库
warning: in the working copy of 'b.txt', LF will be replaced by CRLF the next time Git touches it
[master 7952e76] 新增b.txt文件1 file changed, 1 insertion(+)create mode 100644 b.txtHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git log		# 查询历史日志信息
commit 7952e76b009d616902d9e804d3f17c29580ed967 (HEAD -> master)
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 18:57:32 2024 +0800新增b.txt文件commit 30d0542a85b3f3248e5a363b491978251e631978
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 17:52:28 2024 +0800创建a.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 7952e76b009d616902d9e804d3f17c29580ed967		# 查询最后一次提交的内容
tree 54996d3d5053ca3730310752ed0b7779e87df134					# 最后一次提交指向的状态信息的版本号
parent 30d0542a85b3f3248e5a363b491978251e631978					# 其父版本号,即提交a.txt对应的版本号
author hmteen <sfguo1@126.com> 1704365852 +0800
committer hmteen <sfguo1@126.com> 1704365852 +0800新增b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 54996d3d5053ca3730310752ed0b7779e87df134		# 最后一次提交的状态内容,包含前一次提交的文件和最新提交的文件
100644 blob 04b3abdeac873dcf8d7d9fafe35ecaac711abe45    a.txt	# 对比上一次提交,版本号不变
100644 blob 3f6facf24a61f2aeba635f4220bf5b66b6896921    b.txt	# 新建的文件,拥有一个版本号HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 3f6facf24a61f2aeba635f4220bf5b66b6896921		# 查看文件内容
新增b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 04b3abdeac873dcf8d7d9fafe35ecaac711abe45		# 查看文件内容
创建a.txt,并提交到本地仓库HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ vi b.txt		# 编辑修改文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git add .		
warning: in the working copy of 'b.txt', LF will be replaced by CRLF the next time Git touches itHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git commit -m "修改b.txt文件" .
warning: in the working copy of 'b.txt', LF will be replaced by CRLF the next time Git touches it
[master 0fb383a] 修改b.txt文件1 file changed, 1 insertion(+)HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git log
commit 0fb383ae5f814aa3d8a5af44f7371a048a96b6a6 (HEAD -> master)
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 19:01:09 2024 +0800修改b.txt文件commit 7952e76b009d616902d9e804d3f17c29580ed967
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 18:57:32 2024 +0800新增b.txt文件commit 30d0542a85b3f3248e5a363b491978251e631978
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 17:52:28 2024 +0800创建a.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 0fb383ae5f814aa3d8a5af44f7371a048a96b6a6		# 查看最新一次提交
tree ad1dc728a75b0b9cd6f4113e0dc0d9b0a2125c1f					# 最新一次提交对应的文件状态信息
parent 7952e76b009d616902d9e804d3f17c29580ed967					# 父版本,倒数第二次提交的版本号
author hmteen <sfguo1@126.com> 1704366069 +0800
committer hmteen <sfguo1@126.com> 1704366069 +0800修改b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p ad1dc728a75b0b9cd6f4113e0dc0d9b0a2125c1f
100644 blob 04b3abdeac873dcf8d7d9fafe35ecaac711abe45    a.txt	# 未作修改,版本号不变
100644 blob 647f137f6e509673f5681ed2f6a4cfda7cb075c5    b.txt	# 对比新建该文件时候的版本号,版本号已经改变了,说明是一个新的文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 647f137f6e509673f5681ed2f6a4cfda7cb075c5
新增b.txt文件
修改b.txt问价HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 04b3abdeac873dcf8d7d9fafe35ecaac711abe45
创建a.txt,并提交到本地仓库HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ rm b.txt		# 删除文件内容HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git add .HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git commit -m "删除b.txt文件" .
[master d512d7f] 删除b.txt文件1 file changed, 2 deletions(-)delete mode 100644 b.txtHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git log
commit d512d7f86477af65af85710770ee252b713f04cc (HEAD -> master)
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 19:04:47 2024 +0800删除b.txt文件commit 0fb383ae5f814aa3d8a5af44f7371a048a96b6a6
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 19:01:09 2024 +0800修改b.txt文件commit 7952e76b009d616902d9e804d3f17c29580ed967
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 18:57:32 2024 +0800新增b.txt文件commit 30d0542a85b3f3248e5a363b491978251e631978
Author: hmteen <sfguo1@126.com>
Date:   Thu Jan 4 17:52:28 2024 +0800创建a.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p d512d7f86477af65af85710770ee252b713f04cc
tree 30ed07b83fcd3a42970483553d54f44481630250
parent 0fb383ae5f814aa3d8a5af44f7371a048a96b6a6
author hmteen <sfguo1@126.com> 1704366287 +0800
committer hmteen <sfguo1@126.com> 1704366287 +0800删除b.txt文件HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 30ed07b83fcd3a42970483553d54f44481630250		# b.txt文件已删除,只剩下a.txt文件
100644 blob 04b3abdeac873dcf8d7d9fafe35ecaac711abe45    a.txtHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 04b3abdeac873dcf8d7d9fafe35ecaac711abe45
创建a.txt,并提交到本地仓库HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git cat-file -p 647f137f6e509673f5681ed2f6a4cfda7cb075c5		# 查询修改b.txt文件时的版本号,依旧可以看到文件内容,证明只是删除了引用,文件的内容并没有被删除
新增b.txt文件
修改b.txt问价HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$

Git底层原理图示!!!

image-20240104195151194

第一次:创建a.txt

  • 仅有1个log信息,一个提交版本号,一个状态版本号,一个文件版本号

第二次:创建b.txt

  • 有2个log信息,新增一个提交版本号,新增一个状态版本号(指向上一个父版本),新增一个文件版本号

第三次:修改b.txt

  • 有3个log信息,新增一个提交版本号,新增一个状态版本号(指向上一个父版本),新增一个文件版本号

第四次:删除b.txt

  • 有4个log信息,新增一个提交版本号,新增一个状态版本号(指向上一个父版本),没有新增文件版本号

3、新建一个user分支

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git branch user		# 新建user分支

怎么查看数据最新版本?

疑问:如果创建了多个不同的分支,每个分支下又有不同的提交版本,该怎么确定使用的是哪个分支?怎么确定使用的是哪个版本?

答案:查看.git目录下的HEAD文件

image-20240104195857603

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ cat .git/HEAD		# HEAD内容:给出了当前使用的是哪个版本
ref: refs/heads/masterHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (user)
$ cat .git/refs/heads/master	# master内容:记录了最新的版本号信息
d512d7f86477af65af85710770ee252b713f04cc

不同分支下查看数据的最新版本

HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ cat .git/HEAD
ref: refs/heads/masterHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (user)
$ cat .git/refs/heads/master
d512d7f86477af65af85710770ee252b713f04ccHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (master)
$ git checkout user
Switched to branch 'user'HMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (user)
$ cat .git/HEAD
ref: refs/heads/userHMTeen@LAPTOP-46U4TV6K MINGW64 /d/GSF_Data/Github/Java/Git/git-test-1 (user)
$ cat .git/refs/heads/user
d512d7f86477af65af85710770ee252b713f04cc

可以看到:新增分支后,仅HEAD文件指向的路径发生了变化,指向了一个新增的文件(以新增的分支名字命名的文件),文件内容是最新一次修改的版本号

  • 说明1:新增分支并没有复制已有文件内容,而仅仅是新增了一个地址指向
  • 说明2:新增的分支user,是以master主分支为基础的,指向了master分支最新更改的内容

总结

  • .git文件夹里面的内容就是本地仓库;其同目录下的其他文件及文件夹是工作区;远程仓库是第三方代码托管平台,比如:GitHub、Gitee
  • 文件的新增、修改都会创建一个新的文件;文件的删除不会创建新的文件
  • .git文件夹下的内容总空间 > 工作区文件、文件夹占用空间

这篇关于【QA】Git的底层原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/939796

相关文章

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

bat脚本启动git bash窗口,并执行命令方式

《bat脚本启动gitbash窗口,并执行命令方式》本文介绍了如何在Windows服务器上使用cmd启动jar包时出现乱码的问题,并提供了解决方法——使用GitBash窗口启动并设置编码,通过编写s... 目录一、简介二、使用说明2.1 start.BAT脚本2.2 参数说明2.3 效果总结一、简介某些情

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

hdu4407容斥原理

题意: 有一个元素为 1~n 的数列{An},有2种操作(1000次): 1、求某段区间 [a,b] 中与 p 互质的数的和。 2、将数列中某个位置元素的值改变。 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.Inpu

hdu4059容斥原理

求1-n中与n互质的数的4次方之和 import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWrit

git ssh key相关

step1、进入.ssh文件夹   (windows下 下载git客户端)   cd ~/.ssh(windows mkdir ~/.ssh) step2、配置name和email git config --global user.name "你的名称"git config --global user.email "你的邮箱" step3、生成key ssh-keygen

哈希表的底层实现(1)---C++版

目录 哈希表的基本原理 哈希表的优点 哈希表的缺点 应用场景 闭散列法 开散列法 开放定值法Open Addressing——线性探测的模拟实现 超大重点部分评析 链地址法Separate Chaining——哈希桶的模拟实现 哈希表(Hash Table)是一种数据结构,它通过将键(Key)映射到值(Value)的方式来实现快速的数据存储与查找。哈希表的核心概念是哈希