Skip to content

Git Rebase 与 Cherry-pick 实用指南

背景

在分支合并场景中,经常需要整理提交历史:合并部分提交、保留部分提交、或将特定提交应用到另一个分支。git rebasegit cherry-pick 是完成这些操作的核心命令。

Git Rebase

基本用法

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

bash
git rebase -i <起始commit>

编辑器中会列出从起始 commit 之后的所有提交:

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

在编辑器中将 c2 改为 squash:

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 跳过手动编辑,用 sed 自动将指定范围的 pick 替换为 squash

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

切换默认编辑器

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

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

# 通过环境变量全局生效(写入 ~/.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 可以两端都包含。

典型场景:rebase 后重建提交

结合 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
  • 少量提交用交互式 rebase,大量提交用 git reset --softGIT_SEQUENCE_EDITOR + sed
  • cherry-pick 范围 A..B 是左开右闭,A^..B 是两端包含
  • rebase 前建议先创建备份分支:git branch feat-backup feat

基于 VitePress 构建