计算机基础(二)——Git的底层原理,reverse和reset的区别,rebase作用

本文深入探讨Git的基础概念,包括工作区、暂存区、版本库等分区介绍,blob、tree、commit三种主要对象的关系及实例演示。此外,还详细解析了branch与tag的区别、reset与reverse的不同之处,以及rebase的作用及其与merge的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、分区

2、对象

3、对象实例演示

4、branch和tag

5、reset和reverse区别

6、rebase作用

7、rebase再探究竟,rebase和merge区别


这一篇其实不属于计算机基础的,但是随着大家平时工作还有开源一些项目的版本控制的使用,使用叫多的git。
回过头来,有时在思考reverse和rebase区别,回归到底层的一些原理的时候,就有茅塞顿开的感觉了。

1、分区

首先Git有分三个区,工作区,暂存区和版本库。

2、对象

Git当中一共有3种主要的对象:blob,tree,commit


git add 多一个blob文件,repository的一个文件,内容为文件内容
git add 再多一个blob文件
git commit后 会有两个tree 一个commit
tree,存储blob对象和子tree对象,这类型的对象在Git里面代表的就是一个文件夹,而这个对象的内容就是面向它所包含的文件夹和文件的指针。
commit对象,包含了一个面向根目录tree对象的指针,而且还包含了committer的个人信息还有commit的注释。

三个对象之间关系。总结就是
commit 指向 tree 指向 tree 或者 blob

3、对象实例演示

查看对象内容可以参考官方文档,Git - git-cat-file Documentation
git cat-file --batch-check --batch-all-objects
the SHA-1, type, and size of each object is printed on stdout
sha1跟md5类似是一个摘要值,然后就是对象类型,大小
 

#查看git版本
C:\Users>git --version
git version 2.20.1.windows.1

#创建测试目录
D:\>mkdir gittest

D:\>cd gittest

#git 初始化
D:\gittest>git init
Initialized empty Git repository in D:/gittest/.git/

#创建文件index.txt
D:\gittest>echo "version 1" > index.txt

# index.txt加入暂存区
D:\gittest>git add index.txt

# 查看所有对象内容
D:\gittest> git cat-file --batch-check --batch-all-objects
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13

# 查询sha-1对应的文件内容,该对象对应的内容就是index.txt内容
D:\gittest>git cat-file -p 6c58b76a52188643965f3a6704166e8e0424b7fe
"version 1"

# 创建文件index2.txt
D:\gittest>echo "version 2" > index2.txt
# index2.txt加入暂存区
D:\gittest>git add index2.txt
# 查看所有对象内容
D:\gittest> git cat-file --batch-check --batch-all-objects
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13
8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 blob 13

# 查询sha-1对应的文件内容,该对象对应的内容就是index2.txt内容
D:\gittest>git cat-file -p 8231f0fdc862f06b2bd7b7bfd2f42082d3086b71
"version 2"

#创建新文件夹
D:\gittest>mkdir dir

#创建新文件夹中的新文件
D:\gittest>echo "version 1, inside" > ./dir/inside.txt
 
# inside.txt加入暂存区
D:\gittest>git add ./dir/inside.txt

# 查看所有对象内容
D:\gittest> git cat-file --batch-check --batch-all-objects
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13
8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 blob 13
bf97e71de76bcff2bd8aba44710aa5e665eacb99 blob 21

# 查询sha-1对应的文件内容,该对象对应的内容就是inside.txt内容
D:\gittest>git cat-file -p bf97e71de76bcff2bd8aba44710aa5e665eacb99
"version 1, inside"

#提交到本地仓库
D:\gittest>git commit


D:\gittest> git cat-file --batch-check --batch-all-objects
39bdea2300491cc90f47551887bfe9503cd4a9d9 tree 38
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13
8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 blob 13
bf97e71de76bcff2bd8aba44710aa5e665eacb99 blob 21
d5c2b878425995af5ddc5202f7058a1ff372b3f3 tree 105



D:\gittest>git commit
[master (root-commit) 629a4cf] commit 1
 3 files changed, 3 insertions(+)
 create mode 100644 dir/inside.txt
 create mode 100644 index.txt
 create mode 100644 index2.txt

# 查看所有对象内容,commit之后多了两个tree和一个commit
D:\gittest> git cat-file --batch-check --batch-all-objects
39bdea2300491cc90f47551887bfe9503cd4a9d9 tree 38
629a4cf0fdb33390ad5774b10244512e3d400407 commit 169
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13
8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 blob 13
bf97e71de76bcff2bd8aba44710aa5e665eacb99 blob 21
d5c2b878425995af5ddc5202f7058a1ff372b3f3 tree 105

