06 - Git 高级技巧与故障排查
本章目标:掌握企业实战中的高级 Git 技巧,能独立排查和解决各种 Git 故障。
一、git reflog --- 救命神器
这是 Git 最被低估的功能,关键时刻能救你的命。
bash
# 查看所有操作记录(包括已经 reset 掉的 commit)
git reflog
# 输出示例:
# abc1234 HEAD@{0}: reset: moving to HEAD~3
# def5678 HEAD@{1}: commit: feat: add login
# ghi9012 HEAD@{2}: commit: feat: add register
# jkl3456 HEAD@{3}: commit: feat: add dashboard
常见救命场景
bash
# 场景1:误删了分支
git branch -D feature/important
# 没关系!
git reflog # 找到分支最后的 commit
git checkout -b feature/important abc1234 # 恢复
# 场景2:误执行了 git reset --hard
git reflog # 找到 reset 前的 commit
git reset --hard abc1234 # 恢复
# 场景3:push 后发现代码有问题
git reflog # 找到 push 前的 commit
git reset --hard abc1234 # 回退
git push --force-with-lease # 强制推送(回退远程)
二、git reset 的三种模式
bash
# ===== 模式对比 =====
# --soft:只撤销 commit,保留暂存区和工作区
git reset --soft HEAD~1
# 效果:commit 被撤销,改动仍在暂存区(绿色)
# --mixed(默认):撤销 commit + 暂存区,保留工作区
git reset HEAD~1
# 效果:commit 被撤销,改动在工作区(红色)
# --hard:全部撤销(危险!不可恢复)
git reset --hard HEAD~1
# 效果:commit、暂存区、工作区全部撤销
--soft --mixed --hard
┌──────────┐ ┌──────────┐ ┌──────────┐
暂存区(Staged) │ 保留 ✅ │ │ 清空 ❌ │ │ 清空 ❌ │
├──────────┤ ├──────────┤ ├──────────┤
工作区(Working) │ 保留 ✅ │ │ 保留 ✅ │ │ 清空 ❌ │
└──────────┘ └──────────┘ └──────────┘
使用场景
bash
# 修改最近一次 commit 的内容
git add forgotten-file.js
git commit --amend --no-edit
# 或者
git add forgotten-file.js
git reset --soft HEAD~1
git commit -m "feat: add login (with forgotten file)"
# 撤销最近一次 commit(保留改动)
git reset HEAD~1
# 彻底回退到某个版本(危险操作,慎用)
git reset --hard v1.0.0
三、git revert --- 安全回滚
与
reset不同,revert会创建一个新的 commit 来撤销指定的 commit,不会改变历史。
bash
# 回滚最近一次 commit
git revert HEAD
# 回滚指定 commit
git revert abc1234
# 回滚多个 commit
git revert abc1234..def5678
# 回滚合并 commit(需要指定主线)
git revert -m 1 <merge-commit-hash>
reset vs revert 对比
场景:已 push 到远程的 commit 有问题
git reset --hard HEAD~1
✅ 直接回退
❌ 改变了历史,其他人需要重新 clone
❌ 如果有其他人在基于你的代码开发,会造成灾难
git revert HEAD
✅ 创建新 commit 撤销,不改变历史
✅ 安全,其他人可以正常 pull
❌ 历史中会多一个 "revert" commit
企业规则:已 push 的代码用 revert,未 push 的代码用 reset。
四、git rebase 深入
4.1 rebase vs merge 的本质区别
merge(合并):
* merge commit
|\
| * feature commit 2
| * feature commit 1
|/
* develop commit
rebase(变基):
* feature commit 2
* feature commit 1
* develop commit 2
* develop commit 1
4.2 交互式 rebase(最强大的功能)
bash
# 修改最近 5 次 commit
git rebase -i HEAD~5
# 编辑器显示:
pick abc1234 feat: add login form
pick def5678 feat: add login API
pick ghi9012 fix: fix typo in login
pick jkl3456 feat: add logout button
pick mno7890 fix: fix logout bug
# 命令说明:
# pick = 保留这个 commit
# reword = 保留但修改 commit message
# edit = 保留但修改内容
# squash = 合并到上一个 commit(保留 message)
# fixup = 合并到上一个 commit(丢弃 message)
# drop = 删除这个 commit
# 示例:把 fixup 合并到对应的 feat commit
pick abc1234 feat: add login form
pick def5678 feat: add login API
fixup ghi9012 fix: fix typo in login
pick jkl3456 feat: add logout button
fixup mno7890 fix: fix logout bug
4.3 rebase 的黄金法则
不要对公共分支(main/develop)执行 rebase!
不要对已经 push 到远程且别人正在使用的分支执行 rebase!
为什么?
因为 rebase 会重写 commit hash,
如果别人基于旧的 commit 继续开发,
他们的代码和你的代码就会产生冲突。
五、git bisect --- 二分查找 Bug
bash
# 启动二分查找
git bisect start
# 标记当前版本有 Bug
git bisect bad
# 标记一个已知好的版本
git bisect good v1.0.0
# Git 会自动 checkout 中间的 commit
# 测试后告诉 Git 好坏
git bisect good # 这个版本没问题
git bisect bad # 这个版本有问题
# 重复几次后,Git 会找到引入 Bug 的第一个 commit
# 结束后
git bisect reset
自动化 bisect
bash
# 用脚本自动测试
git bisect start HEAD v1.0.0
git bisect run npm test
# Git 会自动运行 npm test,根据返回值判断好坏
# 0 = good, 非 0 = bad
六、git worktree --- 多分支并行开发
场景:你在开发功能 A,需要紧急修 Bug,但不想 stash 当前工作。
bash
# 在另一个目录 checkout 另一个分支
git worktree add ../hotfix-branch hotfix/fix-bug
# 现在你有两个工作目录:
# 1. 原目录:feature/user-login(继续开发功能 A)
# 2. ../hotfix-branch:hotfix/fix-bug(修 Bug)
# 修完 Bug 后
cd ../hotfix-branch
git add .
git commit -m "fix: critical bug"
git push origin hotfix/fix-bug
# 删除 worktree
git worktree remove ../hotfix-branch
# 查看所有 worktree
git worktree list
七、git archive --- 导出代码快照
bash
# 导出当前分支的代码(不包含 .git 目录)
git archive -o latest.zip HEAD
# 导出指定 tag
git archive -o v1.0.0.zip v1.0.0
# 导出指定目录
git archive -o src.zip HEAD src/
八、git clean --- 清理工作区
bash
# 查看哪些未跟踪文件会被删除(dry run)
git clean -fd --dry-run
# 删除未跟踪的文件和目录
git clean -fd
# 删除被 .gitignore 忽略的文件
git clean -fdx
# 删除所有未跟踪的文件(危险!)
git clean -fdX
九、故障排查手册
9.1 "我的代码去哪了?"
bash
# 查看所有操作记录
git reflog
# 查看 HEAD 指向
git log -1
# 查看分支图
git log --oneline --graph --all
# 查看某个 commit 的详细信息
git show abc1234
9.2 "我误删了文件/分支"
bash
# 恢复删除的文件
git checkout HEAD -- <file>
# 或者
git restore <file>
# 恢复删除的分支
git reflog # 找到最后的 commit
git checkout -b <branch-name> <commit-hash>
9.3 "我 push 了错误的代码"
bash
# 方案1:撤回 push(需要 force push,危险)
git reset --hard HEAD~1
git push --force-with-lease
# 方案2:revert(安全,推荐)
git revert HEAD
git push
9.4 "rebase 冲突太多了"
bash
# 放弃本次 rebase
git rebase --abort
# 或者用 merge 代替
git merge origin/develop
9.5 "git pull 有冲突"
bash
# 方案1:先 rebase 再 pull
git pull --rebase origin main
# 方案2:先 stash 再 pull
git stash
git pull origin main
git stash pop
# 方案3:放弃本地修改
git reset --hard origin/main
9.6 "detached HEAD 是什么?"
bash
# 你 checkout 了一个 commit 而不是分支
git checkout abc1234
# 提示:You are in 'detached HEAD' state.
# 解决:创建一个新分支
git checkout -b temp-branch
# 或者回到之前的分支
git checkout main
9.7 "大文件不小心提交了"
bash
# 从 Git 历史中彻底删除大文件
# 安装 git-filter-repo
pip install git-filter-repo
# 删除指定文件的所有历史
git filter-repo --invert-paths --path large-file.zip
# 或者用 BFG Repo-Cleaner
java -jar bfg.jar --strip-blobs-bigger-than 10M repo.git
十、Git 配置速查
bash
# ===== 查看配置 =====
git config --list # 所有配置
git config --global --list # 全局配置
git config --local --list # 仓库配置
# ===== 设置配置 =====
git config --global <key> <value> # 全局
git config --local <key> <value> # 仓库级
# ===== 删除配置 =====
git config --global --unset <key>
git config --local --unset <key>
# ===== 常用配置项 =====
core.autocrlf # 换行符处理
core.editor # 默认编辑器
pull.rebase # pull 时是否 rebase
push.default # push 默认行为
init.defaultBranch # 默认分支名
十一、Git 别名配置
bash
# 常用别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.last "log -1 --stat"
git config --global alias.unstage "reset HEAD --"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.wip "!git add -A && git commit -m 'WIP: work in progress'"
git config --global alias.undo "reset --soft HEAD~1"
十二、练习清单
学完本章,请完成以下操作:
- 用
git reflog找回一个被git reset --hard删除的 commit - 用
git revert回滚一个已 push 的 commit - 用
git rebase -i把 3 个 commit 压缩成 1 个 - 用
git bisect定位一个引入 Bug 的 commit - 用
git worktree同时在两个分支上工作 - 制造一个 "detached HEAD" 并安全恢复
上一章 :05-企业级CI-CD与代码质量
下一章 :07-完整实战场景演练