当前位置: 首页 > article >正文

git 基础之 merge 和 rebase 的比较

在这里插入图片描述

在团队软件开发过程中,代码合并是一个基本且频繁执行的任务。

Git 提供了多种合并代码的策略,其中最常用的是 merge 和 rebase。

尽管二者的终极目标是相同的——整合代码变更——它们的方法和推荐的使用场景却有所区别。本文将详细介绍和比较这两种策略。

一、基于 merge 的合并介绍

1.1 如何使用

情景 1:

当你的代码处在分支 branch-a,而本地有另外一个分支 branch-b 的时候,使用

git merge branch-b

可以将 branch-b 分支的代码,merge 到当前所处的 branch-a 分支上。

情景 2:

当你的代码处在分支 branch-a,直接使用 git pull origin branch-b 拉取仓库中 branch-b 分支的最新代码时,默认情况下,git pull 命令执行的是 fetch 后跟 merge。也即:

git pull origin branch-b
# 等价于
git fetch origin branch-b  # 拉取远端 branch-b 的最新状态,此刻本地的 branch-b 依旧不是最新代码
git merge origin/branch-b  # 合并远端 branch-b 最新代码,此刻本地的 branch-b 依旧不是最新代码

最新版本的 git 会在项目首次 pull 时,让你设置默认的合并行为;这里说的默认选用 merge 是老版本的 git。

要全局设置 git pull 使用 merge,可以配置

git config --global pull.rebase false

