解决您在评论中添加的内容:
我担心的是......当我提交某些东西时,我会在舞台上提交文件。
没错。但是:
要在阶段添加文件,我需要“git add”它们。
这不太对。我们稍后再讨论这个问题。
当我拉取(即提取 + 合并)时,是否有合并的某些部分将文件添加到阶段?
是的,有。
我可以这样解释。我的错是我在添加修复之前没有做“git status”,但我认为舞台是空的。
现在让我们仔细看看这个。这个暂存区究竟是什么?请注意,它有三个不同的名称:暂存区,这是您一直使用的名称; 索引;有时是 cache(所以你会看到,例如,git rm --cached 和 git diff --no-index 或 git diff --cached 来控制是否涉及索引/缓存/暂存区域)。我将在这里使用 index 这个词,以避免过多地暗示它:staging area 这个名称(在许多方面更好)暗示了关于索引的一些内容用于暂存文件,而名称 cache 暗示了如何使用索引来加速各种操作。
我喜欢定义索引的方式是,您可以使用它来构建您将进行的下一次提交。这是指它在暂存文件中的作用,但提醒您为什么您也在暂存文件:因为您打算进行新的提交。如果它们与旧的完全一样,那么制造新的就没有意义了。所以在某种程度上,我们知道我们正在更改存储在索引中的数据,然后我们将使用git commit 将其转换为新的快照。
关于索引的第一个奇怪的事情是它永远不会1为空。相反,索引通常匹配当前提交。此时您必须运行git commit --allow-empty 来创建新的提交。这不是因为索引本身是空的;相反,这是因为索引与当前提交之间的差异为空。
不过,稍后,您将 git checkout 提交一些提交(可能通过分支名称),或者运行 git commit 来创建一个新提交。在 this 点,索引和当前提交将相互匹配。索引中的内容也是已提交的内容。
当您运行git add 时,您所做的是将工作树文件复制到索引中。如果那是一个 new 文件,那么它现在在索引中,而以前它不存在。如果是 changed 文件,您刚才所做的就是将存储在索引中的数据替换为新数据。无论哪种方式,索引版本现在都与工作树版本匹配。 (练习:索引版本现在是否匹配提交版本?如果工作树版本匹配提交版本会发生什么?)
关于索引的第二个奇怪的事情是在git merge 期间发生了什么。 git merge 处理的情况有多种,其中一些很容易,不要这样做;但其中之一是真正的合并。在真正的合并中,Git 有两个特定的提交——我喜欢称它们为 L 和 R,分别代表左右,或者本地和远程,或者 --ours 和 @ 987654333@——共享一个共同的合并库提交B。 Git 通过实际上运行来查找自公共基础以来发生的事情:
git diff --find-renames B L # what did we change in --ours?
git diff --find-renames B R # what did they change in --theirs?
然后,Git 将 组合 更改,实际上是用每个文件的 三个 版本填充索引:一个来自 B ,一个来自 L,一个来自 R。这三个进入每个文件的索引条目中的“槽”。通常,在非合并中间的情况下,只占用槽零。当我们合并时,slot 0 被引导出来,三个版本进入 slot 1-3。
然后,Git 可以轻松比较这三个版本,并决定采用哪一个(如果 --ours 与 --theirs 中只有一个更改了文件与基础)或如何组合更改(如果 --ours 和--theirs 改变了它)。 如果Git 可以组合更改——好吧,如果它认为可以——它会这样做,并完全丢弃这些编号较高的插槽条目:组合版本进入插槽零像往常一样,该文件已解决。如果 Git 认为它不能组合更改,它会将其最佳猜测和冲突标记写入工作树,然后将编号较高的插槽留在索引中。2 然后你必须自己解决(使用工作树文件,或者三个索引槽条目,或者你喜欢的任何东西)和git add 正确的结果,不管是什么。然后git add 步骤将清除槽 1-3 条目并写入槽零条目。
在这一切结束后,我们回到了更正常的情况。索引现在在每个文件的正常插槽零(无冲突)条目中包含每个文件的副本,因为它应该出现在新的合并提交中。所以现在我们或 Git 可以运行 git commit 来提交最终结果。
如果我们进行真正的合并,并且 R 中的文件既不在 L 也不在合并基础 B 中,该文件的合并结果是“获取新文件”。所以这种情况很简单,git merge 将文件添加到插槽 0 中,而没有真正提及它。
1好吧,有一种明显的情况是索引完全为空,即根本没有文件。例如,这是一个新的、新鲜的、完全空的存储库中的初始状态。请注意,在这种情况下,您也没有任何分支。这是一个特殊的状态:你在分支 master 但分支 master 还不存在!索引确实是空的,根本没有提交。
2这个一般性的描述并不完全是它在内部发生的方式,它都经过优化以使简单的案例快速进行。但这是合乎逻辑的过程。优化流程见the git read-tree documentation。