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

当你使用

git rm --cached myfile 

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

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

编辑:澄清,我希望。

我不认为Git的提交可以logging像“停止跟踪这个文件,但不要删除它”的意图。

制定这样的意图将需要在合并(或重新绑定)删除文件的提交的任何存储库中的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来find提交之前,他们拉你删除。


在一个评论中,你提到你想要“解开但是保留”的文件是运行软件所需的某种configuration文件(直接存储在仓库中)。

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

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

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

有了这样的默认机制,用户应该能够提交一个提交,将foo.conf重命名为foo.conf.default而无需做任何额外的工作。 另外,如果将来还要创build其他安装/存储库,则不必手动复制configuration文件。

无论如何,重写历史需要手动干预…

如果维护存储库中的内容是不可接受的,那么您可能希望从历史中彻底根除它,例如git filter-branch --index-filter … 这相当于重写历史logging,这将需要对每个分支/存储库进行手动干预(请参阅git rebase联机帮助页中的“从上游Rebase恢复”一节)。 configuration文件所需的特殊处理只是从重写中恢复时必须执行的另一步骤:

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

忽略它以防止复发

不pipe你使用什么方法,你可能都希望在configuration文件名中包含.gitignore文件,这样任何人都不会无意中再次git add foo.conf (这是可能的,但需要-f / --force )。 如果你有多个configuration文件,你可能会考虑将它们全部“移动”到一个目录中,而忽略整个目录(“移动”是指改变程序希望findconfiguration文件的位置,启动/部署机制)复制/移动文件到他们的新位置;你显然不希望将mv文件拖入一个你将忽略的目录中)。

如果我不小心犯了这个问题,那么这个问题本来就是一样的,然后试图从一个共享库中删除一个构build文件,这个:

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

对我来说工作得很好,到目前为止还没有提到。

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

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

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

如果你想把它放回去。

编辑:请参阅克里斯·约翰森和KPM的评论,这只适用于本地和文件保持在其他用户的版本控制,如果他们也不这样做。 被接受的答案提供了更完整/正确的方法来处理这个问题。 如果使用这种方法,还有一些链接的注释:

显然有很多的警告发挥这一点。 如果你直接添加文件,它会被添加到索引。 合并提交与此标志将导致合并失败优雅,所以你可以手动处理它。

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

 git reset myfile 

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

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

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

  1. git rm --cached remove_file
  2. 添加文件到gitignore
  3. git add .gitignore
  4. git commit -m "Excluding"
  5. 玩的开心 ;)

我的解决scheme是拉对方的工作副本,然后做:

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

其中说在最新的评论中得到所有的文件path,并从HEAD的父亲检查出来。 任务完成。

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

这是一个从整个提交历史logging中删除文件的所有痕迹的解决scheme,就好像它从来没有存在过,但是保留在你的系统上的文件。

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

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

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

起初看起来很吓人,但是真的很容易,像魅力一样工作! 🙂