#查看一个commit
D:\gittest>git cat-file -p 629a4cf0fdb33390ad5774b10244512e3d400407
tree d5c2b878425995af5ddc5202f7058a1ff372b3f3
author  iaiti<xx@qq.com> 1617247696 +0800
committer  iaiti<xx@qq.com> 1617247696 +0800

# 查看其中一个tree
D:\gittest>git cat-file -p d5c2b878425995af5ddc5202f7058a1ff372b3f3
040000 tree 39bdea2300491cc90f47551887bfe9503cd4a9d9    dir
100644 blob 6c58b76a52188643965f3a6704166e8e0424b7fe    index.txt
100644 blob 8231f0fdc862f06b2bd7b7bfd2f42082d3086b71    index2.txt


# 更改文件内容
D:\gittest>echo "version 2" > index.txt

D:\gittest>git add index.txt

D:\gittest>echo "version 1 new" > index.txt

D:\gittest>git add index.txt

D:\gittest> git cat-file --batch-check --batch-all-objects
0b596a83945ca790976a10bbf005262f1cefe4cc blob 17   		(version 1 new)
39bdea2300491cc90f47551887bfe9503cd4a9d9 tree 38   		(inside.txt)
629a4cf0fdb33390ad5774b10244512e3d400407 commit 169 	(commit)
6c58b76a52188643965f3a6704166e8e0424b7fe blob 13   		(version 1)
8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 blob 13   		(version 2)
bf97e71de76bcff2bd8aba44710aa5e665eacb99 blob 21   		(version 1, inside)
d5c2b878425995af5ddc5202f7058a1ff372b3f3 tree 105  		(dir index.txt  index2.txt)

D:\gittest>git cat-file -p 0b596a83945ca790976a10bbf005262f1cefe4cc
"version 1 new"


#提交第二次
D:\gittest>git cat-file -p beaeb2b94a88d6cf03c096f667859239065d1ba8
tree 4fca214cabbc6f8c6a7243f9ea780b66ee895993
parent 629a4cf0fdb33390ad5774b10244512e3d400407
author iaiti <xx@git.com> 1617247963 +0800 
committer iaiti <git@xx.com> 1617247963 +0800

Commit 2

多次更改和提交两次后,所有对象的对应关系

4、branch和tag

branch 其实就是一个指向某个commit的指针文件,一般被存放在./.git/refs/heads里面,所以branch只是跨commit而已,按照上图所指示出来的,指向的其实就是master分支
head指向最新commit
tag相当于是静态的 branch ,被存储在./.git/refs/tags里面的文件中。它并不跟随HEAD移动。通常用于标记一个特定的commit,例如某个版本的代码,以方便checkout。

5、reset和reverse区别

reset是记录重设,有三种模式

git reset 17cf9ea15f6c63ec04f232c5cd72e0c1b3f657fd
--hard  commit记录重设,但是如果远程仓库已经commit,可以使用git push --force
--mixed commit记录重设,工作区文件修改,暂存区的记录会重置,相当于没到git add阶段,相当于撤销add
--soft   commit记录重设,工作区文件修改和暂存区的记录都会保存

三种模式总结来说就是,相当于做了版本回退,并控制文件是否回退到暂存区前

而reverse,也是回退,但是不是重置commit,而是多出一条commit ,提醒其他的开发者或者公司同事,这里有恢复操作。可以
和reset对比结合看。

问题来了,reverse还有commit,reset的话中间的commit就不见了, 我要回滚怎么操作?

git reflog记录操作,回滚回之前重置的commit记录。

D:\gittest>git ls-files --stage
100644 bf97e71de76bcff2bd8aba44710aa5e665eacb99 0       dir/inside.txt
100644 0b596a83945ca790976a10bbf005262f1cefe4cc 0       index.txt
100644 8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 0       index2.txt
D:\gittest>
D:\gittest>echo "version test index" > index.txt
D:\gittest>
D:\gittest>git ls-files --stage
100644 bf97e71de76bcff2bd8aba44710aa5e665eacb99 0       dir/inside.txt
100644 0b596a83945ca790976a10bbf005262f1cefe4cc 0       index.txt
100644 8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 0       index2.txt

D:\gittest>git add index.txt

