聊聊Git合并和变基

一、 Git Merge 合并策略

1.1 Fast-Forward Merge(快进式合并)

//在分支1下操作,会将分支1合并到分支2中
git merge <分支2>

最简单的合并算法,它是在一条不分叉的两个分支之间进行合并。快进式合并是默认的合并行为,并没有产生新的commit。如下图所示,虚线部分是合并前,在经过如下命令后:

//当前在Main分支下操作
git merge Dev 

image.png
Git 将 Main 和 HEAD 指针移动到 Dev 所在的提交对象上,此时合并完成,不涉及到内容的变更和比较,所以这种合并方式效率很高。从上面的图可以发现,这种合并策略要求合并的两个分支上的提交,必须是一条链上的前后关系。
可以通过git merge --no-off参数来进行关闭快进式合并,关闭后会强制使用Three Way Merge(三路合并),下面来具体讲讲三路合并

1.2 Three Way Merge 三路合并

当两个分支的提交对象不在一条提交链上时,Git 会默认执行三路合并的方式进行合并。
首先 Git 会通过算法寻找两个分支的最近公共祖先节点,再将找到的公共祖先节点作为base节点,并使用三路合并的策略来进行合并,也就是我们常见的合并方式(三路指的是两个需要合并的分支的提交对象(比如下图中的提交对象 1,2),最近共同祖先(提交对象 0)三个对象):
image.png
可以通过传递不同参数来使用不同的合并策略:
git merge [ -s <strategy>] [-X <strategy-option>] <commit>...

  • 参数 -s <strategy>用于设定合并策略
  • 参数 -X <strategy-option>用于为所选的合并策略提供附加的参数

1.3.2 Resolve策略

Resolve 策略是默认的三路合并策略,既可以使用 git merge <分支>又可以使用 git merge -s resolve <分支>来执行合并,该合并策略只能用于合并两个分支,也就是当前分支和另外的一个分支,使用三路合并策略。这种合并策略被认为是最安全、最快的合并分支策略。
比如在 Main 分支下执行以下命令:

//当前在Main分支下操作
git merge Dev

image.png
Git 会创建一个新的提交对象(如上图中的提交对象 3),然后该提交对象将合并提交对象 1 和提交对象 2 的内容,形成提交对象 3。但是一旦遇到两个分支对象有多个共同祖先时,此时 Resolve 策略就无法实现合并了,这个时候就需要用 Recursive策略。

1.3.1 Recursive 策略

如下图所示,在对两个分支上的提交A和B进行合并时,我们发现了它们有两个共同祖先,分别是:ancestor0ancestor1。这就是 Criss-Cross 现象:
image.png
我们在此处复现一下这个现象:

//1.初始化一个recursiveMerge仓库
$ git init recursiveMerge//2.创建一个master-commit1.txt文件并提交
$ git commit -m "master-commit1"
[master (root-commit) 85cba5f] master-commit11 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 master-commit1.txt//3.新建一个分支dev,并切换到dev。在dev分支创建一个dev-commit1.txt文件并提交
$ git checkout -b dev
Switched to a new branch 'dev'
$ git commit -m "dev-commit1"
[dev 9763dcc] dev-commit11 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 dev-commit1.txt//4.切换到master分支,创建一个master-commit2.txt文件并提交
$ git checkout master
Switched to branch 'master'
$ git commit -m "master-commit2"
[master 5c23645] master-commit21 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 master-commit2.txt//5.新建一个分支feature, 切换到feature,合并dev和feature$ git merge dev
hint: Waiting for your editor to close the file... unix2dos: converting file D:/recursiveMerge/.git/MERGE_MSG to DOS format...
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
dos2unix: converting file D:/recursiveMerge/.git/MERGE_MSG to Unix format...
Merge made by the 'ort' strategy.dev-commit1.txt | 01 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 dev-commit1.txt//6.切换到master,合并dev和master
$ git merge dev
hint: Waiting for your editor to close the file... unix2dos: converting file D:/recursiveMerge/.git/MERGE_MSG to DOS format...
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
dos2unix: converting file D:/recursiveMerge/.git/MERGE_MSG to Unix format...
Merge made by the 'ort' strategy.dev-commit1.txt | 01 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 dev-commit1.txt

我们在 Git GUI 中查看此时的分支图像:
image.png
那么Recursive 策略对于这种情况是怎么做的呢?
如果Git在寻找共同祖先时,在参与合并的两个分支上找到了不只一个满足条件的共同祖先,它会先对共同祖先进行合并,建立临时快照。然后,把临时产生的“虚拟祖先”作为合并依据,再对分支进行合并。对于上图而言,会将ancestor 0ancestor 1 先合并成一个虚拟祖先 ancestor 2,最后再将它与A和B提交一起进行三路合并:
image.png
在处理合并时,有可能会出现不同分支在相同文件上的冲突,因此可以使用下列选项来在发生冲突时起作用,常见的有:

