Git Merge+Revert 与 Reset+Cherry-pick 步骤对比

左侧为 Merge+Revert 方案,右侧为 Reset+Cherry-pick 方案。
区别:Merge+Revert 方案在复杂合并和回滚时容易引入副作用,可能导致部分内容被意外撤销;而 Reset+Cherry-pick 方案通过重置和精确挑选提交,能更好地避免这些问题,分支内容更安全、可控。
推荐使用 Reset+Cherry-pick 方案。
方案一:Merge + Revert 方案二:Reset + Cherry-pick
阶段1:初始状态
a:
b: 123
c: 45678
阶段1:初始状态
a:
b: 123
c: 45678
阶段2:b 合并 c 并继续开发
b: 12345678910
阶段2:b 合并 c 并继续开发
b: 12345678910
阶段3:b 回滚合并, b 继续开发
b: 12 3 4 5 6 7 8 910revert(merge c)
差异:
此时 revert(merge c) 实际撤销了 4,5,6,7,8 的更改,但 9,10 依然保留。
阶段3:b 重置并 cherry-pick
b: 123910
差异:
左侧通过 revert 撤销合并,右侧直接 reset 到合并前并 cherry-pick 新提交,避免了 revert 带来的副作用。
阶段4:a 合并 c 的 4,5,6
a: 456
阶段4:a 合并 c 的 4,5,6
a: 456
阶段5:a 合并 b
a: 456123 4 5 6 7 8revert(merge c)910
差异:
revert(merge c) 也被合并进 a,导致 a 上 4,5,6 的更改被撤销。
阶段5:a 合并 b
a: 456123910
差异:
没有 revert(merge c) 的副作用,a 上 4,5,6 保持不变。
最终结果
a: 456123revert(merge c)910
a 分支的 4,5,6 被 revert(merge c) 撤销,内容丢失。
最终结果
a: 456123910
a 分支完整保留了 4,5,6,没有被撤销,内容安全。

阶段 1: a, b, c 分支初始状态

分支 a
分支 b
1 2 3
分支 c
4 5 6 7 8

(初始状态,a 为空,b 有 1, 2, 3,c 有 4, 5, 6, 7, 8)

阶段 2: b 合并 c

分支 b
1 2 3 4 5 6 7 8
分支 c (不变)
4 5 6 7 8
分支 a (不变)

(b 合并 c,来自 c 的提交颜色为橙色)

阶段 3: b 回滚合并, b 继续开发

分支 b
1 2 3 4 5 6 7 8 9 10 revert(merge c)
分支 c (不变)
4 5 6 7 8
分支 a (不变)

(b 回滚合并 c 后继续开发)

阶段 4: a 合并 c 的 4, 5, 6

分支 a
4 5 6
分支 b (不变)
1 2 3 4 5 6 7 8 revert(merge c) 9 10
分支 c (不变)
4 5 6 7 8

(a 合并 c 的部分提交,颜色为橙色)

阶段 5: a 合并 b

分支 a (合并 b 后)
4 5 6 1 2 3 4 5 6 7 8 revert(merge c) 9 10
分支 b (不变)
1 2 3 4 5 6 7 8 revert(merge c) 9 10
分支 c (不变)
4 5 6 7 8

(a 合并 b,来自 b 的提交颜色为绿色)

阶段 6: a 分支最终状态 (体现 revert 效果)

分支 a (最终状态)
4 5 6 1 2 3 revert(merge c) 9 10
分支 b
1 2 3 revert(merge c) 9 10
分支 c
4 5 6 7 8

注意:被 revert 的来自 c 的提交在 a 分支上显示为删除线。

阶段 1: 初始状态

分支 a
分支 b
1 2 3
分支 c
4 5 6 7 8

(初始状态)

阶段 2: b 合并 c,并继续开发

分支 b
1 2 3 4 5 6 7 8 9 10
分支 c (不变)
4 5 6 7 8
分支 a (不变)

(b 合并了 c,之后又有提交 9 和 10)

阶段 3: b 重置和 Cherry-pick (带备份)

分支 b (reset 和 Cherry-pick)
  1. 备份 b 分支: git checkout -b temp_b (当前在 b 分支时)
    临时分支 temp_b (备份)
    1 2 3 4 5 6 7 8 9 10
  2. 切换回 b: git checkout b
    分支 b (当前)
    1 2 3 4 5 6 7 8 9 10
  3. 重置 b 到合并前: git reset --hard <b_before_merge_c_hash> (假设 ` ` 是提交 3)
    分支 b (reset 后)
    1 2 3
  4. Cherry-pick 提交 9 和 10: git cherry-pick <hash_of_9>
    git cherry-pick <hash_of_10>
    或者批量操作git cherry-pick <merge_commit_hash>^..<latest_b_hash>
    分支 b (cherry-pick 后)
    1 2 3 9 10
分支 c (不变)
4 5 6 7 8
分支 a (不变)

(b 重置并 cherry-pick 完成,temp_b 作为备份)

阶段 4: a 合并 c 的 4, 5, 6

分支 a
4 5 6
分支 b (状态如阶段 3 结束)
1 2 3 9 10
分支 c (不变)
4 5 6 7 8

(a 合并了 c 的部分提交)

阶段 5: a 合并 b

分支 a (合并 b 后)
4 5 6 1 2 3 9 10
分支 b (不变)
1 2 3 9 10
分支 c (不变)
4 5 6 7 8

(a 合并了 b)

阶段 6: a 分支最终状态

分支 a (最终状态)
4 5 6 1 2 3 9 10
分支 b
1 2 3 9 10
分支 c
4 5 6 7 8

(最终,a 包含了来自 c 的 4, 5, 6 和来自 b 的 1, 2, 3, 9, 10)