| English | 中文 |
Before attempting recovery, first answer three questions:
Different answers require completely different handling methods.
| Current State | What to Do First | Recommended Handling | What to Avoid |
|---|---|---|---|
| Code not yet committed | git status, and if necessary git stash push -u |
Use git restore, git stash, or manually move files to preserve the current state |
Direct git reset --hard |
| Committed, not yet pushed | git log --oneline -5, git reflog -10 |
Can use reset, commit --amend, rebase -i to clean up local history |
Cleaning up without leaving a backup branch |
| Pushed, but no one is developing based on it | First confirm remote branch and team status | Prioritize git revert; if history must be rewritten, communicate first then push --force-with-lease |
Direct push --force |
| Pushed, and someone is developing based on it | First notify collaborators, confirm scope of impact | Use a new commit to fix, prioritize revert for public branches |
Rewriting public history |
| Secret has been committed | Immediately revoke and rotate secret | Then clean up Git history and platform cache | Ending with just a revert |
| Force push overwrote remote | Find someone who still has the correct commits or local reflog | Restore remote branch with correct commit | Continuing to stack commits on the wrong branch |
If you are unsure which category you belong to, execute only read-only commands first:
git status
git log --oneline --decorate -10
git reflog -10
git branch -vv
Do not rush to execute commands that alter the working tree or history.
Capture the current state first:
git status
git log --oneline --decorate -10
git reflog -10
If the working tree still has uncommitted code, confirm that all of it belongs to you and that you intend to restore it later before temporarily saving it:
git stash push -u -m "backup-before-recovery"
If status includes edits owned by someone else or untracked files with an uncertain source, stop in this worktree, preserve the state, or use a separate worktree.
You made a commit on a branch named main that originally belonged in a feature branch. main is an example; use the wrong branch name established by the checks.
git status --porcelain
git log --oneline -5
This flow applies only when the last commit has not been pushed, no collaborator depends on it, and git status --porcelain prints nothing. If there is staged, unstaged, or untracked content, stop before reset and preserve the state.
git branch feat/right-branch
git reset --hard HEAD~1
git switch feat/right-branch
This will preserve the current commit in a new branch and revert the original branch to its pre-commit state.
If already pushed, prioritize creating a new PR to fix it; do not directly rewrite public branch history.
You can:
git switch -c feat/right-branch <commit-sha>
git push -u origin feat/right-branch
Then undo it on the original branch using revert:
git revert <commit-sha>
git reflog
After finding the position before the reset, first confirm a clean workspace and preserve the current position, then recover:
git status --porcelain
git branch backup-before-recover HEAD
git reset --hard HEAD@{1}
Stop when git status --porcelain prints anything. HEAD@{1} must come from the reflog entry just inspected; do not guess by position.
git reflog
git branch recovered-work <commit-sha>
git switch recovered-work
As long as the commit is still in the reflog, it can usually be recovered.
You can amend the history after confirming with the team:
git revert <commit-sha>
Prioritize using revert because it does not rewrite public history.
Do not just revert.
First revoke and rotate keys, then clean up history, see Remove Secret from History.
git reflog
git log --oneline --decorate -10
<integration-branch> is the actual integration branch that was overwritten, such as main, master, or develop. Have colleagues who still retain the old commits execute:
git log --oneline origin/<integration-branch> -10
git reflog -10
After finding the correct commit, confirming remote permissions and branch rules, and obtaining authorization from the relevant owner:
git push origin <good-sha>:<integration-branch>
If the branch is protected, it requires handling by an administrator or platform owner.
git log --oneline --merges -10
git revert -m 1 <merge-commit-sha>
-m 1 indicates keeping the perspective of the first parent branch, undoing the changes brought by the merged branch.
Do not carelessly run reset --hard on a main branch that has already been pushed and is being used by others.
Immediately revoke and rotate the secret.
Git history cleanup cannot make an already leaked token secure again.
Use git filter-repo or a secure processing flow provided by the platform.
See Remove Secret from History.
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>
This also requires git status --porcelain to print nothing, and <before-rebase-sha> must come from an inspected reflog entry rather than a guessed commit.
For public commits, prioritize using:
git revert <commit-sha>
This adds a reverse commit, keeping history clear and collaborators safe.
git status --porcelain
git clean -nd
git clean -nd only lists candidates; it does not prove that they may be deleted.
After confirming that a path is an untracked file the owner authorizes discarding, name that path precisely:
git clean -f -- <owned-untracked-path>
After confirming path ownership, the expected baseline, and authorization:
git restore --worktree -- <owned-tracked-path>
First run:
git status --porcelain
If git status --porcelain prints anything, stop. Only when the worktree is clean, <verified-ref> has been verified, and local history may be rewritten, preserve the current position and run reset:
git branch backup-before-hard-reset HEAD
git reset --hard <verified-ref>
If there is staged, unstaged, or untracked content that must be retained, stop rather than run a broad restore, clean, or reset.
| State | Priority Plan |
|---|---|
| Not committed | git stash or git restore |
| Committed, not pushed | reset, commit --amend, interactive rebase |
| Pushed, no one developing based on it | Can rewrite history after negotiation |
| Pushed, someone developing based on it | Prioritize git revert |
| Committed a secret | First rotate keys, then clean up history |