【问题标题】:When is tracking but not staging OR unstaging but not untracking useful何时跟踪但不暂存或取消暂存但不取消跟踪有用
【发布时间】:2016-11-09 22:12:42
【问题描述】:

我在 SO 上看到了following 问题,它询问如何在 git 中进行跟踪但不能暂存以及如何取消暂存但不能取消跟踪文件。作为一个 git 初学者,我很好奇这两种情况在哪些特定场景下有用?

【问题讨论】:

  • 请澄清您的反对意见,以便我改进问题。谢谢。

标签: git


【解决方案1】:

从技术上讲,您不能“跟踪但不暂存”文件,在某种意义上也不能“不暂存而不跟踪”,除非 Git 和人们都使用“未暂存”一词来指代别的东西。 (我会稍微描述一下“unstage”的含义。)

如果文件在 Git 所谓的“索引”(即“暂存区”)中有一个条目,则该文件在 Git 中被“跟踪”。 git addgit rm 都在索引中创建或替换了一个条目——git rm 放入了一种“whiteout”条目,意思是“它只是现在在这里,但在我提交之后,让它不在一切都是为了不再被追踪。” (事实上​​,git add 可以像git rm --cached 一样工作,如果文件在索引中,但在工作树中缺失,则这样做。)

您可以通过git ls-files --stage 看到(大部分)索引中的内容;请参见下面的示例。每个文件路径名最多有四个索引“槽”。其中三个仅在合并期间使用。因此,除了合并时,索引中的所有内容始终处于“阶段零”。

stage 一个文件,我们只需运行git add <em>path</em>(或git add -- <em>path</em>,如果path 部分类似于-p,这很有用,尽管您也可以将文件 -p 命名为 ./-p 以防止它看起来像补丁标志)。如果文件已经在索引中,则更新它(通过替换现有的索引条目)。

要“取消暂存”文件,我们通常运行git reset <em>path</em>(如果需要,请添加--,如前所述)。但是,除了一种情况,这不会删除路径的索引条目!相反,它重置(因此得名)索引条目以匹配HEAD 提交。它确实完全删除条目的一种情况是HEAD 提交在该路径名下没有文件。

因此,“取消暂存”文件并没有真正取消-暂存文件:相反,它重新-暂存(或者,更好的是,重置 em>) 将其返回到当前(HEAD)提交,但不触及工作树中的副本。不过这个动作大家都用“unstage”这个词,所以我们不妨习惯一下。 :-)

进入杂草(回答您的其他问题)

您链接到的问题是关于使用git add -N。这在很长一段时间内完全被破坏了,在 Git 2.5 版本中有所修复,在 Git 2.10.1 中仍然部分被破坏(我刚刚在我的测试中)。它有效地将占位符放入索引中,以便跟踪文件 (因为它在索引中,当然),但同时那里没有实际文件。这个索引条目被标记为“特殊”,很像一个白化条目。该行为实际上与 whiteout 条目非常相似——即,git write-tree 确实将文件写入结果树——除了 Intent-to-add 特殊条目在提交后保留,而 whiteout提交后条目被删除。

至于它有什么用途:在我看来,它没有。 :-) 显然,解决错误(-N 在低于 2.5 的 Git 版本中完全失败,2.5 到 2.10 中的小问题)并不是很重要,因此可能很少有人(如果有的话)真正使用它。

它完成的一件事是让git diff 将文件视为已跟踪文件,以便将当前索引与工作树进行比较的git diff 显示添加的文件内容:

$ git status --short
?? thirdfile

(这表示“第三个文件”未被跟踪)

$ git diff

(无输出:git diff 不查看未跟踪的文件)

$ git add -N thirdfile
$ git status --short
AM thirdfile

(这表明该文件现在被跟踪——在索引中,而不是在HEAD 提交中,因此将A 声明为第一个字母——并且也被修改了,因为索引条目是假的但文件存在内容真实)

$ git diff
diff --git a/thirdfile b/thirdfile
index e69de29..1ecbedd 100644
--- a/thirdfile
+++ b/thirdfile
@@ -0,0 +1 @@
+data for file 3

(在这里我们看到了真正的内容)。如果我们使用git ls-index --stage 查看索引,我们会看到1 一个零阶段条目——一个普通文件——其哈希值是空文件的哈希值:

$ git ls-files --stage
100644 e5c143f6fec374d115ef674fc036649d78c625d2 0   README
100644 6b8bd59d197cba9032b59ee3aa3f4e71cfbdc2df 0   dummyfile
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   thirdfile
$ git hash-object -t blob --stdin < /dev/null
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

如果我们清空文件,工作树中的 real 文件现在与存储在索引中的哈希匹配。奇怪的是,虽然git diff 现在什么都没有显示,但git status 仍然表示文件已被修改,与索引版本相比:

$ : > thirdfile 
$ git status --short
AM thirdfile
$ git diff

(最后一个命令不产生输出)。与工作树相比,缓存条目被标记为“意图添加”的文件始终被视为“已修改”,这是“在 Git 2.10.1 中部分损坏”案例的来源,因为这愚弄了 @987654353 @ into 允许提交,即使新提交的内容与HEAD 提交的内容匹配。

一旦你git add(没有-N)文件,索引中带有“intent to add”标记的stage-0 条目将成为具有真实哈希的真实blob(即文件)的真实条目指向存储库中的真实对象。也就是说,真实的条目会覆盖虚假的条目。如果您首先从工作树中删除该文件,然后在该路径上运行 git add,Git 将完全删除带有特殊标记的索引条目,就像您在其上运行 git rm --cached 时 Git 所做的一样。这与在真实(非特殊标记)文件上使用 git rm --cached 不同,在该文件中,Git 将白化条目写入索引。2


1不清楚为什么git ls-files --staged 显示这些意图添加标记的条目。相同的命令跳过白出条目。

2我们可以使用git status --short 来查看白化条目。我们只需在工作树中创建文件,或使用git rm --cached 以便在将白化条目写入索引时文件保留在工作树中。此时git ls-files --stage 显示文件,git diff 显示文件已删除,git status 显示文件已删除并且未跟踪,@ 987654366@ 为文件生成 两个 条目:

$ git rm --cached secondfile
$ git status --short
D  secondfile
?? secondfile
?? thirdfile

要拥有D 条目,索引中必须有内容;但是要拥有?? 条目,Git 必须假装索引中没有任何内容。因此这里有一个secondfile 的白化条目,在索引的一些 扫描中可见,但thirdfile 没有,就在刚才,我在索引中作为其中之一意图添加虚假条目。

【讨论】:

    猜你喜欢
    • 2013-03-17
    • 2011-02-27
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 2013-02-15
    • 1970-01-01
    相关资源
    最近更新 更多