Ours选项

在遇到冲突时,选择当前分支版本,而忽略其他分支版本。如果他人的改动和本地改动不冲突,会将他人的改动合并进来:

# 在冲突合并中,选择当前分支内容,自动丢弃其他分支内容
git merge -s recursive -Xours
Theirs选项

Ours选项相反,遇到冲突时,选择他人的版本,丢弃当前分支版本

# 选择其他分支内容,自动丢弃当前分支内容
git merge -s recursive -Xtheis

此外还有 subtree[=<path>]renormalizeno-renormalize等等选项,具体可以看官方文档Git - merge-strategies Documentation

1.3 Octopus Merge 多路合并

git merge -s octopus <分支1> <分支2> ... <分支N>

此合并策略可以合并两个以上的分支,但是拒绝执行需要手动解决的复杂合并,它的主要用途是将多个分支合并到一起,该策略是对三个及三个以上的分支合并时的默认合并策略。

来做一个实验,此时我的 Git 仓库中有三个分支 feature1,feature2,feature3,执行 octopus 合并:

$ git merge -s octopus feature1 feature2 feature3
Trying simple merge with feature1
Trying simple merge with feature2
Trying simple merge with feature3
Merge made by the 'octopus' strategy.feature1-1.txt | 0feature3-2.txt | 0four.txt       | 0second.txt     | 0third-2.txt    | 0third.txt      | 06 files changed, 0 insertions(+), 0 deletions(-)create mode 100644 feature1-1.txtcreate mode 100644 feature3-2.txtcreate mode 100644 four.txtcreate mode 100644 second.txtcreate mode 100644 third-2.txtcreate mode 100644 third.txt

image.png

1.3.3 subtree策略

这是一个经过调整的 recursive策略,当合并树 A 和树 B 时,如果树 B 和树 A 的一个子树相同,B 树首先进行调整以匹配 A 的树结构,以免两棵树在同一级别进行合并。同时也针对两棵树的共同祖先调整。

git merge -s subtree <树A> <树B>

该部分会单独再出一篇,来姐姐子树合并和子模块合并

1.3.4 ours 策略

这种策略可以合并任意数量的分支,但是合并的结果总是使用当前分支的内容,丢弃其他分支的内容。
这种模式和上面的 recursive策略中的 ours选项不同,ours 选项是在某个分支下,忽略其他人的版本,ours策略是忽略其他的分支。

二、 Git Rebase 变基

rebase是指在另一个基端之上重新应用提交。很多时候我们在两个分支上用rebase。但是**rebase**命令的作用对象不仅仅限于分支。任何的提交引用,都可以被视作有效的**rebase**基底对象。包括一个提交ID、分支名称、标签名称或者**HEAD~1**这样的相对引用。

2.1 标准模式

git rebase默认是标准模式,一般用于多个分支之间:在一个分支中集成另外分支的最新修改。

#当前在Feature分支下操作,会得到如下的变基状态
git checkout Feature
git rebase Main

image.png

#当前在branch1分支下操作,会得到如下的变基状态
git checkout Branch1
#将Main分支中没有Branch1分支的提交,拷贝到Branch2分支中
git rebase Main --onto Branch2

image.png
当执行git rebase命令后,整个变基过程都会自动进行,如果在该命令后加上-i参数后,就会进入到交互模式:

2.2 交互模式

git rebase -i或者git rebase -interactive开始后执行一个交互式rebase 会话。一般用于当前分支的历史提交进行编辑操作。

# 针对该commit 后的提交进行交互式操作
git rebase -i [commit ID]

运行命令后,会跳出交互界面,比如在git bash中输入如下命令:git rebase -i ecd259f
页面会出现下面的界面:
image.png
上图中的两条记录是提交列表,指的是 ID 为ecd259f...的 commit 之前的提交。我们可以对这两个提交进行相关的操作,在上面的页面中也提供了几个命令:

  • pick:保留该commit,和drop相对,也就是什么也不做(在IDEA中不选择,直接rebase,也会得到如下结果)
  • reword:修改该提交的commit message,如果该commit之后也有提交,那么之后的提交信息也会被改变
  • edit: 选择一个提交并修改该提交的内容
  • squash:合并该提交与上一个提交,也可以合并多个,两两合并,间隔合并
  • fixup:与squash类似,但是会抛弃当前的commit message
  • exec: 执行shell命令,运行一条自定义命令

可以在提交列表前面进行参数修改,比如将 pick改成 squash就是将两个提交合并到 ID 为 ecd259f...的提交对象中

squash a5eb754 first commit --init
squash 2df01ad ignoreList

三、总结

