想把回退的功能放回去,Git 说没什么可合的
目标
撤销并恢复合并提交,并在保留出处的前提下带入发布分支上的修复。同时确认机器是如何判定哪些内容已经合入的。
为什么重要
reset 会删除提交,revert 则会添加一个抵消的提交。对已经传到别人手里的历史,只能使用 revert,但在合并提交上,这种抵消并不简单。它有两个父提交,必须由人来指明回到哪一侧的状态。撤销之后的事更重要——merge 依据历史的可达性判断,所以即使再次 merge 被撤销的功能,它也会回答“没有需要合并的东西”。不懂这两点,在处理故障的过程中就会在同一个地方白白浪费 30 分钟。最后两步是 backport 运维的基本功。你要亲手构造出:判定相同的改动是否已经合入,依据的是 patch-id 而不是哈希;以及解决冲突后带过来的提交会被排除在这个判定之外。
步骤
- 在
/root/gitx7/repo创建一段含有合并提交和发布分支的历史。 - 尝试不带
-m撤销合并提交,把拒绝信息保存到notes/revert-m.txt,然后用-m 1撤销。 - 把
git merge feature给出的回答写入notes/reland.txt,再对撤销提交做一次撤销,恢复功能。 - 用
-x把发布分支上的热修复提交带入main。 - 带入发布分支上的配置变更提交时如果发生冲突,先用
--abort退回,再重新来一遍,用--continue完成。把过程保存到notes/conflict.txt。 - 把
git cherry -v main release的结果保存到notes/cherry.txt。 - 把原提交和带入提交的 patch-id 并排写入
notes/patchid.txt。 - 在
notes/report.md中总结什么时候用什么。
参考
- 每个仓库都要指定
git config user.email和user.name才能提交。提交时间请用GIT_AUTHOR_DATE和GIT_COMMITTER_DATE固定。 - 使用
git revert --no-edit和GIT_EDITOR=true,编辑器就不会打开。 - 常见错误:在第 3 步把
merge输出 “Already up to date” 当成失败,去找--force之类的选项。那是准确的回答,解法是对撤销提交再做一次撤销。 - 常见错误:在第 5 步把冲突标记(
<<<<<<<)留在文件里就git add。连这些标记也会被提交。
含有合并提交和发布分支的历史
在 /root/gitx7/repo 创建一段含有合并提交和发布分支的历史。
在 main 上提交基础文件,在 feature 分支上添加 feature.txt 并修改 app.txt 的第二行,然后用 --no-ff 合并。在那个位置创建 release,堆叠热修复、配置变更、发布说明三个提交,再回到 main,把同一个配置值改成不同的值。最后这一个会造成第 5 步的冲突。
合并提交必须指明回到哪一侧
尝试不带 -m 撤销合并提交,把拒绝信息保存到 notes/revert-m.txt,然后用 -m 1 撤销。
合并提交的哈希用 git rev-list --merges main 查找。直接执行 git revert <해시>(占位符为哈希)会被拒绝——请原样保存那一行。还要写下 -m 1 表示以什么为基准,并加上 --no-edit,不打开编辑器直接撤销。
再次 merge 也没有需要合并的东西
把 git merge feature 给出的回答写入 notes/reland.txt,再对撤销提交做一次撤销,恢复功能。
直接执行 git merge feature 试试,它会用一行话回答。请写下为什么会这样回答——merge 依据的不是内容,而是历史的可达性。恢复的办法是对刚才创建的撤销提交再次 git revert。
保留出处地带入
用 -x 把发布分支上的热修复提交带入 main。
添加了 hotfix.txt 的发布提交,其哈希用 git rev-list release -- hotfix.txt 查找。执行 git cherry-pick -x <해시>(占位符为哈希)后,新提交消息的末尾会多出一行。请用 git log -1 --format=%B 确认。
冲突了就退回,再重新来
带入发布分支上的配置变更提交时如果发生冲突,先用 --abort 退回,再重新来一遍,用 --continue 完成。把过程保存到 notes/conflict.txt。
对修改了 conf.txt 的发布提交执行 git cherry-pick 会发生冲突。先用 git status --short 看到 UU,再用 git cherry-pick --abort 干净地退回。然后重新带入,把 conf.txt 改成发布分支确定的值并 git add,最后用 GIT_EDITOR=true git cherry-pick --continue 完成。一定要确认文件中没有残留冲突标记行。
数一数哪些已经合入
把 git cherry -v main release 的结果保存到 notes/cherry.txt。
git cherry -v <upstream> <head>(占位符依次为上游与当前分支)会按 patch-id 判定 head 中的每个提交是否已经存在于 upstream。- 表示有,+ 表示没有。三个提交里只有一个显示为 -,务必写下解决冲突后带入的那个为什么是 +。这个工具的局限就在这里。
哈希不同,但 patch-id 相同
把原提交和带入提交的 patch-id 并排写入 notes/patchid.txt。
git show <커밋> | git patch-id --stable(占位符为提交)会输出两个值——前面是 patch-id,后面是提交哈希。第 4 步用 -x 带入的提交,与原提交的 patch-id 相同。该提交可以用 git log --grep 'cherry picked from commit <해시>'(占位符为哈希)找到。
什么时候用什么
在 notes/report.md 中总结什么时候用什么。
分成五块来写:区分 reset 和 revert 的那个问题、撤销合并提交时的 -m、恢复时为什么不用 merge 而用 revert 的 revert、为什么把 -x 定为规则,以及 patch-id 判定的局限。