想象一下有例如以下情形:代码库中存在两个分支,而且每一个分支都进行了改动。最后你想要将当中的一个分支合并到其它的分支中。个人博客网址 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. POJ 2031 prim

    Building a Space Station Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 4400 Accepted: 2 ...

  2. Android TextView自己主动换行文字排版參差不齐的原因

    今天项目没什么进展,公司后台出问题了.看了下刚刚学习Android时的笔记,发现TextView会自己主动换行,并且排版文字參差不齐.查了下资料,总结原因例如以下: 1.半角字符与全角字符混乱所致:这 ...

  3. ofstream 使用的一点主意事项

    有如下代码段: ofstream ofs; while(...) { ofs.close(); ofs.open(...) ofs << "内容"; ... } ofs ...

  4. linux: Ubuntu安装samba的问题

    Ubuntu安装samba的问题 http://blog.csdn.net/jk110333/article/details/8920841 root@ubuntu:~# apt-get instal ...

  5. Integer ==与Equals【原创】

    package Equals; public class IntegerEquals { public static void main(String[] args) { printLine(128) ...

  6. Table中的JCheckBox TableHeader的全选(全反选)功能

    菜鸟学习ing class CheckDefaultModel extends DefaultTableModel /* * To change this template, choose Tools ...

  7. Leetcode: Median of Two Sorted Arrays. java.

    There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted ...

  8. mysql学习之中的一个:mysql安装

    我用的时mac系统,本来想在mac系统上装一个,可是发现mac系统始终无法用password登入到本机server,很奇怪的问题(在stackflow上看了些回复,也没有找到原因),最后仅仅好装到虚拟 ...

  9. sql: sql developer使用

    在sql developer中登陆某数据库,在procedure里面加入一个proc,种类选ARBOR: CREATE OR REPLACE PROCEDURE PROCEDURE23 IS NAM ...

  10. PHP之验证码代码

    <?php session_start(); $checkcode=""; /*for($i=0;$i<4;$i++) { $checkcode.=dechex(ran ...