Git Rebase 与 Cherry-pick 实用指南
背景
在分支合并场景中,经常需要整理提交历史:合并部分提交、保留部分提交、或将特定提交应用到另一个分支。git rebase 和 git 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 --soft或GIT_SEQUENCE_EDITOR+ sed - cherry-pick 范围
A..B是左开右闭,A^..B是两端包含 - rebase 前建议先创建备份分支:
git branch feat-backup feat