# Git 版本回退与恢复 > 📚 Git 教程系列 - 第 7 篇 > 📅 最后更新:2026-03-15 > ⏮️ 适合人群:想掌握 Git 撤销和恢复操作 --- ## ⚠️ 重要提示 **在操作前请确保:** 1. 重要修改已备份 2. 理解每个命令的后果 3. 团队协作时先沟通 --- ## 🔍 Git 文件状态回顾 ``` 工作区 ──► 暂存区 ──► 版本库 git add git commit ↑ ↑ ↑ │ │ │ checkout reset reset/revert ``` --- ## 📝 撤销工作区修改 ### 撤销单个文件 ```bash # 方法 1:git checkout(旧版本) git checkout -- main.py # 方法 2:git restore(Git 2.23+) git restore main.py # 查看状态 git status ``` ### 撤销所有修改 ```bash # 撤销所有未暂存的修改 git checkout -- . git restore . # 警告:这会丢失所有未保存的修改! ``` ### 查看修改内容 ```bash # 查看工作区与暂存区的差异 git diff # 查看特定文件 git diff main.py ``` --- ## 📦 撤销暂存区 ### 从暂存区移除 ```bash # 方法 1:git reset(旧版本) git reset HEAD main.py # 方法 2:git restore(Git 2.23+) git restore --staged main.py # 方法 3:git rm(仅移除暂存,保留文件) git rm --cached main.py ``` ### 查看状态 ```bash # 查看暂存区状态 git status # 查看暂存区与工作区的差异 git diff --staged ``` --- ## ⏮️ 修改提交 ### 修改最后一次提交 ```bash # 修改提交信息 git commit --amend -m "新的提交信息" # 添加遗漏的文件 git add forgotten-file.py git commit --amend --no-edit # 修改作者信息 git commit --amend --author="New Author " ``` **⚠️ 注意:** 如果已推送到远程,需要强制推送: ```bash git push -f origin main ``` --- ## 🔄 版本回退 ### 使用 git reset ```bash # 查看提交历史 git log --oneline # 软回退(保留暂存区) git reset --soft a1b2c3d # 混合回退(默认,保留工作区) git reset --mixed a1b2c3d git reset a1b2c3d # 硬回退(丢弃所有修改) git reset --hard a1b2c3d # 回退到上一个版本 git reset --hard HEAD~1 # 回退到上上个版本 git reset --hard HEAD~2 ``` ### reset 选项对比 | 选项 | 工作区 | 暂存区 | 版本库 | |------|--------|--------|--------| | `--soft` | ✅ 保留 | ✅ 保留 | ◀ 回退 | | `--mixed` | ✅ 保留 | ❌ 撤销 | ◀ 回退 | | `--hard` | ❌ 丢弃 | ❌ 丢弃 | ◀ 回退 | --- ## ↩️ 使用 git revert(安全回退) ### 基本用法 ```bash # 撤销某次提交(创建新提交) git revert a1b2c3d # 撤销多次提交 git revert a1b2c3d..e5f6g7h # 撤销最近 3 次提交 git revert HEAD~2..HEAD # 不自动提交 git revert -n a1b2c3d ``` ### revert vs reset | 特性 | revert | reset | |------|--------|-------| | 原理 | 创建新提交 | 移动 HEAD 指针 | | 历史 | 保留 | 删除 | | 安全性 | 高 | 低 | | 协作 | ✅ 推荐 | ❌ 危险 | | 适用 | 已推送的提交 | 本地提交 | --- ## 🔮 使用 git reflog(后悔药) ### 什么是 reflog? **reflog** 记录 HEAD 指针的所有移动,即使被 reset 也能找回。 ```bash # 查看 reflog git reflog # 输出示例: # a1b2c3d HEAD@{0}: commit: 新功能 # e5f6g7h HEAD@{1}: reset: moving to HEAD~1 # i9j0k1l HEAD@{2}: commit: 重要修改 # m3n4o5p HEAD@{3}: checkout: moving to main ``` ### 恢复误删的提交 ```bash # 1. 查看 reflog git reflog # 2. 找到误删前的 commit # 假设是 HEAD@{2} # 3. 恢复 git reset --hard HEAD@{2} # 或创建新分支 git branch recovered HEAD@{2} ``` ### reflog 清理 ```bash # reflog 默认保留 90 天 # 手动清理过期的 reflog git reflog expire --expire=now --all # 垃圾回收 git gc --prune=now ``` --- ## 🛠️ 数据恢复 ### 恢复误删的文件 ```bash # 方法 1:从最近提交恢复 git checkout HEAD -- deleted-file.txt git restore deleted-file.txt # 方法 2:从特定提交恢复 git checkout a1b2c3d -- deleted-file.txt # 方法 3:使用 reflog git reflog git checkout HEAD@{2} -- deleted-file.txt ``` ### 恢复误删的分支 ```bash # 1. 查看 reflog git reflog # 2. 找到分支删除前的 commit # 假设是 a1b2c3d # 3. 恢复分支 git branch recovered-branch a1b2c3d ``` ### 恢复误删的标签 ```bash # 查看标签的 reflog git reflog show --all | grep "tag: v1.0.0" # 恢复标签 git tag v1.0.0 a1b2c3d ``` --- ## 🚨 紧急情况处理 ### 情况 1:强制推送后想恢复 ```bash # 1. 查看 reflog git reflog # 2. 找到强制推送前的 commit # 假设是 a1b2c3d # 3. 恢复 git reset --hard a1b2c3d git push -f origin main ``` ### 情况 2:合并错了分支 ```bash # 如果刚合并 git merge --abort # 如果已提交 git reset --hard HEAD~1 ``` ### 情况 3:rebase 失败 ```bash # 中止 rebase git rebase --abort # 继续 rebase(解决冲突后) git rebase --continue # 跳过当前 commit git rebase --skip ``` --- ## 💡 实用技巧 ### 查看提交差异 ```bash # 查看某次提交的修改 git show a1b2c3d # 查看两次提交的差异 git diff a1b2c3d e5f6g7h # 查看文件的历次修改 git log -p -- main.py ``` ### cherry-pick(挑选提交) ```bash # 从其他分支挑选提交 git cherry-pick a1b2c3d # 挑选多次提交 git cherry-pick a1b2c3d..e5f6g7h # 不自动提交 git cherry-pick -n a1b2c3d ``` ### 使用 git bisect 查找 bug ```bash # 启动 bisect git bisect start # 标记当前版本有问题 git bisect bad # 标记某个版本没问题 git bisect good v1.0.0 # Git 会自动切换到中间版本 # 测试后标记 good 或 bad git bisect good git bisect bad # 找到 bug 后退出 git bisect reset ``` --- ## 🎯 最佳实践 ### 提交前检查 ```bash # 1. 查看状态 git status # 2. 查看修改 git diff # 3. 查看暂存区 git diff --staged # 4. 测试代码 # (运行单元测试、手动测试等) # 5. 提交 git commit -m "清晰的提交信息" ``` ### 安全的回退流程 ```bash # 1. 创建备份分支 git branch backup-branch # 2. 尝试回退 git reset --hard HEAD~1 # 3. 如果没问题,删除备份 git branch -d backup-branch # 4. 如果有问题,恢复 git reset --hard backup-branch ``` ### 团队协作时的回退 ```bash # 1. 通知团队成员 # 2. 使用 revert 而不是 reset git revert a1b2c3d # 3. 如果必须 reset # - 确保没人基于你的代码工作 # - 强制推送前通知 git push -f origin main ``` --- ## 📊 命令对比表 | 命令 | 作用域 | 可恢复 | 适用场景 | |------|--------|--------|----------| | `git checkout --` | 工作区 | ✅ | 撤销未暂存的修改 | | `git restore --staged` | 暂存区 | ✅ | 撤销暂存 | | `git commit --amend` | 最后一次提交 | ⚠️ | 修改提交信息 | | `git reset --soft` | 版本库 | ✅ | 回退但保留暂存 | | `git reset --mixed` | 版本库 + 暂存区 | ✅ | 回退但保留工作区 | | `git reset --hard` | 全部 | ⚠️ | 彻底回退 | | `git revert` | 版本库 | ✅ | 安全回退(已推送) | | `git reflog` | 所有操作 | ✅ | 找回误删的数据 | --- ## 🎯 小结 | 场景 | 命令 | |------|------| | 撤销工作区修改 | `git checkout -- file` | | 撤销暂存 | `git reset HEAD file` | | 修改提交 | `git commit --amend` | | 回退版本 | `git reset --hard commit` | | 安全回退 | `git revert commit` | | 找回数据 | `git reflog` | | 恢复误删 | `git checkout commit -- file` | | 挑选提交 | `git cherry-pick commit` | --- > 💡 **下一步**:继续学习 [08-最佳实践与常见问题](./08-最佳实践与常见问题.md)