TL;博士
索引总是更新的。指数保持不变
下一次你打算做出的承诺
,所以它永远不会是空的。(什么,从来没有?好吧,几乎从来没有:里面是空的
新的
您刚刚创建的存储库没有文件,如果您运行
git commit
马上。它也是空的如果你
git rm
一切
(第三章)
长
你在这里的困惑几乎肯定与
the comment PetSerAl made
是的。那些对Git不熟悉的人经常被告知或展示,或者至少让他们相信提交和/或Git的索引包含
变化
,但这是假的一旦你摆脱了这种不正确的信念,git的一些奥秘就开始变得更有意义了。(不是
全部的
对任何人都有意义,甚至对我。所以不用担心如果需要很长时间
grok
吉特。)
在吉特,a
犯罪
包含
所有文件的完整快照
是的。它还包含一些元数据信息
关于
提交本身,如您的姓名、电子邮件地址和时间戳。元数据中包含提交的
起源
提交,或者,对于合并提交,多个父级,复数形式
比较
向他们的父母承诺git会向您显示更改。每个提交都有自己唯一的散列ID,例如
8858448bb49332d353febc078ce4a3abcc962efe
(这是git存储库中git的提交的id)。该提交是快照,但该提交有父级(在本例中,
67f673aa4a...
),所以Git可以
显示
你
8858448bb4...
通过提取
二者都
较早的
67f673aa4a
和
8858448bb4
,然后比较两者这个
git show
命令就是这么做的,所以你看到的就是
改变
在里面
8858448bb4号
,而不是什么
是
在里面
8858448BB4号
是的。
(这就像告诉你今天比昨天暖和或凉爽5度,风或多或少,而不是把天气当成一堆数字数据库存储绝对值,但我们主要想知道它是否更好。)
索引存储下一次可以执行的提交
您可以通过各种方式看到git的提交,当然也可以按照它们的hash id命名它们,正如我在上面所做的那样。你可以看到你的
工作树
这就是git允许您直接查看和编辑文件的地方:在您的计算机上,它们以正常的日常形式存在。但你不能
看见
指数很好。有点看不见这是个问题,因为它也很关键。
大多数版本控制系统根本没有索引,或者如果有类似的索引,就保留它
好隐蔽
你不必知道但是吉特做了一件奇怪的事
强迫
你要了解git的索引,同时还要把它隐藏起来。
如果您真的想查看索引中的文件列表,可以使用
git ls-files
:
$ git ls-files | head
.clang-format
.editorconfig
.gitattributes
.github/CONTRIBUTING.md
.github/PULL_REQUEST_TEMPLATE.md
.gitignore
.gitmodules
.mailmap
.travis.yml
.tsan-suppressions
$ git ls-files | wc -l
3454
在这个Git的Git存储库中,索引中有将近3500个文件那是很多文件这是
为什么
Git把它隐藏起来:里面有太多东西无法理解。
但这也是
为什么
Git通过将他们与他们的父母进行比较来显示我们的承诺显示
全部内容
8858448bb4号
太多了,所以
git show 8858448bb4
告诉我们什么
改变
在里面
8858448bb4号
,与其父对象的比较git对索引采取了相同的策略,向我们展示了我们所拥有的
改变
而不是把整件事都扔了。
我认为,这正是人们认为Git正在存储更改的原因吉特
显示
更改,因此git必须
储存
他们但不是Git存储所有快照吉特
算出
每次你让Git给你看东西的时候都会有变化。
考虑到这一点,让我们看看
看见
索引。
索引位于
之间
当前提交和工作树
我们现在知道,每个提交都是一个完整的快照。如果Git在我们每次提交文件时都为每个文件创建一个新副本,那么存储库将很快变得非常大所以它不会这么做,而且
方式
但这并不简单。每次提交时
是
完整的快照,文件
里面
每次提交都是完全、完全、100%只读的。他们谁也不能
曾经
改变。这意味着每次提交都可以
分享
它的一些或所有文件与一些早期提交!
Git只需要确保每次我们运行
git提交
,它
冻结
所有的文件内容,如果不是永远的话,至少只要这个新的承诺继续存在。所以每次提交中的文件都会被冻结他们也是
压缩的
变成一种特殊的git-only格式(对于文本文件非常有效,但对于像图像这样的二进制文件通常不太好)。这种压缩需要时间,有时需要很多时间,但它使存储库保持较小。
显然,冻结的git-only文件只对git本身有用,因此我们需要
现在的
提交取出,解冻,解压缩,并使有用这些有用的拷贝
工作树
,我们工作的地方。
其他版本控制系统也做同样的事情。在假设的XYZ版本控制系统中,运行
xyz checkout
commit
它从deep freeze warehouse中复制提交,解冻,解压缩,并将其存储在您的工作树中你做了一些工作,最后你跑了
xyz commit
是的。现在它会扫描整个工作树,重新压缩每个文件,冻结它,并检查仓库中是否已经有了冻结的版本,或者还需要将这个版本放入其中当你去喝咖啡或其他什么的时候,每一个步骤都需要几秒钟或几分钟。
git使用它的索引所做的是非常聪明的:索引是
中转区
,介于deep freeze warehouse(包含提交的存储库)和有用表单(工作树中解冻的文件)之间。最初,它包含
相同的
文件在深度冻结它们已经解冻(有点),但仍然是特殊的git-only形式,并且它们与工作树中完全解冻的解压版本配对。
就像你一样
改变
工作树中的文件,或添加和/或删除文件,索引副本将与工作树不同步现在吉特可以
比较
索引副本到工作树副本,并告诉您
已更改但尚未上演
是的。
一旦你有了你想要的文件,你就可以运行
git add
file
是的。这个
重新压缩文件
,并将该副本放入索引中现在,索引副本(这是一个完整的副本,只是压缩的)与
工作树
复制,但与
坚信的
收到。
在任何时候,你都可以让Git比较
坚信的
(
HEAD
)将每个文件的副本复制到
指数
副本:
git diff --cached
对于相同的文件,Git什么也不说对于不同的文件,Git列出了文件并显示了不同之处。
类似地,在任何时候,您都可以让git比较
指数
将每个文件的副本复制到
工作树
副本:
git diff
对于相同的文件,Git什么也不说对于不同的文件,Git列出了文件并显示了不同之处。
(注:增加
--name-status
有
git diff
显示文件名,前缀为
M
对于修改过的,如果修改过的话Git使用
A
对于新添加的文件,
D
对于已删除的文件,等等。文件是
删除
在索引中,只需将其从索引中完全删除文件是
补充
在索引中,如果它在索引中,但不在
头部
.)
这个
git status
命令运行
这两种比较
,和
--名称状态
限制器对于不同于
头部
索引,这些是
准备提交
是的。对于索引和工作树不同的文件,它们是
不准备提交
.
形象地说:
HEAD index work-tree
---------- ---------- ----------
README.txt README.txt README.txt
main.py main.py main.py
这个
头部
副本被冻结,因为它处于提交状态索引和工作树副本可以更改,但最初,
三个都匹配
. 更改工作树副本并使用
git add
复制回来
进入之内
索引,压缩并生成它(如果“en Git ing”是一个单词,则不是)如果你根本不想在索引中更改它,你可以使用
git reset
(违约
--mixed
操作,或它在任何单个文件上的工作方式)将冻结的文件复制回索引中。
这也是为什么
Git提交
是如此之快,相比之下
XYZ提交
当你跑的时候
Git提交
,git已经拥有了所有将以正确形式提交到新提交中的文件。它不必重新压缩所有的工作树文件,看看它们是否与冻结的提交版本匹配这个
指数
所有这些都准备好了:它所要做的就是冻结索引副本,如果这与之前的提交相同,
分享
上次提交的文件。
此外,由于索引“知道”哪些文件与工作树匹配,哪些不匹配,
一
还有关于存储库中内容的额外信息,这使得
git checkout
速度也更快假设你在
master
有大约3500个文件,而你
git签出
另一个分支大约有3300个文件都是完全相同的两次提交之间大约有200个文件不同(可能有一些是新的或删除的)。Git可以使用
指数
要知道它可能需要在
工作树
,并且完全避免接触那些大约3300个文件。
因此,代替xyz系统扫描,可能接触3500个文件,git扫描,可能接触200个文件,节省了超过94%的工作。
一
这通常需要扫描工作树索引保存(
缓存
)数据
关于
工作树,以便加快速度。这就是为什么索引有时被称为
隐藏物
. 其他vcse,比如Mercurial,有一个工作树缓存(Mercurial称之为
dirstate公司
,但与git的索引不同,它被正确地隐藏了:您不必知道它。