从Git历史记录中永久删除文件

10

假设我在我的git项目中完成了5次提交。

在第4次提交时,我不小心添加了我的credentials.json文件并将其推送到仓库中。
在第5次提交时,我删除了该文件,并进行了一次提交,将此更改推送到仓库中。

目前最新的提交中没有显示该文件。 但是如果用户查看提交历史记录,他可以进入第4次提交并检查我的文件内容。

如何永久删除提交历史记录中的文件,以便看起来从未将该文件添加到仓库中。

注意:
我已经尝试过以下命令:

git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch Credentials.json" \
  --prune-empty --tag-name-filter cat -- --all

没有任何错误提示,但该文件未从历史记录中删除。

实际上,该文件位于 /src 文件夹内。 但奇怪的是,当我使用下面的命令(包括完整路径)时:

git filter-branch --force --index-filter   "git rm --cached --ignore-unmatch ~full-path/src/Credentials.json"   --prune-empty --tag-name-filter cat -- --all

我遇到了错误:~full-path/src/Credentials.json超出了存储库范围。

这是因为在提交5时已经删除了我的文件吗?在这种情况下我该怎么办?
重新创建存储库是唯一的选择吗?


更新凭据并将文件留在历史记录中不是解决方案,对吧? - pic0
@pic0 不行...这是必须永久删除的敏感数据。 - Akshunya
1
如果您将其推送到公共存储库(或可能变为公共的私有存储库或存在不受信任的贡献者),您应该考虑其已被泄露。您需要立即撤销文件中的任何凭据。然后,您可以使用 git rm 命令删除该文件。它仍将保留在您的提交历史中,但不会包含任何有效的凭据。我知道之前已经提到过,但还是要再次强调 - 有一些机器人会扫描所有新的提交,寻找凭据,并且它们只需要几毫秒就能够获取它们。稍后从存储库中删除文件并不能解决问题。 - undefined
4个回答

11

警告:在执行以下操作之前,始终备份原始仓库。


无需创建新的仓库。git filter-branch 可以使用。

git filter-branch 中不要使用完整路径,而是使用 相对路径 src/Credentials.json

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch src/Credentials.json" --prune-empty --tag-name-filter cat -- --all

顺便说一下,对于新手来说,bfg 更易于使用。(bfg 可接受没有路径的文件名。)

bfg --delete-files Credentials.json

参考文献


bfg可能需要额外的Java安装,这是我想避免的。 - Akshunya
@Akshunya,我已在我的端上测试了该命令并且它可以正常工作。你运行上述命令时是否在第5次提交? - Simba
是的,我在提交5。这里需要遵循额外的步骤吗? - Akshunya
1
它不起作用:文件仍然在历史记录中可见。要小心这些解决方案,因为它们没有正常工作。唯一的方法是完全删除整个存储库并创建一个新的。 - Giox
1
这让我的整个代码库变得一团糟,我在运行之前应该多了解一下这个命令...现在从代码库开始的每个提交都被复制了一遍。 - Stoyan
1
查看 /u/Monochrome 的回答:为了强制在远程推送相同的更改,必须同时运行“git push origin --force --all”。 - MRule

8
@Simba的回答是有效的,但是你还需要使用git push origin --force --all进行强制推送。

所以(1)

git filter-branch --force --index-filter "git rm -rf --cached --ignore-unmatch <relative_path_to_file>" --prune-empty --tag-name-filter cat -- --all

然后(2)

git push origin --force --all

7
假设没有人克隆存储库,您可以使用git rebase -i重写历史并删除文件。
使用git rebase -i <commit-hash-of-commit-3>。这将打开一个编辑器,其中列出了从提交4开始的提交列表。您可以选择删除提交(通过删除行并保存文件),编辑提交等。
选择提交4的“编辑”。保存文件。您会回到shell,并将文件添加到git“索引”中,但尚未提交。
现在,您可以使用git rm credentials.json来删除文件,然后使用git commit --amend修改提交。(更新
最后git rebase --continue完成。您会回到shell,文件将不再是存储库的一部分。
如果您稍后添加了依赖于Credentials.json文件的提交,则在“继续”阶段可能会收到错误。Git会停止在有问题的提交处,然后您可以再次使用git命令(重置/添加)来修改提交并继续。

在rebase命令中,提交哈希应该是commit-4而不是3,对吗? - Akshunya
无法工作! 在执行 git reset credentials.json 后,我执行了 git rebase --continue。 但是文件仍然存在。 事实上,当我执行 git commit -v 时,它根本没有显示任何更改。 - Akshunya
保存文件后(使用Shift X然后按Y进行缓冲区保存),我执行了git reset。之后执行git status,显示已完成1个命令,剩余命令和“无需提交,工作树干净”。 - Akshunya
我遇到了一个错误:“无法应用'Id for commit 5'”,我猜测这是因为我正在删除credentials.json文件,而它与我的当前更改不一致。所以,在第一步保存文件时,我应该同时编辑提交4和提交5吗? - Akshunya
1
完美无缺! 这里可以使用 git rebase --continue。 此外,需要强制推送到远程仓库。因此,在最后执行 git push origin --force --all 即可完成任务。 - Akshunya
显示剩余4条评论

1

我建议阅读GitHub的帮助页面

简而言之:

  • 您可以使用BFG Repo-Cleaner

    bfg --delete-files Credentials.json my-repo.git

  • 您可以使用git filter-branch

    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
    (其中路径为例如src/Credentials.json这也可能对您有所帮助

值得注意的是,如果任何人已经拥有该存储库的副本,则还必须在那里删除它! (或者您强制重新克隆/拉取存储库)


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