你在开发过程中使用Git Rebase还是Git Merge?
摘要:在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相关的要点有这几个:
- 在自己的分支上做Rebase;
- 要Rebase正确的目标分支,注意这个目标分支不是你的远程分支,这个地方经常有人犯错;
- Rebase要常做,以避免出现冲突,或者冲突的难度增加;
- 在合入代码之前,一定要最后做一次Rebase再Merge;
- 最好用Squash Merge, 添加正确的提交消息;
- 不要在主分支上做Rebase;
- 尽量不要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?的更多相关文章
- 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% ...
- git rebase vs git merge详解
https://medium.com/@porteneuve/getting-solid-at-git-rebase-vs-merge-4fa1a48c53aa#.std3ddz0g 请参考另外一篇文 ...
- git rebase VS git merge? 更优雅的 git 合并方式值得拥有
写在前面 如果你不能很好的应用 Git,那么这里为你提供一个非常棒的 Git 在线练习工具 Git Online ,你可以更直观的看到你所使用的命令会产生什么效果 另外,你在使用 Git 合并分支时只 ...
- git rebase VS git merge
git rebase VS git merge 写在前面 如果你不能很好的应用 Git,那么这里为你提供一个非常棒的 Git 在线练习工具 Git Online(回复公众号「工具」,获取更多内容) , ...
- git rebase 与git merge 小结
git merge是用来合并两个分支的. $ git merge b 将b分支合并到当前分支 同样 $ git rebase b ,也是把 b分支合并到当前分支 ---------------- ...
- git rebase 和 git merge 总结
git merge 和 git rebase 都是用于合并分支,但二者是存在区别的. 在使用时,记住以下两点: 当你从 remote 去 pull 的时候,永远使用 rebase(除了一个例外) 当你 ...
- git rebase与 git合并(error: failed to push some refs to)解决方法
1.遇到的问题 本地有一个git仓库,在github上新建了一个空的仓库,但是更新了REWADME.md的信息,即在github上多了一个提交. 关联远程仓库,操作顺序如下: git remote a ...
- git rebase 和 git merger
& git merge 在上图中,每一个绿框均代表一个commit.除了c1,每一个commit都有一条有向边指向它在当前branch当中的上一个commit. 图中的项目,在c2之后就开了另 ...
- git rebase和git merge的区别
前言: 平时工作中发现一般同事在同步远程代码的时候都是用git pull,其实git pull包含有两个操作,一个是fetch远程的代码,一个是将本地当前的代码和远程代码进行merge,即git ...
随机推荐
- 牛客网数据库SQL实战解析(21-30题)
牛客网SQL刷题地址: https://www.nowcoder.com/ta/sql?page=0 牛客网数据库SQL实战解析(01-10题): https://blog.csdn.net/u010 ...
- GitBook 常用插件
目录 必看说明 插件说明 page-treeview 目录 code 代码 pageview-count 阅读量计数 popup 图片点击查看 tbfed-pagefooter 页面添加页脚(简单版) ...
- os.path获取当前路径及父路径
import os pwd = os.getcwd() print("当前目录: " + pwd) father_path_method1 = os.path.dirname(pw ...
- Java中解析wav音频文件信息:音频声道数,采样频率,采样位数、声音尺寸
前言:请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i 音频解析方法: public static int toInt(byte[] b) { return ((b[3] << 2 ...
- win环境下安装配置openCV-4.3.0
win环境下安装openCV-4.3.0 首先下载 推荐国内镜像 官网太太太慢了 附上 下载地址 下载之后打开exe解压到目录都是常规操作 环境变量的配置 依次打开到系统变量的path 新建一个路径为 ...
- 解决git add README.md 时报错 fatal: pathspec 'README.md' did not match any files
解决办法一: 直接在远程仓库创建然后在本地$ git pull origin master 解决办法二: 换成$ touch README.md在本地创建修改后再commit push上去
- PHP - 附件下载
<?php $file_name = "textuse.zip";//下载文件名 $file_dir = "E:/www/xiazaiwenjian/"; ...
- Android开发之数据存储——SharedPreferences基础知识详解,饿补学会基本知识,开发者必会它的用法。
一.数据存储选项:Data Storage --Storage Options[重点] 1.Shared Preferences Store private primitive data in key ...
- 【学习中】Unity插件之NGUI 完整视频教程
课程 章节 内容 签到 Unity插件之NGUI 完整视频教程 第一章 NGUI基础控件和基础功能学习 1.NGUI介绍和插件的导入 6月29日 2.创建UIRoot 6月29日 3.学习Label控 ...
- Codeforces1249E By Elevator or Stairs?
题意 给定整数c和数组a,b,\(a_i\)表示通过爬楼梯的方法从第\(i\)层到\(i+1\)层需要的时间,\(b_i\)表示通过坐电梯的方法从第\(i\)层到\(i+1\)层需要的时间,坐电梯前需 ...