1. 背景介绍
Git 仓库中每一个修改都会保存记录,所以如果仅仅是删除敏感信息,然后commit,那么那个敏感信息至少会在两个历史commit里面出现,也就是出现和删除的两次commit,可以使用以下命令搜索:
1 2 |
git log -S 'sensitive string' -p --all |
2. 方案选择
所以如果想要从 git 里面彻底删除某一行代码的痕迹,有两种方案:
* git rebase
使用 rebase,将敏感信息第一次出现、删除前后的两个commit合并,这中间的所有commit都会被合并成一个commit,于是中间出现后又被删除的敏感信息就没有办法回溯了
- git filter-branch
使用 filter-branch,会将你的每一个历史 commit 重写,可以指定一定的规则,用来对某个commit状态下的所有信息进行修改
提示:
无论使用 rebase 还是 filter-branch,都会在本地 reflog 里面留下一下信息可以回溯到修改之前的状态,但是reflog是可以清空的,而且不会随着 push 传输到远程仓库的,可以放心使用。
3. 操作步骤
此处以方案二为例(filter-branch)
3.1 Clone 代码并备份
将原代码 Clone 两份,一份作备份,另一份进行以下操作
3.2 重写历史 commit
假设你要将所有分支、所有代码里的 "admin888" 字符串修改为 "********", 命令如下:
1 2 |
git filter-branch -f --tree-filter 'find . -type f ! -path "./.git*" -exec sed -i "s/admin888/********/g" {} ;' HEAD --all |
3.3 清空 reflog
你有两种办法获得一个干净的 reflog
* 方案1:
1 2 3 4 |
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin git reflog expire --expire=now --all git gc --prune=now |
- 方案2:
将代码上传到新的仓库,然后再clone下来,这样也是不会带有任何历史 reflog 的
3.4 删除并重新创建 Github 仓库
大概是因为 Github 对历史 commit 有缓存,导致即使项目里面原 commit id 已经不存在,但还是能通过 commit id 访问到旧代码,因此我们需要删除仓库,并创建一个同名的仓库
但是:如果不想删除仓库(比如想要留着你那充满荣耀的 star 和 fork 记录),可以给 github 提 ticket 解决
3.5 上传代码
虽然仓库重建,但是名称没变,因此 remote-url 也无需修改;
使用 --force --all 参数,强制上传每个分支
1 2 |
git push --force --all |
3.6 重新 clone 仓库确认
在一个新的目录,clone好仓库,然后尝试使用第一节提到的 git log 搜索敏感信息是否存在
4. 参考资料
https://help.github.com/articles/removing-sensitive-data-from-a-repository/