OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 097

Git 场景手册:修正、撤销与恢复

按当前操作和数据保存状态选择恢复路径,避免扩大丢失。

所在专题Git:从快照到协作与恢复 ↗
约 8 分钟阅读开始阅读

恢复能力取决于内容是否已保存为对象、引用与 reflog 是否保留,以及当前操作状态;.git 存在并不保证找回未提交编辑。


第一类:提交修正 (Commit Fixes)#

1. 刚刚提交完,发现漏了一个文件/写错了提交信息

  • 症状:后悔药吃得晚了一秒。
  • 处方:
    git add <forgotten_file>
    git commit --amend --no-edit  # 合并到上一次提交,不改信息
    # 或者
    git commit --amend -m "新的正确信息"

2. 把不该提交的大文件提交了,怎么彻底删掉?

  • 症状:.git 文件夹瞬间爆炸,即使删除了文件,历史记录里依然占用空间。
  • 处方:先建立独立备份,在新克隆中验证历史清理范围。Git 官方不推荐 filter-branch;更适合使用 git filter-repo,例如以下会重写包含该路径的历史:
# 在专用于历史清理的新克隆中,路径为仓库相对路径占位符
git filter-repo --path <large_file_path> --invert-paths

以下保留为旧教程命令的解释,参数不代表现代推荐流程,不应直接在共享仓库执行: bash git filter-branch --force --index-filter \ 'git rm --cached --ignore-unmatch <large_file_path>' \ --prune-empty --tag-name-filter cat -- --all 清理后先检查分支、标签和对象范围,并与协作者协调重新克隆或重建引用。旧教程的 git push origin --force --all 会扩大覆盖范围,不能作为自动下一步;发布前限定每个 ref 并核对服务器保护。文件改名历史需要逐一纳入清理,单一路径过滤不一定覆盖旧名字。密钥泄露应先撤销或轮换,改写历史不能撤回别人的克隆。


第二类:分支救急 (Branch Rescue)#

3. 在错误的分支上写了半天代码,还没提交

  • 症状:本该在 feature 分支写,结果在 master 上写了一堆。
  • 处方:
    git stash -u             # 1. 保存已追踪及未追踪内容(忽略文件另行处理)
    git switch <right_branch> # 2. 切换到正确分支
    git stash pop            # 3. 恢复现场

4. 代码写到一半,紧急需要修 Bug,但不想提交“半成品”

  • 症状:代码处于不可编译状态,不想留下垃圾 commit。
  • 处方:使用 Stash (见 Git 02)。
    git stash -u             # 保存当前进度(含新文件)
    # ... 修 Bug ...
    git stash pop            # 回来继续写

第三类:撤销与恢复 (Undo & Recovery)#

5. 执行了 git reset --hard,代码全丢了

  • 症状:心跳停止,那是你一星期的心血。
  • 处方:利用 reflog (见 Git 04)。
    git reflog               # 找到 reset 之前的那个哈希值 (例如 abc1234)
    git branch recovery/saved-tip abc1234 # 先为确认过的提交建立恢复引用

6. 已经 Push 到远程的代码,想撤回

  • 场景 A:分支历史改写已协调、允许替换远端末端。
    • 先检查状态并备份;原教程中的 git reset --hard HEAD~1 会丢弃本地修改,git push -f 会覆盖远端历史,不能作为普通撤销步骤。若只需撤销末次提交同时保留文件,可以用 git reset --soft HEAD~1;发布改写时使用限定目标及明确期望值的 --force-with-lease(见 远程协作),仍须核对远端权限及协作者状态。
  • 场景 B:公共分支(禁止强制推送)。
    • 处方:使用 revert。
    git revert <commit_hash> # 产生一个“相反”的新提交,抵消之前的修改
    git push

第四类:同步与冲突 (Sync & Conflicts)#

7. Pull 失败,提示冲突,怎么优雅解决?

  • 症状:满屏红色警告,代码里全是 <<<<<<< HEAD。

  • 处方:

    1. 手动编辑冲突文件,保留正确代码。
    2. git add <conflicted_file>。
    3. git merge --continue 或 git commit。
  • ** 放弃合并**:git merge --abort

    • 效果:尝试重建合并前状态;若开始时已有未提交修改且又被编辑,可能无法完整恢复。
    • 代价:你之前所有手动解决冲突的代码会全部丢失!它就像时光倒流,假装这次合并从未发生过。如果你已经花了一小时解冲突,千万不要手滑执行这个命令。
    • 之后怎么办:检查 git status 确认操作状态和保存的改动,再选择重新 merge、按协作策略 rebase 或保持独立分支。Pull 也可能使用 rebase;此时继续和放弃应使用 git rebase --continue / git rebase --abort,不能混用 merge 命令。git reset --hard origin/<branch> 会丢弃工作区修改并移动当前分支,且不自动 fetch,不能用来绕过冲突。

8. Fork 的仓库如何同步原作者的更新?

  • 症状:你的仓库落后原作者几个月了。
  • 处方:
    git remote add upstream https://example.com/upstream/project.git
    git fetch upstream
    git switch master
    git merge upstream/master # 或者 rebase

终极生存法则#

  1. 及时保存:WIP 提交或适当 stash 可保存内容,但 reflog 会过期,不等于永久备份。
  2. 理解 HEAD:知道你现在在哪(哪个分支,哪个提交)。
  3. 先检查再恢复:找到候选提交后先建立恢复引用并检查,不以 hard reset 反复试探。


恢复的三个边界

reset --hard 会覆盖已追踪内容,也可能覆盖或删除阻挡目标路径的未追踪文件;并非通用的清空所有未追踪文件命令。已提交对象可在仍保留时通过引用或 reflog 找回,未提交编辑则未必存在对象。reflog 默认可达记录约 90 天、不可达记录约 30 天过期,实际配置、维护和对象回收决定窗口。

共享分支一般以 git revert 新增反向提交保留历史;revert 合并提交还需指定正确的主线父提交,并理解对后续合并的影响。所有继续、终止与清理命令都应先对应 status 所显示的操作。

参考与延伸

  1. Git reset ↗
  2. Git 引用日志 ↗
  3. Git revert ↗
  4. Git merge 终止 ↗
  5. Git 旧过滤工具风险 ↗
  6. git-filter-repo 作者文档 ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

Git:从快照到协作与恢复

  1. 01Git 的底层模型:对象、快照与引用
  2. 02从第一次 add,到撤回一次修改。
  3. 03Git 分支:合并、冲突与现场保存
  4. 04Git 远程协作:抓取、追踪与双远端
  5. 05Git 进阶:变基、拣选与二分排错
  6. 06Git 场景手册:修正、撤销与恢复
CONTINUE READING / 下一篇sops 原理:混合加密与接收者

理解密文版本管理、数据密钥与多接收者授权的边界。