ChatGPT解决这个技术问题 Extra ChatGPT

Git:如何从索引中删除文件而不从任何存储库中删除文件

当你使用

git rm --cached myfile

它不会从本地文件系统中删除,这是目标。但是,如果您已经对文件进行了版本控制并提交,将其推送到中央存储库,并在使用该命令之前将其拉入另一个存储库,它将从该系统中删除该文件。

有没有办法从版本控制中删除文件而不从任何文件系统中删除它?

编辑:澄清,我希望。

也许您可以扩展您的用例。索引是下一次提交的暂存区,那么如果您不想从当前分支中删除文件,为什么还要从索引中删除文件呢?
对不起。我的意思是说 myfile 由于某种原因很久以前就已经提交和分发了。现在的目标是在不从人们的系统中删除它的情况下将其从版本控制中删除。出现此问题的原因是因为我不小心对配置文件进行了版本化。配置文件是必需的,所以我不想从外部系统中删除它。
我已将问题编辑为更清楚。
git rm --cached 不会从另一个工作目录中删除文件。只有在该目录中工作的人执行拉取时,该文件才会被删除。可以使用“git checkout HEAD@{1} foo”轻松恢复该文件(如果在拉取后立即执行。)

C
Chris Johnsen

我不认为 Git 提交可以记录诸如“停止跟踪此文件,但不要删除它”之类的意图。

制定这样的意图将需要在 Git 之外的任何存储库中进行干预,这些存储库合并(或变基到)删除文件的提交。

保存副本、应用删除、恢复

可能最简单的做法是告诉您的下游用户保存文件的副本,拉取您的删除,然后恢复文件。如果他们通过 rebase 拉动并对文件进行“携带”修改,他们将发生冲突。要解决此类冲突,请使用 git rm foo.conf && git rebase --continue(如果冲突提交除了已删除文件之外还有更改)或 git rebase --skip(如果冲突提交仅更改为已删除文件)。

在提交删除文件后将文件恢复为未跟踪

如果他们已经提取了您的删除提交,他们仍然可以使用 git show 恢复文件的先前版本:

git show @{1}:foo.conf >foo.conf

或使用 git checkout(William Pursell 的评论;但请记住将其从索引中重新删除!):

git checkout @{1} -- foo.conf && git rm --cached foo.conf

如果他们在拉取您的删除后采取了其他操作(或者他们正在使用 rebase 拉入分离的 HEAD),他们可能需要 @{1} 以外的其他内容。他们可以在删除您的删除之前使用 git log -g 来查找提交。

在评论中,您提到要“取消跟踪但保留”的文件是运行软件所需的某种配置文件(直接来自存储库)。

将文件保持为“默认”并手动/自动激活它

如果继续在存储库中维护配置文件的内容并非完全不可接受,您可以将跟踪文件从(例如)foo.conf 重命名为 foo.conf.default,然后在应用重命名提交。或者,如果用户已经使用存储库的某些现有部分(例如,脚本或由存储库中的内容配置的其他程序(例如 Makefile 或类似))来启动/部署您的软件,您可以将默认机制合并到启动/部署过程:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

有了这样的默认机制,用户应该能够提取将 foo.conf 重命名为 foo.conf.default 的提交,而无需做任何额外的工作。此外,如果您将来进行其他安装/存储库,您可以避免手动复制配置文件。

改写历史无论如何都需要人工干预……

如果在存储库中维护内容是不可接受的,那么您可能希望使用 git filter-branch --index-filter … 之类的东西将其从历史记录中彻底根除。这相当于重写历史记录,这将需要对每个分支/存储库进行手动干预(请参阅 git rebase manpage 中的“从上游 Rebase 恢复”部分)。配置文件所需的特殊处理只是从重写中恢复时必须执行的另一个步骤:

保存配置文件的副本。从重写中恢复。恢复配置文件。

忽略它以防止再次发生

无论您使用哪种方法,您都可能希望将配置文件名包含在存储库的 .gitignore 文件中,这样就不会有人无意中再次 git add foo.conf(有可能,但需要 -f/--force)。如果您有多个配置文件,您可能会考虑将它们全部“移动”到一个目录中并忽略整个内容(“移动”是指更改程序期望找到其配置文件的位置,并获取用户(或启动/部署机制)将文件复制/移动到新位置;您显然不希望将文件 git mv 放入您将忽略的目录中)。


