Git中的暂存区有啥用?

Posted

技术标签:

【中文标题】Git中的暂存区有啥用?【英文标题】:What's the use of the staging area in Git?Git中的暂存区有什么用? 【发布时间】:2018-08-20 01:24:34 【问题描述】:

git add .git add <filename> 将其添加到暂存区有什么意义?为什么不只是git commit -m "blabla"

我不明白暂存区的价值。

【问题讨论】:

这里的文字很重要,尤其是如果您稍后使用谷歌搜索:它不是临时 分支。它在 Git 文档中有三个名称:indexstaging area(不是分支!)和cache 【参考方案1】:

在 Git 中有许多 staging 的用途。下面列出了一些:

    staging 帮助您将一个大的更改拆分为多个提交 - 假设您处理了一个大的更改,涉及大量文件和相当多的不同子任务。你实际上并没有提交任何这些——正如他们所说,你“在区域内”,你不想考虑以正确的方式拆分提交。 (而且你足够聪明,不会把整个事情都放在按喇叭的大承诺上!)。 现在更改都经过测试并且可以正常工作,您需要正确提交所有这些,在几个干净的提交中,每个提交都专注于代码更改的一个方面。 使用索引,只需暂存每组更改并提交,直到没有更多更改未决。如果你也喜欢 git gui,它真的很适合,或者你可以使用 git add -p 或者,对于较新的 git,使用 git add -e。

    暂存有助于审查更改 - 暂存可帮助您在审查复杂提交时“检查”个别更改,并专注于尚未通过审查的内容。让我解释。在提交之前,您可能会使用 git diff 来查看整个更改。如果您在查看每个更改时对其进行分阶段,您会发现您可以更好地专注于尚未分阶段的更改。 git gui 在这里很棒。它的两个左侧窗格分别显示未暂存和暂存更改,您只需单击文件名左侧的图标即可在这两个窗格(暂存/未暂存)之间移动文件。更好的是,您甚至可以暂存文件的部分更改。在 git gui 的右侧窗格中,右键单击您批准的更改并选择“stage hunk”。只是该更改(不是整个文件)现在已上演;事实上,如果同一文件中还有其他未暂存的更改,您会发现该文件现在同时出现在左上窗格和左下窗格中!

    在合并发生冲突时暂存有帮助 - 发生合并时,干净合并的更改会在暂存区域和工作树中更新。当您执行 git diff 或 git gui 的左上方窗格时,只会显示未完全合并(即导致冲突)的更改。同样,这让您可以专注于需要您注意的事情——合并冲突。

    暂存可帮助您保留额外的本地文件 - 通常,不应提交的文件进入 .gitignore 或本地变体 .git/info/exclude。但是,有时您希望对无法排除的文件进行本地更改(这不是好的做法,但有时会发生)。例如,也许您升级了构建环境,现在它需要一个额外的标志或选项以实现兼容性,但如果您将更改提交到 Makefile,其他开发人员就会遇到问题。当然,您必须与您的团队讨论并制定一个更永久的解决方案,但现在,您需要在工作树中进行更改才能完成任何工作!另一种情况可能是您想要一个临时的新本地文件,并且您不想打扰忽略机制。这可能是一些测试数据、日志文件或跟踪文件,或用于自动化某些测试的临时 shell 脚本……随便什么。在 git 中,您所要做的就是永远不要暂存该文件或该更改。就是这样。

    staging 帮助你潜入小改动 - 假设你正处于一个有点大的改动的中间,并且你被告知需要尽快修复一个非常重要的错误。通常的建议是在单独的分支上执行此操作,但假设此修复程序实际上只是一两行,并且可以很容易地进行测试而不会影响您当前的工作。使用 git,您可以快速做出并仅提交该更改,而无需提交您仍在处理的所有其他内容。同样,如果您使用 git gui,左下方窗格中的任何内容都会被提交,因此只需确保只有更改到达并提交,然后推送!

【讨论】:

由于您测试了工作树的内容,这与提交的索引不同,看起来您最终可能会提交在所有 5 种情况下都未测试的内容。这本身就使索引的使用容易出错。暂存区是一个暴露的实现元素,它不仅能带来帮助,还能带来困惑。例如,你知道 git rebase 时暂存区未提交的更改和工作目录之间的交互吗? git结账呢?那么各种 git reset 调用呢? 你应该提交你测试过的代码。这个暂存区域促进了一种更可能导致损坏的变更集的不良做法。我想知道有多少次需要更改的文件因此而从提交中省略? “当合并有冲突时暂存有帮助”当“推”回主仓库时,这肯定会更有用吗?为什么会与自己的代码更改发生冲突? Git 的主题曲不是“每个提交都是神圣的”,而是“团队宣布为神圣的每个提交都是神圣的”。与旧 vcs 可以支持的唯一提交视图相关联的人被关在一个敞开着门的笼子里,拒绝离开,因为外面很可怕而且不为人知。..【参考方案2】:

