如何在不删除内容的情况下取消大量文件

我不小心用git add -A添加了很多临时文件

我设法使用以下命令取消文件,并设法删除脏索引。

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

上面的命令列在git help rm. xml文件中。但遗憾的是,我的文件在执行时也被删除了,即使我给了缓存选项。如何在不丢失内容的情况下清除索引?

此外,如果有人能解释这个管道操作的工作方式,这将是有帮助的。

267145 次浏览

使用git reset HEAD重置索引而不删除文件。(如果你只想重置索引中的一个特定文件,你可以使用git reset HEAD -- /path/to/file来这样做。)

在shell中,管道操作符获取左边进程的stdout,并将其作为stdin传递给右边进程。本质上相当于:

$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out

但是它是$ proc1 | proc2,第二个进程可以在第一个进程输出数据之前开始获取数据,并且不涉及实际的文件。

恐怕第一个命令行会无条件地从工作副本中删除git暂存区的所有文件。第二种方法取消了所有被跟踪的文件,但现在已经删除了。不幸的是,这意味着您将丢失对这些文件的所有未提交的修改。

如果你想让你的工作副本和索引恢复到在最后一次提交时,你可以使用下面的命令(小心翼翼地):

git reset --hard

我说“小心”,因为git reset --hard 是否会删除工作副本中未提交的更改和索引。然而,在这种情况下,听起来好像您只是想回到上次提交时的状态,而未提交的更改无论如何都会丢失。

更新:从你对Amber的回答的评论中,听起来你还没有创建任何提交(因为HEAD无法解析),所以这恐怕不会有帮助。

至于这些管道是如何工作的:git ls-files -zgit diff --name-only --diff-filter=D -z都输出一个由字节0分隔的文件名列表。(这很有用,因为与换行符不同,0字节保证不会出现在类unix系统的文件名中。)程序xargs本质上是从标准输入构建命令行,默认情况下是从标准输入获取行并将它们添加到命令行的末尾。-0选项表示标准输入由0字节分隔。xargs可能会多次调用该命令,用完标准输入中的所有参数,确保命令行不会太长。

举个简单的例子,如果你有一个名为test.txt的文件,包含以下内容:

hello
goodbye
hello again

... 然后命令xargs echo whatever < test.txt将调用命令:

echo whatever hello goodbye hello again

如果你有一个原始的repo(或HEAD未设置)<一口> < em > [1] < / em > < /一口>,你可以简单地

rm .git/index

当然,这将要求您重新添加您做了想要添加的文件。


注意(正如评论中解释的那样)这通常只会发生在回购是全新的(“原始”)或没有提交的情况下。更严格地说,当没有签出或工作树时。

只是想说得更清楚一点:)

git stash && git stash pop

如果HEAD没有设置(也就是说,您还没有提交,但您不想因为已经设置了想要保留的其他回购配置而放弃.git),您也可以这样做

git rm -rf --cached .

把一切都取消。这实际上与sehe的解决方案相同,但避免了Git内部的混乱。

# EYZ0

如果你只想撤销一个过度热心的“git add”运行:

git reset

您的更改将被取消,并准备好供您重新添加。


# EYZ1

它不仅会取消您添加的文件,还会恢复您在工作目录中所做的任何更改。如果你在工作目录中创建了任何新文件,它不会删除它们。

如果你想取消所有的更改使用下面的命令,

git reset --soft HEAD

如果您想取消阶段更改并从工作目录恢复它们,

git reset --hard HEAD

警告:不要使用以下命令,除非您想丢失未提交的工作!

使用git reset已经解释过了,但是你要求对管道命令进行解释,所以这里是:

git ls-files -z | xargs -0 rm -f
git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached

命令git ls-files列出git知道的所有文件。选项-z对它们施加了特定的格式,即xargs -0所期望的格式,然后在它们上调用rm -f,这意味着在不检查您的批准的情况下删除它们。

换句话说,“列出git知道的所有文件并删除本地副本”。

然后我们到达git diff,它显示了git所知道的项目的不同版本之间的变化。这些可以是不同树之间的变化,本地副本和远程副本之间的差异,等等 在这里,它显示了未分阶段的变化;您已更改但尚未提交的文件。选项--name-only表示只需要(完整的)文件名,而--diff-filter=D表示只对已删除的文件感兴趣。# EYZ2 然后,这将被传输到我们之前看到的xargs -0中,它对它们调用git rm --cached,这意味着它们将从缓存中删除,而工作树应该保持独立——除了您刚刚从工作树中删除了所有文件之外。现在它们也从你的索引中删除了

换句话说,所有的更改(阶段性的或非阶段性的)都消失了,您的工作树是空的。哭一场,从原始文件或远程文件签出你的文件,然后重做你的工作。诅咒写下这些地狱般的诗句的施虐狂;我完全不知道为什么会有人想这么做。


TL, DR:你刚刚冲洗了所有东西;从现在开始使用git reset

2019年更新

正如其他人在相关问题中指出的那样(见在这里在这里在这里在这里在这里在这里在这里),你现在可以用git restore --staged <file>取消文件。

要取消项目中的所有文件,从存储库的根目录运行以下命令(该命令是递归的):

git restore --staged .

如果你只想取消一个目录中的文件,在运行上述操作之前导航到它或运行:

git restore --staged <directory-path>

笔记

  • git restore2019年7月中引入,并在2.23版本中发布。
    使用--staged标志,它从HEAD恢复工作树的内容(因此它与git add相反,不删除任何更改)

  • 这是一个新命令,但是旧命令的行为保持不变。因此,使用git resetgit reset HEAD的旧答案仍然完全有效。

  • 当对阶段性未提交的文件运行git status时,这是Git现在建议用于取消阶段性文件的方法(而不是v2.23之前使用的git reset HEAD <file>)。