理解git结构与简单操作(四)合并分支的方法与策略

接上节,此时的dev分支与master分支的进度就不一样了,所以需要将dev分支与master分支同步。这里需要的就是合并分支的操作,大家应该都知道用git merge或者git rebase

git merge

merge,即「合并」。

fast-forward

当出现我们上面图中的那种情况时,时间线只有一条,dev分支只不过是落后master分支而已。此时我们在dev分支上执行git merge maseter时,git就仅仅会把dev分支指针移动到master分支所在的位置,假装合并了,就变成了这样:

这种merge的方式叫做「fast-forward」,也是git默认的merge方式。

如果情况改变了,举个例子:我们在开发过程中,一直使用的是master分支,这时出了一个很严重的bug,我们就需要建立一个叫topic的分支来处理这个bug,但主要的功能工期又不能拖,所以master分支与topic分支就同时向前推进,此时时间线如图所示:

(此图出自git自己的帮助文件,使用命令git help merge即可看到。想看其他命令的帮助就git help <command>即可):

这时候,topic上的bug修改完毕,需要合并回master分支,需要的操作为:切换到master分支git checkout master,合并devgit merge dev

注意,这时候的这两条分支是真正的「分支」了,他们在时间线上岔开了,各自分支都有自己独有的东西。

因为此时的topic分支的末端并不在master分支的父端,需要把不同的修改同步起来,单纯的指针移动不能完成这一步,fast-forward方式也就不可能实现了。

这时,git便会将两个分支不同的地方取出,合并成一个commit,然后把master指针指向这个新的commit(就是在master上生成了一次commit)。这样,topic分支上的修改就同步到master分支上了。此时分支情况如图:

no fast-forward

BTW,能够进行fast-forward的merge情况下,也可以通过增加--no-ff命令来强制不使用fast-forward模式。假如还是回到我们master-dev两个分支的例子,master领先于dev分支:

这时我们不用fast-forward,在落后的dev分支上执行git merge master --no-ff,git会在dev上强行创建一个commit,把master分支上不同于dev的修改加进去,分支线就会变成这种诡异的样子:

(本手残渣画图实在是不好看,就直接用GUI工具source tree上的情况截图了)

底层上,git会把将要合并的两个分支的各个commit快照进行差异比较,求出它们之间的最长公共子序列,并把公共子序列从中去掉,得出各自存在两个分支中的不同修改,并将其合并成一个commit放在当前分支的顶端。

这里仅仅说明一点原理,具体实现方式与算法本人也只是懂一点皮毛,只要明白fast-forward与不使用的情况下merge,分支会产生什么样的情况,用来工作就没有任何问题了。

squash

除了--no-ff,merge还有另一种合并的方式:--squash。这种方法在符合fast-forward的情况下依然会执行fast-forward方式,不会有任何改变。但当遇到如下情况时:

假设我们要将topic合并到master上来,squash方式会集中topic的「A、B、C」三次commit中的修改合并,并添加到暂存区中

这时master分支与topic分支不会有任何的变动,只不过暂存区中会被添加topic上修改的集合(暂存区=A+B+C)。

这时我们就可以查看暂存区中的内容是不是符合一次提交,之后commit就可以了。git help merge里是这么描述的:「create a single commit instead of doing a merge」,结合上面的讲解就可以理解squash的意思了吧。

git merge 解决冲突

fast-forward中是没有冲突的(不明白为啥没冲突的面壁思过)。而在其他情况时,如果两个分支同时有对同一个文件(行)的修改,就会产生冲突。这时git会在产生冲突的文件里写一堆这样的东西:

上面的「<<<<<<<< HEAD」直到「========」的部分,就是当前分支的修改(看到HEAD就知道是指向当前分支的指针了)。而「========」到下面的「>>>>>>> dev」的部分自然就是dev分支合并过来的修改啦。

这时需要你仔细对比冲突,如果跟同事合作的话就要商量好,然后把「<<<<< HEAD ===== >>>>> dev」之类git给你加上的东西和不需要的修改部分删掉。接下来git status就会看到下面的提示:

上面绿的的东西自然就在暂存区了,这些代表dev分支上并不冲突的部分。下面的红色文件就代表你冲突的文件,当你修改之后需要走一遍add -> commit的流程(这个commit可以不指定commit message),也可以直接执行git commit -a,就完成merge创建新commit的过程了。

