研究 Git:合并冲突解决的是意图,不只是标记

冲突标记能够指出文本重叠,却不能告诉我们两个人原本想实现什么。

edyang · 2015-02-05

冲突标记能够指出文本重叠,却不能告诉我们两个人原本想实现什么。

本文使用Git 2.x 与独立演示仓库。Git(分布式版本管理)保存提交对象和引用,工作区、暂存区与提交历史不是同一份状态。每次操作先判断它改变哪个区域,再决定是否适合当前协作情境。

1. 从现象推到机制

三方合并参考共同祖先和两端修改。自动合并成功也可能产生语义冲突,例如一边改变返回单位,另一边增加基于旧单位的判断。真正完成合并,需要恢复双方合理意图并验证相关行为。

研究 Git:合并冲突解决的是意图,不只是标记的处理、反馈与观察关系

图中的四个节点分别表示共同祖先、两端变化、组合实现、行为验证。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。

2. 最小实现与输入条件

先查看冲突路径和双方提交说明,再对照共同祖先。完成编辑后检查差异,确认没有残留标记与被意外删除的业务分支。

1
2
3
4
5
6
git status
git diff --cc
git log --oneline --all -8
# 人工理解并合并后
git add src/Demo.java
git diff --cached

示例在没有私人资料的临时仓库执行。先看 status、diff 与 log,再运行改变状态的命令;共享历史优先新增提交表达修复,不用改写历史掩盖已经发生的变化。

3. 用对照区分原因

下表列出需要主动改变的条件。预期行为来自机制分析,复现时还需记录运行环境和原始输出,不能将预期当作已经测得的结果。

改变的条件 需要验证的行为
两边修改不同文本 仍可能存在契约不兼容
同一判断条件被同时修改 需要解释双方业务目的
删除标记后代码能编译 仍应验证组合后的行为

对照 1:两边修改不同文本

仍可能存在契约不兼容。观察时记录调用方与被调方的共同假设。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 2:同一判断条件被同时修改

需要解释双方业务目的。观察时记录共同祖先与两端变化。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 3:删除标记后代码能编译

仍应验证组合后的行为。观察时记录原有两组场景是否都通过。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

4. 适用条件与取舍

不要把整文件选择某一边作为默认解决办法。确实放弃一方改动时,应在提交说明中交代被替代的规则和原因。

一次正常运行只覆盖了这组输入。继续扩展前,应把上面的异常对照保留下来,尤其关注“删除标记后代码能编译”这一分支。后续方案若改变了图中任意一处依赖,原来的判断就要重新验证,不能仅凭界面相似或返回值相同沿用结论。

同月延伸

参考资料

  1. Pro Git 第二版
  2. Git 2.2.0 版本说明