删除已提交到github的历史记录

GitHub历史记录彻底删除指南:移除提交的敏感信息(密钥/密码)

做开发时最头疼的事之一:不小心把密钥、密码、配置文件里的敏感信息提交到GitHub,哪怕立刻删除文件再提交,历史记录里依然能查到——这等于把敏感信息暴露在公网。今天结合我踩过的坑,分享彻底删除Git历史中敏感文件/内容的方法,核心用git filter-branch,还会补充更高效的替代方案和预防措施。

一、核心场景:为什么普通删除没用?

如果只是用git rm删除文件再提交,只是在最新提交中移除了文件,但Git的提交历史依然保留该文件的所有版本,任何人都能通过git log/git checkout回到旧版本查看敏感信息。

必须通过「重写Git提交历史」的方式,彻底抹除敏感文件在所有历史记录中的痕迹。

二、实操步骤:用git filter-branch彻底删除指定文件

以你提到的deploy/deploy-dev.js(含密钥)为例,完整操作流程如下(全程在本地仓库执行):

1. 第一步:克隆完整仓库(确保本地有全量历史)

先把远程仓库完整克隆到本地(如果已有本地仓库,跳过此步,但建议备份):

1
2
git clone https://github.com/你的用户名/你的仓库名.git
cd 你的仓库名

2. 第二步:执行filter-branch命令(核心)

运行你提供的命令,重写所有分支的历史,删除指定文件:

1
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch deploy/deploy-dev.js' --prune-empty --tag-name-filter cat -- --all

关键参数解释(避免瞎用):

参数 作用
--force 强制覆盖已有的filter-branch备份(如果之前执行过)
--index-filter 对索引(暂存区)执行命令,而非工作区(效率更高)
git rm --cached --ignore-unmatch 文件名 从索引中删除文件,--ignore-unmatch避免文件不存在时报错
--prune-empty 删除重写后空的提交(比如仅包含被删除文件的提交)
--tag-name-filter cat 保留标签(标签名不变)
-- --all 作用于所有分支(包括远程跟踪分支)

执行完后,本地Git历史中所有包含deploy/deploy-dev.js的提交都会被重写,该文件的痕迹会被彻底抹除。

3. 第三步:强制推送到远程GitHub(风险⚠️)

本地历史重写后,必须强制推送覆盖远程仓库的历史(这是关键步骤):

1
2
3
git push origin master --force
# 如果是其他分支(如main),替换为:
git push origin main --force

重要提醒:

  • 强制推送会覆盖远程仓库的历史,如果是多人协作仓库,必须提前通知所有协作者:
    • 协作者需先备份本地修改;
    • 执行git pull --rebase同步新历史,而非普通git pull(避免历史冲突);
  • 若仓库是公开的,即使删除历史,敏感信息可能已被GitHub缓存、搜索引擎快照抓取,后续需更换密钥(见文末补救措施)。

4. 第四步:清理本地缓存(彻底删除)

执行以下命令清理Git的缓存和无用对象,确保本地无残留:

1
2
3
4
# 清理悬空对象(被重写历史抛弃的对象)
git gc --prune=now
# 进一步优化仓库
git prune

三、更高效的替代方案:BFG Repo-Cleaner

git filter-branch速度慢(仓库历史久、提交多的话要等很久),推荐用BFG Repo-Cleaner(专门清理Git历史的工具,速度快10-100倍):

1. 安装BFG(需Java环境)

1
2
3
4
# 下载BFG(Linux/Mac)
wget https://repo1.maven.org/maven2/com/madgag/bfg/1.14.0/bfg-1.14.0.jar
# 重命名方便使用
mv bfg-1.14.0.jar bfg.jar

2. 执行删除命令(更简洁)

1
2
3
4
5
6
7
8
9
# 克隆裸仓库(速度更快)
git clone --mirror https://github.com/你的用户名/你的仓库名.git
# 删除指定文件(保留最新提交的版本,历史版本全部删除)
java -jar bfg.jar --delete-files deploy/deploy-dev.js 你的仓库名.git
# 进入裸仓库,清理
cd 你的仓库名.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
# 强制推送
git push

BFG的优势:语法更简单、速度快,还支持批量删除(比如--delete-files *.key删除所有密钥文件)。

四、关键注意事项(避坑+补救)

1. 强制推送的风险

  • 多人协作仓库:强制推送会覆盖远程历史,协作者的本地仓库会和远程冲突,必须让所有人同步新历史;
  • 已发布的标签:如果标签关联了旧历史,需重新推送标签(git push --tags --force)。

2. 敏感信息已泄露的补救

即使删除了历史,敏感信息可能已被:

  • GitHub的缓存/存档保留;
  • 其他用户Fork了仓库;
  • 搜索引擎快照抓取;

必须做

  • 立即更换泄露的密钥/密码/Token;
  • 若涉及企业密钥,通知安全团队评估风险;
  • 对重要仓库开启GitHub的「Secret scanning」(自动检测敏感信息)。

3. 针对“删除文件内容而非整个文件”的场景

如果只是想删除文件里的某行敏感内容(比如密钥),而非整个文件,用以下命令:

1
git filter-branch --force --tree-filter 'sed -i "/敏感内容关键词/d" 文件名' --prune-empty --tag-name-filter cat -- --all

比如删除config.js里含API_KEY的行:

1
git filter-branch --force --tree-filter 'sed -i "/API_KEY/d" config.js' --prune-empty --tag-name-filter cat -- --all

五、预防措施:避免下次提交敏感信息

  1. 用.gitignore:提前把敏感文件(如deploy-dev.js.envconfig/*.key)加入.gitignore,禁止Git追踪:
    1
    2
    3
    4
    # 编辑.gitignore
    echo "deploy/deploy-dev.js" >> .gitignore
    git add .gitignore
    git commit -m "添加敏感文件到gitignore"
  2. 用git-crypt加密:对必须提交的配置文件,用git-crypt加密后再提交;
  3. 用环境变量/密钥管理服务:密钥不写在代码里,改用环境变量、GitHub Secrets、阿里云KMS等;
  4. 提交前检查:用git status确认待提交文件,避免误提交;也可配置pre-commit钩子,自动检测敏感信息。

总结

关键点回顾

  1. 彻底删除Git历史中的敏感文件,核心是「重写历史」,而非普通删除;
  2. 轻量仓库用git filter-branch,大仓库推荐BFG Repo-Cleaner(速度更快);
  3. 强制推送会覆盖远程历史,多人协作需提前通知;
  4. 敏感信息泄露后,更换密钥是首要操作,删除历史只是补充;
  5. 预防大于补救:用.gitignore、环境变量避免敏感信息提交。

这套流程能彻底抹除GitHub历史中的敏感文件,但切记:公开仓库的敏感信息一旦提交,即使删除历史,也可能被缓存,所以核心还是做好预防,提交前多检查。


删除已提交到github的历史记录
https://cszy.top/2018-01-18 删除已提交github的commit历史记录/
作者
csorz
发布于
2018年1月18日
许可协议