Recovery depends on whether content has been saved as objects, whether references and reflogs remain, and the state of the current operation. The presence of .git does not guarantee that uncommitted edits can be recovered.
Category 1: Commit fixes#
1. You just committed and realize you missed a file or wrote the wrong commit message
- Symptom: You notice one second too late.
- Remedy:
git add <forgotten_file> git commit --amend --no-edit # 合并到上一次提交,不改信息 # 或者 git commit --amend -m "新的正确信息"
2. You committed a large file that should not be there. How do you remove it completely?
- Symptom: The
.gitdirectory suddenly balloons. Even after deleting the file, it still occupies space in history. - Remedy: First create an independent backup, then verify the scope of the history cleanup in a fresh clone. Git’s official documentation discourages
filter-branch;git filter-repois a better fit. For example, the following rewrites history containing that path:
# 在专用于历史清理的新克隆中,路径为仓库相对路径占位符
git filter-repo --path <large_file_path> --invert-pathsThe following is retained only to explain a command from an older tutorial. Its arguments do not represent a recommended modern workflow, and it should not be run directly in a shared repository:
bash git filter-branch --force --index-filter \ 'git rm --cached --ignore-unmatch <large_file_path>' \ --prune-empty --tag-name-filter cat -- --all
After cleanup, check the branches, tags, and scope of affected objects first, and coordinate with collaborators to reclone or rebuild references. The older tutorial’s git push origin --force --all broadens what will be overwritten and must not be treated as an automatic next step. Before publishing, scope each ref explicitly and check server-side protections. Include each historical filename in the cleanup; filtering a single path may not cover previous names. If a secret has leaked, revoke or rotate it first; rewriting history cannot recall other people’s clones.
Category 2: Branch rescue#
3. You have spent hours writing code on the wrong branch but have not committed yet
- Symptom: You meant to work on the
featurebranch but wrote a lot of code onmasterinstead. - Remedy:
git stash -u # 1. 保存已追踪及未追踪内容(忽略文件另行处理) git switch <right_branch> # 2. 切换到正确分支 git stash pop # 3. 恢复现场
4. You need to fix an urgent bug halfway through development, but do not want to commit unfinished work
- Symptom: The code does not compile, and you do not want to leave a throwaway commit.
- Remedy: Use
Stash(see Git 02).git stash -u # 保存当前进度(含新文件) # ... 修 Bug ... git stash pop # 回来继续写
Category 3: Undo & recovery#
5. You ran git reset --hard and lost all your code
- Symptom: Your heart stops. That was a week’s work.
- Remedy: Use
reflog(see Git 04).git reflog # 找到 reset 之前的那个哈希值 (例如 abc1234) git branch recovery/saved-tip abc1234 # 先为确认过的提交建立恢复引用
6. You want to undo code already pushed to the remote
- Scenario A: The history rewrite has been coordinated, and replacing the remote branch tip is permitted.
- Check the current state and make a backup first. The original tutorial’s
git reset --hard HEAD~1discards local changes, andgit push -foverwrites remote history; neither should be treated as a routine undo step. If you only need to undo the last commit while keeping the files, usegit reset --soft HEAD~1. When publishing rewritten history, use--force-with-leasewith a scoped target and an explicit expected value (see Remote collaboration); you must still check remote permissions and the state of collaborators’ work.
- Check the current state and make a backup first. The original tutorial’s
- Scenario B: A public branch where force pushes are prohibited.
- Remedy: Use
revert.
git revert <commit_hash> # 产生一个“相反”的新提交,抵消之前的修改 git push - Remedy: Use
Category 4: Sync & conflicts#
7. Pull fails and reports conflicts. How do you resolve them cleanly?
Symptom: Red warnings fill the screen, and your code is full of
<<<<<<< HEAD.Remedy:
- Manually edit the conflicting files and keep the correct code.
git add <conflicted_file>.git merge --continueorgit commit.
** Abort the merge**:
git merge --abort- Effect: Attempts to reconstruct the pre-merge state. If you had uncommitted changes when the merge began and edited them further, complete recovery may not be possible.
- Cost: All the code you wrote to resolve conflicts manually will be lost! It is like turning back time and pretending the merge never happened. If you have already spent an hour resolving conflicts, be very careful not to run this command accidentally.
- What next?: Check
git statusto confirm the operation state and retained changes, then choose to merge again, rebase according to your collaboration policy, or keep a separate branch. Pull may also use rebase; in that case, usegit rebase --continue/git rebase --abortto continue or abort, rather than mixing in merge commands.git reset --hard origin/<branch>discards working-tree changes and moves the current branch. It does not fetch automatically and must not be used to bypass conflicts.
8. How do you sync a fork with the original author’s updates?
- Symptom: Your repository is months behind the original author’s.
- Remedy:
git remote add upstream https://example.com/upstream/project.git git fetch upstream git switch master git merge upstream/master # 或者 rebase
The ultimate survival rules#
- Save promptly: WIP commits or an appropriate stash can preserve content, but reflogs expire and are not a permanent backup.
- Understand HEAD: Know where you are: which branch and which commit.
- Inspect before recovering: Once you find a candidate commit, create a recovery reference and inspect it first; do not repeatedly experiment with hard resets.
Three limits of recovery
reset --hard overwrites tracked content and may also overwrite or delete untracked files blocking target paths; it is not a general command for removing all untracked files. Committed objects can be recovered through references or reflogs while they remain, but uncommitted edits may never have been stored as objects. By default, reachable reflog entries expire after about 90 days and unreachable entries after about 30 days; the actual window depends on configuration, maintenance, and object pruning.
On shared branches, the usual approach is to preserve history by adding an inverse commit with git revert. Reverting a merge commit also requires selecting the correct mainline parent and understanding the effect on later merges. Before using any continue, abort, or cleanup command, make sure it matches the operation shown by status.
References & further reading
- Git reset ↗
- Git reflog ↗
- Git revert ↗
- Aborting a Git merge ↗
- Risks of Git’s older filtering tool ↗
- git-filter-repo author documentation ↗
Adapted from technical notes. Examples use generic names.
Continue along a reading path
Git: from snapshots to collaboration and recovery
- 01Git's underlying model: objects, snapshots, and references
- 02From the first add to undoing a change.
- 03Git branches: merging, conflicts, and saving work in progress
- 04Remote collaboration with Git: fetching, tracking, and two remotes
- 05Advanced Git: rebasing, cherry-picking, and bisecting
- 06A Git scenario handbook: correcting, undoing, and recovering