涉及操作:git merge <branch>, git merge <branch> --no-ff, git merge <branch> --squash, git checkout <branch>, git help <command>

git rebase

除了merge,git还有一种分支合并的方式,叫做git rebase。

rebase,就是「re」与「base」结合,官方译名「变基」(咖喱gaygayʕ •ᴥ•ʔ)。这个「变基」的含义从字面上确实不是很好理解,先来看一下rebase示例:

回到我们master-dev两个分支的例子,master领先于dev分支:

这时候我们在dev分支上执行git rebase master,master便与dev合并了,如图所示:

此时你内心OS:这不是跟fast-forward模式下的merge一样么?莫急莫急,我们再看一下出现这样情况下的分支(作者偷懒拿前面图糊弄了嘿嘿嘿):

不着急解释原理,我们先看看在topic上执行git rebase master的结果(就是将master合并到topic上):

看图得知:master上的「F」「G」两次提交,变成了topic分支的父节点,整个分支又重新合成为一条时间线。在本例中,你可以想象「biu」的一下把topic分支拔下来,然后「pu」的一下把它插到了master的顶端(大雾)。

当然,git肯定不是像上面那样「biu」「pu」地操作分支的。

git help rebase中是这样描述git rebase的:

git-rebase - Reapply commits on top of another base tip

翻译一下,就是「将你的commit们在另一个基准点上重新应用」。注意这里的「reapply」,git并不会直接移动commit本身,而是会为需要rebase的分支上的commit分别创建一个patch「补丁」,然后将patch在基准点上依次应用,重建出一条时间线

可以参照上面的两张图梳理一下流程:

当我们在topic分支上执行git rebase master时,代表了我们要将我们当前的分支(topic)应用到指定的master分支上。

此时topic与master的共同父节点是「E」,topic的特有commit是「A」「B」「C」,git就会按照时间点,分别创建「A」「B」「C」的patch「A'」「B'」「C'」,然后将topic分支的基准点设置为master分支的顶点「G」(「变基」了!),依次将「A'」「B'」「C'」Apply到「G」上。

现在是不是理解「rebase变基」是什么意思了!

git rebase 解决冲突

rebase产生的冲突与merge其实是相同的。但由于rebase操作会按照patch一个个打补丁上去,每打一个都有可能会产生冲突,跟merge的产生一个commit这种一次性操作不一样,解决冲突之后也就不是提交commit,而是git add <file>之后执行git rebase --continue

也就是「打一个补丁,解决一次冲突,然后继续下一个补丁」的过程。

如果你不耐烦了,也可以git rebase --abort直接不进行rebase了。

涉及操作:git rebase <branch>, git rebase <branch> --onto <commit id>, git rebase --continue, git rebase --abort

关于分支处理策略的选择

上面讲了好多关于分支的东西,可能会让人困惑:分支涉及到的东西这么多,本身又复杂,多分支处理也复杂,应该怎样利用分支才好?分支合并的策略选哪一种呢?这里我说一下个人的见解:

首先,git保存的是修改这一点,可以很清楚的让我们知道代码发生了哪些改变。在这样的情况下,我们利用commit时间线就可以明确地区分哪个人在什么时间做了什么事情,也就是给了你「查看历史」与「修改历史」的权力,这对一个软件项目来说是至关重要的。

有关git多个分支的设计,其实是非常巧妙的。多个分支解决了以代码本身不同版本、不同功能或不同目的的开发方向(比如开发新功能或改bug,又暂时不想修改主要版本)开发时的代码版本管理问题,能够很方便地管理工作区的文件内容。

所以,我对多分支系统利用的理解是这样的:

  • 分支是需要充分利用的。首先要确定一个master分支,作为这个项目最终上线的版本,要保证合并到master分支上的代码都是确定无误的、测试通过的。
  • 在开发过程中,可以使用一个development分支来开发,用其部署测试环境,使这个分支成为可以随意修改的分支,增加开发的灵活度。
  • 在master或者dev分支出现问题,或者要分头行动时,为每个分支在合适的父节点上创建新的功能分支或bug分支来处理这些问题,可以保证主要的代码不会出错,就算是开发出问题,直接删除该分支便是,基本不用涉及到文件层面的修改。
  • 所以,对工作区的修改应该仅限于增加新内容和修复bug之类的操作,其他的都应该交给git去处理,保证版本树是一条路,复杂的功能删除也不用一行一行找。
  • 当某个分支的某些commit出现问题时,可以先将没有问题的部分建立分支保存起来,保证那些内容不会出问题。

