博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
git merge —— 为什么比diff & patch好
阅读量:6368 次
发布时间:2019-06-23

本文共 1830 字,大约阅读时间需要 6 分钟。

hot3.png

基于开源软件做二次开发是很常见的。这类开发常常遇到的问题是,当我们已经针对开源软件做了很多修改,与上游主干版本之间已经渐行渐远;此时上游主干有了更新,此时如何把上游的更新与我们自己的修改合并起来?假定上游主干版本为A,我们在A的基础上开发了A';此时上游主干更新到B,现在我们要做的事情就是相应更新到B'。

一个做法是用diff工具生成A'与A的差异(patch),然后在B上面应用这个patch,期望得到B'。用数学的公式表示就是:
  B' = B + (A' - A)      ···· (i, using diff & patch)
如果使用git做版本控制,以上的做法是可行的,但不是最优的。更好的做法是以A为基础,生成A'和B两条分支,然后执行 git checkout B; git merge A'。有一种误解认为这个merge操作执行的就是上面的公式(i),其实不然,git merge的算法叫做3-way merge(准确的说叫recusive 3-way merge,当两个分支有多个共同父亲时它比普通3-way merge表现得更好),用公式表示如下:
  B' = merge(A, A', B)   ···· (ii, using 3-way merge)
(ii) 比 (i) 好在哪里?
用diff工具生成patch时,我们所做的每一处修改,会连同它的“定位信息”(行号,以及修改处前三行与后三行的原始文本)一并保存到patch中。patch被应用时,会在原文件中寻找“定位信息”,然后将修改应用。那么,当我们把 patch(A' - A) 在 B 上应用的时候,很有可能定位信息本身被修改了,这样patch会失败,此时需要手工修改patch文件。
3-way-merge能在很大程度上解决这个问题。对于diff & patch会失败的情况,很多时候merge能够成功;其余则会产生冲突,但修改冲突也比手工改patch更为人性化。
算法本身就不描述了,单举一个例子来说明吧:
======
(1) 版本A
mkdir test
cd test
git init 
vi test.txt
1111
2222
3333
4444
5555
6666
git add test.txt
git commit -m "init"
(2) 版本A',位于分支b1
git checkout -b b1
vi test.txt  # 插入一行abcdefg,尾部增加一行bottom
1111
2222
3333
abcdefg
4444
5555
6666
bottom
git add test.txt
git commit -m "modified on b1"
(3) 版本B,位于分支b2
git checkout master -b b2
vi test.txt  # 顶部增加一行add top line,“2222”做了修改,尾部增加一行bottom
add top line
1111
22222222
3333
4444
5555
6666
bottom
git add test.txt
git commit -m "modified on b2"
(4) 版本B',使用git merge成功合并
git checkout -b testmerge
git merge b1
cat test.txt # 两条分支的修改成功合并,注意尾部的bottom也只增加了一行
             # 如果用 patch & diff 方法,
             #   因为patch的两个定位信息(行号、上下文)都遭到了破坏
             #   是一定不会成功的

add top line

1111
22222222
3333
abcdefg
4444
5555
6666
bottom

从上面这个例子也可以基本看出3-way merge的算法:
(1) 两个分支中如果一个分支对某处做了修改,另一个分支未修改,则保留修改
(2) 两个分支如果都对某处做了修改,且修改内容相同,则保留修改(不是做两遍)
3-way merge在下面的情况下会产生冲突:
(3) 两个分支如果都对某处做了修改,且修改内容不同,则产生冲突
至于什么叫“某处”,是基于文件三个版本的LCS(最长公共子序列)确定的,就不赘述了。

转载于:https://my.oschina.net/jiangyouxin/blog/108717

你可能感兴趣的文章
在CentOS Linux系统上,添加新的端口,启用ssh服务
查看>>
dbcp数据库连接池简单使用
查看>>
leetcode-38-Count and Say
查看>>
从零开始写一个node爬虫(上)—— 数据采集篇
查看>>
java调用远程服务器shell脚本
查看>>
贪吃蛇
查看>>
Elixir 1.2带来多项功能增强和性能提升
查看>>
Rust发布1.32版本,跟踪、模块化、宏等方面均有改进
查看>>
借助Unity AR Foundation构建跨平台AR应用
查看>>
快讯:阿里巴巴加入JCP执行委员会
查看>>
Yelp开源数据管道项目最新组件——数据管道客户端库
查看>>
Windows 10推出周年更新,Edge浏览器支持扩展并改进JavaScript支持
查看>>
Apache软件基金会宣布Apache Unom成为顶级项目
查看>>
又拍云刘平阳,理性竞争下的技术品牌提升之道
查看>>
为所有PHP-FPM容器构建单独的Nginx Docker镜像
查看>>
DevOps实战:Graphite监控上手指南
查看>>
微软Azure CDN现已普遍可用
查看>>
为什么你写的代码糟透了?
查看>>
tomcat线程池策略
查看>>
百度开源AI硬件开发平台BIE-AI-Box和BIE-AI-Board
查看>>