D:\gittest>git ls-files --stage
100644 bf97e71de76bcff2bd8aba44710aa5e665eacb99 0       dir/inside.txt
100644 be06e3be42f6a2955d61750c86646b7869177f47 0       index.txt
100644 8231f0fdc862f06b2bd7b7bfd2f42082d3086b71 0       index2.txt
D:\gittest>


D:\gittest>echo "version test index" > index.txt

D:\gittest>git add index.txt

git commit -m comit3

D:\gittest>git log
commit b3a0d90be0da1862b4c82fb6beafffaf4113148e (HEAD -> master)
Author: <E8><94><A1><E5><9D><A4><E6><89><BF> <xx.com>
Date:   Thu Apr 29 19:51:51 2021 +0800

    Revert "comit3"

    This reverts commit 6fccca25df481aa1d53ad60075bb37d5e87d8593.

commit 6fccca25df481aa1d53ad60075bb37d5e87d8593
Author: <E8><94><A1><E5><9D><A4><E6><89><BF> <xx.com>
Date:   Thu Apr 29 19:51:21 2021 +0800

    comit3

6、rebase作用

变基,Git - git-rebase Documentation 可以查看相关指令信息,

git rebase -i  [startpoint]  [endpoint] 给用户交互界面进行操作

挑选变基的commit

git rebase -i 674c40b

然后移除多余的commit信息,s的话是合并前面的提交

从这里可以看到,变基可以合并我前面提交无用的记录。让整个提交的历史更加的简洁,之前有网友举例,vue作者尤雨溪就有这样的处理。

rebase分支不要使用在公共分支上。

7、rebase再探究竟,rebase和merge区别

除了合并提交信息,让其更简洁外,是不是还有其他作用,都是合并,那和merge区别是什么,需要这样思考。

假如我有一条功能分支比较久没同步线上代码,或者主分支其实多人合作合并频繁的时候,按照平时的操作都是拉一条分支,然后将master merge到自己分支

结果是这样的


而变基能让自己的一条分支形成直线,不受其他的干扰。

总结来说,merge是当前开发分支领先于要合并的分支,那就merge过去,比如开发功能和测试完毕想合并到线上,就是用merge。

如果当前分支许久没拉下来,落后master的,就用rebase,就只把当前的内容合并到自己分支上,而不用理会是什么分支合并过来的。master主分支才需要查看谁合了什么上去。

### 如何在 IntelliJ IDEA 中撤销 Git Pull 操作 当开发者希望撤销已经执行的 `git pull` 命令时,可以采取几种不同的策略来恢复工作环境至拉取前的状态。具体方法取决于当前的工作场景以及是否已有新的提交被创建。 #### 使用 Reset 方式回退到最近一次本地提交之前 如果仅需简单地丢弃由 `pull` 引入的所有更,并返回到最后一个本地提交,则可以通过重置分支实现: ```bash # 切换到目标分支 git checkout main # 查看 reflog 找到最后一次 pull 之前的 commit hash git reflog # 假设找到的hash为 abcdefg,那么执行如下命令回到该状态 git reset --hard abcdefg ``` 此方式适用于尚未于新获取的内容做出任何额外修改的情况;它将直接把 HEAD 移动到指定的历史点并覆盖工作区中的改动[^1]。 #### 反转 Merge 或 Rebase 来取消 Pull 效果 对于那些希望通过更安全的方式处理的情形,比如不想丢失可能存在的未推送到远程的新提交,应该考虑使用 revert 或者 reverse merge/rebase 技术。这允许保留现有历史记录的同时消除特定更新的影响。 - **Revert Merges:** 如果 `pull` 导致了一个合并(merge),则可通过反转这次合并不影响其他部分。 ```bash # 获取最新的合并commit id (通常是HEAD) git log --merges # 对选定的合并commit应用revert操作 git revert -m 1 <merge-commit-id> ``` - **Abort a Rebase or Resolve Conflicts During an Incomplete Rebase:** 若正在进行 rebase 并遇到冲突或其他问题想要停止过程,可随时终止重新底的过程而不改原有代码库结构。 ```bash git rebase --abort ``` 以上两种情况均可以在不破坏既有工作的前提下有效地逆转因 `pull` 行为带来的化[^2]。 #### 在 IntelliJ IDEA GUI 下完成上述动作 除了命令行外,IntelliJ IDEA 提供了图形界面支持这些功能。例如要进行硬重置,可以选择 VCS -> Git -> Reset... ,然后选择合适的模式对应的提交版本即可达到相同效果。同样地,针对合并后的反向操作也可以通过 IDE 的交互窗口轻松达成目的[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iaiti

赏顿早餐钱~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值