Cherry-pick — 是一条 Git 命令,它将指定提交中的更改应用到当前分支,而不会携带源分支的完整历史。与 merge 或 rebase 不同,cherry-pick 逐个处理每个提交:开发者根据哈希值选择具体的提交,只移动它的更改。根据 Git 文档(2026),当完整的 merge 显得多余或危险时,cherry-pick 特别适合在发布分支之间精确移动修复。该命令会创建一个带新哈希值的新提交,但保留原始消息和作者。
要点
Cherry-pick — 是 git cherry-pick 命令,它从现有提交中提取更改,并将其作为新提交应用到当前分支。源提交保持在原分支中,而在目标分支中会创建更改的副本。当需要移动特定修复而无需移动整个分支时,此命令很有用。
语法:git cherry-pick <commit-hash>。Git 分析指定提交与其父提交之间的差异(diff),并将该差异应用到当前分支。如果多个文件发生更改,它们会一起被移动。该命令也接受范围:git cherry-pick A..B — 从 A 到 B 的所有提交,不包括 A。
标志扩展了功能:-n(--no-commit)将更改应用到工作目录和索引而不创建提交 — 当需要将多个提交的更改合并为一个时很有用。-x 标志会在提交消息中添加一行(cherry picked from commit ...),从而简化在历史中跟踪更改来源。
# 按哈希值 cherry-pick 单个提交
git cherry-pick a1b2c3d
# Cherry-pick 多个提交(按顺序)
git cherry-pick a1b2c3d e4f5g6h i6j7k8l
# 不自动提交的 cherry-pick
git cherry-pick -n a1b2c3d
# -x 标志会添加对原始提交的引用
git cherry-pick -x a1b2c3d
主要场景 — 在发布分支之间移动修复。设想一下:在 develop 中发现并修复了一个严重 bug。release/v2.1 发布分支已经分离,其中也存在这个 bug。将整个 develop merge 到 release 会带来大量未完成的代码,而 cherry-pick 一个包含修复的提交则是安全而精确的解决方案。
第二种场景 — 撤销更改(revert)之后再进行恢复。如果一个提交通过 git revert 被撤销,之后发现撤销是错误的 — cherry-pick 被撤销的提交可以恢复更改。这比撤销 revert 更正确,因为它不会产生重复冲突。
第三种场景 — 合并来自不同 feature 分支的提交到一个测试分支中进行集成测试。与其合并多个未完成的分支(带有未完成的代码),不如从每个分支中选择已完成的提交并测试它们协同工作。
Cherry-pick 与 rebase 和 merge 的区别在于它作用于单个提交层面,而不是整个分支。如果 rebase 移动分支的所有提交,merge 合并两个分支,那么 cherry-pick 只选择需要的提交。这使它成为一个更精确的工具,但也更加手动。
另一个区别 — 作者身份。在 cherry-pick 中,Git 默认保留原始提交的作者(Author),但提交者(Committer)变成当前用户。通过 -x 标志可以在提交消息中跟踪来源。在 rebase 中,作者和提交者都是带新哈希值的当前用户。
性能:cherry-pick 一个提交比 merge 两个包含大量提交的分支更快。但如果需要移动数十个提交,最好创建一个临时分支并执行 rebase — 这样更高效,也不需要指定数十个哈希值。
| 操作 | 适用范围 | 副作用 |
|---|---|---|
| Cherry-pick | 单个提交 | 新哈希值,代码重复 |
| Rebase | 分支的所有提交 | 重写历史,新哈希值 |
| Merge | 完整合并分支 | Merge 提交,保留历史 |
多个提交可以用一条命令移动,用空格列出它们的哈希值:git cherry-pick A B C。Git 会按指定顺序依次应用提交。如果某个提交引起冲突,cherry-pick 会暂停,开发者必须解决冲突,之后用 git cherry-pick --continue 命令继续。
提交范围:git cherry-pick A..B(A 之后到 B 的所有提交,不包括 A)和 git cherry-pick A^..B(从 A 开始到 B 的所有提交,包括 A)。当需要移动一个分支中的所有提交但无需父级关联时,范围很方便 — 例如,将完成的 feature 从旧分支移动到新分支。
--strategy 标志决定 Git 如何应用更改。默认使用 recursive 策略,但可以指定 ours 或 theirs 来自动选择冲突的一侧。--mainline 标志用于 cherry-pick merge 提交 — 指定计算 diff 所依据的父级编号(1 或 2)。
# Cherry-pick 提交范围
git cherry-pick develop~5..develop~2
# Cherry-pick merge 提交(指定父级)
git cherry-pick -m 1 m9n0o1p
# 使用 theirs 策略
git cherry-pick --strategy=recursive \
--strategy-option=theirs a1b2c3d
# 解决冲突后继续
git cherry-pick --continue
Cherry-pick 时的冲突发生在被移动提交的更改触及目标分支中已被修改的相同行时。Git 暂停执行,标记冲突文件并等待解决。在状态中,此类文件显示为 both modified。
冲突时的操作顺序:打开冲突文件,找到冲突标记(<<<<<<<、=======、>>>>>>>),编辑内容,移除标记,为已解决的文件执行 git add,然后运行 git cherry-pick --continue。如果冲突无法解决 — git cherry-pick --abort 会取消整个 cherry-pick,将分支恢复到原始状态。
常见问题:提交已经包含与现有更改等效的更改。在这种情况下,Git 在尝试 cherry-pick 时会报告“nothing to commit”或“empty commit”。--keep-redundant-commits 和 --empty=keep 标志会强制 Git 创建空提交以保持顺序,而 --skip 允许跳过这样的提交。
# Cherry-pick 期间发生冲突 — 停止
git cherry-pick a1b2c3d
# 错误:无法应用 a1b2c3d... 提交消息
# 解决冲突 → 添加到索引
git add src/conflicted_file.swift
git cherry-pick --continue
# 跳过空提交(已应用)
git cherry-pick --skip
# 完全中止
git cherry-pick --abort
第一条规则:始终检查被移动的提交是否自包含。如果提交 A 依赖提交 B 中的更改,而 B 没有被移动,那么 cherry-pick A 可能会破坏构建。在 cherry-pick 之前,最好通过 git show --stat <hash> 检查提交修改了哪些文件。
第二条规则:记录 cherry-pick。使用 -x 标志,以便在提交消息中保留对源提交的引用。这将有助于在后续分析历史时理解更改的来源。没有 -x,cherry-pick 看起来像一个普通提交,它的来源只能通过 git log --graph 来确定。
第三条规则:避免在分歧过大的分支之间进行 cherry-pick。如果自提交创建以来已过去很长时间且代码库发生重大变化,冲突将变得众多且复杂。在这种情况下,最好在目标分支中重新进行修复 — 这比解决数十个冲突花费的时间更少。
常见问题
Cherry-pick 提交 — 通过 git cherry-pick 将指定提交的更改应用到当前分支。该命令创建一个新提交,具有相同的更改但新的哈希值。源提交在其分支中保持不变。当只需要一个特定提交时,这是合并整个分支的替代方案。
Cherry-pick 在需要移动一个或多个特定提交而无需移动整个分支时被选择。Merge 用于完整合并分支。cherry-pick 的典型场景 — 将 bug 修复从开发分支移动到发布分支,而发布分支中其他更改尚未准备好。
在完成之前 — git cherry-pick --abort 完全取消操作。成功完成之后 — git revert <hash> 创建一个取消 cherry-pick 更改的提交。与 --abort 的区别:revert 不会从历史中删除提交,而是创建一个新的反向提交。
当更改已经存在于目标分支时,会出现空提交。使用 git cherry-pick --skip 跳过这样的提交,或使用 git cherry-pick --keep-redundant-commits 创建空提交以保持哈希序列。
Cherry-pick 将选定的提交(单个或列表)移动到当前分支。Rebase 将分支的所有提交移动到新基线上。Cherry-pick 不会更改源分支,rebase 会重写历史。Cherry-pick 精确但手动;rebase 自动化但可能对公共分支造成危险。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。