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


163

使用时

git rm --cached myfile

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

有没有一种方法可以仅从版本控制中删除文件而不从任何文件系统中删除它?

编辑:澄清,我希望。


也许您可以扩展用例。索引是下一次提交的暂存区域,所以如果不想从当前分支中删除文件,为什么还要从索引中删除文件?
CB Bailey 2010年

1
对不起。我的意思是说myfile由于某种原因已经提交并在很久以前发布了。现在的目标是从版本控制中删除它,而不从人们的系统中删除它。出现此问题的原因是因为我不小心对配置文件进行了版本控制。配置文件是必需的,因此我不想从外部系统中将其删除。
Fletcher Moore 2010年

我已对问题进行了更清晰的编辑。
Fletcher Moore 2010年

3
git rm --cached不会从其他工作目录中删除文件。仅当在该目录中工作的某人执行拉取时,该文件才会被删除。可以使用“ git checkout HEAD @ {1} foo”轻松恢复文件(如果在提取之后立即执行。)
William Pursell,2010年

Answers:


119

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

要实现这样的意图,将需要在Git之外对合并(或基于)删除该文件的提交的任何存储库进行干预。


保存副本,应用删除,还原

可能最简单的方法是告诉您的下游用户保存文件的副本,撤消删除,然后还原文件。如果它们通过重新设置拉动并且正在“修改”文件,则它们将发生冲突。要解决此类冲突,请使用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.conffoo.conf.default,然后cp foo.conf.default foo.conf在应用重命名提交后指示用户进行操作。或者,如果用户已经使用存储库的某些现有部分(例如脚本或由存储库中的内容配置的其他程序(例如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联机帮助页中的“从上游资源恢复” )。配置文件所需的特殊处理只是从重写中恢复时必须执行的另一步骤:

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

忽略它以防止再次发生

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


5
令人难以置信的彻底回应。谢谢!
Fletcher Moore 2010年

以下是汤姆·鲍尔(Tom Power)的答案,看来与您的第一句话相矛盾。
Mike S

1
@MikeS:的作用--{,no-}assume-unchanged纯粹是局部的:其状态未直接记录在提交中。它可以帮助防止存储库将新的更改提交到文件,但不会将其从版本控制中删除。如果您可以为所有相关的相关非裸存储库设置它,那么它可能会帮助您解决问题,但是您不能直接将+推拉/重新设置到其他相关的非裸存储库中(尤其是那些根据原始问询者对问题的澄清评论,您无法控制:请参阅“人民制度” /“外国制度”)。
克里斯·约翰森

1
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
尼克·沃林金

1
@NickVolynkin:问题是否已经表明这不足以达到要求者的目的:(自动)在将结果提交提交到另一个存储库中时自动保留文件?
克里斯·约翰森

86

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

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添加文件,它将被添加到索引中。合并带有此标志的提交将导致合并失败,因此您可以手动进行处理。


7
这不是所提到的特定问题的答案。它仅适用于您自己的本地存储库,因此每个用户都必须自己执行此操作。真痛苦
KPM

28

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

git reset myfile

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


1
reset仅在文件不在当前HEAD提交中时才从索引中删除文件,否则只会将索引版本还原为当前HEAD版本。
CB Bailey 2010年

1
也许我误解了这个问题,但这似乎与从索引中删除文件而不影响任何提交有关。
Armand 2010年

正如查尔斯所说,重设不会“删除文件”。输入git help reset以获取更多信息。
Simon B.

4
这回答了标题为“如何从索引中删除文件而不从任何存储库中删除文件”的问题。尽管OP确实在询问“我如何在不删除本地副本的情况下取消跟踪文件”。
hewsonism

@hewsonism OP确实说“任何文件系统”(甚至在进行任何编辑之前)。
jbobbins 2015年


15

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

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


1

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

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

这表示在最新注释中获取所有文件路径,并从HEAD的父目录中检出它们。任务完成。


0

上述解决方案在大多数情况下都可以正常工作。但是,如果您还需要删除该文件的所有痕迹(例如,敏感数据,例如密码),您也将希望从整个提交历史记录中删除它,因为仍然可以从该文件中检索该文件。

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

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

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

要查看您的更改,您可能需要转到存储库的GitHub根目录并刷新页面。然后,通过链接导航到曾经拥有该文件的旧提交,以查看该文件已被删除。对我来说,仅刷新旧的提交页面并没有显示更改。

一开始它看起来很吓人,但实际上很简单,而且就像一个魅力一样起作用!:-)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.