如何从Git历史记录中删除文件?

495

不久前,我添加了必须保密的信息(文件)。从项目中删除它不是问题,但我还需要从 git 历史中删除它。

我使用 Git 和 Github(私有账户)。

注意:在这个讨论串中展示了类似的内容,但那里是一个旧文件被添加到一个特性分支,该分支合并到开发分支,最后合并到主分支,因此进行了很多更改。所以这不是同一种情况,需要做的是改变历史记录,并且为了保护隐私而隐藏那些文件。


3
你需要改写历史记录,例如使用git rebase命令,然后用git push -f命令推送代码。 - Cory Kramer
建议的重复内容中描述的 filter-branch 方法可以实现您想要的功能。 - 1615903
1
还有一个指向BFG的链接,可能比使用git filter-branch更快。该链接在https://dev59.com/fXI95IYBdhLWcg3w5iU4#17890278/上。 - Hasturkun
但是要更快并且完成相同的任务,需要使用Java,我看过@Hasturkun的内容。 - Marcos R. Guevara
3
这些解决方案都没有起作用...GIT应该有一个相应的命令...它非常有用... - marcolopes
显示剩余2条评论
9个回答

494

58
警告:这会产生大量的提交并导致分歧。完成后可能需要强制推送,但我太害怕了。 - sudo
5
赞同 @sudo 的说法,但这对我不小心提交了 .env 的新分支确实有效。解决方法简单明了。 - Joe Scotto
13
你也可以将一段提交范围指定为最后一个参数。如果所需要的提交是最近的,使用 <previous_hash>..HEAD 可以节省一些时间。 - Victor Sergienko
7
之后只有我能使用git push --force命令。 - Sebastian
27
Git的当前版本对于filter-branch命令有如下警告:“警告:git-filter-branch存在许多问题,可能会导致历史记录重写,建议在执行之前按Ctrl-C中止操作,然后使用其他过滤工具,例如'git filter-repo' (https://github.com/newren/git-filter-repo/)。有关详细信息,请参阅filter-branch手册页。要消除此警告,请设置FILTER_BRANCH_SQUELCH_WARNING=1。” - Ryan Lundy
显示剩余16条评论

216

git-filter-repo

git建议在执行git filter-branch命令时使用第三方附加组件git-filter-repo。有一个很长的理由清单,说明为什么git-filter-repo比其他任何替代品更好,我的经验是它非常简单和非常快速。

此命令会从所有分支的所有提交中删除文件。

git filter-repo --invert-paths --path <path to the file or directory>

可以通过使用多个--path参数来指定多个路径。您可以在此处找到详细的文档: https://www.mankier.com/1/git-filter-repo

7
我收到了一个错误信息:“git: 'filter-repo'不是 git 命令。请参见 'git --help'。” - cikatomo
20
这是一个第三方工具,你需要安装它。https://github.com/newren/git-filter-repo/blob/main/INSTALL.md - Vladimir Jovanović
4
这个方法可行,但它会移除.git,所以我想为什么不手动删除.git并重新初始化呢? - chovy
4
这应该被设置为新的最佳答案,因为它更加更新。 - GuyStalks
7
@cikatomo 另一种安装方法是 pip install git-filter-repo - Kaushal Modi
显示剩余14条评论

167
如果您最近提交了该文件,或者该文件在一到两个提交中发生了更改,那么我建议您使用rebasecherrypick来删除该特定的提交。
否则,您将不得不重新编写整个历史记录。
git filter-branch --tree-filter 'rm -f <path_to_file>' HEAD

当您对更改感到满意并已经确保一切看起来都很好时,您需要更新所有远程分支 -

git push origin --force --all

注意:这是一个复杂的操作,你必须知道自己在做什么。首先,尝试在演示存储库上执行此操作,以了解其工作原理。同时,您还需要让其他开发人员知道此操作,以便他们在此期间不会做出任何更改。


1
重写整个历史记录后,为了将更改保存到存储库(GitHub),必须做什么? - Marcos R. Guevara
3
为什么你的建议使用 --tree-filter 而不是像 @PetroFranko 的回答中那样使用 --index-filter - einpoklum
3
天啊,它成功了!我的意思是,这真的非常非常简单。我以前曾用困难的方法做过,但这次更容易。提示:路径必须是相对路径。 - Antebios
没起作用:\ 文件仍在本地存储库中,在“git push”之后仍然在git远程存储库中,而且所有修订版本都在那里!:\ - marcolopes
WARNING: git-filter-branch has a glut of gotchas generating mangled history rewrites. Hit Ctrl-C before proceeding to abort, then use an alternative filtering tool such as 'git filter-repo' (https://github.com/newren/git-filter-repo/) instead. See the filter-branch manual page for more details; to squelch this warning, set FILTER_BRANCH_SQUELCH_WARNING=1. - Jake
显示剩余7条评论

65

从你提交的文件中删除文件并重写历史记录(这将从你提交的文件创建新的提交哈希):

有两种方法:

  1. 使用git-filter-branch
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <path to the file or directory>' --prune-empty --tag-name-filter cat -- --all

使用git-filter-repo
pip3 install git-filter-repo
git filter-repo --path <path to the file or directory> --invert-paths

现在强制推送仓库:git push origin --force --all,并告诉你的合作者进行rebase操作。

1
@alper,您需要将“PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA”替换为要删除的文件,例如:“README.md”如果您想要删除它。 - suhailvs
10
针对 git filter-repo:我收到了以下信息:中止: 拒绝破坏性地覆盖版本库历史记录,因为这看起来不像是一个新克隆。 (预期是新打包的版本库) 请改用新克隆。如果您想继续,请使用—force。 如果我强制执行,我会得到以下信息:致命: 'origin' 不似乎是 git 版本库, 无法从远程存储库读取 - alper
git filter-branch 对我很有用! - Federico Peralta
3
еңЁMacдёҠпјҢжҲ‘дҪҝз”ЁдәҶgit filter-branchж–№жі•пјҢиҖҢfilter-repoж–№жі•еҲҷеҲ йҷӨдәҶиҝңзЁӢжәҗгҖӮ - Ilya Sheershoff
2
这个可行,但我忘记先备份文件了,现在它不见了。 :-( - kr37
显示剩余3条评论

47

我阅读了这篇GitHub文章,它引导我使用以下命令(类似于被接受的答案,但更加强大):

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

6
它比被接受的答案更有效,但它也会删除本地文件。如果您不想浪费重写时间,请在此之前将其复制。 - Kaepxer
1
这对我在 Mac 上很有帮助,当 filter-repo 正在删除远程 origin 时。 - Ilya Sheershoff
我的本地文件没有被删除,可能是因为它被输入到了.gitignore文件中。 - S.aad
1
在完成所有清除操作后,不要忘记执行“git push --force”。 - Jim Wilcox
1
非常好用,谢谢。如果要删除一个目录,我还添加了-r选项。 - Meir Gabay

16
  • 首先,将其添加到您的.gitignore文件中,并不要忘记提交该文件 :-)

  • 您可以使用此网站:http://gitignore.io 为您生成.gitignore并将所需路径添加到您的二进制文件/文件夹中

  • 一旦将文件添加到.gitignore中,您可以使用BFG删除“旧”的二进制文件。


如何从代码库中删除大文件

您可以使用 git filter-branch 或 BFG。 https://rtyley.github.io/bfg-repo-cleaner/

BFG Repo-Cleaner

是 git-filter-branch 的替代品。

BFG 是一个更简单、更快速的替代方案,用于从 Git 仓库历史记录中清理坏数据

*** 删除超大文件 ***

  • 删除密码、凭据和其他私人数据

示例(来自官方网站)

在所有这些示例中,bfg 是 java -jar bfg.jar 的别名。

# Delete all files named 'id_rsa' or 'id_dsa' :
bfg --delete-files id_{dsa,rsa}  my-repo.git

enter image description here


它是第三方清理工具吗? - alper
使用它安全吗? - alper
确实,这是一个被社区使用了几年的非常“老”的工具。源代码在GitHub上,因此您和社区都可以浏览它。 - CodeWizard
我刚发现GitHub不会在用户请求运行垃圾收集器时删除已删除的提交(https://dev59.com/lpLea4cB1Zd3GeqP46Nj#34594815)。当我们使用像GitHub这样的第三方工具时,无论提交什么,我们都需要向他们请求删除,这真的很不好。 - alper

11

使用bfg repo-cleaner软件包是另一种可行的替代git-filter-branch的方法。显然,它也更快...


2
以下命令应依次在每个项目中应用,以删除特定文件的历史记录,但你必须在开始时备份项目,因为该文件将被删除:
  • git filter-branch --index-filter "git rm --cached --ignore-unmatch ProjectFolderName/src/main/resources/application-prod.properties" HEAD

  • git push origin --force --all

  • git update-ref -d refs/original/refs/heads/master

.........................................................
  • git filter-branch --index-filter "git rm --cached --ignore-unmatch ProjectFolderName/src/main/resources/application.properties" HEAD

  • git push origin --force --all

  • git update-ref -d refs/original/refs/heads/master


2
删除文件(们)
bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

在您的存储库历史记录中,无论在哪里找到,请替换密码.txt中列出的所有文本,并运行:

bfg --replace-text passwords.txt

之后,你需要将你的更改推送到GitHub/GitLab/BitBucket。
git push --force

关于BFG工具的更多信息请点击这里

此外,由于该技术会重写您的存储库历史记录,改变现有提交的SHAs,因此您应该修改任何依赖的提交。所以,请合并并关闭所有未完成的PR!


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