值得将 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 areaindexcache,包含建议的下一次提交。

您首先检查一些提交。此时,您拥有每个文件的 三个 个副本:

一个在当前提交中(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 参数上也是如此。通常这往往是不可见的,至少在你开始编写复杂的提交钩子之前是这样。)

【讨论】:

是的。 Mercurial 是一个更加用户友好的 VCS 的众多原因之一。 Git 在使用起来更加尴尬的情况下赢得了人气竞赛,真是太可惜了。【参考方案3】:

staging area 就像一个草稿空间,您可以在其中git add 一个或多个文件的版本保存到您的下一个commit(在其他项目的下一个版本中的单词)。

请注意,您可以将文件的版本复制到暂存区域,也可以在提交之前将它们带到out of the staging area,这就是我将其称为粗略草稿空间的原因。

git add 命令的实际作用是将文件的该版本从工作目录复制到暂存区。

(这是一种常见的误解,人们可能会在他们的心智模型中认为文件已被移动,但实际上它是复制的。)

将文件的更新版本添加到您的存储库所经历的过程:

1️⃣在您的working directory中编辑。工作目录就像一个工作台,您可以在其中编辑文件、添加新文件和删除文件。 2️⃣然后使用git add命令将文件添加到暂存区 3️⃣最后在你使用git commit命令时包含在下一次提交中

能够选择将哪些文件添加到暂存区域并包含在提交中的好处是您可以通过这种方式更好地组织您的工作。

您可以添加与一项工作相关的所有更新文件,并且当您提交时,您可以添加一条提及该工作的消息。

这样你可以更好地组织你的提交。

This video?以非常简单直观的方式解释了以上所有内容,因此可能会有所帮助!

附言另一个小花絮,以防有人好奇暂存区在您的 .git 目录中的真正位置。它由 .git 目录中的 index file 表示!

【讨论】:

【参考方案4】:

我们想要一个暂存区,因为我们想准确选择提交的内容/时间

Microsoft Word 具有您建议的方法(假设您没有打开“跟踪更改”)。对文档所做的任何更改都会一起保存。没有暂存区。你别无选择。简单,但不灵活。

但是 Git 给了你更多的力量。您可以选择记录所做更改的时间和方式。复杂但功能强大。

从根本上说:Git 用户是程序员:我们聪明且能干,我们想要这种灵活性。

示例:

弗雷迪写了一些精湛的歌词。在他已经写出它们之后,他如何将它们保存在四个单独的提交中?

妈妈,刚刚杀了一个人

用枪顶着他的头

扣动扳机,现在他死了

妈妈,生活才刚刚开始

暂存区使他有可能做到这一点。这是一个类似于软件开发的工作流程。

【讨论】:

如果您在 Word 中打开了“cmets/review”功能,那么您可以拒绝不喜欢的内容。也许选择一个不同的例子? @adolfgarlic(我添加了一条注释:您的建议以避免混淆)【参考方案5】:

如果您认为 staging 毫无用处,那么您可能也意识到 git 和软件开发的全部功能。Staging 意味着您希望将这些文件提交到当前分支。有时您可能不想提交某些文件,因此这些文件不会被暂存。

例如:- 一些特定于您的系统的默认配置,因此您可能不想将这些配置文件提交到每个人都在使用它们的分支。 我希望它能消除你的疑惑! :-)

【讨论】:

我看不出这对 OP 有何帮助...您提供的示例根本不需要分期 - 如果您不想提交一些更改,那么您就不要- 不需要分期来不提交某事(在不存在分期的理论模型中)。 Sonulohani 给出了一个很好的用例列表,其中 staging 很有用,所以我认为 OP 得到了答案。但我认为***的 git 用户应该承认,对于微不足道的 git 用户来说,staging 可能根本没有任何用途,尤其是对于那些只使用 GitHub 之类的服务作为自己私人事物的代码存储的人。

以上是关于Git中的暂存区有啥用?的主要内容,如果未能解决你的问题,请参考以下文章

Git 工作区版本库中的暂存区和版本库之间的关系

如何将提交移动到 git 中的暂存区?

百思不得其解,tortoisegit是把git中的暂存区概念干掉了吗

Git | 删除暂存区的修改

Git 工作区暂存区和版本库

Git 工作区暂存区和版本库