如何在不删除内容的情况下取消暂存大量文件
Posted
技术标签:
【中文标题】如何在不删除内容的情况下取消暂存大量文件【英文标题】:How to unstage large number of files without deleting the content 【发布时间】:2011-10-29 12:55:26 【问题描述】:我不小心添加了很多使用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
中列出。但遗憾的是,即使我提供了缓存选项,我的文件也在执行时被删除。如何清除索引而不丢失内容?
如果有人能解释这种管道操作的工作方式,那也会很有帮助。
【问题讨论】:
rm -f
不是 git 命令,也没有 --cached
选项。在您执行 git rm
之前,您的本地文件已被删除,所以我认为您不能合理地责怪 git rm
。
@sarat,请考虑将正确答案更改为 Ian Maddox 高度支持的答案,因为 git reset --hard
不是正确答案并且实际上会删除内容。这会让用户感到困惑——就像我一样。
@sarat 正如 Marco 所说,继续。此页面获得大量流量。
@MarcoPashkov & Ross 谢谢大家。完成。
【参考方案1】:
git reset
如果您只想撤消过分热心的“git add”运行:
git reset
您的更改将取消暂存,您可以随意重新添加。
不要运行git reset --hard
。
它不仅会取消暂存您添加的文件,还会恢复您在工作目录中所做的任何更改。如果您在工作目录中创建了任何新文件,它不会删除它们。
【讨论】:
我欠你一品脱伊恩 我经常发现我也必须执行git checkout -- *
【参考方案2】:
如果您有原始存储库(或 HEAD 未设置)[1] 您可以简单地
rm .git/index
当然,这需要您重新添加确实想要添加的文件。
[1] 注意(如 cmets 中所述)这通常只会在 repo 是全新的(“原始") 或者如果没有提交。从技术上讲,只要没有结帐或工作树。
只是让它更清楚:)
【讨论】:
是的,它更像是删除创建的索引本身。好消息是,我不需要重新初始化 git。谢谢! 确定操作安全吗?我只是这样做(实际上将索引移到一边)并准备删除所有其他文件。 @inger “如果你有一个原始的仓库”。你显然没有那个。 实际上,我想知道您所说的“原始存储库”是什么意思(我对 google 也不感到幸运).. 所以您的意思实际上是一个空的存储库? @inger 同意。我不得不假设 OP 碰巧遇到了这种确切的情况——他没有具体说明,但他的描述留下了这种可能性。无论如何,我只是分享信息,不能影响投票:(。在答案文本中添加了一个警告词,以防将来对其他人有所帮助。【参考方案3】:使用git reset HEAD
重置索引而不删除文件。 (如果您只想重置索引中的特定文件,可以使用git reset HEAD -- /path/to/file
来执行此操作。)
在 shell 中,管道运算符获取左侧进程的stdout
,并将其作为stdin
传递给右侧的进程。 基本上相当于:
$ proc1 > proc1.out
$ proc2 < proc1.out
$ rm proc1.out
但它是$ proc1 | proc2
,第二个进程可以在第一个完成输出之前开始获取数据,并且不涉及实际文件。
【讨论】:
但是如何将它与多个文件一起使用。我以前从未提交过这些文件。 只需键入git reset HEAD
而不指定其他任何内容,它将重置整个索引。然后你可以只重新添加你想要的文件。
我收到以下错误。我以前从未提交过这些项目。 $ git reset HEAD fatal: ambiguous argument 'HEAD': unknown revision or path not in the working tree. Use '--' to separate paths from revisions
然后试试git reset
,不要HEAD
。
我已经尝试过,我最终遇到了以下错误。 $ git reset fatal: Failed to resolve 'HEAD' as a valid ref.
【参考方案4】:
git stash && git stash pop
【讨论】:
我会执行 'git stash && git stash pop' 这样存储也会被删除。 'apply' 会将存储留在存储列表中。【参考方案5】:如果 HEAD 未设置(即,您还没有提交,但您不想只是吹走.git
,因为您已经设置了要保留的其他 repo 配置),您也可以做
git rm -rf --cached .
取消所有内容。这实际上与 sehe 的解决方案相同,但避免了与 Git 内部的混淆。
【讨论】:
这实际上是告诉 Git 删除缓存区域中的所有内容。 缓存也被称为暂存区,所以我不确定你在说什么。 来自 sehe,rm .git/index 非常危险 - 请务必阅读他关于全新 repo 的注释!这在其他 99.999% 的时间里更安全。我没有仔细阅读,在我的工作副本上执行 rm .git/index 后不得不吹掉我的工作副本并重新克隆。 不要使用这个命令!它将所有项目更改为未跟踪状态(包括未暂存的项目)。这不是原始问题的解决方案。使用 'git rm' 命令的正确解决方案是仅指定要取消暂存的文件: git rm -rf --cached.git
,因为您已经设置了要保留的其他回购配置。我已经编辑以澄清这一点。【参考方案6】:
警告:除非您想丢失未提交的工作,否则请勿使用以下命令!
已经解释了使用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
表示您只对已删除的文件感兴趣。 (嘿,我们不是刚删了一堆东西吗?)
然后将其通过管道传输到我们之前看到的xargs -0
,它在它们上调用git rm --cached
,这意味着它们会从缓存中删除,而工作树应该不理会-除非您刚刚从您的文件中删除了所有文件工作树。现在它们也已从您的索引中删除。
换句话说,所有更改,分阶段或非分阶段都消失了,您的工作树是空的。大叫一声,从源头或远程检查您的文件,然后重做您的工作。诅咒写下这些地狱诗句的虐待狂;我不知道为什么有人要这样做。
TL;DR:你只是冲洗了所有东西;从现在开始重新开始使用git reset
。
【讨论】:
【参考方案7】:2019 年更新
正如其他人在相关问题中指出的那样(请参阅 here、here、here、here、here、here 和 here),您现在可以使用以下命令取消暂存文件git restore --staged <file>
.
要取消暂存项目中的所有文件,请从存储库的根目录运行以下命令(该命令是递归的):
git restore --staged .
如果您只想取消暂存目录中的文件,请在运行上述命令之前导航到该目录或运行:
git restore --staged <directory-path>
注意事项
git restore
在July 2019 中引入,并在 2.23 版本中发布。
使用--staged
标志,它从 HEAD 恢复工作树的内容(因此它与git add
相反,并且不会删除任何更改)。
这是一个新命令,但旧命令的行为保持不变。因此,git reset
或 git reset HEAD
的旧答案仍然完全有效。
当使用暂存的未提交文件运行 git status
时,现在是 Git 建议用于取消暂存文件的方法(而不是以前 v2.23 之前的 git reset HEAD <file>
)。
【讨论】:
【参考方案8】:恐怕这些命令行中的第一个无条件地从工作副本中删除了 git 暂存区域中的所有文件。第二个取消暂存所有已跟踪但现已删除的文件。不幸的是,这意味着您将丢失对这些文件的任何未提交的修改。
如果您想将工作副本和索引恢复到上次提交时的状态,您可以(小心)使用以下命令:
git reset --hard
我说“小心”,因为git reset --hard
会清除工作副本中未提交的更改和索引。但是,在这种情况下,您似乎只想回到上次提交时的状态,而未提交的更改无论如何都已丢失。
更新:从您的 cmets 看来,Amber 的回答表明您尚未创建任何提交(因为 HEAD 无法解决),所以恐怕这无济于事。
至于这些管道是如何工作的:git ls-files -z
和git 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
【讨论】:
我从未进行过任何提交,所以它会说无法解析 HEAD。我们在这种情况下做什么。非常感谢您详细解释管道。 如果您刚刚更改了 git ignore 并使用 git add --all 来包含大量文件,请不要运行 git reset --hard 来取消暂存它们。他们将被删除!! 呜哇哇!!也许您需要突出显示“小心”这个词。我刚刚看到这三个词“git reset --hard”,而我所有未暂存的文件都是...... fufff!走了!!!!!!【参考方案9】:如果您想取消暂存所有更改,请使用以下命令,
git reset --soft HEAD
如果您想取消暂存更改并从工作目录中恢复它们,
git reset --hard HEAD
【讨论】:
以上是关于如何在不删除内容的情况下取消暂存大量文件的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用临时文件的情况下在 python 的 tarfile 中写入大量数据
如何在不下载文件的情况下搜索amazon S3存储桶中的文件内容