值得将 Git 处理此问题的方式(Git 让您了解并使用暂存区域)与 Mercurial 处理此问题的方式进行比较。在 Mercurial 中,您完全按照您的建议工作:您只需运行 hg commit,Mercurial 就会找出您更改的内容并提交它。您确实必须 hg add 一个 new 文件,但如果您只是更改现有文件,没有什么特别的事情要做:您更改它们并提交,然后就完成了。
Mercurial 的行为似乎(并且在我的观察中一直是)更加新用户友好。 Git 实际上可以让你通过使用git commit -a 获得大部分相同的效果。也就是说,您只需将-a 添加到您将使用的任何其他选项中,Git 将执行与 Mercurial 几乎相同的操作。但这有点像拐杖,因为最终,除非您了解暂存区,否则您会发现 Git 所做的一些非常莫名其妙的事情。
Hidd3N's answer 展示了您可以使用 Git 暂存区的多种方式。但是,如果您退后一步,比较一下 Mercurial 和 Git,我认为您可以了解更多实际情况。
请记住,任何版本控制系统 (VCS) 的工作是让您检索每个提交的版本曾经。 (而且,由于 Git 和 Mercurial 都在整个系统的快照基础上工作,因此在这里很容易比较它们。有一些更老的 VCS 一次只对一个文件进行操作:您必须特别检查-in / 提交每个单独的文件。Git 和 Mercurial 一次创建所有内容的快照。)这些提交的快照应该永远存在,并且永远不会改变。也就是说,它们是只读的。
不过,只读文件不适合处理。所以任何 VCS必须在某种程度上/某处有两个独立的东西:
- 您处理文件的地方:这是您的工作树;和
- 存储快照的地方:这是您的版本数据库、存储库或其他词——Git 将这些东西称为 objects,而 Mercurial 有一组更复杂的结构,所以我们只需调用他们对象在这里。
Git 的对象存储区有一堆只读对象:实际上,每个文件一个,每个提交一个,等等。您可以随时添加新对象,但不能更改任何现有对象。
正如 Mercurial 所展示的,对于单独的暂存区域没有要求:VCS 可以使用 work-tree 作为提议的提交。当您运行hg commit 时,Mercurial 会打包工作树并从中进行提交。当您在工作树中进行更改时,您会更改建议的下一次提交。 hg status 命令向您显示您要提交的内容,即:当前提交和工作树之间的不同之处。
然而,Git 选择在只读提交和读/写工作树之间插入这个中间区域。这个中间区域,staging area 或 index 或 cache,包含建议的下一次提交。
您首先检查一些提交。此时,您拥有每个文件的 三个 个副本:
- 一个在当前提交中(Git 总是可以通过名称
HEAD 找到它)。这个是只读的;你不能改变它。它是一种特殊的、压缩的(有时非常压缩)、仅限 Git 的形式。
- 一个在索引/暂存区。这个匹配现在的
HEAD,但它可以改变。这是建议进入 next 提交的那个。这也是特殊的 Git-only 形式。
- 最后一个在您的工作树中,以您可以在其中工作的普通形式。
git add 所做的是将文件从工作树复制到暂存区域,覆盖用于匹配 HEAD 提交的文件。
当您运行git status 时,它必须进行两个单独的比较。一个比较HEAD 提交到索引/暂存区域,以查看下一次提交会有什么不同.这就是to be committed。第二个比较发现索引/暂存区域和工作树之间的不同之处。这就是not staged for commit。
当您运行git commit -a 时,Git 会根据第二个比较简单地复制到暂存区。更准确地说,它相当于git add -u。 (它秘密地使用 temporary 暂存区执行此操作,以防由于某种原因提交失败,以便您的常规暂存区/索引在提交期间不受干扰。其中一些取决于在额外的git commit 参数上也是如此。通常这往往是不可见的,至少在你开始编写复杂的提交钩子之前是这样。)