Skip to content

Git Rebase 与 Cherry-pick 实用指南 ​

分支合并场景中经常需要整理提交历史:把若干提交压成一个、丢弃中间过程提交、或把某个提交单独应用到另一个分支。git rebase 和 git cherry-pick 是完成这些操作的核心命令。本文覆盖两者的常用姿势:交互式 rebase 的命令清单、少量与大量提交的压缩方案、cherry-pick 的范围语法,以及改写历史后的推送注意事项。

Git Rebase ​

基本用法 ​

交互式 rebase 可以对一系列提交重新编排:

bash
git rebase -i <起始commit>

编辑器中会列出起始 commit 之后的全部提交:

text
pick abc1234 c1 message
pick def5678 c2 message
pick ghi9012 c3 message

可用的操作命令:

命令 缩写 作用
pick p 保留该提交不变
squash s 将该提交压缩到前一个提交,合并 commit message
fixup f 同 squash,但丢弃该提交的 commit message
reword r 保留提交,但修改 commit message
edit e 暂停在该提交,可修改内容后继续
drop d 丢弃该提交

典型场景:合并部分提交 ​

假设 feat 分支上有 5 个提交(c1-c5),合并到 develop 前想把 c1、c2 压缩为一个提交:

bash
git checkout feat
git rebase -i c1~1

c1~1 表示 c1 的父提交,rebase 的编辑列表从 c1 开始。在编辑器中将 c2 一行改为 squash:

text
pick   c1  message
squash c2  message
pick   c3  message
pick   c4  message
pick   c5  message

保存后编辑合并后的 commit message。完成后合并到 develop:

bash
git checkout develop
git merge feat

develop 上的提交历史变为 c1'、c3、c4、c5。

大量提交的压缩 ​

当需要压缩的提交数量很多(如 100 个),逐行手改编辑器不现实,有两种替代方案。

方案一:soft reset + 重新提交

bash
# 找到第 N+1 个提交的 hash
git log --oneline | head -n 101 | tail -n 1

# soft reset 到前 N 个提交之前,改动全部回到暂存区
git reset --soft <第N+1个提交的父提交>

# 重新提交压缩后的内容
git commit -m "合并前N个提交的信息"

# 把剩余提交 cherry-pick 回来
git cherry-pick <c_{N+1}>..<feat的HEAD>

方案二:用 sed 自动替换

通过 GIT_SEQUENCE_EDITOR 环境变量替换 rebase 的序列编辑器,用 sed 自动把指定范围的 pick 改为 squash:

bash
# 将 todo 列表第 2 到第 100 行的 pick 替换为 squash
GIT_SEQUENCE_EDITOR="sed -i '2,100s/^pick/squash/'" git rebase -i <起始commit>

GIT_SEQUENCE_EDITOR 只影响 rebase 生成的提交序列编辑,不改变其他 Git 行为。

切换默认编辑器 ​

交互式 rebase 依赖文本编辑器,不想用默认编辑器时可以临时或永久指定:

bash
# 全局设置为 vim
git config --global core.editor "vim"

# 临时使用 vim
GIT_EDITOR=vim git rebase -i ...

# 通过环境变量全局生效(写入 ~/.bashrc 或 ~/.zshrc)
export EDITOR=vim
export VISUAL=vim

Git Cherry-pick ​

基本用法 ​

将指定的提交应用到当前分支:

bash
git cherry-pick <commit-hash>

批量操作 ​

cherry-pick 支持范围语法,一次应用多个提交:

bash
# 左开右闭:不含 c3,含 c5
git cherry-pick c3..c5

# 两端都包含:含 c3 和 c5
git cherry-pick c3^..c5

多个不连续的提交也可以一次指定:

bash
git cherry-pick c3 c7 c10

范围语法 A..B 是左开右闭(不含 A,含 B);用 A^..B 可以两端都包含。

典型场景:压缩后重建提交 ​

结合 soft reset 使用,先压缩一批提交,再把剩余提交按范围 cherry-pick 回来:

bash
# 将前 100 个提交压缩为一个
git reset --soft <base-commit>
git commit -m "feat: 初始实现"

# 将剩余提交按范围 cherry-pick 回来
git cherry-pick c101^..c150

要点 ​

  • rebase 会改写提交历史。已完成 rebase 的分支如果已推送到远程,再次推送需要 git push --force-with-lease——它在远端被他人更新过时会拒绝推送,比裸 git push -f 安全
  • 少量提交用交互式 rebase,大量提交用 git reset --soft 或 GIT_SEQUENCE_EDITOR + sed
  • cherry-pick 范围 A..B 是左开右闭,A^..B 是两端包含
  • rebase 前建议先创建备份分支:git branch feat-backup feat,操作失误时可以从备份恢复
最近更新

基于 VitePress 构建