摘要:在git里面经常的一个争论是到底用rebase还是用merge?

1. 痛苦吗?代码历史中的迷失羔羊

我们先来看一个真实的代码提交历史图形化截图:

图片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/c8b97f4dbb5f7d49fc3eb3624eafff79/london-tube-map-commit.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

不知道大家看到这张图以后有什么感受?是不是很无语呢?我是无语凝噎的感受。代码历史到了这个地步,基本上是废了的!!!

通过本文我们就来谈一下代码历史线的问题。这里涉及到一个代码历史的管理问题,如果你希望拥有比较清晰的代码历史,从而可以很快速地追溯你以前的代码记录的话,你一定要关注这个话题。

如果你作为一个程序员用过mercurial,你可能对这个rebase概念已经有所了解。目前程序员用的最多的source control工具是git。在git里面经常的一个争论是到底用rebase还是用merge?

说争论实际上是不太准确的。因为在实际工作中,这主要有两种情况,一是根本就不知道rebase,另外一种是根本就不知道怎么用rebase。

那我们就说一下rebase和merge的区别,在功能上rebase把你当前的修改工作提升到最前沿,
你自己独有的修改记录顺序不会改变,但是时间主要会基于当前目标分支的时间戳进行调整。

Merge不会改变时间戳。这样就会导致不同的人在合并自己修改代码记录的时候,会出现相互交错的情形。本文开篇是一张代码提交历史的截屏,里面的连线就像电路板一样复杂。

出现这样的情况,主要是因为程序员不做rebase直接merge造成的。

而类似这样电路板状的代码提交历史是没有意义的,因为太过复杂了。几乎没有可读性。如果你想去查看某些历史记录的时候,很容易被迅速淹没在这些信息海洋里面无法自拔,最后失去自我,迷失了。

2. Git Merge vs. Rebase

小注:虽然已经参考链接中标注,但是有必要再强调一下此节翻译参考了如下链接的英文内容:

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Git merge 和rebase的目的是一样的,它们都是将多个分支合并成一个。虽然他们最终的目标是一样的,但这两种方法实现的方式是不同的。那么我们应该用哪个呢?

这里我们有一个示例仓库,它有两个不同的分支:主分支和特性分支。我们想把它们融合在一起。让我们来看看如何使用这些方法来解决这个问题。

图片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/fc73a41ce658a6a566e2a54d60534ade/git-flow.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Merge

当你运行 git merge 时,你的 HEAD 分支会生成一个新的提交,并保留每个提交历史的祖先。

图片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/673b91456bdc6fd454c5ad203f825568/git-merge-2.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Fast forward merge是一种不创建提交的合并类型,会更新分支指针到上一次提交。

Rebase

Rebase是将一个分支的修改重写到另一个分支上,而不需要创建新的提交。

你在特性分支上的每一个提交,都会在主分支上创建一个新的提交。这看起来就像这些提交一直是写在主分支之上的一样。

图片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/5ade4f7276bc6ad18dad4b6078950ac9/git-rebase.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Merge的优点和缺点

优点

  • 使用简单,易于理解。
  • 保持源分支的原始上下文。
  • 源分支上的提交与其他分支的提交是分开的。
  • 可以保留提交历史。

缺点

图片源自 https://storage.kraken.io/kk8yWPxzXVfBD3654oMN/c8b97f4dbb5f7d49fc3eb3624eafff79/london-tube-map-commit.png

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

Rebase的优点和缺点

优点

  • 代码历史是简化的、线性的、可读的。
  • 与许多独立的特性分支的提交历史相比,操作单个提交历史更容易。
  • 干净、清晰的提交信息可以更好地跟踪一个bug或何时引入的某个功能。可以避免众多的单行提交污染历史。

缺点

  • 会更改历史提交时间,可能会丢失上下文。

比起Merge,你需要更加小心的使用Rebase。

应该用Merge还是Rebase?

当你的团队对于rebase不熟悉时,那么git merge就是你的正确选择。

  • Merge允许保存任何给定功能的提交历史,而不必担心覆盖提交和改变历史。
  • 它可以避免不必要的 git revert或reset。

另一方面,如果你更看重干净、线性的代码历史,那么git rebase是最合适的。这种方式可以避免不必要的提交,并保持更集中和线性的变化!