Git merge 和 Git rebase 的区别与联系

在日常对冲突的处理中,很明显的区别在于 rebase 的处理方式能让提交链更加清晰,而使用 merge 方式会显得提交链复杂交错。
下面我们具体来看看两者的区别与联系

区别

  1. 合并方式git merge 创建一个新的合并提交,将两个分支的更改合并到一起,而 git rebase 将一系列提交从一个分支转移到另一个分支,并重新组织这些提交:
  2. 提交历史git merge 保留每个分支的独立提交历史,形成一个合并的提交历史树,而git rebase修改提交历史的结构,使提交历史更线性:

image.png

  1. 冲突处理:在合并过程中,如果存在冲突,git mergegit rebase 都需要手动解决冲突。但是,解决冲突的方式略有不同。git merge 在合并提交中保留冲突的解决方案,而 git rebase 在每个冲突点停下来,必须在解决冲突后才能继续进行rebase操作。
  2. 提交ID:由于 git rebase 重新应用提交,所以重新组织后的提交具有新的提交ID,而 git merge 创建的合并提交保留了原始提交的ID。比如上图中,git rebase 命令执行后,对应的 master 分支的三个 commit 对象的提交 ID 都要被修改。

联系

  1. 合并操作:无论是 git merge 还是 git rebase,它们都是用于将一个分支的更改合并到另一个分支上。两者都是在对分支进行合并,是来解决冲突的。
  2. 版本同步:无论是 git merge 还是 git rebase,它们都可以用于将分支与上游分支同步,以确保分支包含上游的最新更改。
  3. 解决冲突:无论是 git merge 还是 git rebase,在合并过程中都可能存在冲突,需要手动解决冲突。

参考资料

https://www.geeksforgeeks.org/merge-strategies-in-git/
https://morningspace.github.io/tech/git-merge-stories-2/
https://git-scm.com/docs/merge-strategies/

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

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

相关文章

mysql注入联合查询

环境搭建 下载复现漏洞的包 下载小皮面板 将下载好的文件解压在小皮面板的phpstudy_pro\WWW路径下 将这个文件phpstudy_pro\WWW\sqli-labs-php7-master\sql-connections\db-creds.inc 中的密码更改为小皮面板中的密码 选择php版本 在小皮中启动nginx和数据库 使用环回地址访…

JavaScript 学习笔记(JS进阶 Day4)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度&#xff0c;分享学习笔记&#xff0c;希望能对大家有所帮助。推荐先按顺序阅读往期内容&#xff1a; 1. JavaScript 学习笔记&#xff08;Day1&#xff09; 2. JavaSc…

NodeJs环境安装与配置

最近电脑重装了系统&#xff0c;开发环境啥的都得重装&#xff0c;顺便记录下 nodeJs 的安装与配置&#xff0c;方便需要的同学查看&#xff0c;也方便自己以后查找。 安装 下载地址&#xff1a;https://nodejs.cn/download/ 根据需要选择自己环境需要的下载即可&#xff0c;…

【cdh】hive执行SQL提示缺少3.0.0-cdh6.3.2-mr-framework.tar.gz文件

问题&#xff1a;执行SQL报错提示缺少文件 异常信息如下 在hdfs上查看的时候连文件夹都没有&#xff0c;所以这个异常会抛出&#xff0c;但是我是基于CDH搭建的&#xff0c;可以直接基于下面操作 执行完成之后查看HDFS文件 重新执行SQL发现可以正常执行了

web前端项目-实现录音功能【附源码】

录音功能 运行效果&#xff1a;本项目可实现录音软件的录音、存储、播放等功能 HTML源码&#xff1a; &#xff08;1&#xff09;index.html&#xff1a; <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/h…

【BUG】联想Y7000电池电量为0且无法充电解决方案汇总

因为最近火灾很多&#xff0c;所以昨天夜晚睡觉的时候把插线板电源关掉了&#xff0c;电脑也关机了。 各位一定要注意用电安全&#xff0c;网上的那些事情看着真的很难受qvq。 第二天早上起床的时候一看发现电脑直接没电了&#xff0c;插上电源后也是显示 你一定要冲进去啊(ू˃…

springboot外出务工人员信息管理系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把疫情防控期间某村外出务工人员信息管理与现在网络相结合&#xff0c;利用java技术建设疫情防控期间某村外出务工人员信息管理系统&#xff0c;实现疫情防控期间某村外出务工人员信息的信息化。则对于进一步提高疫情防控期间某村外…

2024阿里云和腾讯云的第一战打响:搭建《幻兽帕鲁》私服游戏

