如何撤消git rm --cached <文件名>?

时间:2019-10-24 11:01:17

标签: git

在暂存文件(跟踪文件)后,我意识到它需要进行一些更改,因此为了取消暂存,我使用了 git rm --cached <filename>。因此,我丢失了所有更改。有办法撤消吗?

3 个答案:

答案 0 :(得分:2)

git rm --cached仅从索引中删除新文件,而不从工作树中删除。这样做要小心。如果这是现有文件,则只需暂存该文件。

您可以使用git add <filename>重新添加。

更常见的取消变更的方法是使用git reset HEAD <filename>

但是...不必取消暂存文件即可添加更多更改。您可以进行进一步的更改,然后使用git add <filename>重新进行更改。

答案 1 :(得分:1)

您需要再次添加。这是命令示例集。

echo testmodify>> FOO //Appends "testmodify" to FOO
git add FOO // Stage FOO to commit
git rm --cached FOO // Unstage FOO
git add FOO // Stage FOO

FOO仍包含“ testmodify”

答案 2 :(得分:0)

Git使用短语阶段性更改阶段性更改可能会引起很大的困惑。

为避免混淆,这是您需要了解的内容:

  • Git有一个被Git调用的东西,称为 index 临时区域,有时甚至是现在很少使用的 cache 。这三个名称都只涉及一件事情。在这里,我将其称为索引。

  • 索引最初包含每个文件的副本 1 ,位于您检出的提交中。 (此当前提交也称为HEAD。)这些文件为仅Git格式。 您看不到这些文件。(这是一个夸大的说法-有一些特殊的Git技巧可以查看它们,但通常它们是不可见的。)您可以的文件见在您的工作树中,该树包含普通的日常文件。

  • 当您提交 next 提交时,Git将使用当时索引中的文件。也就是说,当您运行git commit -m "some message"(或在git commit且没有-m收集到您的消息之后)时,Git将在那时打包索引中的所有文件。当时的 ,并使用它们进行新的提交。

  • 因此,如果您已经更改或替换了工作树中的文件,则必须首先将其复制回索引。否则,Git只会重新使用原始文件。

运行git add file时,Git会获取工作树副本,将其压缩为仅Git的特殊格式,然后将压缩后的副本填充到索引中。现在,索引副本不再与HEAD副本匹配,但与工作树副本匹配。

如果再次更改工作树副本 ,那么现在这三个副本都是不同的!此时,git status会告诉您,您已经“已将变更暂存为提交”,并且也已“已将变更 not 已暂存为提交”。

您可以随时将工作树副本更改为任何内容。这对索引副本没有影响。

使用计算机上任何可删除文件的工具,您可以删除工作树副本而无需删除索引副本。您也可以使用git rm --cached删除 index 副本,而无需删除工作树副本。而且,您可以使用git rm删除两个副本。这些都不会影响任何现有的提交-无法更改永远的任何现有提交!但是删除索引副本确实会影响 next 提交,因为运行git commit时,Git会打包当时索引中的所有文件,因此如果文件是< 从索引中消失了,它将不在 next 提交中。

由于索引中的内容是下一次提交中的内容,因此可以很好地描述索引:无论如何,索引还是下一次提交中的内容。确实还有一些其他的角色,尤其是在合并过程中,但是我们将不在这里讨论。


1 从技术上讲,索引实际上包含对副本的引用。但是效果至少与索引拥有实际副本一样,至少直到您开始研究如何直接使用git update-index来操纵索引为止。


如何“取消变更”

要将当前(HEAD)提交中的文件以当前提交中的格式返回索引 ,可以使用git reset -- file。仅当文件名类似于--选项或分支名称时,才需要使用git reset。例如,如果您有一个名为master 的文件和一个分支名称为master,则git reset master似乎要使用分支名称,因此您必须写git reset -- master来告诉git您的意思是文件 master

因此: git reset -- file将文件从HEAD提交复制到索引。即使您删除了索引副本,这也是正确的:reset只会将其放回原处。如果HEAD提交中的文件不是,也是如此。如果您已将文件F添加到索引中,然后决定它根本不应该包含在索引中,则可以git reset -- F并将其从索引中删除

(如果愿意,您也可以git rm --cached F:在这一点上具有相同的效果。但是,如果您只想使索引副本与HEAD副本匹配,请使用git reset因为这对两种情况都有效:存在 HEAD副本,或者没有。)

你怎么知道要上演什么?

同样,您实际上不能看到索引中文件的副本。那么您如何知道它是否与其他副本匹配?答案是:git status以简短有用的方式告诉您。

假设您的工作树中有三个文件,分别为README.mdmain.pyutil.py。这些文件中的前两个来自HEAD提交,您现在已经自己创建了util.py,因此HEAD提交中的 not 索引中的不是