有关git代码合并策略的选择,虽然git提供了非常丰富的方法,但一个team使用的方法应该大体固定成同一个,这样能避免很多混乱,然后在适当的时机使用不同的策略。在《Pro Git》这本书中总结的就很好,我摘下来总结下:

选择merge还是rebase取决于你对commit历史时间线的定义。

有两种观点:第一种认为,commit历史应该显示的是什么时候具体发生了什么事,比如分支的创建与合并过程,有哪些分支,分别合并在了什么地方等等。另一种认为,commit历史应该显示的是这个项目经历过的状态,而不考虑具体的分支构建过程。

每一个团队,每一个人都是不同的。git作为一个如此强大的工具提供给了你解决任何问题的思路,你就要考虑清楚你的团队到底需要什么。

一个两全其美的方法就是:rebase你本地的修改,push到多人环境中时用merge。

乱糟糟的时间线&&完整的分支结构 vs 清爽的一条线&&舍弃修改过程,看你团队取舍咯。

文章链接

理解git结构与简单操作(一)git的本质

理解git结构与简单操作(二)工作区与暂存区

理解git结构与简单操作(三)认识版本库与分支

理解git结构与简单操作(四)合并分支的方法与策略

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/255199.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

摄像机标定

利用摄像机所拍摄到的图像来还原空间中的物体。在这里&#xff0c;不妨假设摄像机所拍摄到的图像与三维空间中的物体之间存在以下一种简单的线性关系&#xff1a;[像]M[物],这里&#xff0c;矩阵M可以看成是摄像机成像的几何模型。 M中的参数就是摄像机参数。通常&#xff0c;这…

Linux下Tomcat重新启动

在Linux系统下&#xff0c;重启Tomcat使用命令操作的&#xff01; 首先&#xff0c;进入Tomcat下的bin目录 cd /usr/local/tomcat/bin 使用Tomcat关闭命令 ./shutdown.sh 查看Tomcat是否以关闭 ps -ef|grep java 如果显示以下相似信息&#xff0c;说明Tomcat还没有关闭 root …

大数据和人工智能的关系是什么?

何为大数据&#xff1f;何为人工智能&#xff1f; 大数据&#xff0c;百度百科上是这么定义的&#xff0c;指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率…

张正友标定法 【计算机视觉学习笔记--双目视觉几何框架系列】

三、致敬“张正友标定” 此处“张正友标定”又称“张氏标定”&#xff0c;是指张正友教授于1998年提出的单平面棋盘格的摄像机标定方法。张氏标定法已经作为工具箱或封装好的函数被广泛应用。张氏标定的原文为“A Flexible New Technique forCamera Calibration”。此文中所提到…

软工网络15个人阅读作业2——提问题

提出问题 快速通读教材《构建之法》&#xff0c;并参照提问模板&#xff0c;提出5个问题。 问题一&#xff1a; p83有一段话&#xff1a; 两人在一起合作&#xff0c;自然会出现不同意见&#xff0c;每个人都有自己的想法&#xff0c;在两个人平等合作的情况下&#xff0c;不存…

绝对路径VS相对路径

绝对路径&#xff1a;不必赘述&#xff0c;就是从盘符开始写直到找到你所需要的文件为止&#xff0c;把所有的目录写完整即可。但是在做网站的时候绝对不推荐用绝对路径&#xff0c;因为不可能服务器中的路径和在做设计时候所用的电脑的路径一致&#xff0c;也不可能说在服务器…

四、极大似然参数估计

四、极大似然参数估计 此篇博文&#xff0c;玉米将和大家分享一下“张氏标定”除几何推导外的另外一大精髓&#xff1a;参数估计。 张教授在大作“A Flexible New Technique for Camera Calibration”中的原话如下&#xff1a;” The above solution is obtained through minim…

xtrabackup安装使用

2019独角兽企业重金招聘Python工程师标准>>> 【MySQL】xtrabackup安装使用 拾荒者charley 关注 2018.03.19 09:19 字数 186 阅读 17评论 0喜欢 0 前言&#xff1a;说到MySQL备份&#xff0c;主要采用的方法无非就是mysqldump/mysqldumper以及我们今天要说的热备利器…

2017/3/10 morning

转载于:https://www.cnblogs.com/bgd140206325/p/6529497.html

六、张正友标定法小结

