前言
在软件开发中,有时候因为各种原因忘记完善 .gitignore
文件导致提交了很多不必提交的文件, 后期编译导致大量的文件发生变更提交。针对这种情况,需要从git所有提交中删除这些变更。
介绍
如果你想从 Git 仓库的所有提交历史中删除特定文件,可以使用 git filter-repo 工具(推荐)或 git filter-branch(较旧的方法)。这将重写整个提交历史,因此请确保在操作前备份仓库或创建一个新分支
操作
为了数据安全, 建议操作前备份数据!!!
使用 git filter-repo
(t推荐)
首先安装 git filter-repo(如果尚未安装),然后执行以下命令:
# 安装 git filter-repo(根据你的系统选择合适的安装方式)
# Ubuntu/Debian: sudo apt-get install git-filter-repo
# macOS (Homebrew): brew install git-filter-repo
# Windows (Git for Windows): git filter-repo --version # 通常已包含
# 从所有提交中删除指定文件或目录
git filter-repo --invert-paths --path path/to/file1 --path path/to/dir/
# 示例:删除所有提交中的 secrets.txt 和 logs/ 目录
git filter-repo --invert-paths --path secrets.txt --path logs/
# 强制推送至远程仓库(注意:这会覆盖远程历史)
git push origin --force --all
使用 git filter-branch
(旧方法)
如果无法使用 git filter-repo,可以使用 git filter-branch(但性能较差):
# 从所有提交中删除指定文件, 文件夹需要带 -r
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch path/to/file' \
--prune-empty --tag-name-filter cat -- --all
# 强制推送至远程仓库
git push origin --force --all
处理复杂路径(含空格或特殊字符)
如果路径中包含空格或特殊字符,需要用双引号或转义字符处理:
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch "path/to/my dir" path/to/file\ with\ space.txt' \
--prune-empty --tag-name-filter cat -- --all
操作后的清理
无论使用哪种方法,操作后都应执行以下命令清理残留对象并减小仓库体积:
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now --aggressive
错误处理
fatal: delete refs/original/refs/heads/doorFace_dual_xct: expected SP but got: ?
问题原因 git for-each-ref
默认输出原始引用名,若引用名中包含空格、问号等特殊字符,会破坏 git update-ref 期望的命令格式(delete
解决方案
使用更健壮的引用名处理方式,避免特殊字符干扰:
# 使用 --shell 选项确保引用名被正确转义
git for-each-ref --shell --format='delete %(refname)' refs/original | sh
备选方案
如果上述方法仍有问题,可以手动查看并删除 refs/original/ 下的引用:
# 查看所有 refs/original/ 引用
git show-ref | grep refs/original/
# 手动删除(逐个执行,替换 <refname> 为实际引用名)
git update-ref -d refs/original/<refname>
操作实例
建议操作之前将所有.gitignore
完善, 然后提交。确保缓存区无数据。
# 第一步
git filter-branch --force --index-filter 'git rm -r --cached --ignore-unmatch .idea/ app/src/main/protogen/ \
app/src/generated/ app/src/main/java/com/aqhby/doorface/facehelper/facedb/autogen/ app/release/ app/.cxx/' \
--prune-empty --tag-name-filter cat -- --all
# 第二步
git show-ref | grep refs/original/
# 第三步
git update-ref -d refs/original/refs/heads/doorFace_Dual_xct
git update-ref -d refs/original/refs/heads/master
git update-ref -d refs/original/refs/remotes/origin/doorFace_Dual_xct
git update-ref -d refs/original/refs/remotes/origin/doorFace_xct_branch
git update-ref -d refs/original/refs/remotes/origin/master
# 第四步
# 安全清理引用
git for-each-ref --shell --format='delete %(refname)' refs/original | sh
# 清除 reflog 并垃圾回收
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# 查看历史提交文件, 文件已经不存在。 结束
评论 (0)