Git 分支操作避坑指南:merge、cherry-pick、revert 与 reset 怎么选?
Git 中有四类操作经常被混淆:合并分支、挑选提交、撤销远程代码、重置本地历史。
它们都可能让代码"发生变化",但解决的并不是同一个问题。真正需要判断的是:要处理整个分支还是部分提交,以及这些提交是否已经共享。
本文统一使用 a 作为来源分支,b 作为接收改动的目标分支。
先看场景,再选命令
| 你的需求 | 应该使用 | 核心作用 |
|---|---|---|
把 a 的整体开发成果合并到 b |
merge |
合并分支 |
只把 a 上的某几个提交带到 b |
cherry-pick |
挑选提交 |
| 错误提交已经推送,需要保留记录并撤销代码 | revert |
新增一条反向提交 |
| 提交尚未推送,只想整理本地历史 | reset |
移动本地分支位置 |
最简单的记忆方式是:
整体合并用 merge,部分提交用 cherry-pick;远程撤销用 revert,本地整理用 reset。
Merge:整个分支都需要
应用场景
a 是已经开发完成的功能分支,里面的提交基本都需要进入 b。这时应该保留完整的开发过程,把两个分支的历史合并起来。
bash
git switch b
git merge a
合并的接收方永远是当前分支。先切换到 b,再执行 git merge a,表示把 a 合并到 b。
不适合的场景
如果 a 上只有一两个修复需要进入 b,其余功能还没有完成,整体 merge 会带入不需要的代码。此时更适合使用 cherry-pick。
Cherry-pick:只需要部分提交
应用场景
a 分支上有一个重要修复,但 b 不需要 a 的其他开发内容。例如:
- 从开发分支挑选一个修复到发布分支;
- 把某个补丁同步到多个维护版本;
- 临时迁移少量彼此独立的提交。
bash
git switch b
git cherry-pick
cherry-pick 迁移的是提交产生的改动,并在 b 上创建一条新提交,因此新旧提交的哈希值不同。
不适合的场景
如果需要迁移大量相互依赖的提交,逐个 cherry-pick 容易遗漏提交,也容易产生冲突。此时应该重新评估是否直接 merge 更合适。
Revert:远程保留记录,但代码需要撤销
应用场景
错误提交 C 已经推送到远程,其他开发者可能已经拉取。现在既不能删除远程记录,又必须撤销它带来的代码。
text
撤销前:A --- B --- C
撤销后:A --- B --- C --- R
撤销 C
revert 会新增反向提交 R:原提交 C 继续保留在历史中,但它引入的代码被 R 抵消。
bash
git revert
git push origin b
这正适合以下情况:
- 线上提交出现问题,需要安全回滚;
- 主分支或共享分支中的改动需要撤销;
- 团队要求保留完整、可审计的提交记录。
如果只想撤销某次提交中的一部分代码,可以使用 git revert --no-commit 先生成反向改动,检查并调整范围后再提交。
不适合的场景
如果错误提交从未推送,只存在于自己的本地分支,使用 revert 会额外增加一条撤销记录。本地历史整理通常使用 reset 更直接。
Reset:整理尚未共享的本地历史
应用场景
reset 主要用于处理尚未推送的本地提交。它不会生成新的撤销记录,而是让当前分支回到指定提交。
假设 C 是刚完成但尚未推送的本地提交:
text
重置前:A --- B --- C
重置后:A --- B
分支都会退回 B,三种模式的区别在于 C 中的代码如何处理:
| 模式 | C 的提交记录 | C 的代码 | 典型用途 |
|---|---|---|---|
--soft |
从当前分支移除 | 保留并处于已暂存状态 | 修改提交说明、重新提交 |
--mixed |
从当前分支移除 | 保留但取消暂存 | 拆分提交、继续修改代码 |
--hard |
从当前分支移除 | 一并丢弃 | 删除确定不需要的本地实验 |
bash
git reset --soft HEAD~1
git reset --mixed HEAD~1
git reset --hard HEAD~1
其中 HEAD~1 表示当前提交的上一个提交。
不适合的场景
如果提交已经推送到共享分支,reset 会造成自己的历史与远程历史不一致。想让远程接受改写后的历史,通常需要强制推送,并可能覆盖其他人的提交。
因此,公共分支需要撤销代码时优先使用 revert。reset --hard 也应格外谨慎,因为它会同时丢弃受 Git 管理的本地文件改动。
五个常见需求,快速做出选择
功能分支开发完成,准备进入主分支
使用 merge,因为需要的是整个分支。
只想把一个紧急修复同步到发布分支
使用 cherry-pick,因为只需要某次提交。
错误代码已经推送,但远程记录必须保留
使用 revert,让远程新增撤销记录,同时恢复代码。
本地刚提交就发现提交说明写错
使用 reset --soft,保留代码和暂存状态后重新提交。
本地实验完全失败,提交和代码都不要了
确认没有需要保留的内容后,使用 reset --hard 回到实验前的提交。
最容易犯的三个错误
合并方向弄反
要把 a 合并到 b,应先切换到 b,再执行 git merge a。
已经推送的提交直接 reset
这会改写共享历史。远程记录需要保留时,应使用 revert。
把 reset --hard 当成普通撤销按钮
--hard 会丢弃本地文件改动。只想重新整理提交时,通常应该使用 --soft 或 --mixed。
总结
Git 命令的选择可以归结为两个问题:
- 需要的是整个分支,还是部分提交?
- 提交只存在于本地,还是已经共享到远程?
对应关系如下:
- 整个分支进入目标分支:
merge; - 只迁移少量指定提交:
cherry-pick; - 保留远程历史并撤销代码:
revert; - 整理尚未共享的本地提交:
reset。
不要把"回滚"当成一个统一动作。先判断历史是否已经共享,再决定使用 revert 还是 reset,才能避免把一次简单撤销变成团队事故。
发布摘要与标签
公众号导语 / 掘金文章简介:
merge、cherry-pick、revert 和 reset 分别适用于哪些场景?本文不堆砌命令,而是从整体合并、挑选提交、远程撤销和本地历史整理四类实际需求出发,讲清它们的选择边界。
推荐标签:
Git、版本控制、开发工具、工程实践、代码管理