为了搭建《幻兽帕鲁》游戏私服&#xff0c; 2024年阿里云 VS 腾讯云的第一场战争开始了…… 事情是这样的&#xff1a; 1月19日&#xff0c;最离谱新游 《幻兽帕鲁》突然爆火了&#xff0c;这是一款日本开发商展耗费4年开发的冒险类游戏&#xff0c;这款戏一推出就迅速俘获了…

DOM 型 XSS 攻击演示(附链接)

一、介绍 DOM&#xff08;Document Object Model&#xff09;型 XSS&#xff08;Cross-Site Scripting&#xff09;攻击是一种 Web 应用程序中的安全漏洞&#xff0c;其特点是攻击者成功地注入了恶意脚本&#xff0c;这些脚本在用户的浏览器中执行&#xff0c;从而导致恶意行为…

AcWing 895. 最长上升子序列(DP序列模型)

[题目概述] 给定一个长度为 N 的数列&#xff0c;求数值严格单调递增的子序列的长度最长是多少。 输入格式 第一行包含整数 N。 第二行包含 N 个整数&#xff0c;表示完整序列。 输出格式 输出一个整数&#xff0c;表示最大长度。 数据范围 1 ≤ N ≤ 1000 &#xff0c; …

【刷题】 leetcode 面试题 08.05.递归乘法

递归乘法 1 题目描述2 思路一&#xff08;返璞归真版&#xff09;3 思路二&#xff08;二进制乘法器版&#xff09;4 思路三&#xff08;变态版&#xff09;Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见&#xff01;&#xff01;&#xff01; 1 题目…

不确定优化入门:用简单实例讲明白随机规划、鲁棒优化和分布鲁棒优化

文章目录 1 引言2 学习动机3 经典问题4 解决方案4.1 忽略不确定性4.2 随机规划4.3 鲁棒优化4.4 分布鲁棒优化 5 总结相关阅读 1 引言 按2024的原定计划&#xff0c;今年开始要学习不确定优化了。 粗略翻阅了一些相关的书籍和教程&#xff0c;大都包含许多数学公式&#xff0c…

SpringBoot引入主盘探活定时任务

主盘探活通常是指检查存储设备&#xff08;例如硬盘&#xff09;是否可读写&#xff0c;但在Java中并没有直接针对硬件级别的磁盘探活API。然而&#xff0c;我们可以模拟一个场景&#xff0c;即检查某个目录或文件是否可以被Java程序正常读写&#xff0c;以此作为主盘活跃的一个…

HCIP复习课(bgp实验)

1、ip配置&#xff1a; R1&#xff1a; R2&#xff1a; R9&#xff1a; R10&#xff1a; R11&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a; R7&#xff1a; R8&#xff1a; 2、隧道配置&#xff1a; R2&#xff1a; 静态&#xff1a; R10&am…

第15次修改了可删除可持久保存的前端html备忘录:换了一个容器时钟,匹配背景主题:现代深色

第15次修改了可删除可持久保存的前端html备忘录&#xff1a;换了一个容器时钟&#xff0c;匹配背景主题&#xff1a;现代深色 备忘录代码 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta http-equiv&qu…

WSL2 Debian系统添加支持SocketCAN

本人最近在使用WSL2&#xff0c;Linux系统选择的是Debian&#xff0c;用起来很不错&#xff0c;感觉可以代替VMware Player虚拟机。 但是WSL2 Debian默认不支持SocketCAN&#xff0c;这就有点坑了&#xff0c;由于本人经常要使用SocketCAN功能&#xff0c;所以决定让Debian支持…

Axolotl:一款极简的大模型微调(Finetune)开源框架

今天给大家分享一款工具&#xff0c;Axolotl[1] 是一个旨在简化各种AI模型的微调过程的工具&#xff0c;支持多种配置和架构。 特点&#xff1a; 可训练各种 Huggingface 模型&#xff0c;如 llama、pythia、falcon、mpt支持 fullfinetune、lora、qlora、relora 和 gptq使用简…

Maven入门及其使用

目录 一、Maven入门 1.1 初识Maven 1.2 Maven的作用 1.2.1 依赖管理 1.2.2 统一项目结构 1.2.3 项目构建 1.3 Maven坐标 1.4 Maven仓库 1.4.1 Maven仓库概述 二、Maven的下载与安装 2.1 安装步骤 2.1.1 解压安装&#xff08;建议解压到没有中文、特殊字符的路径下。&#xff09…

数据湖技术之应用场景篇

数据湖技术有较多的应用场景&#xff0c;本篇文章是针对一些典型的痛点场景做了一些介绍和说明。比如说在线数据抽取场景原有模式对线上库表产生较大压力&#xff0c;flink多流join维护的大状态导致的稳定性问题等等&#xff0c;具体场景如下图所示&#xff1a; 场景1:在线数据…

车载电子电器架构 —— 多核处理器刷写策略

车载电子电器架构 —— 多核处理器刷写策略 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消…