这里要注意的是,如果你不正确地重写了历史,可能会导致严重的问题,所以在使用Rebase时请确保知道你在做什么。

3. 一杯水与一桶水

先说一下一杯水和一桶水的关系,这个关系可以用来描述老师向学生传授知识的情形。主要意思是说老师要是给学生一杯水的话,这个老师必须要有一桶水才行。

其实对于我们软件行业来说,这个道理也是适用的。

关于本文的聚焦点代码历史,我们想给外部呈现的是清晰干净的代码历史记录。要到的这个目标,我们需要做很多的工作,这项工作相较于干净的代码历史就是一桶水与一杯水的关系。

这也是我们经常说的,对自己狠一点,让别人舒服一点。对自己狠一点不是一句空话,实际上是让自己绞尽脑汁的去想,如何把这个事情做好?把自己放在对方的角度上去看我们的输出结果。我们问自己,我作为这些代码的维护者和接收者,是不是可以接受这样混乱的代码历史记录,答案当然是否定的。

明白了这一点,在我们做代码历史管理的时候,再苦再累也是值得的。

一些有多年工作经验的程序员,他们可能用过很多代码管理的工具,这些代码管理工具在使用的时候经常用的一个操作就是merge。进入到git时代以后,这些程序员也保留了这样的习惯,直接就merge。

我跟一些程序员聊过,他们甚至都没有意识到有rebase这个操作。有的则觉得rebase太麻烦了,用了几次就放弃了。

这绝对是人之常情。

当我们习惯了用一种方式做事的时候,我们做得越久感觉越安全,因为它是行之有效的,能够解决问题的。当有另外一种更好的方式,但是却与以前的方式有很大差异的时候,我们就会有本能的排斥心理。这是源于我们对未知领域的一种恐惧感。

离开舒适区以后,我们大多数人都会有一种不适应,有的甚至会产生很强烈的失落感。

但是当我们回归本心的时候,我们会发现我们所付出的一切,经受的痛苦都是值得的。因为我们的初心就是让用户满意。代码历史的用户就是我们这些程序员。

4. 如何正确做rebase?

要点备注:

Rebase相关的要点有这几个:

  1. 在自己的分支上做Rebase;
  2. 要Rebase正确的目标分支,注意这个目标分支不是你的远程分支,这个地方经常有人犯错;
  3. Rebase要常做,以避免出现冲突,或者冲突的难度增加;
  4. 在合入代码之前,一定要最后做一次Rebase再Merge;
  5. 最好用Squash Merge, 添加正确的提交消息;
  6. 不要在主分支上做Rebase;
  7. 尽量不要force push;

在主分支上应该rebase吗? 怎么去做rebase?

首先,我要强调一下,在主分支上不要做rebase。这是因为如果你在主分支上做了rebase,如果你是第1次push可能没有问题,但是如果别的人也做了一个rebase,这个时候就导致你的主分支上有两个不同的head,这个时候如果想再push的话就存在问题了。

如果一切可控的话,你可以非常粗暴的使用强制push。但是如果团队成员比较多,会导致这样的操作会冲掉其他已经进来的提交。

除非万不得已,我们坚决不能在主分支上去做rebase。

接下来说一个正确使用rebase的场景。在接到一个任务以后,我们会在主分支上最新的节点处提交上创建一个新的分支。在新的分支上,我们会不断的进行新的提交,直到完成这个分支任务。

到这个时候,我们想创建一个merge request或者pull request,在此之前,我们首先要做的就是rebase,rebase选的目标分支是我们的主分支。

完成这次rebase操作以后,我们就可以创建mr或者pr了。在审查过程中可能有很多修改意见,修改完成以后需要先
rebase再push。如此反复几次,mr或者pr审批通过。此时要做一次squash merge把数次提交打包合成一个到主分支上。

以上是我对在正常工作流程中如何使用rebase进行了一个现实案例的描述讲解,希望大家去体验一下,告诉我体会,请留言说说你的想法。

参考文献

https://dev.to/neshaz/git-merge-vs-git-rebase-5134

https://www.perforce.com/blog/vcs/git-rebase-vs-merge-which-better

https://product.hubspot.com/blog/git-and-github-tutorial-for-beginners

https://git-scm.com/docs/gittutorial

点击关注,第一时间了解华为云新鲜技术~

