2

我了解典型的 Git 工作流程是一个三步过程:(修改工作树中的文件)->(使用 修改索引git add/rm/etc)->(运行git commit)。

但是,为什么 Git 不把工作树当作暂存区呢?例如,您修改了一个文件,它会自动“暂存”以进行提交,除非您明确告诉 git 不要暂存它。这更像是一种“选择退出”方法而不是“选择加入”,这对我来说很有意义,因为您的工作树中 99% 的文件都将被提交。它还会使整个git stash机制变得多余,因为您可以简单地从工作树中创建一个临时分支,而不是稍后save存储apply

如果工作树和索引之间的分离有正当理由,我很想听听......也许我的困惑源于我还没有完全了解 Git 的事实。

4

2 回答 2

4

Git站点实际上很好地解释了暂存区是什么、它存在的原因、它提供的好处以及在提交时绕过它的方法。

取自http://git-scm.com/about/staging-area

暂存区

与其他系统不同,Git 有一个叫做“暂存区”或“索引”的东西。这是一个中间区域,可以在完成提交之前对提交进行格式化和审查。

Git 与其他工具的不同之处在于,它可以快速暂存一些文件并提交它们,而无需提交工作目录中的所有其他修改文件,也不必在提交期间在命令行上列出它们。

这允许您仅暂存已修改文件的部分内容。在您意识到忘记提交其中一个文件之前,对一个文件进行两次逻辑上不相关的修改的日子已经一去不复返了。现在,您可以暂存当前提交所需的更改,并为下一次提交暂存其他更改。此功能可根据需要扩展到对文件进行尽可能多的不同更改。

当然,如果你不想要那种控制,Git 也可以很容易地忽略这个特性——只需在你的提交命令中添加一个“-a”,以便将所有文件的所有更改添加到暂存区域。

希望这可以帮助。干杯!

于 2014-11-20T01:44:27.667 回答
2

Mercurial 基本上是“没有索引的 git”,因此证明它是可以做到的。任何“为什么”的问题都属于很多灰色地带。但这就是索引提供的内容:

  • 非常快的“git commit”:索引已经包含下一个提交;它只需要重新格式化为树对象和最终提交对象。

  • 一个暂存区,这样你就可以使提交与工作目录不匹配。(不是每个人都认为这是一件好事。)在 Mercurial 中,要提交文件AC同时省略 的工作版本B,您必须发出提交命令,其中包含(或排除)所有文件的名称一次全部拼写出来。在 git 中,您可以设置一个阶段,运行git diff --cached(或--staged),决定它是否正确或需要调整,git add或者git reset调整阶段,运行另一个git diff --cached,等等。(在 Mercurial 中,我发现通过将所有“不需要的”更改移出存储库区域hg commit,然后将这些更改移回,最容易实现相同的目标。)

  • 易于修改未发布的提交。习惯了 git 中的暂存区和修改过程后,当我在 Mercurial 中进行修改时,我惊讶地发现我当前的整个工作树都变成了新的修改提交。(我不应该感到惊讶,但我是!这又回到了不同的哲学:在 hg 中,你将“尚未准备好”的部分完全移出 repo,以免它们潜入。)

  • 棘手的黑客。(同样,不是每个人都认为这是一件好事。)特别是您可以在索引中设置位,例如“假设不变”或“打算添加”,这会影响未来的提交(再次因为索引在某种意义上是“正在构建的下一个提交”)。

  • 一种在发生合并冲突时保留并因此轻松访问正在合并的文件的方法。

最后一个值得一些额外的解释。假设您正在合并old-fix到一个文件feature并在其中重命名。合并意识到它需要从 branch和from获取文件(以其旧名称)并将它们合并。但是存在合并冲突,您的版本系统停止并需要您的帮助来完成合并。featureFAold-fixFAfeature

现在假设您要查看FAin的版本old-fix,并将其与FAin进行比较feature。如果您从字面上签出分支old-fix,则没有名为的文件FA!但是 git 将它存储在索引中,以便您可以看到它,而不必知道旧名称是什么,因为索引正在构建下一个提交(保留新FA名称)。

您也可以查看feature版本,当然这更容易,因为您知道它的名称为FA. 但它在索引中。此外,如gitrevisionsold-fix中所述,通用(基本)版本(也与 中的旧名称相同)在索引中:

A colon, optionally followed by a stage number (0 to 3) and a
colon, followed by a path, names a blob object in the index at the
given path. A missing stage number (and the colon that follows it)
names a stage 0 entry. During a merge, stage 1 is the common
ancestor, stage 2 is the target branch's version (typically the
current branch), and stage 3 is the version from the branch which
is being merged.

也就是说,:1:FA是文件的共同祖先FA:2:FAfeature的版本,:3:FAold-fix的版本。

所有这些精细控制都会导致初学者(有时甚至是专家)出现一些错误,因此 Mercurial 的无索引版本可能更适合您的工作。但是,使用git commit -a,您将获得与 Mercurial 基本相同的行为,因此您通常可以忽略它,直到您需要它为止。

于 2014-11-20T01:55:51.627 回答