前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >记一次"诡异"的git merge错误

记一次"诡异"的git merge错误

作者头像
LNAmp
发布2018-09-05 15:36:40
1.9K0
发布2018-09-05 15:36:40
举报

前言

今天照常开发,在日常部署测试的时候进行git merge 竟然出现了"代码丢失"的情况,相当诡异,特此记录。

问题由来

首先介绍下公司的日常发布测试的策略,公司使用git进行代码管理。如果某应用同时有多人开发,采用的方式是A会基于master新建feature_a分支,B基于master新建feature_b分支,然后在日常测试部署的时候通常会新建一个新的tag分支,如tag/20160711_test_xxxx,然后将要测试部署的分支feature_a和feature_b合并到tag分支上去,然后使用tag分支部署并且测试。这样做是完全没有问题的,但是诡异的事情发生了,今天这么操作的时候合并出的tag分支丢了一行import,mavan编译一直出错

问题描述与分析

最开始碰到这个问题的时候我一直以为是发布构建系统的问题(公司内部系统),后来又怀疑是我在解决merge冲突的时候手贱删除了这行,重新merge还是出现这个问题。后来由于还得开发其他功能,想着要不先让feature_b分支先单独发布测试好了。一直到下午手里的事情忙完了准备搞定这个问题,发现同事feature_b分支还是没有测试好,想着不能等他了,开始着手解决这个问题。

问题描述如下,feature_a和feature_b同时修改了某个文件xx.java,feature_a上xx.java大概类似于:

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.A
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void aSpecMethod(A a){
  }
}

feature_b上的xx.java大概类似于:

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.B
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void bSpecMethod(B b){
  }
}

按理说合并出来的代码应该类似于:

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.A
import com.xx.xx.B
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void aSpecMethod(A a){
  }

  public void bSpecMethod(B b){
  }

}

但是最终合并出来的代码却是类似于这样:

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.B
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void aSpecMethod(A a){
  }

  public void bSpecMethod(B b){
  }

}

筒子们发现问题了吗,NMmerge之后丢了import com.xx.xx.A这样,maven编译一直报解析不了A的错误,A都没引进来,能解析就怪了...

我也是年轻呀,开始的一个小时一直纠结在是不是这个发布系统的问题(哈哈,对不起,让你背锅了),后来开始仔细研究git merge的原理,期间看到了How-does-Git-merge-work这篇文章讲得比较通透。git merge的原理简单来说就是x+y-w的过程,其中w是x+y的merge base(也就是最近公共祖先),也即是说把y-w(y分支对w分支的改动)patch到x分支上,或者说是把x-w(x分支对w分支的改动)patch到y分支上,具体的做法就是:

merge过程

在知道原理之后就开始查看feature_b和feature_a分支分别对于xx.java文件的改动,发现feature_b(同事分支)将import com.xx.xx.A这句删掉了(看到这我就应该反应过来的,但是我还是太连清...),我当时想你删了就删了呗,我在feature_a分支引用进来了呀,最后合并肯定还是存在的嘛(我承认自己没仔细想),我接着checkout 到feature_a看了下,有import com.xx.xx.A这句呀,最后合并的时候肯定应该有的呀,git merge肯定不能因为某些分支删了这行就不新增其他分支的代码,心中一千匹草泥马在奔腾呀!!!!

但是...重要的是但是,我知道git merge首先会找他们的merge base,会基于这个合并,在该场景里应该是master(feature_a和feature_b都是基于master新建的),我就checkout到了master上查看了下,发现master上赫然存在import com.xx.xx.A这行(当时xx.java没有并没有引用到A.java类,这个import是多余的),我瞬间反应过来问题了!!

问题解决-真相大白

问题就在于x+y-w时和w是强相关的,而在这个案例里面,w(也就是master)的代码为:

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.A
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

master中虽然没有引用A,但是却把A引进来了(应该是某次删除代码的时候忘了把Import删掉了)

先分析下xx.java的合并过程吧 x:代表feature_a w:master y:代表feature_b 合并过程为x+(y-w) y-w在这个过程中表现 增加

代码语言:javascript
复制
-import com.xx.xx.A
+import com.xx.xx.B
+public void bSpecMethod(B b){
+}

x为

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.A
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void aSpecMethod(A a){
  }
}

合并出来的代码应该为

代码语言:javascript
复制
package xxx.xx
import com.xx.xx.B
import com.xx.xx.Common

class xx {
  public void commonMethod(Common common){
  }

  public void aSpecMethod(A a){
  }


public void bSpecMethod(B b){
}

}

哈哈,import com.xx.xx.A就这么丢了,而且还就应该丢,丢才是正确的!

筒子们,看出来问题了吗,问题就在于同事B看到xx.java中A并没有被引用的时候把A 的import干掉了,而我在xx.java中加入的方法刚好用到了A(我以为A是我import进去的,没想到竟然master上竟然存在),造成结果就是git 记住的改动是feature_b把A的import干掉了,feature_a对这个import没有修改,结果就是...

知道了原因,解决就很简单了,故意将Import A挪个位置并Push让git意识到change,这样下次merge的时候git既会知道feature_b的改动也会知道feature_a的改动会触发一次merge conflict,然后手动解决就好了

警示

在对类进行修改删除了某些方法时,一定要将无用的import清理掉,保持import区的干净!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.07.11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 问题由来
  • 问题描述与分析
  • 问题解决-真相大白
  • 警示
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档