Git Merge+Revert 与 Reset+Cherry-pick 步骤对比
左侧为 Merge+Revert 方案,右侧为 Reset+Cherry-pick 方案。
区别:Merge+Revert 方案在复杂合并和回滚时容易引入副作用,可能导致部分内容被意外撤销;而 Reset+Cherry-pick 方案通过重置和精确挑选提交,能更好地避免这些问题,分支内容更安全、可控。
推荐使用 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)
- 备份 b 分支:
git checkout -b temp_b
(当前在 b 分支时)临时分支 temp_b (备份)1 2 3 4 5 6 7 8 9 10 - 切换回 b:
git checkout b
分支 b (当前)1 2 3 4 5 6 7 8 9 10 - 重置 b 到合并前:
git reset --hard <b_before_merge_c_hash>
(假设 `` 是提交 3) 分支 b (reset 后)1 2 3 - 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)