想象一下有例如以下情形:代码库中存在两个分支,而且每一个分支都进行了改动。最后你想要将当中的一个分支合并到其它的分支中。个人博客网址 http://swinghu.github.com/

那么要问合并的处理过程是怎么样的呢?Git是对每一个分支,根据分支的历史数据依照序列化操作,还是它仅仅是合并每一个分支里文件的最后版本号?这是一个问题,我想对gitmerge操作有必要进行分析一下。

回顾一下。我们知道Git的版本号库内部结构是以有向无环图(directed
acyclic graph
)组织起来的:每一次commit都会生成一个版本号树的快照(snapshot),而且该快照保存了一个指向其父节点(该分支的近期上一次的提交快照)的引用(通常当前提交仅仅有一个父节点,可是初试提交快照没有父节点,而一次合并(merge)操作有2个或多个父节点)。

就像这样。每次提交都递归的建立某些节点集指向父节点的引用。

有时候,当我们考虑提交的父节点提交树和当前节提交节点树做差异比較时(diff),将一次提交想象成一次修补补丁(patch)是有助于我们理解git 的工作机理。依照这样的方式,我们能够这样觉得,提交树就是集成应用了全部父节点的补丁修补。一颗在两个分支上做merge操作的树,因此就能够觉得是两个分支应用了其各自全部的父节点修补补丁程序,然后做一次联合操作Union。

可是那不是git merge 的真正运行方式。原因是。首先。假设以那样工作的话。运行会很的慢!,而且在运行过程中它要再一次又一次处理全部的之前合并时造成的冲突。如此,git
merge
 真正是怎样操作的呢?

我喜欢用数学的思维方式思考:给定两个提交 A和 B,合并提交(commit)操作 A∨B 就能够描写叙述为: [A∨B ]=[ A]+[ B]−[ C ] 这里的 C是A 和 B的合并共同拥有项(近期提交树祖先共同含有的部分)。我们必需要“减去” C。由于假设不这种话,我们就会有两个A∧B。

这个操作x+y−z 被叫做三向合并。

你能够觉得运行路径为将x−z 应用到x 上,或者将 x−z应用到y 上。

其实diffpatch操作并没有字面上依照上面的的操作行事,相反而是使用了:最长公共子序列算法来实现。x−w和序列x,序列w的差异就是我们知道的在求最长公共子序列时的赋值(中间可能要去除到两个序列的公共部分)。为了构造三向合并x+y−w,我们对x和w在求公共子序列的时候进行赋值。对y和w在求公共子序列的时候赋值。然后输出每一个要么:

  • 三个序列的共同拥有部分,或者
  • 在x 中出现。可是在y 和 w 中不存在的部分,或者
  • 在y 中出现,可是在x 和w 中没有出现的部分

同一时候我们要删除那些序列,要么:

  • 出如今y 和 w可是在x中没有出现,或者
  • 出如今x和w中可是在y中没有出现。

举个栗子,下面是x,y,z 运行merge操作后的结果:

  1. x: w: y: ↦ merged:
  2. milk milk milk milk
  3. juice juice
  4. flour flour flour flour
  5. sausage sausagegit
  6. eggs eggs eggs eggs
  7. butter butter

在x,y与w的行序可能只说明了一种在三向合并的输出行上的一种偏序关系。假设是这种话,因为相同的块w,在x,y 之间以不同的方式被编辑-因此我们说那就是一个合并冲突。将会输出该信息,让用户手动解决。

git 向你显示合并冲突的时候,默认情况下,你将会看到x和的冲突块:

然而,冲突块会变得更easy解决,当你可以看到合并基准w的时候。

我建议打开开关:

  1. ~/.gitconfig

通过设置merge.conflictstyle 为diff3,则

  1. git config --global merge.conflictstyle diff3

如今你能够看到解决方案为:

  1. I had two eggs and three sausages for breakfast.