git status命令运行两个比较:

  • 首先,它将HEAD中的每个文件与索引中的每个文件进行比较。因此,这将HEAD:README.md(HEAD副本)与:README.md(索引副本)进行比较。 2 然后将HEAD:main.py:main.py比较。

    对于每个相同的文件,git status表示没有

    对于每个不同的文件,git status表示存在为提交而进行的更改。如果文件已完全从索引中删除,则您已进行了删除。如果索引中的文件是全新文件,则说明您已暂存了一个新添加的文件。

    因此,如果您知道HEAD提交中的内容,则现在知道索引中的哪些文件相同:任何git status都没有提及的

  • 接下来,HEAD告诉了您git status与索引之间的区别之后,继续将索引中的每个文件与工作树中的每个文件进行比较。因此,在这里,它将:README.mdREADME.md进行比较,将:main.pymain.py进行比较,并发现索引中没有util.py

    对于每个相同的文件,git status表示没有

    对于每个不同的文件,git status报告不是准备提交的更改。没错,因为git commit不会使用工作树,而只会使用索引。

    对于类似util.py的文件,该文件位于工作树中,但不包含在索引中的 中,git status将其报告为未跟踪的文件 。这就是未跟踪的文件:在工作树中但不在索引中的文件。

请注意,如果您从索引中删除文件,该文件将立即被取消跟踪!如果您git add将文件放在索引中,那么现在就可以对其进行跟踪了。


2 这种有趣的HEAD:file:file语法特定于Git本身,并且仅适用于 some Git命令。其中之一是git show:例如,实际上您可以使用README.md来查看git show :README.md的索引副本。由于git show是面向用户的命令,因此可以非常安全地执行此操作:git show HEAD:filegit show :filegit show <commit:>file都是查看特定副本的非常好的方法已转换为内部Git形式的特定文件,可以保存在提交中,也可以准备提交。

您还可以使用git ls-files查看文件的所有索引副本的名称。在一个大的存储库中,这会打印出 lot 个名称!但是,它并不适合日常使用,也不是非常用户友好的命令。


提交 read 索引; git checkout 向其写入

要进行新的提交,只需将正确的文件复制到索引中并运行git commit。索引已经具有 current 提交中的所有文件,因此,您只需要更新要更改的任何文件,或添加所需的任何新文件,或者删除所有要删除的文件。然后您git commit进行一次 new 提交。现在,此新提交是HEAD提交,现在是HEAD提交和索引匹配。

如果HEAD提交和索引匹配,而这两个匹配工作树,则一切都是“干净的”,您可以使用以下命令轻松切换到另一个提交:

git checkout otherbranch

(或新的Git 2.23 git switch命令,它像git checkout branch的友好变体,没有将所有其他Git工具推入一个命令中,git checkout可以(取决于您的计算方式)在三到七个不同的工作之间。

假设此检查成功, 3 必须:

  1. otherbranch开头的所有文件填充索引(并删除所有不相关的文件);
  2. 使用otherbranch开头的所有文件填充您的工作树(并删除所有不相关的文件);和
  3. 使名称HEAD指的是otherbranch的尖端提交。

完成所有操作后,您的HEAD提交,索引和工作树将再次匹配。


3 即使索引和工作树不是“干净的”,git checkout命令有时也会成功 *。 “干净”在这里定义不明确,但是要详细了解git checkout何时允许您在进行修改时切换分支,请参见Checkout another branch when there are uncommitted changes on the current branch


结论

您不能看到文件的索引副本!您可以并且应该做的是使用git status,该文件将HEAD文件比较到索引副本。在一个拥有成百上千个甚至数百万个文件的大型项目中,Git几乎对所有文件都什么都不说。它只会提及不同的那些。那更有用。

只要您的HEAD,索引和工作树都匹配,git status就说没什么。当git status看到某些不匹配的内容时,它会根据是否在为提交而进行的更改和/或在没有为提交而进行的更改下打印文件名,具体取决于是否是HEAD和索引副本不同意,或者是索引和工作树副本不同意,或者两者都有。

git add将文件复制到索引中。如果他们以前已经在那儿了,那么现在它们被工作树中的副本所覆盖。如果他们以前不在那里,那么现在就可以了。

git rm从索引中删除文件。如果没有--cached,它会从工作树中删除相同的文件。使用--cached,它可以单独保留工作树副本,这对 now 来说很好,但是以后的git checkout可能需要删除工作树副本!

通常,Git将尽力不破坏具有宝贵数据的任何工作树文件。 What's "precious", though?好吧,如果已经添加并提交了工作树文件util.py并与HEAD:util.py:util.py匹配,那么此时util.py不是 不再珍贵,因为如果您愿意,它就在提交中。因此,您可以git checkout进行 没有util.py的旧提交,而Git从您的工作树中删除util.py将会非常安全。只需git checkout它返回的最新命令即可。

一些Git命令,包括git reset --hard销毁工作树文件。 git reset --hard背后的理论是您想要重置索引您的工作树。默认模式为git reset --mixed,仅重置索引副本。 4 这就是git reset -- file“取消登台”文件的原因-将HEAD:file复制到{{ 1}} –但不会碰到:file的工作树副本。


4 特别是filegit reset --softgit reset --mixed仅允许您执行每个文件。当您只想使用git reset --hard来制作一个文件时,它总是使用git reset -- file。对于其他情况,您必须使用--mixed的许多备用模式之一。 Git 2.23引入了一个新命令git checkout,目的是减少混乱。时间会证明它是否这样做:git restore在技术上仍处于试验阶段。