(三)分支与合并 - git cherry-pick 命令的使用
文章目录
- 1. 命令概述
- 2. 命令格式
- 3. 基本用法
- 4. 高级用法
- 4.1 一次采摘多个提交
- 4.2 采摘一个范围内的提交
- 4.3 编辑提交信息 (-e)
- 4.4 不自动提交 (-n / --no-commit)
- 4.5 在提交信息中追加来源 (-x)
- 4.6 遇到冲突时
- 5.注意事项
- 5.1 使用场景
- 5.2 注意事项
- 6. 补充信息
1. 命令概述
核心思想:git cherry-pick 的作用是“采摘”一个或多个已有的提交,并将这些提交的更改作为一个新的提交应用到当前分支上。
形象比喻:想象你的 Git 提交历史是一棵樱桃树,每个提交都是一颗樱桃。cherry-pick 允许你从树的任意枝干(分支)上,精准地摘下一颗或几颗樱桃(提交),然后嫁接到你当前的枝干(分支)上。
与 merge 和 rebase 的区别:
merge:将整个分支的所有更改整合到另一个分支,会产生一个合并提交。rebase:将一个分支的所有提交“重新播放”到另一个分支的末端,从而形成线性的历史。cherry-pick:选择性地应用某些提交,而不是整个分支。它只关心你指定的一个或多个提交的更改。
2. 命令格式
最基本的命令格式如下:
git cherry-pick <commit-hash>
你也可以一次应用多个提交:
git cherry-pick <commit-hash-A> <commit-hash-B> <commit-hash-C>
或者使用范围(但请注意,这会按顺序应用从 A 到 B 的所有提交,不包括 A,但包括 B)
git cherry-pick <commit-hash-A>..<commit-hash-B>
如果要包括 A,需要使用:
git cherry-pick <commit-hash-A>^..<commit-hash-B>
3. 基本用法
假设我们有以下提交历史:
C---D---E feature/branch (特性分支)/
A---B---F---G main (主分支)
现在,你在 main 分支上工作,但你只想将特性分支上的提交 D 的更改应用到 main 分支。
1.切换到目标分支:
git checkout main
2.执行 cherry-pick:
git cherry-pick D
这里的 D 是提交 D 的哈希值(例如 a1b2c3d)。
3.结果:
Git 会计算提交 D 引入的更改,并尝试将其应用到 main 分支的当前提交 G 上。如果成功,历史会变成:
C---D---E feature/branch/
A---B---F---G---D' main
注意:D' 是一个全新的提交,它的内容和提交信息与 D 相同,但哈希值不同,因为它的父提交是 G。
4. 高级用法
4.1 一次采摘多个提交
按顺序指定它们的哈希值:
git cherry-pick D E
这会在 main 分支上按顺序创建两个新提交 D' 和 E'。
4.2 采摘一个范围内的提交
如果你想将 C 到 E 的所有提交(包括 C 和 E)都应用到 main:
git cherry-pick C^..E
或者
git cherry-pick B..E # 因为 B 是 C 的父提交,B..E 包括 C, D, E
4.3 编辑提交信息 (-e)
默认情况下,cherry-pick 会使用原提交的提交信息。如果你想在应用时修改它,可以加上 -e 选项,这会打开编辑器让你修改。
git cherry-pick -e D
4.4 不自动提交 (-n / --no-commit)
这个选项非常有用。它会让 Git 将更改应用到工作区和暂存区,但不会自动创建提交。这允许你:
- 检查一下应用的更改是否正确。
- 将多个
cherry-pick的更改合并成一个提交。 - 对代码做一些调整后再提交。
git cherry-pick -n D
# 检查更改,或者继续修改...
git commit -m “手动合并特性D的更改,并做了调整”
4.5 在提交信息中追加来源 (-x)
在自动生成的提交信息中,会追加一行 (cherry picked from commit <original-commit-hash>)。这在大型项目中非常有助于追溯提交的原始来源,推荐在合入上游更改时使用。
git cherry-pick -x D
4.6 遇到冲突时
cherry-pick 和 merge、rebase 一样,可能会遇到冲突。
- 解决冲突:手动编辑标记了冲突的文件。
- 标记已解决:使用
git add <file-name>将解决后的文件标记为已解决。 - 继续:运行
git cherry-pick --continue来完成操作。 - 中止:如果你想放弃整个
cherry-pick操作,回到执行前的状态,运行git cherry-pick --abort。 - 跳过:跳过当前这个提交(在一次性采摘多个提交时有用),运行
git cherry-pick --skip。
5.注意事项
5.1 使用场景
1.修复特定 bug:一个 bug 在 main 和 develop 分支上都存在。你在 develop 分支上修复并提交了。你可以直接 cherry-pick 这个修复提交到 main 分支,而无需合并整个 develop 分支。
2.移植特定功能:一个功能由多个提交构成,但你现在只想将其中的一两个核心提交应用到稳定版分支。
3.代码审查后重构:在代码审查后,你在一个特性分支上创建了新的提交来重构代码。你可以只 cherry-pick 这个重构提交到主分支,而不引入其他试验性代码。
4.撤销错误的合并:有时可以用 cherry-pick 将正确的提交应用到被错误合并的分支上,但这需要谨慎操作。
5.2 注意事项
1.破坏提交依赖:这是 cherry-pick 最大的风险。如果提交 E 依赖于提交 C 和 D 的更改,而你只 cherry-pick 了 E,那么代码很可能无法编译或运行不正确。务必确保你采摘的提交是自包含的,或者你理解并处理了所有依赖。
2.创建重复提交:如果你 cherry-pick 了一个已经被合并过的提交,会导致历史中出现两个内容几乎相同的提交,造成混乱。使用 -x 选项可以在一定程度上缓解这个问题。
3.非首选工作流:cherry-pick 是一种“救火”或“精细化”操作的工具。对于常规的功能集成,merge 或 rebase 通常是更推荐的方式,因为它们能更好地保留完整的历史和上下文。
4.哈希值改变:牢记 cherry-pick 创建的是新提交,所以哈希值会改变。这意味着你不能通过哈希值来简单地判断两个分支上的提交是否是同一个“物理”提交。
6. 补充信息
与 git merge 和 git rebase 的对比总结
| 特性 | git cherry-pick | git merge | git rebase |
|---|---|---|---|
| 操作对象 | 一个或多个特定提交 | 整个分支(最新提交) | 整个分支(一系列提交) |
| 历史记录 | 选择性复制提交 | 历史可能不连贯 创建合并提交 | 保留分支结构 线性历史,重写提交历史 |
| 适用场景 | 移植单个修复/功能,选择性应用更改 | 集成完整功能,合并长期分支 | 清理本地历史,在合并前整理提交 |
| 风险 | 可能破坏提交依赖 | 历史可能变得复杂(菱形历史) | 重写公共历史是危险的 |