你在开发过程中使用Git Rebase还是Git Merge?的更多相关文章

  1. git rebase和git merge的用法

    http://softlab.sdut.edu.cn/blog/subaochen/2016/01/git-rebase%E5%92%8Cgit-merge%E7%9A%84%E7%94%A8%E6% ...

  2. git rebase vs git merge详解

    https://medium.com/@porteneuve/getting-solid-at-git-rebase-vs-merge-4fa1a48c53aa#.std3ddz0g 请参考另外一篇文 ...

  3. git rebase VS git merge? 更优雅的 git 合并方式值得拥有

    写在前面 如果你不能很好的应用 Git,那么这里为你提供一个非常棒的 Git 在线练习工具 Git Online ,你可以更直观的看到你所使用的命令会产生什么效果 另外,你在使用 Git 合并分支时只 ...

  4. git rebase VS git merge

    git rebase VS git merge 写在前面 如果你不能很好的应用 Git,那么这里为你提供一个非常棒的 Git 在线练习工具 Git Online(回复公众号「工具」,获取更多内容) , ...

  5. git rebase 与git merge 小结

    git merge是用来合并两个分支的. $ git merge b   将b分支合并到当前分支 同样  $ git rebase b ,也是把 b分支合并到当前分支 ---------------- ...

  6. git rebase 和 git merge 总结

    git merge 和 git rebase 都是用于合并分支,但二者是存在区别的. 在使用时,记住以下两点: 当你从 remote 去 pull 的时候,永远使用 rebase(除了一个例外) 当你 ...

  7. git rebase与 git合并(error: failed to push some refs to)解决方法

    1.遇到的问题 本地有一个git仓库,在github上新建了一个空的仓库,但是更新了REWADME.md的信息,即在github上多了一个提交. 关联远程仓库,操作顺序如下: git remote a ...

  8. git rebase 和 git merger

    & git merge 在上图中,每一个绿框均代表一个commit.除了c1,每一个commit都有一条有向边指向它在当前branch当中的上一个commit. 图中的项目,在c2之后就开了另 ...

  9. git rebase和git merge的区别

    前言:    平时工作中发现一般同事在同步远程代码的时候都是用git pull,其实git pull包含有两个操作,一个是fetch远程的代码,一个是将本地当前的代码和远程代码进行merge,即git ...

随机推荐

  1. 【C艹】关于sort用法之重构cmp(comp)函数的笔记

    众所周知,balabalabalabala············. 所以掌握sort函数(库文件:<algorithm>)的用法还是很有必要的. 一般选手只会简单地用用sort排一排数组 ...

  2. 配置tomacat外部应用

    原来我们的项目一般放置在tomcat文件夹的webapp下,现在我放到外面,也希望tomact可以找到他

  3. 【Flutter 实战】自定义动画-涟漪和雷达扫描

    老孟导读:此篇文章是 Flutter 动画系列文章第五篇,本文介绍2个自定义动画:涟漪和雷达扫描效果. 涟漪 实现涟漪动画效果如下: 此动画通过 CustomPainter 绘制配合 Animatio ...

  4. Mysql启动后停止的解决方法

    安装mysql后,服务无法正常启动,报错如下: 解法方法: 1           以管理员身份运行命令提示符 2           用命令进行mysql安装目录的bin目录: cd C:\Prog ...

  5. 单表千万行数据库 LIKE 搜索优化手记

    我们经常在数据库中使用 LIKE 操作符来完成对数据的模糊搜索,LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式. 如果需要查找客户表中所有姓氏是“张”的数据,可以使用下面的 SQL 语句 ...

  6. Roads in the North (树的直径)

    Building and maintaining roads among communities in the far North is an expensive business. With thi ...

  7. C013:颠倒显示三位数

    代码: #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int original; do{ printf(&q ...

  8. elo system

    今天了解了一下游戏中的PVP模块的实现,大多数的游戏都使用到了ELO算法,刚开始的时候并不清楚这个算法是做什么的,对此开始大量查找有关于ELO算法的资源,功夫不负有心人,总算找到一些有用的资源了. 先 ...

  9. VS调试出现解决 尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题

  10. python3 for

    当range中只有一个参数时,此参数表示终点,但不包括.(从0开始) 当range中有两个参数时,分别表示起点和终点.(左闭但不包括终点) 当range中有三个参数时,分别表示起点和终点,和步长,意思 ...