如果你已经从版本控制中取消了某些文件(例如通过 .gitignore 或手动删除),但这些文件在之前的提交中仍然存在,那么它们会继续占用仓库的历史记录空间。为了彻底清理这些文件,你需要从 Git 的历史记录中移除它们。以下是详细的步骤和方法:


1. 使用 git filter-branch 删除文件

git filter-branch 是一个强大的工具,可以重写 Git 历史以删除特定的文件或目录。

删除单个文件

假设要删除名为 large-file.txt 的文件,运行以下命令:

git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch large-file.txt' \
--prune-empty --tag-name-filter cat -- --all

删除整个目录

如果要删除某个目录(例如 logs/),可以使用:

git filter-branch --force --index-filter \
'git rm -r --cached --ignore-unmatch logs/' \
--prune-empty --tag-name-filter cat -- --all

参数说明:

  • --index-filter: 作用于索引,而不是工作目录。
  • --cached: 只影响暂存区中的文件,不会修改工作目录。
  • --ignore-unmatch: 如果文件不存在,忽略错误。
  • --prune-empty: 删除空的提交。
  • --tag-name-filter cat: 更新标签以匹配新的提交历史。
  • --all: 遍历所有分支。

2. 使用 BFG Repo Cleaner 删除文件

BFG Repo Cleaner 是一个更简单、更快的工具,用于清理大文件或敏感数据。

安装 BFG

下载 JAR 文件并确保你有 Java 环境:

wget https://repo1.maven.org/maven2/com/madgag/bfg/1.13.0/bfg-1.13.0.jar

删除文件

假设要删除 large-file.txt

java -jar bfg.jar --delete-files large-file.txt my-repo.git

删除整个目录

删除 logs/ 目录:

java -jar bfg.jar --delete-folders logs my-repo.git

Warning

不支持带/的路径名,只允许文件夹的名称


清理完成后执行垃圾回收

运行以下命令清理未引用的对象:

cd my-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive

3. 强制推送更新到远程仓库

由于你修改了提交历史,需要强制推送更改到远程仓库:

git push origin --force --all
git push origin --force --tags
  • --force : 强制推送,覆盖远程仓库的历史记录。
  • --all : 推送所有分支。
  • --tags : 推送所有标签。

注意:强制推送会影响所有协作者的工作流,因此在团队协作时需谨慎操作,并提前通知团队成员。


4. 检查清理效果

完成上述步骤后,可以通过以下命令检查仓库大小是否减小:

git count-objects -v
du -sh .git

5. 注意事项

  1. 备份仓库:在执行任何重写历史的操作前,请务必备份你的仓库,以防意外。
    cp -r my-repo.git my-repo-backup.git
  2. 协调团队:如果你的仓库是多人协作的,通知团队成员重新克隆仓库,避免因历史记录被重写导致冲突。
  3. LFS 文件:如果文件是通过 Git LFS 管理的,可能需要额外清理 LFS 对象。可以使用以下命令删除 LFS 文件:
    git lfs prune

总结

通过 git filter-branch 或 BFG Repo Cleaner,你可以从 Git 历史中彻底删除不需要的文件或目录。完成清理后,记得执行垃圾回收并强制推送到远程仓库。如果你还有其他问题或需要进一步的帮助,请随时告诉我!