同一个冲突,正在解第四遍
目标
在冲突标记中看到共同祖先,让 git 记住解决过一次的方案,并通过内容确认 -X ours 和 -s ours 会使结果文件有什么不同。
为什么重要
解决冲突靠的不是技术,而是判断。然而默认的冲突标记缺少判断所需的一项信息——原来是什么。不知道这一点,就无法区分“一方删除的”和“双方改成不同内容的”,选错的话,别人的修改就会悄悄消失。zdiff3 补上了这一栏。而在需要反复做出同一个判断的情形——不断 rebase 长期存在的分支,或定期把发布分支合回来——rerere 能让这个判断只做一次。最后两步要把名字相近、常被弄反的两个旋钮(knob)区分开来。如果出于想带入内容的目的使用 -s ours,历史中会写着已经合并,而代码里什么也没进来。
步骤
- 在
/root/gitx8/repo创建若干分支,它们对同一行做了不同的修改。 - 把默认冲突标记和
zdiff3标记并排保存到notes/zdiff3.txt。 - 打开
rerere,解决一次冲突并完成合并。 - 撤销那次合并后再重新合并,把 git 自己应用了相同解决方案的情形保存到
notes/replay.txt。 - 用
-X ours合并sidefix,并把结果保存到notes/xours.txt。 - 用
-s ours合并legacy,并把结果保存到notes/sours.txt。 - 把两个旋钮的区别整理到
notes/strategies.txt。 - 在
notes/report.md中总结减少重复冲突的方法。
参考
- 每个仓库都要指定
git config user.email和user.name才能提交。提交时间请用GIT_AUTHOR_DATE和GIT_COMMITTER_DATE固定。 - 看过冲突之后,可以用
git merge --abort干净地退回。 - 常见错误:在第 4 步看到 rerere 已经把文件改好了,就以为连提交也完成了。rerere 只应用,不暂存。
- 常见错误:第 6 步之后发现没有
legacy.txt就当作失败。这正是-s ours要做的事,也是这一步的要点。
对同一行做了不同修改的分支
在 /root/gitx8/repo 创建若干分支,它们对同一行做了不同的修改。
把 handler.txt 写成从 a 到 g 的七行,在第一个提交处创建 topic、sidefix、legacy 三个分支。topic 和 main 对第二行做不同的修改,sidefix 修改第二行和第六行。第六行要离得远一些,这样在第 5 步才能看到不发生冲突的那部分改动。
显示原来是什么的那一栏
把默认冲突标记和 zdiff3 标记并排保存到 notes/zdiff3.txt。
先用 git merge topic 制造冲突,原样抄下 handler.txt,再 git merge --abort。然后用 git -c merge.conflictStyle=zdiff3 merge topic 再次制造同样的冲突,就会多出一栏。请补充一行说明那一栏是什么。
让它记录一次解决方案
打开 rerere,解决一次冲突并完成合并。
用 git config rerere.enabled true 打开,然后执行 git merge topic。把冲突的 handler.txt 第二行改成保留双方的 b by main and topic,git add 之后提交。请看提交时 git 说记录了什么,以及 .git/rr-cache 里生成了什么。
从第二次起,git 替你解决
撤销那次合并后再重新合并,把 git 自己应用了相同解决方案的情形保存到 notes/replay.txt。
用 git reset --hard HEAD~1 删掉合并提交,再次执行 git merge topic。输出中会多出一行,handler.txt 已经是解决后的状态。但查看 git status 仍然是 UU——因为它只应用,不暂存。请 git add 并提交来完成。
只在冲突的位置选我方的
用 -X ours 合并 sidefix,并把结果保存到 notes/xours.txt。
执行 git merge -X ours -m '<메시지>' sidefix(占位符为提交消息)。第二行发生了冲突,所以留下我方的;第六行没有冲突,所以 sidefix 的改动原样合入。sidefix-only.txt 也会进来。请原样抄下结果文件,并补充一行说明留下了什么、进来了什么。
只记下“已合并”,却什么也不带入
用 -s ours 合并 legacy,并把结果保存到 notes/sours.txt。
执行 git merge -s ours -m '<메시지>' legacy(占位符为提交消息)。结束后去找 legacy.txt,找不到。再看看 git diff --name-only HEAD^1 HEAD 是不是什么也没输出——这表示结果树与合并前一个字符也不差。然而 git merge-base --is-ancestor legacy main 为真。
名字相似的两个旋钮
把两个旋钮的区别整理到 notes/strategies.txt。
请用表格来写,四行就够了:它是什么(选项还是策略)、没有冲突的对方改动会怎样、对方新增的文件会怎样、什么时候使用。必须以第 5、6 步亲眼见到的文件名作为依据。
减少重复冲突的方法
在 notes/report.md 中总结减少重复冲突的方法。
请写明:两行配置(rerere.enabled、merge.conflictStyle)为什么值得默认打开,rerere 记住什么、不记住什么,如何删除解错的方案,以及一开始就少制造冲突的习惯。