下图是一个更加复杂的示例,branch-a 签出 branch-bbranch-c,按照时间顺序(图中由下到上)发生了如下事情

  1. branch-a 签出 branch-bbranch-c
  2. branch-b 提交了一次代码(节点 b1
  3. branch-c 提交了一次代码(节点 c1
  4. branch-b 提交了一次代码(节点 b2
  5. branch-c 提交了一次代码(节点 c2
  6. branch-c 被合并进了 branch-a(图中这种情况不会发生任何冲突,因为 branch-c 签出、提交、合并过程中,branch-a 并未发生代码改变)
  7. branch-b 提交了一次代码(节点 b3
  8. branch-b 被合并进了 branch-a(此时有可能发生冲突,因为 branch-bbranch-c 可能修改同一个位置的代码)
    在这里插入图片描述

1.2 合并方式

git merge 创建一个新的合并提交,它具有两个父提交,分别指向合并前两个分支的最新提交。

例如上面的例子中,branch-c 被合并进 branch-a

  • 节点 a2 就是新的合并提交
  • 节点 a1c2 就是 a2 的两个父提交

1.3 历史记录呈现形式

使用 merge 时,历史记录保持了分支形式,从而可以清晰地展示各个分支的合并点与路径。

例如上面的例子中,合并后即便删掉 branch-bbranch-c,提交历史也会保留,即: b1b2b3c1c2

1.4 冲突处理方式

如果合并时遇到冲突,Git 会停止合并过程,让用户一次性解决冲突,然后创建一个新的合并提交来完成合并过程。

二、基于 rebase 的合并介绍

2.1 如何使用

情景 1

当你的代码处在分支 branch-a,而本地有另外一个分支 branch-b 的时候,使用

git rebase branch-b

可以将 branch-b 分支的代码,merge 到当前所处的 branch-a 分支上。

git rebase 命令用于将一个分支的更改重新应用到另一个分支上。在分支上执行 git rebase 时,Git 将更改从一个分支上提取出来,然后在基底分支的头部重新应用它们。

情景 2

要使 git pull 默认执行 rebase 而不是 merge,可以通过 git config --global pull.rebase true 命令进行设置。

关于 rebase 的示例,要比 merge 的复杂一些,让我们先考虑如下情况

  1. branch-a 签出 branch-bbranch-c
  2. branch-b 提交了一次代码(节点 b1
  3. branch-c 提交了一次代码(节点 c1
  4. branch-b 提交了一次代码(节点 b2
  5. branch-c 提交了一次代码(节点 c2
    在这里插入图片描述

此时如果处于 branch-a 分支上,执行

git rebase branch-c

将得到如下的分支和提交结构

在这里插入图片描述
此时如果处于 branch-a 分支上,执行

git rebase branch-b

将得到如下的分支和提交结构
在这里插入图片描述
那么,为什么 branch-c 的操作早于 branch-b,但是整体操作完,b1b2 位于 c1c2 之前呢?

这是因为执行 git rebase branch-name 的时候,会找到当前分支和 branch-name 分支的共同祖先,然后把当前分支在最早公共祖先之后的提交,好像新的提交一样一个个提交到 branch-name 的最新代码之后。

在上面的例子中,branch-a 分支和 branch-b 的公共祖先是 a1,所以会以 branch-b 的最后一次提交(b2)作为基础,将 branch-aa1 之后的提交(c1c2)依次应用上去。

合并方式

rebase 通过提取分支上的更改,并将它们应用到目标分支的最新提交之后,从而使得项目历史线性化

在上面的例子中我们可以看到,使用 rebase 合并得到的提交记录不像使用 merge 合并得到的提交记录一样交错在一起,不容易拆分。

历史记录呈现形式

使用 rebase 会产生一个线性的历史记录,好像所有更改都是顺序发生的,使得项目历史看起来像是单线程进行的。

冲突处理方式

rebase 过程中的冲突必须按照每个提交顺序单独解决。解决每个冲突后,需使用 git rebase --continue 来继续 rebase 过程。

三、二者对比

适用场景比较

  • merge 适合于需要保持详细合并历史的公共分支,如主分支或发布分支。
  • rebase 更适合于个人开发分支,在合并到公共分支之前,保持历史记录的整洁和线性。
比较维度mergerebase
合并方式创建新的合并提交,有两个父提交提取提交在目标分支最新提交后重新应用
历史记录呈现形式分支式,能看到分支合并情况线性,看上去像所有提交在一条直线上
冲突处理方式一次性解决冲突后提交合并结果逐个解决每个提交的冲突,使用 git rebase --continue 继续
适合的公共分支场景多开发者频繁合并,要求完整历史记录需要线性历史记录,对美观度有要求
适合的个人分支场景无特殊要求,记录分支合并历史即可保持历史整洁和线性,便于审查

在实际开发中,团队可能会结合使用 merge 和 rebase 策略来充分利用它们的优势,例如在个人分支上使用 rebase 保持历史整洁,最后在合并到公共分支时使用 merge。


http://www.kler.cn/a/401954.html

相关文章:

  • 基于Java Springboot川剧科普平台
  • MySQL系列之数据授权(privilege)
  • 量化交易系统开发-实时行情自动化交易-4.1.3.A股平均趋向指数(ADX)实现
  • WQ9101 WIFI6模组移植实操
  • SD模型微调之Textual Inversion和Embedding fine-tuning
  • golang开源框架:go开源验证框架validator
  • 运维面试题.云计算面试题之三ELK
  • VGG16-Pytorch实现人脸识别
  • C/C++实现tcp客户端和服务端的实现(从零开始写自己的高性能服务器)
  • AI 驱动低代码平台:开创智能化用户体验新纪元
  • vue功能基础元素使用
  • Java中日志采集框架-JUL、Slf4j、Log4j、Logstash
  • 在 macOS 和 Linux 中,波浪号 `~`的区别
  • 使用C++编写一个程序,模拟掷骰子的过程,输出1到6之间的随机数。
  • 【企业级分布式系统】ELK优化
  • 使用Go语言开发一个高性能的Web服务器,支持静态文件服务和实时通信。
  • 《深入理解 Spring MVC 工作流程》
  • 实验十三 生态安全评价
  • MySQL扩展varchar字段长度能否Online DDL
  • 【服务器】端口映射
  • 爬虫开发工具与环境搭建——使用Postman和浏览器开发者工具
  • 【嵌入式Linux】Linux设备树详解
  • 【算法设计与分析实训】第1关:求序列的最大字段和
  • 高阶云服务-ELB+AS
  • Android CPU核分配关联进程
  • Java网络编程1 - 介绍网络编程、网络编程三要素