TT Lab
开始
学习 学习路径 课程

Git 实战

想把回退的功能放回去,Git 说没什么可合的

在 TT Lab 中继续学习

目标

撤销并恢复合并提交,并在保留出处的前提下带入发布分支上的修复。同时确认机器是如何判定哪些内容已经合入的。

为什么重要

reset 会删除提交,revert 则会添加一个抵消的提交。对已经传到别人手里的历史,只能使用 revert,但在合并提交上,这种抵消并不简单。它有两个父提交,必须由人来指明回到哪一侧的状态。撤销之后的事更重要——merge 依据历史的可达性判断,所以即使再次 merge 被撤销的功能,它也会回答“没有需要合并的东西”。不懂这两点,在处理故障的过程中就会在同一个地方白白浪费 30 分钟。最后两步是 backport 运维的基本功。你要亲手构造出:判定相同的改动是否已经合入,依据的是 patch-id 而不是哈希;以及解决冲突后带过来的提交会被排除在这个判定之外。

步骤

  1. 在 /root/gitx7/repo 创建一段含有合并提交和发布分支的历史。
  2. 尝试不带 -m 撤销合并提交,把拒绝信息保存到 notes/revert-m.txt,然后用 -m 1 撤销。
  3. 把 git merge feature 给出的回答写入 notes/reland.txt,再对撤销提交做一次撤销,恢复功能。
  4. 用 -x 把发布分支上的热修复提交带入 main。
  5. 带入发布分支上的配置变更提交时如果发生冲突,先用 --abort 退回,再重新来一遍,用 --continue 完成。把过程保存到 notes/conflict.txt。
  6. 把 git cherry -v main release 的结果保存到 notes/cherry.txt。
  7. 把原提交和带入提交的 patch-id 并排写入 notes/patchid.txt。
  8. 在 notes/report.md 中总结什么时候用什么。

参考

含有合并提交和发布分支的历史

在 /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 判定的局限。