交互式 rebase — 整理提交历史
# 合并最近 3 个 commit
git rebase -i HEAD~3
# 编辑器打开:
pick abc1234 feat: add login
pick def5678 fix: typo in login
pick ghi9012 fix: another typo
# 改为:
pick abc1234 feat: add login
squash def5678 fix: typo in login
squash ghi9012 fix: another typo
# → 3 个 commit 合并为 1 个整洁的 "feat: add login"
rebase 命令速查
| 命令 | 效果 |
|---|
pick | 保留此 commit |
reword | 保留但改 message |
squash | 合并到上一个 commit,保留 message |
fixup | 合并到上一个,丢弃 message |
drop | 删除此 commit |
edit | 暂停,允许修改 commit 内容 |
# 编辑某个旧 commit
git rebase -i HEAD~5
# 把 pick 改为 edit → git 暂停在那个 commit
# 修改文件 → git add → git commit --amend
# git rebase --continue
# 把一个 commit 拆成两个
git rebase -i HEAD~3
# 标记 edit → reset HEAD^ → 分批 add + commit
变基 vs 合并
# merge: 保留真实历史,产生合并 commit
git merge feature
# 历史:A─B─C─D─E─F (merge commit)
# rebase: 重写历史,线性干净
git checkout feature
git rebase main
# 历史:A─B─C─D'─E' (无额外 merge commit)
原则:公共分支用 merge,个人分支用 rebase。永远不要 rebase 已经 push 的分支。
cherry-pick — 跨分支摘 commit
# 把某个 commit 摘到当前分支
git cherry-pick abc1234
# 摘一串
git cherry-pick abc1234..def5678 # (abc, def]
git cherry-pick abc1234^..def5678 # [abc, def]
# 冲突时:
# 解决冲突 → git add → git cherry-pick --continue
# 放弃:git cherry-pick --abort
# 不自动 commit(方便修改)
git cherry-pick -n abc1234
# 修改... → git add → git commit
bisect — 二分定位 Bug
# 启动
git bisect start
git bisect bad HEAD # 当前版本有 bug
git bisect good v1.0 # v1.0 没有 bug
# Git 自动 checkout 中间版本 → 你测试
# 如果有 bug: git bisect bad
# 如果没有: git bisect good
# 重复 ~log2(N) 次
# Git 定位到引入 bug 的第一个 commit
# 结束: git bisect reset
# 自动化(有测试脚本时)
git bisect start HEAD v1.0
git bisect run npm test # Git 自动二分跑测试
reflog — 后悔药
# 查看所有 HEAD 移动记录(默认保留 90 天)
git reflog
# abc1234 HEAD@{0}: commit: feat: add login
# def5678 HEAD@{1}: rebase (finish): ...
# ghi9012 HEAD@{2}: reset: moving to HEAD~3
# 恢复误删的分支
git branch -D feature # 手抖删了!
git reflog # 找到 feature 最后的 commit
git checkout -b feature HEAD@{3} # 恢复
# 恢复 rebase 前状态
git rebase -i HEAD~5 # rebase 搞砸了!
git reflog # 找到 rebase 前的 HEAD
git reset --hard HEAD@{1}
# 撤销 git reset --hard
git reset --hard HEAD~3 # 啊啊啊不该 reset!
git reflog
git reset --hard HEAD@{1} # 回到 reset 前
stash — 暂存工作区
git stash # 暂存所有改动
git stash pop # 恢复最近一次 stash
git stash list # 查看所有 stash
git stash drop stash@{2} # 删除某个 stash
# 部分 stash
git stash -p # 交互式选择 stash 哪些
# 带消息
git stash save "WIP: refactor parser"
常用场景速查
| 场景 | 命令 |
|---|
| 修改最近一次 commit | commit --amend |
| 撤销工作区改动 | checkout -- <file> |
| 撤销暂存区 | reset HEAD <file> |
| 回退到某版本(保留改动) | reset --soft HEAD~3 |
| 回退到某版本(丢弃改动) | reset --hard <commit> |
| 创建新分支并切换 | checkout -b feature/x |
| 删除远程分支 | push origin --delete feature/x |
| 查看某个文件的改动历史 | log -p -- <file> |
| 看谁改了某行 | blame <file> -L 10,20 |