(注意,这个操作会对称性的(关于w和结果进行交换,因此你真正须要的是查看w)这里有另外两种其它的案例须要考虑,可能行为:

  • 出如今x和y中,可是在w中没有出现
  • 出如今w中。可是没有在x 和y 中出现

某些三向合并算法常常将这样的行标记为冲突行。

然而Git,将会优雅的输出或者直接删除该行,依次,假定该行没有改变。

这样的效果叫做意外清理合并。偶尔某些情形在实际应用中非常实用,尤其是用户把版本号搞砸了,各自合并同一个补丁的两个不同的版本号。

可是我觉得掩盖这样的错误不是一种好的行事方式,我希望这样的行为能够并关闭。尽量避免由于他所能带来的这样的长处而使用它吧。

假设你细致。非常有观察力,你可能已经发现我在上述说明中存在的一个漏洞了:因为commit提交 A和B可能各自又包括commit,他们近期的共同祖先可能不是唯一的!

一般。他们最有可能的情形是,近期的共同祖先是 C1,C2,C3,C4,⋯Ck−1,Ck ,在这样的情况下,git
merge
 操作将会递归的运行:它首先构造合并 C=C1∨C2∨C3⋯Ck−1∨Ck 。并以此作为三向合并[ A ]+[ B ]−[ C ] 的基础(base)。

这就是为什么Git的默认合并策略并称为递归的。
假定两个分支例如以下图所看到的。A,B,C,D,E是master分支的历史快照(snapshot);A,B,X,Y,Z是feature分子的历史快照。命令

  1. git merge feature

首先查找“master”(当前分支)和“feature”的共同祖先。它或多或少的等价于下面命令:

  1. git merge-base master feature

在我们的举的样例里,他们的共同祖先是B。

假设在C,D,E和X,Y,Z提交中没有冲突,git 将会创建一次“merge
commit 
” merge commit会有两到多个父亲。 新的图将会是以下这个样子。每一次git
commit
 提交都会生成一棵树,一到多个“父亲节点”。作者的名字,email,日期和提交者的姓名。email,日期。

merge提交和普通的提交的唯一差别就是祖先的数量。

在第二幅图中,merge commit提交被以M标注出来了。
假设提交存在冲突,用户就会被要求解决冲突,并手动创建合并提交,在冲突解决后

  1. git commit -a

将会创建合并提交。这条命令没什么特殊的语法。Git 已经知道了用户已经在进行合并了(已经在尝试合并)。

Git中的merge命令实现和工作方式的更多相关文章

  1. Git中的merge命令实现中出现问题及其解决

    Git中的merge命令实现和工作方式 2015年8月17日星期一 丹丹 git代码在合并两个分支的时候总是会出现一下的错误提示,不能正常的完成合并分支,错误提示如图所示: 但是在其他的终端是可以完成 ...

  2. GIT中常用的命令

    最近项目中使用到了GIT,所以记录一下GIT中常用的命令. GIT使用的客户端有Git Bash:http://code.google.com/p/msysgit/ 还有乌龟TortoiseGit:h ...

  3. 总结下git中一些常用命令

    一.目录操作 1.cd 即change directory,改变目录,如 cd d:/www,切换到d盘的www目录. 2.cd .. cd+空格+两个点,回退到上一目录. 3.pwd 即 print ...

  4. Git知识总览(五) Git中的merge、rebase、cherry-pick以及交互式rebase

    上篇博客聊了<git分支管理之rebase 以及 cherry-pick相关操作>本篇博客我们就以Learning Git中的关卡进行展开.下方列举了LearningGit中的 merge ...

  5. Git中分支merge和rebase的适用场景及区别

    Git merge是用来合并两个分支的. git merge b      # 将b分支合并到当前分支 同样 git rebase b,也是把 b分支合并到当前分支 原理 如下: 假设你现在基于远程分 ...

  6. Git中特别的命令

    Rebase 假设我们的分支结构如下: rebase 会把从 Merge Base 以来的所有提交,以补丁的形式一个一个重新达到目标分支上.这使得目标分支合并该分支的时候会直接 Fast Forwar ...

  7. 关于Git中分支merge和rebase的适用场景及区别

    最近刚接触Git,下面对一些基本的使用做一下总结. 本文是转载于CSDN:http://blog.csdn.net/rryqsh/article/details/8230560 几乎所有的版本控制工具 ...

  8. git中的merge与rebase

    之前一直对git的merge与rebase很困惑,而且一般也只使用merge而不是使用rebase.今天受高人指点理清了两者的区别. 首先对于两者而言,他们的结果是一样的,差异在于合并的方式(产生的结 ...

  9. git 中的 merge 和 rebase

    示例分支:master . dev 把 dev 分支上的新内容合并到 master 上 先切换分支到master git checkout master 合并操作 git merge dev 或者 g ...

随机推荐

  1. OCP-1Z0-051-题目解析-第8题

    8. View the Exhibit and examine the structure of the CUSTOMERS table. Which two tasks would require ...

  2. c语言,结构体

    数据类型分为4种, 简单数据类型,构造数据类型,指针数据类型,空类型. 结构体属于构造数据类型,用struct标识. 声明一个结构体: Typedef  struct和struct c c++ typ ...

  3. WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理

    原文:WCF技术剖析之十:调用WCF服务的客户端应该如何进行异常处理 在前面一片文章(服务代理不能得到及时关闭会有什么后果?)中,我们谈到及时关闭服务代理(Service Proxy)在一个高并发环境 ...

  4. springMVC 使用jstl

    jsp页面获取数据,感觉最方便的就是使用jstl+EL了,各种封装好的函数非常简单易用,接下来写如何使用jstl: 1.下载jstl-1.2_1.jar 2.由于项目是: xmlns="ht ...

  5. android怎样实现自动点击功能

    一个按钮之类的控件的自动点击的话,可以定时调用 button.performClick();

  6. Swift - 使用位运算提取颜色,合并颜色

    通常我们可以使用16进制的格式表示RGB颜色,比如0x2f88c0.通过位操作运算,能很方便的将其中的R,G,B颜色各部分分别提取出来.反之,也可以将R,G,B颜色值组合成一个完整的颜色. 1,提取颜 ...

  7. sql: update from

    sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通过将要更新的表与其它的数据源连接起来,就可以在update的表达式 中引 ...

  8. 跨服务器查询sql (摘要)

    首先推荐一个神作:http://www.cnblogs.com/daniel206/archive/2008/01/16/1041748.html 大神比较详细了.而且条理很清晰. 然后摘录一些其他的 ...

  9. ImageMagick wrapper for php

    https://code.google.com/archive/p/phmagick/

  10. poj1860 解题报告

    题意:这里有N种货币,分别记为1~N,有M种货币交换的方式,每一种方式有A,B两种钱币,有RAB, CAB, RBA and CBA,四个数,表示交换率, Nick手上有其中的一种货币S,货币S的钱数 ...