Appearance
拣选 (Cherry-pick)
概述
Git Cherry-pick 允许你选择性地将某个提交应用到当前分支。这在需要从其他分支获取特定修改时非常有用,而不需要合并整个分支。
什么是 Cherry-pick
Cherry-pick 就像是"摘樱桃"——从一棵树(分支)上挑选你需要的果实(提交),移植到另一棵树上。它可以将任意提交的修改复制到当前分支。
Cherry-pick 的特点
- 选择性合并:只获取需要的提交
- 精确控制:避免引入不需要的修改
- 灵活性高:可以在任意分支间操作
- 创建新提交:产生新的提交哈希
git cherry-pick 用法
基本用法
bash
# 拣选单个提交
git cherry-pick <commit-hash>
# 拣选多个提交
git cherry-pick <commit1> <commit2> <commit3>
# 拣选提交范围
git cherry-pick <start-commit>..<end-commit>
# 拣选范围(不包含起始提交)
git cherry-pick <start-commit>..<end-commit>
# 拣选范围(包含起始提交)
git cherry-pick ^<start-commit>..<end-commit>常用选项
bash
# 只应用修改,不自动提交
git cherry-pick -n <commit-hash>
git cherry-pick --no-commit <commit-hash>
# 编辑提交信息
git cherry-pick -e <commit-hash>
git cherry-pick --edit <commit-hash>
# 使用原始提交信息
git cherry-pick -x <commit-hash>
# 保留原始作者信息
git cherry-pick --keep-redundant-commits
# 自动提交(默认行为)
git cherry-pick --commit
# 处理冲突时使用我们的版本
git cherry-pick --ours
# 处理冲突时使用他们的版本
git cherry-pick --theirs高级用法
bash
# 拣选并修改提交信息
git cherry-pick -e <commit-hash>
# 拣选合并提交
git cherry-pick -m <parent-number> <merge-commit>
# 拣选时保留原始提交时间
git cherry-pick --allow-empty
# 从另一个仓库拣选
git cherry-pick --strategy=recursive -X theirs <commit>选择性合并提交
场景一:从开发分支拣选 Bug 修复
bash
# 1. 查看开发分支的提交历史
git log --oneline feature/development
# 输出示例:
# a1b2c3d 添加用户登录功能
# e4f5g6h 修复密码验证 Bug
# i7j8k9l 优化数据库查询
# m0n1o2p 修复 XSS 漏洞
# 2. 切换到主分支
git checkout main
# 3. 只拣选 Bug 修复
git cherry-pick e4f5g6h
git cherry-pick m0n1o2p
# 4. 推送到远程
git push origin main场景二:批量拣选提交
bash
# 1. 查看需要拣选的提交范围
git log --oneline feature-branch
# 输出:
# commit-d (HEAD) 最新提交
# commit-c
# commit-b
# commit-a 起始提交
# 2. 拣选从 commit-a 到 commit-d 的所有提交
git cherry-pick commit-a..commit-d
# 或者使用 ^ 包含起始提交
git cherry-pick ^commit-a~1..commit-d场景三:拣选合并提交
bash
# 合并提交有两个父提交,需要指定使用哪个
git cherry-pick -m 1 <merge-commit>
# -m 1 表示使用第一个父提交(主分支)
# -m 2 表示使用第二个父提交(合并进来的分支)使用场景
1. 热修复发布
bash
# 开发分支修复了紧急 Bug
# feature-branch: fix-critical-bug
# 发布分支需要这个修复
git checkout release/v1.2
git cherry-pick fix-critical-bug
# 推送发布
git push origin release/v1.22. 回退错误的提交
bash
# 如果拣选了错误的提交,可以回退
git cherry-pick --abort
# 或者重置到拣选前的状态
git reset --hard HEAD~13. 重建提交历史
bash
# 创建新分支,拣选需要的提交
git checkout -b new-feature
# 按顺序拣选提交
git cherry-pick commit-a
git cherry-pick commit-b
git cherry-pick commit-c4. 团队协作中的选择性合并
bash
# 团队成员的分支有多个功能
# 只需要其中一个功能
# 查看提交
git log --oneline teammate-branch
# 拣选特定功能的提交
git cherry-pick feature-specific-commit处理冲突
冲突发生时的处理
bash
# 当拣选发生冲突时
git cherry-pick <commit>
# error: could not apply <commit>...
# hint: after resolving the conflicts, mark the corrected paths
# 查看冲突文件
git status
# 手动解决冲突
# 编辑冲突文件...
# 标记为已解决
git add <resolved-files>
# 继续 cherry-pick
git cherry-pick --continue
# 或者放弃本次操作
git cherry-pick --abort
# 或者跳过这个提交
git cherry-pick --skip自动解决冲突策略
bash
# 使用我们的版本(当前分支)
git cherry-pick -X ours <commit>
# 使用他们的版本(被拣选的提交)
git cherry-pick -X theirs <commit>
# 忽略空白变化
git cherry-pick -X ignore-space-change <commit>Cherry-pick 工作流程示例
完整的发布修复流程
bash
# 1. 在开发分支修复 Bug
git checkout develop
git commit -m "修复: 用户登录超时问题"
# commit-hash: abc1234
# 2. 拣选到发布分支
git checkout release/v1.0
git cherry-pick abc1234
# 3. 拣选到主分支
git checkout main
git cherry-pick abc1234
# 4. 推送所有分支
git push origin develop release/v1.0 main批量拣选脚本
bash
#!/bin/bash
# 从 feature 分支拣选特定提交到 main
COMMITS=(
"abc1234"
"def5678"
"ghi9012"
)
git checkout main
for commit in "${COMMITS[@]}"; do
echo "Cherry-picking $commit..."
if git cherry-pick "$commit"; then
echo "Success: $commit"
else
echo "Conflict in $commit, please resolve manually"
exit 1
fi
done
echo "All commits cherry-picked successfully!"Cherry-pick vs Merge vs Rebase
| 操作 | 特点 | 适用场景 |
|---|---|---|
| Cherry-pick | 选择性获取提交 | 只需要特定修改 |
| Merge | 合并整个分支 | 完整功能集成 |
| Rebase | 变基重新应用提交 | 保持线性历史 |
对比示例
bash
# Merge:合并所有修改
git merge feature-branch
# Rebase:变基所有提交
git rebase feature-branch
# Cherry-pick:只获取需要的提交
git cherry-pick <specific-commit>最佳实践
1. 使用 -x 选项记录来源
bash
# 在提交信息中添加来源
git cherry-pick -x <commit>
# 提交信息会包含:
# (cherry picked from commit abc1234...)2. 避免重复拣选
bash
# 检查提交是否已经被拣选
git log --oneline --grep="cherry picked from commit abc1234"
# 或者使用 git log 的 --cherry 选项
git log --cherry --oneline main...feature-branch3. 小批量拣选
bash
# 不推荐:一次拣选太多提交
git cherry-pick commit-a..commit-z
# 推荐:分批拣选,便于处理冲突
git cherry-pick commit-a..commit-f
git cherry-pick commit-g..commit-l4. 在功能分支上使用
bash
# 创建专门的功能分支进行拣选
git checkout -b hotfix/login-bug
git cherry-pick <bug-fix-commit>
# 测试通过后合并
git checkout main
git merge hotfix/login-bug常见问题
Q: Cherry-pick 后提交哈希变了?
这是正常现象。Cherry-pick 会创建新的提交,提交哈希会改变,但内容相同。
bash
# 原提交
abc1234 修复登录 Bug
# Cherry-pick 后的新提交
def5678 修复登录 BugQ: 如何查看哪些提交已被拣选?
bash
# 使用 git log 查看带有 cherry-pick 标记的提交
git log --oneline --grep="cherry picked from"
# 使用 git cherry 查看未合并的提交
git cherry -v main feature-branchQ: Cherry-pick 会影响原分支吗?
不会。Cherry-pick 只是复制提交内容,原分支保持不变。
Q: 如何撤销 Cherry-pick?
bash
# 如果 cherry-pick 还在进行中
git cherry-pick --abort
# 如果已经完成,使用 reset
git reset --hard HEAD~1
# 或者创建反向提交
git revert HEAD总结
Git Cherry-pick 是精确控制代码合并的利器:
| 功能 | 命令 | 说明 |
|---|---|---|
| 拣选提交 | git cherry-pick <commit> | 应用指定提交 |
| 拣选范围 | git cherry-pick a..b | 应用提交范围 |
| 不自动提交 | git cherry-pick -n | 只应用修改 |
| 记录来源 | git cherry-pick -x | 添加来源标记 |
| 继续操作 | git cherry-pick --continue | 解决冲突后继续 |
| 放弃操作 | git cherry-pick --abort | 取消拣选 |
使用建议:
- 用于选择性获取特定修改
- 使用
-x选项记录提交来源 - 避免大量拣选,分批进行
- 解决冲突后及时测试
