想象一下,你有一棵树有一个文件。假设此文件只有两种可能的状态:a
和b
。如果它丢失或不存在,ø
。我正在尝试构建一个表来理解所有可能的git-status
es。我相信我所拥有的是有道理的,然而,我已经用**
标记了问题:
head index working status
a a a no changes**
a a b unstaged:modified**
a a ø unstaged:deleted**
a b a staged:modified, unstaged:modified
a b b staged:modified
a b ø staged:modified, unstaged:deleted
a ø a no changes**
a ø b unstaged:modified**
a ø ø staged:deleted**
ø a a staged:new file
ø a b staged:new file, unstaged: modified
ø a ø staged:new file, unstaged: deleted
ø ø a untracked
对于*, ø, *
中的任何一个,我几乎觉得它取决于父树,以及它是否在索引中...例如,a, ø, ø
就好像你已经删除了来自工作树的blob,以及索引。但是,从索引中删除是什么样的?只是将父树添加到暂存区域并删除了树条目吗?如果是这种情况,那么blob本身的索引中没有条目是有道理的。
对于index = head,(a,a,a
,a,a,b
,a,a,ø
)的任何记录,我假设除非您正在使用管道命令,否则实际上不会发生此状态。
如果你在我的桌子上看到错误,和/或任何光线都会很好!提前谢谢。
答案 0 :(得分:1)
基于提交的版本控制系统(如Mercurial和Git)需要一种方法来区分当前提交中的内容 - 这与任何提交一样,永远不会被更改 - 并且< em>我们将在下一次提交中做什么,当然我们必须在我们进行提交之前进行更改。 Mercurial本质上使用工作树,但Git添加了一个额外的层,它调用 index 。然后Git能够为索引分配一些额外的属性:当且仅当文件在索引中时,文件才被跟踪。在合并期间,索引具有额外的属性(我们将在这里忽略:-))。我将在最后留下最后一个复杂因素。
但是,从索引中删除是什么样的?
从索引中删除文件相当于(相当字面上)从索引中删除文件。尝试运行git ls-files --stage
以查看我的意思:对于第一行(a, a, a = no changes
),您会发现索引中有一个名为a
的文件。对于您的行a, ø, a
,文件a
不再位于索引中(因此不将在您现在制作的新提交中)。
结果,调用文件&#34;上演&#34;可能有点误导。如果a
根本不在索引中(但在HEAD
中),则该文件将被删除&#34;,但只需说出&#34更简单34;不在索引&#34;。一旦文件不在索引中,它也不会被跟踪,因此工作树版本将成为未经跟踪的文件!
这意味着您的a, ø, b
条目也有误:此处文件已暂存,b
的工作树变体是未跟踪的文件。
a, a, ø
条目可能是最难命名的。该文件仍在索引中,因此它将在您从此向前进行的每个提交中,直到您从索引中删除它为止。但是,该文件根本不在工作树中,因此您无法看到它将进入提交状态。如果在此状态下运行git add file
,Git会通过删除索引条目将工作树文件不存在复制到索引中。
(Mercurial具有类似的状态,因为隐藏的内部数据结构称为 manifest ,它扮演与Git索引相同的角色。如果文件丢失从工作树中,但是在清单中,Mercurial调用文件缺少 .Mercurial尝试将工作树视为进入下一次提交的内容,所以你会认为如果文件像这样简单地消失了,它也应该从下一次提交中消失。根据文档,Mercurial最初表现得这样,但发现这很容易出错。)
git ls-tree -r HEAD
查看当前提交的整个树(如果只有一棵树,您不需要-r
)。git ls-files --stage
查看当前索引的整个树:索引就像一个展平的树,如果你有一个名为dir
的文件d1
的子目录(子树), d2
,您获得名为dir/d1
和dir/d2
的索引条目(与提交相对应,其中顶部树将具有名为dir
的子树,并且子树将具有两个名为{{0}}的子树{1}}和d1
)。d2
)查看工作树。您的工作树本身对ls
的意义非常小,它只是将现有索引(无论其中的任何内容)转换为一个或多个树对象以存储到新提交中。 (这会改变你运行git commit
的文件路径名参数或git commit
或类似。这里Git可能会向索引添加文件,甚至切换到它使用的临时备用索引,直到提交完成这取决于在提供其他路径时,您是使用-a
还是--include
。)因为Git拥有并公开了索引,所以它可以并且确实以两种不同的方式公开了另一个功能。索引每个条目有两个标志位,称为假设未更改和 skip-worktree 。要使用--only
查看这些标志位,您必须添加git ls-files
参数,但它们的作用可以相对简单地描述 - 有点过于简单,结果如下:
如果在索引条目上设置了assume-unchanged或skip-worktree标志,Git应该只是关闭它的眼睛&#34;在执行--debug
等操作时,工作树中的内容。
这可以加速Git,但有一定的副作用。副作用可能是我们使用的比特。
当您运行git status
时,Git会运行两个 git status
。一个比较git diff
与索引,第二个比较索引与工作树。它是确定HEAD
输出的第一列的第一个差异,以及决定第二列的第二个差异。
假设未更改和跳过工作树位告诉Git在第二个差异期间不要打扰比较文件。 1 请注意,对于要设置的这些位,索引必须有一个条目用于文件,即文件必须跟踪,以便像这样被跳过。我们可以假设索引条目与git status --short
条目匹配(如果它没有,它将在下一次提交之后!),因此这些标志位的效果是我们从未将文件视为已修改,HEAD
通常也会跳过文件:它不会将工作树版本复制回索引。
我们的假设 - 索引条目与提交相匹配 - 导致我们在某些极端情况下误入歧途,并且是两个位的原因。有关详细信息,请参阅Git - Difference Between 'assume-unchanged' and 'skip-worktree'
1 第一个差异非常快,因为特殊的表单文件(blob)存储在提交或索引中时。具体来说,Git可以通过比较它们的哈希ID来判断任何一个文件的内容是否与任何其他文件的内容匹配。如果哈希ID匹配,则文件相同;如果没有,文件是不同的。 Git目前并不是在寻找完整的差异,而只是git add
样式差异:&#34;文件是否相同?&#34;
第二个差异要慢得多,因为在最坏的情况下,Git必须打开并读取每个文件的全部内容。即使只是询问文件系统关于该文件(调用--name-status
系统调用)也比Git的内部比较哈希ID技巧慢得多。