git push --force 会直接丢弃远程提交,强制将远程分支 HEAD 指向本地提交,使同事新推送的 commit 立即不可见,进入悬空状态约30天后被GC永久删除。

git push --force 会直接丢弃远程提交
执行 git push --force 后,远程分支的 HEAD 会强制指向你本地的提交,所有被跳过的远程提交(比如同事刚 push 的 commit)在远程仓库中立即不可见。Git 服务器不会立刻删除这些提交,但它们会进入“悬空”状态:无法通过正常命令拉取,git log origin/branch 看不到,git fetch 也同步不到。多数托管平台(GitHub/GitLab)默认保留悬空提交约 30 天,之后 GC 自动清理——过期即永久丢失。
用 reflog 恢复本地误删的提交
如果你自己刚强推、还没关闭终端或本地仓库没被清理,git reflog 通常还能找回被覆盖前的远程提交哈希。例如:
git reflog show origin/dev
# 输出类似:a82b1e4@{0}: fetch --prune origin: forced-update只要看到目标 commit(如 a82b1e4),就能立刻恢复:
- 先切回对应分支:
git checkout dev - 重置到该 commit:
git reset --hard a82b1e4 - 再用
--force-with-lease推送(比--force安全):git push --force-with-lease origin dev
注意:reflog 是本地记录,不跨机器;如果已关终端或执行过 git gc,这条路径就失效了。
远程仓库已 GC?只能靠协作恢复
一旦远程悬空提交被 GC 清理(或你本地也没 reflog),唯一可行的补救方式是找还保留该提交的协作者:
- 让同事运行
git log origin/dev,确认他本地是否还有被覆盖的 commit - 如果他有,让他执行:
git push origin a82b1e4:dev(把那个 commit 直接推到远程 dev 分支) - 若多人协作且没人保留,又没备份,这部分代码实质上已不可逆丢失
这种场景下,--force-with-lease 原本可以避免——它会在推送前检查远程 HEAD 是否和你本地记录一致,不一致就中止,给你留出喊停的机会。
强制覆盖后 tag 失效是隐性坑
如果有人基于被覆盖的 commit 打了 tag(比如 v1.2.3),这个 tag 在强推后依然存在,但指向一个“不存在”的提交。后续 git clone --branch v1.2.3 或 git checkout v1.2.3 会失败,报错 fatal: reference is not a tree。修复必须由有权限的人重新基于新 commit 打 tag,旧 tag 无法自动迁移。


















