从Git历史记录中移除文件而不删除该文件

3
我使用了GitHub提供的清除提交历史中文件的说明,但是它将该文件从我的系统中删除了。这让我感到惊讶,因为git rm --cached命令本身应该不会影响文件本身。但是在该页面上的实际示例中也可以看到这种行为:在大型git filter-branch ...命令之前和之后尝试运行ls

我正在使用Git 2.6.1。

如何从提交历史记录中删除一个文件,而不会删除文件本身?显然,我可以制作一个备份(在我的情况下我已经这样做了),但这只是一个解决方法,而不是解决方案。


1
制作备份是解决方案。 - Schwern
Git主要是一个Unix程序。在Unix中,你不会将每个可行的情况都集成到可执行文件中。相反,你会编写(希望是)小型的独立程序来协同完成你的目标。 - Petr Skocik
2个回答

4
当使用git-filter-branch后,它会检出新的分支头。这将使您的工作目录处于干净状态。您想要从历史记录中删除的文件已被删除。提前备份是解决方案。
如果您忘记备份,仍然可以找回它!Git需要很长时间才能丢弃东西,您的原始提交仍然存在。在git-filter-branch之后,将有一个名为original/refs/heads/master(如果您过滤了master)的分支,其中包含原始提交。您可以从那里恢复文件。
通常,您可以使用git reflog恢复过滤和变基。它是每次HEAD更改(即您checkout或rebase或merge或filter等)的日志。例如,在执行Github过滤器示例后,git reflog如下...
abaabaf (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: filter-branch: rewrite
8ef0c30 (refs/original/refs/remotes/origin/master, refs/original/refs/heads/master) HEAD@{1}: clone:

我可以使用8ef0c30HEAD@{1}(即HEAD的上一个位置)或original/refs/remotes/origin/masteroriginal/refs/heads/master来回到过滤器运行之前的状态。

感谢您提供详细答案。该点需要在我在问题中提供的指南中进行澄清。 - shadowtalker

4

首先:

(必须要说的是)

当使用git filter-branch时,您正在按照自己的(可能有缺陷的)规范以一种自动化的方式进行历史重写。因此,在执行此操作之前,无论如何都应该备份您的repo,或者在一个新的单独克隆的repo上执行操作。

为什么文件也从您的工作副本中消失了

git filter-branch将指定命令应用于每个适用的提交。但是,它不会检出这些提交到您的工作副本中来执行该操作。相反,它默认将它们检出到.git-rewrite/中,或者您使用-d选项指定的目录中。(请参阅git filter-branch文档,选项-d <directory>。)

在重写适用的提交之后,Git检出生成的新分支。由于这是从具有该文件的分支(该分支的预重写版本)切换到没有该文件的分支(该分支的后重写版本),因此该文件也从您的工作副本中删除。

如何保留该文件

好吧,备份一下。

(请注意,如果您正在重写所有分支和所有标签,就像在https://help.github.com/articles/remove-sensitive-data/的示例中所做的那样,标记或分支将不是一个足够的备份。)

如果您没有这样做,如何检索该文件

请参见Schwern的答案


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接