如果我从一个干净的工作树开始并运行git checkout <branch> <file>
,其中<branch>
有这个文件的不同版本,我最终会进行分阶段而不是非分阶段的更改。
这是什么原因?这只是为了与git mv
等其他命令保持一致,您期望进行更改吗?使用git checkout
解决合并冲突时是否方便?还是有其他理由吗?
这对我来说似乎有些奇怪,因为仅使用git checkout <branch> <file>
并未提供任何关于我是否计划进行更改的指示。
它实际上是Git作者选择透露的实现细节。
Git不能 - 或者更确切地说,无法将文件直接从存储库读取到工作树中。它已经(或曾经)通过中介首先传递它们:它必须在其他地方复制它们,或者至少复制它们的重要统计数据。只有这样,Git才能将数据复制到工作树文件.2“其他地方”是索引条目。索引也称为暂存区域。
当你git checkout
整个提交时,无论如何这都是你想要的。因此,首先复制到索引然后再复制到工作树的内部限制实际上是一个加分。因此,这种首先复制到索引中,然后再导入工作树的机制被嵌入到实现中。然后,最终,面向用户的git checkout
前端获得了检出一个单独文件或一些小文件子集的能力......并且它继续通过索引这样做。实现细节成为记录的功能。
请注意,有时,索引在冲突合并期间用作帮助区域。在这种情况下,对于某些文件F,最多有三个条目,在编号的槽1(基础),2(--ours
)和3(--theirs
)中,而不是正常槽零中的一个条目。如果是这样,您可以将三个索引槽条目中的任何一个提取到工作树,而不会干扰索引。但是如果你使用git checkout
从其他一些提交或树中提取文件,Git会将文件复制到索引中,并将其写入插槽零。这有消除更高编号的插槽的副作用,解决合并冲突!
1主要是哈希ID。作为ElpieKay noted in a comment,Git必须将提交哈希解析为树形哈希,然后搜索各种树以找到感兴趣的文件,以便它可以获得blob哈希。索引条目本身也包含更多数据,包括工作树文件的stat
结构数据,以使Git快速运行。
2您仍然可以使用此工作流程,使用git read-tree
将树复制到索引中,然后使用git checkout-index
将索引复制到工作树。最初,Git由一堆shell脚本组成,例如git-checkout
,包裹着一些基本的C编码片段,如git-read-tree
。 (这些名字都是这样的连字符,并且没有前端git
命令。)
git checkout
总是将项目从索引中复制到工作树中。