GIT | 合并分支后"丢失了部分最新修改”

154 阅读2分钟

现象

先来看看这样一个场景,在dev分支上执行git merge feat后,内容会发生怎样的改变?

image.png

当时自己乍一看觉得第二行会发生冲突或者被更新为feat2,第4行则自动合并到dev分支中

前段时间的实习开发中就遇到了类似场景,最终的现象是没有发生合并冲突,第二行保持dev2不变,且第4行被更新为4。 也就意味着我的feat开发分支只有一部分新代码被合并到了目标dev分支中

image.png

复现

image.png

剖析

Git Merge 原理

git-scm.com/docs/git-me…

git-scm.com/book/en/v2/…

image.png git merge 基础是 three-way merge

想合并C4、C5,就要先找到两者的共同祖先C2,然后计算C4和C2的差异、以及C5和C2的差异,最后合并这两个差异

image.png

回顾问题

首先看下分支提交情况

image.png 确定要合并的commit分别是 192f4fbe 和 66a7b503,两者的公共祖先是 57b286a5。 看图可以猜测得到,实际可以通过执行命令 git merge-base 192f4fbe 66a7b503 验证

注意,192f4fbe 这个 commit 由 dev 和 feat 两个分支合并而来,其父commit有两个!

官方文档有对应说明

Figure 24. Three snapshots used in a typical merge.

Instead of just moving the branch pointer forward, Git creates a new snapshot that results from this three-way merge and automatically creates a new commit that points to it. This is referred to as a merge commit, and is special in that it has more than one parent.

通过 git cat-file -p 也可验证

image.png

此时答案已经浮出水面了,将 three-way merge 规则代入当前场景进行推导

  1. 针对第二行,公共祖先值为 feat2,dev分支值为 dev2,feat分支值为 feat2。 只有dev分支做了修改,没有冲突,值为 dev2
  2. 针对第四行,公共祖先和dev分支都没有值,只有feat分支新增为4,所以也没有冲突,值为4

经验教训

当前组内开发的Git分支模型大致是:

  • 生产环境分支是 release
  • 测试环境分支是 dev
  • 个人开发功能时从 release 中切出 feat_NYRE 分支、从dev中切出 dev_NYRE 分支。开发完后将 feat_NYRE 合并到 dev_NYRE,再将 dev_NYRE 分支合并到 dev 分支中(便于本地解决与dev的冲突)进行测试

按照当前模型,是不能在个人的 dev_NYRE 分支上直接写代码的,只能在 feat_NYRE 分支上开发,然后merge到 dev_NYRE 中。

而我就是在某个需要紧急添加修复代码的时候,直接在 dev_DYRE 分支上进行开发,事后又忘记同步到开发分支 feat_NYRE 中去,从而导致部分代码合并不到 dev_DYRE 中