六、张正友标定法小结 这一博文&#xff0c;是玉米后补上的。因为觉得前面用了三篇博文来描述张氏标定法&#xff0c;略显散乱。在这里总结一下&#xff0c;使条理清晰一点。另外关于张氏标定所得参数也还有两点需要澄清。下面这个总结&#xff0c;其实也是在“A Flexible New …

SqlServer图形数据库初体验

SQL Server2017新增了一个新功能叫做图形数据库。图形指的拓扑图形&#xff0c;是一些Node表和Edge表的合集&#xff0c;Node对应关系数据库中的实体&#xff0c;比如一个人、一个岗位等&#xff0c;Edge表指示Node之前的关系&#xff0c;比如张三在经理岗位。图形表比较适合用…

Oracle CASE WHEN 用法介绍

1. CASE WHEN 表达式有两种形式 --简单Case函数 CASE sex WHEN 1 THEN 男 WHEN 2 THEN 女 ELSE 其他 END --Case搜索函数 CASEWHEN sex 1 THEN 男 WHEN sex 2 THEN 女 ELSE 其他 END 2. CASE WHEN 在语句中不同位置的用法 2.1 SELECT CASE WHEN 用法 SELECT grad…

五、畸变矫正—让世界不在扭曲

五、畸变矫正—让世界不在扭曲 这篇博文所要讲述的内容&#xff0c;是标定的主要用途之一&#xff1a;矫正摄像机的畸变。对于图像畸变矫正的方法&#xff0c;张正友教授也在其大作“A Flexible New Technique forCamera Calibration”中给出。 玉米在这里先为大家介绍一下&…

《MySQL必知必会》[01] 基本查询

《MySQL必知必会》&#xff08;点击查看详情&#xff09;1、写在前面的话这本书是一本MySQL的经典入门书籍&#xff0c;小小的一本&#xff0c;也受到众多网友推荐。之前自己学习的时候是啃的清华大学出版社的计算机系列教材《数据库系统概论》&#xff0c;基础也算是半罐水&am…

(七)立体标定与立体校正 【计算机视觉学习笔记--双目视觉几何框架系列】

七、立体标定与立体校正 这篇博文中&#xff0c;让玉米和大家一起了解一下&#xff0c;张氏标定是怎样过渡到立体标定的&#xff1f;在这里主要以双目立体视觉进行分析。对于双目立体视觉&#xff0c;我们有两个摄像头。它们就像人的一双眼睛一样&#xff0c;从不同的方向看世界…

让 jQuery UI draggable 适配移动端

背景&#xff1a; 在移动端&#xff0c;本人要实现对某个元素的拖动&#xff0c;想到使用 jQuery UI 的 draggable 功能。但是发现此插件的拖动只支持PC端&#xff0c;不支持移动端。 原因&#xff1a; 原始的 jQuery UI 里&#xff0c;都是mousedown、mousemove、mouseup来描述…

LAMP(7限定某个目录禁止解析php、 限制user_agent、 PHP相关配置、PHP扩展模块

限定某个目录禁止解析php防止***上传一个目录文件php&#xff0c;网站会从而解析php,对我们的网站有很大的危险。因此&#xff0c;我们需要在能上传文件的目录直接禁止解析PHP代码禁止步骤1.编辑虚拟主机配置文件&#xff1a;增添内容核心配置文件内容<Directory /data/wwwr…

编译器的功能是什么

1、编译器就是将“一种语言&#xff08;通常为高级语言&#xff09;”翻译为“另一种语言&#xff08;通常为低级语言&#xff09;”的程序。一个现代编译器的主要工作流程&#xff1a;源代码 (source code) → 预处理器(preprocessor) → 编译器 (compiler) → 目标代码 (obje…

八、走向三维

八、走向三维 我们前面花了七篇博文做铺垫&#xff0c;我们所做的一切努力都是为了最后的这一击——立体成像。因为玉米的这个系列文章是对双目视觉几何框架的总结。此处跳过匹配&#xff0c;假设左右图像点的完美匹配的。只看在几何上&#xff0c;三维坐标是如何被还原的。相对…

L~M方法

L~M方法&#xff1a; L~M&#xff08;Levenberg-Marquardt&#xff09;方法有些让人摸不清头脑。玉米觉得L~M让人困扰的主要原因有两点&#xff1a;一是L~M从何而来、二是L~M怎么样用&#xff1f;因为玉米也不是研究最优化理论的&#xff0c;所以玉米在这里用较为通俗的观点&a…