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

前言

今天照常开发,在日常部署测试的时候进行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大概类似于:

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大概类似于:

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){
  }
}

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

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){
  }

}

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

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)的代码为:

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在这个过程中表现 增加

-import com.xx.xx.A
+import com.xx.xx.B
+public void bSpecMethod(B b){
+}

x为

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){
  }
}

合并出来的代码应该为

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区的干净!!!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏软件

测试人员的“偷懒大法”

(文 松心耐雪作品) 偷懒大法 测试一项重复而又累的工作,我想作为一个测试人员应该都是深有体会的,那么如何给自己减负呢?那就要学会“偷懒”。对测试来说繁杂的事情...

22250
来自专栏CSDN技术头条

现代开发人员必备的十款工具,来看看你漏了啥?

几年前,作为一名开发人员,你需要的就是编辑器、编译器,以及某种版本控制系统。(可悲的是,许多开发人员目前仍然不能正确地使用版本控制系统) 现在,即使是要做基本的...

22180
来自专栏我和未来有约会

基于Cairngorm的Silverlight开发系列

最近做了几个silverlight的项目都用到了MVC的开发架构,在silverlight中,MVC、MVVM等架构都很多。各个第三方的公司在推出自己的架构的同...

38290
来自专栏张善友的专栏

Windows Server AppFabric Beta 2 for For Vistual Studio 2010已经发布

Windows Server AppFabric Beta 2 For Vistual Studio 2010/.NET Framework 4.0已经发布了,...

19670
来自专栏FreeBuf

伽利略远程监控系统完全安装指南

7月初,外媒用臭名昭著形容意大利的网络军火商公司hacking team及其被黑事件,黑吃黑的黑客将该公司rcs系统的安装程序、源代码和邮件打包供所有人下载,更...

404100
来自专栏施炯的IoT开发专栏

How-to:利用MultiTouchVista模拟Windows Phone 7的多点触摸

引言     近来有消息称,WP7会在明年下半年在中国上市,这对于广大国内的爱好者来说,无疑是个杯具,一般来说,我们只能用模拟器来进行测试了。上回写到了《How...

22490
来自专栏林德熙的博客

win10 支持默认把触摸提升鼠标事件 打开 Pointer 消息

在 WPF 经常需要重写一套触摸事件,没有UWP的Pointer那么好用。 如果一直都觉得 WPF 的触摸做的不好,或想解决 WPF 的触摸问题,但是没有方法,...

35910
来自专栏数据和云

122Architecture 全面解读 - 第一篇 全局解析+ADG+IM模块

Oracle自发布12.1之后,就一直声称要全面转云,在之后的三四年里,一直杳无音信,大家都在猜测,Oracle又在憋什么大招,果然,2017阳春三月,大招来了...

39090
来自专栏张善友的专栏

微软为“离线”做好准备:推出同步框架

微软推出他们称为微软同步框架(Microsoft Sync Framework)的同步平台,这一框架允许开发者创建离线式的应用、设备和服务,可以与任何应用的任意...

21450
来自专栏Coding+

如何多端同步 Hexo 框架博客

这个必要性其实不用多说,用着用着你就自己能体会到,比如头天晚上在家里发布了一篇技术文章,第二天在公司 Coding 的过程中突然想到之前发的文某个地方有 Bug...

16610

扫码关注云+社区

领取腾讯云代金券