在日常工作中,我们经常遇到以下场景:1、因疏忽在Git上提交了一个较大的二进制文件,虽然已将其删除,但每次克隆代码时所需的磁盘空间仍未减少;2、不慎将账号密码提交到Git上,尽管已经删除,但这些信息仍然可以通过历史提交被发现,存在安全隐患。如何解决这些问题呢?
Git的分布式版本控制系统在每次提交时都会保留历史记录,因此即使我们删除了敏感信息和文件,它们仍然可以通过历史提交被发现,Git版本库记录了历史变动的所有内容。那有没有什么工具能改写Commit历史记录呢?那么就引入了今天文章的主角: Git Filter-Repo。
一、工具简介
Git filter-repo 工具是一个强大的命令行工具,可以帮助重新构造、重写、压缩和精简现有 Git 仓库中的提交历史记录。它允许使用不同的filter(如文件、分支、作者、时间等)来修改Git 仓库的历史记录。常用功能如下:
-
剥离大文件(或大目录) -
按路径剥离不需要的文件 -
提取想要的路径及其历史记录(剥离其他所有内容) -
重组文件布局(例如将所有文件移动到子目录中以准备与另一个存储库合并,使子目录成为新的顶级目录,或将具有独立文件名的两个目录合并到一个目录中) -
重命名tags(通常也准备与另一个存储库合并) -
替换或删除密码等敏感文本 -
重写提交消息等等
1.1 安装条件
必要条件:
-
git >= 2.22.0 至少;某些功能 需要 git >= 2.24.0 或更高版本 -
python3 >= 3.5
PS:mac版本Git 默认带该功能,直接执行以下命令测试即可,如果执行该命令失败,可以参考1.2
git fitler-repo -h
1.2 安装方式
-
下载git-filter-repo文件
wget https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo
-
执行命令
python3 git-filter-repo --help

二、删除方式
2.1 项目结构
项目config目录下有两个配置文件application.yml 和application_local.yml
2.2 删除敏感配置文件
-
删除config/application.yml下的配置文件
git filter-repo --path config/application.yml --path-rename config/application.yml:deleted_data --invert-paths
-
设置远程仓库地址
git remote add origin git@git.github.com:test/es-alert.git
-
强制推送更改到远程仓库的所有分支
git push --force --all
此时直接执行强制push命令,大概率会失败,由于Gitlab中,master分支默认是保护分支,需要关闭其保护分支特性,允许强制push。
2.3 更改敏感配置信息

-
更改配置信息,例如上图的password是123456,改成newpassword
git filter-repo --replace-text <(echo "123456==>newpasssword")
-
设置远程仓库地址
git remote add origin git@git.github.com:test/es-alert.git
-
强制推送更改到远程仓库的所有分支
git push --force --all
-
更改后效果,历史所有Commit上的密码都被更改

2.4 彻底删除敏感数据
项目开发者从旧的存储库历史记录创建的任何分支进行Rebase,_而不是Merge_。一次Merge操作并且提交将可能会重新引入之前的历史记录。可以执行如下命令
-
清除历史记录中的不必要的引用
git for-each-ref --format="delete %(refname)" refs/original | git update-ref --stdin
-
清除所有分支的 reflog 记录,包括不可用的提交,使其过期并立即删除。
git reflog expire --expire=now --all
-
运行 Git 垃圾回收(gc),并清除过时的对象和引用。通过设置 –prune 参数为 now,这将清除 refs 目录中过期的引用,并且立即回收不再使用的 Git 对象
git gc --prune=now
当然也有一个一步到位的方法,直接删除本地的代码仓库,从Gitlab上重新Clone一份代码进行开发。
三、风险
3.1 破坏性操作
因为Git是一个分布式的版本控制系统,它会保留每个提交的历史记录,即使最新提交删除了敏感信息,历史上留下的提交记录依然会泄露敏感信息。该工具相当于重写整个仓库的历史记录,这是一种破坏性操作,不宜轻易使用。它写入与存储库中的原始对象相对应(但从中过滤)的新commits, trees, tags, and blobs ,然后删除原始历史记录并只留下新的。这意味着一旦操作到Gitlab上,将无法进行回退,如果出于某种原因想回退到历史版本的代码,此时服务很大可能起不来,例如你删除了数据库密码,那么回退到历史版本时,由于历史代码未接入配置中心,服务启动时将会连不上数据库。
3.2 公共库影响
如果代码已经已经发布或共享,如go mod中被其他项目代码引用,由于使用git filter-repo,其commit ID对应的hash值将会发生变化,将会导致服务无法编译或启动
3.3 目录结构变化较大
有部分项目,项目结构产生较大的变化,例如文件名、文件目录都经过多次更改,那么需要指定多个文件路径,否则会解决不彻底。针对文件路径,可以采用glob模式进行匹配。
3.4 大仓库
针对使用时间较长的仓库,或者较大的仓库,使用该命令修改,会导致执行时间过长。如果同时间执行多个仓库,可能会对Gitlab造成压力。
3.5 数据可能丢失
用git push –force命令强制推送修改到远程仓库。这种操作可能导致数据丢失。当多个人同时在同一个分支上工作时,如果一个人进行了强制推送,那么其他人所做的提交将会被覆盖,从而导致数据的丢失。
3.6 限制

参考链接
https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository https://github.com/newren/git-filter-repo https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html
原文始发于微信公众号(洋洋自语):Git Filter-Repo: 重新定义Git历史Commit
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/273068.html