【问题标题】:What is the use of Staging area in gitgit中暂存区有什么用
【发布时间】:2020-03-29 11:23:10
【问题描述】:

我是 git 的新手。

我刚刚介绍了工作目录和暂存区的概念。

我对暂存区的使用不是很清楚。

如果暂存区不存在并且我们可以直接从工作目录提交到本地 repo,会出现什么问题?

抱歉,如果我的问题很愚蠢。

感谢您的问候, 京东

【问题讨论】:

标签: git


【解决方案1】:

除了Obsidian's answer,它还涉及到您可以 使用索引/暂存区域(同一个底层 Git 事物的两个短语)。 可以构建一个没有索引/暂存区的版本控制系统。

Mercurial 就是这样一个系统。在 Mercurial 中,工作树建议的下一次提交。这确实需要一些额外的幕后技巧,但系统运行良好,而且 Mercurial 的新手使用它的麻烦远少于 Git 的新手使用 Git。从中可以清楚地看出,索引/暂存区是一个艰难的概念。这不是绝对必要的——尽管它确实启用了各种技巧——而且一个没有的系统更容易使用。

但 Git 确实有它,所以如果您使用 Git,请记住 Git 始终为每个文件保留 三个 个副本1:@ 中的冻结一个987654322@(当前提交),索引中暂存的提交,以及您可以在工作树中查看和编辑的提交。使用git add 工作树复制到 索引中。使用git reset 复制 冻结的HEAD 复制 索引。如果您有 Git 2.23 或更高版本,请使用 git restore 索引复制 工作树。

(如果你的 Git 版本比那个旧,有一个 git checkout 模式可以从索引复制到工作树。你不能复制到 HEAD 副本,因为它被冻结了!所以唯一的选择是:@ 987654329@ -> 索引,HEAD -> 索引 -> 工作树,索引 -> 工作树和工作树 -> 索引。)

旁注:花哨的git add -pgit reset -p 通过将索引副本提取到临时文件、比较临时副本和工作树副本并进行任何您喜欢的更改来完成他们的工作——然后为git add -p ,将更新后的临时副本放回索引中。


1从技术上讲,所有 Git 化(压缩、冻结格式)的副本在所有可能的范围内都共享。索引中的内容是 blob 对象的哈希 ID。当您从工作树副本更新索引时,Git 准备一个新的或重用的 blob 对象,准备好提交,并更新索引哈希 ID。除了没有使用额外的磁盘空间这一事实之外,这在使用 Git 进行普通工作时通常是不可见的。您可以将索引副本视为私有副本,只要您记住 git ls-files --stagegit update-index 在现实中使用 blob 哈希即可。

请注意,即使您从不提交某些 blob,只要 blob 仍在索引中,Git 就会一直保留它……除了添加工作树的一个相当讨厌的错误,从 Git 2.5 开始并在 Git 2.15 中修复.同时,使用git add -p 会创建大量未使用的 blob 对象,这些对象最终会被垃圾回收,但在此之前确实会占用一些额外的磁盘空间。

【讨论】:

  • "但是 Git 确实有它,所以如果您使用 Git,请记住 Git 始终保留每个文件的三个副本:HEAD 中的冻结副本(当前提交),暂存的副本在索引中,以及您可以在工作树中查看和编辑的那个。” ...这是我对官方文档的不满,将索引的性质与它的使用方式混为一谈。即使是专业人士也会陷入这个陷阱并开始做出错误的推论。 git add 将内容添加到存储库 并更新索引条目。 Git 确实保留三个副本。 Git 保留一份副本,以及一个指向它的索引条目。工作树是你的。
  • @jthill:是的,有时我会包含这个细节——但在大多数人使用 Git 的级别上,那个特定的细节是无关紧要的。是否以及何时开始使用git update-index 替换索引副本很重要,因为现在您需要知道首先使用git hash-object -w
【解决方案2】:

你的问题一点也不傻。它是构成整个 Git 大厦的少数基本概念之一。

  • 工作目录 是您工作的实际位置,您可以在签出文件时看到文件,其中包含(除其他外).git 子目录。这将形成您的 git 存储库,以及您最初克隆的远程存储库的本地副本。
  • index 是 Git 实际遵循的文件列表:它由一个单一的、平面的、二进制文件组成,该文件在 .git 子目录下包含大小固定的条目,简称为 @987654323 @。这意味着位于工作目录中但 Git 未明确遵循的所有文件将始终保持不变。

您还需要知道 Git 是一个基于快照的 SCM 系统:每次修改文件时,都会重新完整记录一次。 Git 不会记录版本之间的差异(至少现阶段不会)。因此,每个提交都由一个树状文件列表构成,该文件列表引用每个提交的当前版本。

这就是索引开始变得聪明的地方:当您使用git add将文件添加到跟踪列表时,您不仅仅是将其名称和路径添加到索引中:Git 还将其当前内容保存在一个对象中,从而开始构建实际即将到来的提交的有效负载。然后当您执行git commit 时,git 只是将此索引的内容保存为新修订版。这就是使该索引事实上成为“暂存区”的原因。

这有几个后果:

  • 在您的新提交中实际记录的实际上是文件的状态,就像您执行 git add 时一样,而不是 git commit ;
  • 您可以轻松决定实际提交的内容:您不必提交自上次提交以来修改过的每个跟踪文件;
  • 要确定存储库的状态,git 只需比较工作目录、索引和最后一次提交(实际上是 HEAD 当前引用的那个)的状态。

我们可以通过以下方式总结最后一点:

  • 所有工作目录、索引和上次提交都引用相同的文件内容:存储库是最新的:
  • index 和 commit 相同,但工作目录包含不同的文件内容:已经进行了一些修改,需要添加:“unstaged changes”;
  • 工作目录和索引相同,但与上次提交不同:已进行了一些修改并已标记为记录:“分阶段更改”;
  • 所有三个实体都不同:一些修改已被更改,但自上次调用git add(这仍然完全合法)或您使用@987654329 执行了基于补丁块的部分添加后,您再次修改了文件@ 仅选择文件中感兴趣的内容:“暂存更改”和“未暂存更改”都显示在 git status 中。

最后,这提供了最后但并非最不重要的优势:由于修改检测是基于文件内容而不是其最后修改时间,因此您可以轻松取消您所做的事情。当文件“意外”恢复到最初的状态时,它会自动从git status的列表中消失。

【讨论】:

    【解决方案3】:

    您可以使用它来选择要提交的内容——该文件中的这几行更改,该文件中的那个部分...如果没有暂存区域,这种事情将很难做到。

    我喜欢使用git add -p 命令添加要提交的内容,该命令会遍历所有更改的文件并逐段显示差异,您可以在其中选择将每个文件与其他文件分开。然后你提交结果(可能再次运行git add -p 以创建另一个提交)。

    【讨论】:

      猜你喜欢
      • 2018-08-20
      • 2017-09-23
      • 2011-07-20
      • 2020-12-23
      • 1970-01-01
      • 2020-09-06
      • 2013-11-06
      • 2023-02-09
      • 1970-01-01
      相关资源
      最近更新 更多