Pulpcode

捕获,搅碎,拼接,吞咽

0%

妹妹你大胆的merge吧

刚毕业那会,初学git的时候,很多命令都不知道咋用,比如git merge,我很害怕旧代码把我的新代码给覆盖了。后来我才发现这种想法是多余的,git从来不会让旧代码把新代码覆盖。

首先先分类当merge代码的时候会发生什么?

简单的merge

比如你在开发一个购买水果的网站代码,这个时候有新的需求要购买苹果,然后你在master上切出一个分支:

1
git checkout -b feature-sale-apple

之后你开发完成,并测试通过,需要把feature-sale-apple的代码合并到master。这个时候只要切换到master分支:

1
git checkout master

然后合并 feature-sale-apple就行了。

1
git merge feature-sale-apple

那么如果你当时在feature-sale-apple试图merge master呢?

1
git merge master

实际上什么都不会发生。

merge1

在git中,当你试图把一个分支的直属父分支,merge进来时候,git什么都不会做。
而你试图把一个直属子分支merge进来的时候,git也仅仅是把head指针前移而已。(你仔细想想,在上图中,绿色分支和红色分支的内容是一样的。)

这其中的根本原则就是,旧版本不会覆盖到新版本上。

产生冲突

让我们把这个例子变得复杂一点

你在feature-sale-apple开发代码的时候,也有另一个人从master checkout出了分支:git checkout -b feature-sale-banana, 然后他先开发完成了,并且先merge 到了master分支上。

然后你开发完了feature-sale-apple的功能,打算也merge到master上。

这个时候,你的feature-sale-apple会覆盖feature-sale-banana的代码么?

merge2

当你要merge的分支和你当前的分支不是直属关系时,git会试图找到这两分支的公共父节点。如果两个分支没有修改同一文件的同一个地方,那好说,要产生的新commit,就是简单的把相对于父分支,最新的代码结果指过去就行了。
如果两个分支都相对于父分支,修改了的同一个文件的同一个地方。那就会产生冲突。

也就是说,对于两个分支,A分支的代码内容是(a部分是新加的内容):

1
2
a
b

B分支的代码内容是(c部分是新加的内容):

1
2
b
c

那么在merge的时候,就是简简单单的变为了:

1
2
3
a
b
c

除非你的A分支的内容是把b改成b1:

1
b1

而B分支把b改成b2,这个时候merge才会产生冲突,文件会变为如下类似的结构:

1
2
3
4
5
>>>
b1
=======
b2
<<<

所以旧代码是不会覆盖新代码的,修改了相同的地方,也会被冲突标识出来。

为什么有人说自己的旧代码被新代码覆盖了?

其实很多人会反驳说,自己确实遇到过新代码被旧代码覆盖的情况。

其实被覆盖的原因,是因为branch A和branch B都需要对同一块代码进行修改,然后在合并代码的时候,后fetch下代码的同学,在发现冲突时,手动解决时将之前同学的代码改为自己的,并提交了。

所以时常更新远程分支的代码是个好习惯,而且还要注意不要遇到冲突,就简单的选择自己写的那一部分。

而且还有一部分人,很害怕merge,因为一看到冲突就害怕,如果真的遇到很多冲突,你害怕了,完全可以用git reset --hard撤回到原来的commit。

这使我想到了上小学的时候,在正大剧场看过的一部电影,主要讲的是男主克服心理阴影,最后成功获得跳水冠军。男主一直的心理阴影是害怕跳到水里之后撞到池底。后来有一个人给他演示了个实验,就是找了一把手枪,对着一个装满水的桶里开了一枪,然后桶并没有事,以此来告诉他,完全没有担心撞到池底的必要。所以我们所担心的事,只不过我们不熟悉这个模型,只要熟悉掌握了,自然就收放自如了。类似你知道merge这个操作有多安全,你就可以放心大胆的merge了。