Skip to content

Git删除误提交的内容

报错步骤和解释

step 1 遍历所有历史记录递归删除文件

shell
git filter-branch --force --index-filter "git rm -rf --cached --ignore-unmatch filename" --prune-empty --tag-name-filter cat -- --all
git filter-branch --force --index-filter "git rm -rf --cached --ignore-unmatch filename" --prune-empty --tag-name-filter cat -- --all

这个命令的作用是遍历整个提交历史,删除指定的文件,并重写项目历史。

具体来说:

--force:强制执行过滤分支操作,即使存在分支冲突也继续执行。

--index-filter:后面跟要执行的命令,这里是删除指定文件。

--cached:只从索引中删除,工作树不受影响。

--ignore-unmatch:忽略不存在于索引中的文件。

--prune-empty:删除因为文件全部被删除而变空的提交。

--tag-name-filter:后面跟命令,这里用cat表示保持标签名不变。

-- --all:针对所有分支进行操作。

所以这条命令的效果是,在项目完整历史中删除指定的filename文件,并清理由此产生的空提交记录。重写历史后,这个文件就好像从来没有被加入过版本控制一样。

需要注意的是,这会重写项目全部历史,不要在公共分支上轻易使用,以免对其他人产生影响。

step 2 删除Git的reflog文件

shell
rm -rf .git/refs/original
rm -rf .git/refs/original

这个命令用于删除 Git 的 reflog,即删除 .git/refs/original 目录。

reflog 在 Git 中用于记录分支提交历史的引用日志,它可以让你在丢失提交的情况下找回数据,是 Git 的一个重要的恢复机制。

但是有时为了某些目的,比如去除项目中不想保留的敏感信息,需要删除 reflog。

rm -rf .git/refs/original 这个命令就是用来删除整个 reflog 的。

删除后,你就无法通过 reflog 恢复到之前的状态了。所以在执行这个命令前,一定要慎重考虑,确认真的不需要保留 reflog。

另外,要完全删除历史信息,除了删 reflog 外,还需要使用 git filter-branch 等命令来重写提交记录。

所以 rm -rf .git/refs/original 只是删除 reflog 的一步,还需要其他操作来完全抹去项目的历史记录。这需要谨慎对待。

step 3 立即清除Git的引用日志(reflog)

shell
git reflog expire --expire=now --all
git reflog expire --expire=now --all

这个命令的作用是立即清除 Git 的引用日志(reflog)。

git reflog expire 用于管理引用日志的过期时间,默认保存90天。

--expire=now 参数表示立即设置全部引用日志的过期时间为现在,即清空所有的引用日志。

--all 参数表示不仅清理本地分支的reflog,还清理远程跟踪分支的reflog。

总之,git reflog expire --expire=now --all 将立即清除所有本地分支和远程跟踪分支的引用日志,无法通过引用日志恢复提交记录。

需要注意的是:

  1. 这只是删除引用日志,不影响实际的提交记录,如果想要完全重写历史,还需要配合filter-branch等命令。

  2. 如果已推送到远程仓库,其他人仍可能有备份保留引用日志,所以无法从服务器端完全清除引用日志。

  3. 删除引用日志会使某些Git操作更难恢复,如重置到以前的提交。

所以这个命令要慎重使用,确实需要清除引用日志时再执行。

step4 立即进行Git垃圾回收和优化

shell
git gc --prune=now
git gc --prune=now

git gc --prune=now 命令的作用是立即进行 Git 垃圾回收和优化。

git gc 命令表示运行 Git 垃圾回收进程,它会做两件事:

  1. 压缩 Git 数据库 - 将松散的对象打包成单个文件,使仓库变小。

  2. 删除不可达对象 - 删除所有不属于任何提交的commit对象及相关文件。

--prune=now 选项强制立即进行第二步删除不可达对象的操作,默认 gc 会延迟一段时间才会删除。

这样做的目的是防止删除仍在使用的对象。但是 --prune=now 会跳过等待时间,强制立即删除。

总结:

  • git gc - 执行 Git 垃圾回收与优化
  • --prune=now - 强制立即删除不可达对象

这个命令可以减少仓库的磁盘用量。但要注意它会删除对象,这样可能影响到 Git 的正常使用或丢失一些历史,所以需要谨慎使用。

step5 强制推送当前分支到远程仓库,并覆盖远程仓库的改动

shell
git push --force
git push --force

git push --force 命令的作用是强制推送当前分支到远程仓库,并覆盖远程仓库的改动。

常规的 git push 如果远程仓库存在新提交,会被拒绝,必须先拉取远程更新后再推送。

但是 git push --force 会无视这种情况,直接推送本地版本覆盖远程,使远程仓库匹配本地仓库。

使用时需要注意:

  • 这会使远程仓库的提交历史被重写,其他人的提交可能会丢失
  • 一旦推送,之前的提交记录无法恢复
  • 不应该在共享使用的分支上使用,这会使其他人的工作受到破坏

只有在符合下面条件时才可以安全使用 --force:

  • 可以确定不会覆盖其他人的工作
  • 推送一个新的分支或标签
  • 修复本地错误的提交

在公共分支上,应避免使用 --force,以免对他人造成破坏。需要强制推送时,也应先告知团队成员。