令人难以置信的彻底回应。谢谢!
下面汤姆鲍尔的回答似乎与您的第一句话相矛盾。
@MikeS: --{,no-}assume-unchanged 的效果纯粹是本地的:它的状态不直接记录在提交中。它可以帮助防止存储库提交对文件的新更改,但不会将其从版本控制中删除。如果您可以为所有相关的、相关的、非裸存储库设置它,那么它可能会对您的情况有所帮助,但它不是您可以直接推+拉/变基到其他相关的、非- 裸存储库(尤其是您无法控制的存储库,根据原始提问者对问题的澄清评论:请参阅“人民系统”/“外国系统”)。
I do not think a Git commit can record an intention like “stop tracking this file, but do not delete it”. - 现在可以使用 git rm --cached foo.conf
@NickVolynkin:问题是否已经表明这不足以满足提问者的目的:(自动)在将结果提交拉入另一个存储库时保留文件?
T
Tom Power

本周我意外提交时遇到了同样的问题,然后尝试从共享存储库中删除构建文件,并且:

http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html

对我来说效果很好,到目前为止还没有提到。

git update-index --assume-unchanged <file>

要从版本控制中删除您感兴趣的文件,然后照常使用所有其他命令。

git update-index --no-assume-unchanged <file>

如果你想把它放回去。

编辑:请参阅 Chris Johnsen 和 KPM 的评论,这仅适用于本地,如果其他用户不这样做,该文件仍处于版本控制之下。接受的答案提供了更完整/正确的方法来处理这个问题。如果使用此方法,链接中还有一些注释:

显然,有很多注意事项与此有关。如果你直接 git add 文件,它将被添加到索引中。合并带有此标志的提交将导致合并正常失败,因此您可以手动处理它。


这不是针对提到的具体问题的答案。它仅适用于您自己的本地存储库,因此每个用户都必须自己执行此操作。这是一种痛苦。
m
mkUltra

要从索引中删除文件,请使用:

git reset mylife

这不应影响您的本地副本或其他任何人的副本。


reset 仅当文件不在当前 HEAD 提交中时才从索引中删除该文件,否则它只是将索引版本恢复为当前 HEAD 版本。
也许我误解了这个问题,但它似乎与从索引中删除文件而不影响任何提交有关。
正如查尔斯所说,重置不会“删除文件”。键入 git help reset 以获取更多信息。
这回答了标题为“如何在不从任何存储库中删除文件的情况下从索引中删除文件”的问题。尽管 OP 确实在问“如何在不删除本地副本的情况下取消跟踪文件”。
@hewsonism OP 确实说过“任何文件系统”(甚至在任何编辑之前)。
B
Brandon Minnick

git rm --cached remove_file 添加文件到 gitignore git add .gitignore git commit -m "Excluding" 玩得开心 ;)


这是最简单的。
@Julien 我的想法完全正确,不知道为什么接受的答案必须是博士论文
@lasec0203 因为像这样,Git 仍然会在其他所有人拉取文件后立即删除该文件。问题是如何在不删除索引的情况下从索引中获取某些内容。似乎几乎不可能的事情。
a
awgy

执行 git rm --cached 命令后,尝试将 myfile 添加到 .gitignore 文件(如果不存在则创建一个)。这应该告诉 git 忽略 myfile

.gitignore 文件是版本化的,因此您需要提交它并将其推送到远程存储库。


T
Tom Viner

我的解决方案是提取另一个工作副本,然后执行以下操作:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

它说获取最新评论中的所有文件路径,并从 HEAD 的父级中检出它们。任务完成。


S
SherylHohman

上述解决方案适用于大多数情况。但是,如果您还需要删除该文件的所有痕迹(即密码等敏感数据),您还需要将其从整个提交历史记录中删除,因为仍然可以从那里检索该文件。

这是一个解决方案,它从您的整个提交历史记录中删除文件的所有痕迹,就好像它从未存在一样,但仍将文件保留在您的系统上。

https://help.github.com/articles/remove-sensitive-data/

如果您在本地 git 存储库中,则实际上可以跳到第 3 步,并且不需要执行空运行。就我而言,我只需要步骤 3 和 6,因为我已经创建了 .gitignore 文件,并且位于我想要处理的存储库中。

要查看您的更改,您可能需要转到存储库的 GitHub 根目录并刷新页面。然后浏览链接以找到曾经拥有该文件的旧提交,以查看它现在已被删除。对我来说,简单地刷新旧的提交页面并没有显示更改。

起初它看起来很吓人,但实际上,它很容易,而且像一个魅力! :-)