输入关键词开始搜索

Git 进阶 — rebase / cherry-pick / bisect / reflog

交互式 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"

常用场景速查

场景命令
修改最近一次 commitcommit --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