动手恢复前,先回答三个问题:
不同答案,处理方式完全不同。
| 当前状态 | 先做什么 | 推荐处理 | 避免什么 |
|---|---|---|---|
| 代码还没提交 | git status、必要时 git stash push -u |
用 git restore、git stash、手工移动文件保留现场 |
直接 git reset --hard |
| 已提交,还没 push | git log --oneline -5、git reflog -10 |
可以用 reset、commit --amend、rebase -i 整理本地历史 |
整理前不留备份分支 |
| 已 push,但没人基于它开发 | 先确认远端分支和团队状态 | 优先 git revert,确实要整理历史时先沟通再 push --force-with-lease |
直接 push --force |
| 已 push,且有人基于它开发 | 先通知协作者,确认影响范围 | 用新 commit 修正,公共分支优先 revert |
改写公共历史 |
| secret 已经提交 | 立即废弃并轮换 secret | 再清理 Git 历史和平台缓存 | 只做 revert 就结束 |
| force push 覆盖远端 | 找到仍保留正确提交的人或本地 reflog | 用正确 commit 恢复远端分支 | 继续在错误分支上叠加提交 |
如果不确定自己属于哪一类,先只执行只读命令:
git status
git log --oneline --decorate -10
git reflog -10
git branch -vv
不要急着执行会改写工作区或历史的命令。
先保存现场:
git status
git log --oneline --decorate -10
git reflog -10
如果工作区还有未提交代码,先确认全部内容都属于自己并准备稍后恢复,才可临时保存:
git stash push -u -m "backup-before-recovery"
状态中有其他 owner 的编辑或来源不清的未跟踪文件时,停止在这个工作区操作,保留现场或使用独立 worktree。
你在名为 main 的分支上提交了本来应该在 feature 分支里的 commit。main 是示例,实际以检查到的错误分支名为准。
git status --porcelain
git log --oneline -5
以下流程只适用于最后一个 commit 尚未 push、没有协作者依赖,并且 git status --porcelain 没有输出的情况。有 staged、unstaged 或 untracked 内容时,停止在 reset 前并保留现场。
git branch feat/right-branch
git reset --hard HEAD~1
git switch feat/right-branch
这会把当前 commit 保留到新分支,并让原分支回到提交前。
如果已经 push,优先新建 PR 修正,不要直接重写公共分支历史。
可以:
git switch -c feat/right-branch <commit-sha>
git push -u origin feat/right-branch
然后在原分支上用 revert 撤销:
git revert <commit-sha>
git reflog
找到 reset 前的位置后,先确认工作区干净并保留当前位置,再恢复:
git status --porcelain
git branch backup-before-recover HEAD
git reset --hard HEAD@{1}
git status --porcelain 有输出时停止。HEAD@{1} 必须来自刚才检查的 reflog 条目,不能按位置猜测。
git reflog
git branch recovered-work <commit-sha>
git switch recovered-work
只要 commit 还在 reflog 里,通常可以救回来。
可以和团队确认后修正历史:
git revert <commit-sha>
优先用 revert,因为它不会改写公共历史。
不要只 revert。
先废弃并轮换密钥,再清理历史,见 Remove Secret from History。
git reflog
git log --oneline --decorate -10
<integration-branch> 是被覆盖的实际集成分支名,例如 main、master 或 develop。让仍保留旧提交的同事执行:
git log --oneline origin/<integration-branch> -10
git reflog -10
找到正确 commit、确认远端权限和分支规则,并得到相关 owner 的授权后:
git push origin <good-sha>:<integration-branch>
如果分支受保护,需要管理员或平台 owner 处理。
git log --oneline --merges -10
git revert -m 1 <merge-commit-sha>
-m 1 表示保留第一父分支的视角,撤销被合入分支带来的变化。
不要对已经 push 且被别人使用的主分支随意 reset --hard。
立即废弃并轮换 secret。
Git 历史清理不能让已经泄露的 token 重新安全。
推荐使用 git filter-repo 或平台提供的安全处理流程。
git rebase --abort
git status
git add <files>
git rebase --continue
git reflog
git status --porcelain
git branch backup-before-rebase-recover HEAD
git reset --hard <before-rebase-sha>
这里同样要求 git status --porcelain 没有输出,<before-rebase-sha> 来自已检查的 reflog,不能使用猜测的提交。
公共 commit 优先用:
git revert <commit-sha>
这样会新增一个反向 commit,历史清楚,协作者也安全。
git status --porcelain
git clean -nd
git clean -nd 只列出候选文件,不能证明它们可以删除。
确认路径是 owner 授权丢弃的未跟踪文件后,精确指定路径:
git clean -f -- <owned-untracked-path>
确认路径归属、预期基线和授权后:
git restore --worktree -- <owned-tracked-path>
先运行:
git status --porcelain
git status --porcelain 有输出时停止。只有工作区干净、<verified-ref> 已核实且本地历史允许重写时,才保留当前位置并执行 reset:
git branch backup-before-hard-reset HEAD
git reset --hard <verified-ref>
出现任何需要保留的 staged、unstaged 或 untracked 内容时,停止,不执行广泛的 restore、clean 或 reset。
| 状态 | 优先方案 |
|---|---|
| 未提交 | git stash 或 git restore |
| 已提交未 push | reset、commit --amend、交互式 rebase |
| 已 push 无人基于它开发 | 可以协商后重写历史 |
| 已 push 且别人基于它开发 | 优先 git revert |
| 提交了 secret | 先轮换密钥,再清理历史 |