我不小心用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帮助rm中列出。但遗憾的是,我的文件在执行时也被删除了,即使我给了缓存选项。如何在不丢失内容的情况下清除索引?

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


当前回答

去重置

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

git reset

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


不要运行git重置——很难。

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

其他回答

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

git rm -rf --cached .

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

2019年更新

正如其他人在相关问题中指出的(参见这里,这里,这里,这里,这里,这里,这里和这里),你现在可以用git restore—staging <file>取消文件的阶段。

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

git restore --staged .

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

git restore --staged <directory-path>

笔记

git restore was introduced in July 2019 and released in version 2.23. With the --staged flag, it restores the content of the working tree from HEAD (so it does the opposite of git add and does not delete any change). This is a new command, but the behaviour of the old commands remains unchanged. So the older answers with git reset or git reset HEAD are still perfectly valid. When running git status with staged uncommitted file(s), this is now what Git suggests to use to unstage file(s) (instead of git reset HEAD <file> as it used to prior to v2.23).

git stash && git stash pop

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

如果你想让你的工作副本和索引恢复到上次提交时的状态,你可以(小心地)使用以下命令:

git reset --hard

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

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

As for how those pipes work: git ls-files -z and git diff --name-only --diff-filter=D -z both output a list of file names separated with the byte 0. (This is useful, since, unlike newlines, 0 bytes are guaranteed not to occur in filenames on Unix-like systems.) The program xargs essentially builds command lines from its standard input, by default by taking lines from standard input and adding them to the end of the command line. The -0 option says to expect standard input to by separated by 0 bytes. xargs may invoke the command several times to use up all the parameters from standard input, making sure that the command line never becomes too long.

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

hello
goodbye
hello again

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

echo whatever hello goodbye hello again

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

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

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知道的所有文件并删除本地副本”。

Then we get to git diff, which shows changes between different versions of items git knows about. Those can be changes between different trees, differences between local copies and remote copies, and so on. As used here, it shows the unstaged changes; the files you have changed but haven't committed yet. The option --name-only means you want the (full) file names only and --diff-filter=D means you're interested in deleted files only. (Hey, didn't we just delete a bunch of stuff?) This then gets piped into the xargs -0 we saw before, which invokes git rm --cached on them, meaning that they get removed from the cache, while the working tree should be left alone — except that you've just removed all files from your working tree. Now they're removed from your index as well.

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


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