likes
comments
collection
share

git中被误解的概念

作者站长头像
站长
· 阅读数 11

我是一个自认为git重度使用的开发者,相关git课程买了2本,git官方教程常年收藏,其中 7.7节<<重置秘密>>更是逐字研读,其他网上开源的git教程更是研读无数,但最终也只能当一个储存代码的工具,碰上git diff、git diff --chache等命令,还是搞不清,到底比对的是哪里的不同?

有没有跟我一样的,用了很长时间的git,也研究了好多次git,但最终还是感觉哪里不对劲,还是没有把握把git说清。

这一次又在研究git,朝着git的山头又一次冲锋,可能冲锋的次数多了,量到了,这次豁然开朗了。

三大区域

git分三大区域。

工作区

工作区就是内容的存放目录,你的任何代码操作都是在工作区进行。

暂存区

暂存区是存放与工作区差异的地方。

commit(历史区)

其中commit比较特殊,在很多资料里都没有明确的中文名,有的叫HEAD快照,有的叫commit,有的叫版本库,我们姑且叫历史区。

"修改"的误区

三大区的定义任何一本git资料上都能找到,上边只是简单介绍一下,其中对暂存区的介绍,可能任何人看了都要拿板砖拍我了,因为这种解释没有任何可理解性。这句话严格意义上说是错误的。后边解惑。

看一下别的教程里的一些解释片段。

  • 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

  • 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

  • add 指令除了 git add 文件名 这种用法外,还可以使用 add . 来直接把工作目录下的所有改动全部放进暂存区。

  • reset --soft 会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。

这些解释都很标准,没有任何问题,注意这些定义中的"修改"和"差异"这些词,再看一下git status命令查看当前git状态。

git status的时候也会把这些差异显示出来。如下图:

git中被误解的概念

图中分别显示工作区修改的内容,暂存区修改的内容。

所有的资料,所有的使用帮助都在告诉你个概念,工作目录放着你新的修改内容,暂存区放着与工作区的差异。

我一直以来也是这样理解的。

所以一直也搞不清"修改"的代码到底是啥东西,到底有啥规律。

直到我换了个思路理解。

工作目录放着全部代码,不管新添加的还是原来的,存放着的就是全部代码。

暂存区跟工作目录一样,也放着全部代码,并不存在"修改"概念。

git status显示的只是一个增量状态,并不是工作区和暂存区真实的全部代码。

每次你在工作区添加新代码时候,工作区存放的代码就是你增加新代码后的全部代码,git status中查看的状态是你增量的代码,他会用历史区的代码跟你工作区的代码进行比对,把差异显示出来。同时也会把暂存区的代码跟你工作区的代码进行比对,然后也把差异显示出来。

git add的时候是把你工作区的代码,提交到暂存区,因为暂存区有你改动前的代码,所以提交的代码可以理解为提交了一个"修改",但不管怎么样最终暂存区的代码跟工作区的一样了,所以git status查看就看不出差异了。

理解 git diff

  • git diff
  • git diff --cached
  • git diff HEAD

以前一直较劲脑汁想搞清这三个命令后显示的到底是谁跟谁的不同,可惜都未能成功,直到真的理解了暂存区和工作区。

  1. git diff 显示的是工作区全部代码与暂存区全部代码的差异。经过比对工作区和暂存区的代码,然后把差异进行显示。这里有的资料就说暂存区存放着和工作区的"差异"。但这个差异很显然是在显示的时候,通过比对得出的结果,并不是把差异真的放在暂存区了。

  2. git diff --cached 显示的是暂存区全部代码与历史区中的代码差异。有的资料说暂存区存放着和历史区的差异,那你跟第一条命令放一块,如果没有理解到暂存区存放着“全部代码”这个概念,执着的盯着"差异"去理解这个命令,你会困惑"差异"为啥会变。暂存区一会存放着和工作区的差异?一会存放着和历史区的差异?很矛盾,很无解。

  3. git diff HEAD 显示的是工作区全部代码与历史区代码进行比对,并显示差异。

所有的diff出来的差异都是经过比对后的结果,所有区存放的是代码,并不是"差异"。

理解git reset

这个命令也是很让人困惑的命令,困惑后边跟着--soft --hard时候,工作区和暂存区到底有啥东西。

  1. git reset commitid

其他资料中的解释:reset 不加参数:保留工作目录,并清空暂存区

这是某些资料里的解释,但其实本质是把指向的历史区代码放进了暂存区,而工作区代码没有任何变化。暂存区代码比工作区代码少了,出现了差异,同时暂存区与历史区代码相同,看着像是暂存区"差异"清空了。

  1. git reset --soft commitid

其他资料中的解释: reset --soft 会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。

这个命令的本质是工作区和暂存区存放的所有的代码都没有任何变动,变动的是HEAD指向的commit从"当前"位置指向了指定位置。

因为工作目录和暂存区的代码完全一样而又跟历史区的不一样,所以看着像是把"暂存区与历史区的差异"放进了暂存区。

  1. git reset --hard commitid

这个就更好解释了,把指定历史区的代码放在完全放在工作区和暂存区,最终工作区,暂存区,历史区代码都一样,不存在差异

验证

以上所说的理解跟大部分资料都不一样,可能有人会怀疑,对我所说的暂存区存放所有的是"全部文件"而不是存放差异有怀疑,说我这个概念是为了理解而杜撰出来的。

那你可以仔细阅读我之前说的git官方教程7.7节<<重置秘密>>,里边会介绍一个git底层命令

git ls-files -s

可以查看当前暂存区的文件记录,这个记录是一个hash值,但足够表明暂存区到底是"清空"还是有东西,如果git status查出来的暂存区状态为空,那用这个命令查看暂存区,如果有东西,那就证明,暂存区存放的并不是"差异""修改",而是"完整代码"。

转载自:https://juejin.cn/post/7223674554221183033
评论
请登录