git 分支-变基

在git中,将一个分支的更改集成到另一个分支有两种主要方式:合并(merge)和变基(rebase)。在本节中,将学习什么是变基,如何执行变基操作,为什么它是一个非常强大的工具,以及在哪些情况下不希望使用它。

基本变基

如果回到基本合并的一个早期示例,会发现工作分叉了,并在两个不同的分支上进行了提交。

正如我们已经介绍过的那样,最简单的集成分支的方法是使用合并(merge)命令。它在两个最新的分支快照(C3和C4)与两者的最近公共祖先(C2)之间执行三方合并,创建一个新的快照(和提交)。

然而,还有另一种方法:可以获取在C4引入的更改补丁,并将其重新应用在C3之上。在git中,这被称为变基(rebase)。使用rebase命令,可以获取在一个分支上提交的所有更改,并在不同的分支上重放它们。

对于这个示例,将检出experiment分支,然后将其变基到master分支上,如下所示:

$ git checkout experiment

$ git rebase master

First, rewinding head to replay your work on top of it...

Applying: added staged command

这个操作通过前往两个分支的共同祖先(当前所在的分支和要变基到的分支),获取当前分支中每个提交引入的差异,将这些差异保存到临时文件中,将当前分支重置为与要变基到的分支相同的提交,最后依次应用每个更改。

在这一点上,可以返回到master分支并执行快进合并。

$ git checkout master

$ git merge experiment

现在,C4'指向的快照与合并示例中C5所指向的快照完全相同。集成的最终产品没有任何区别,但变基使历史记录更清晰。如果检查变基分支的日志,它看起来像是一个线性的历史记录:似乎所有的工作都是按顺序完成的,即使最初是并行完成的。

通常,会这样做来确保提交在远程分支上能够干净地应用 - 也许是试图贡献但不维护的项目中。在这种情况下,会在一个分支上进行工作,然后在准备好向主项目提交补丁时,将的工作变基到origin/master分支上。这样,维护者就不需要进行任何集成工作 - 只需要一个快进合并或一个干净的应用。

请注意,无论最终得到的最终提交是变基的最后一个提交还是合并后的最终合并提交,指向的快照都是相同的 - 只有历史记录是不同的。变基将一系列工作中的更改按照它们被引入的顺序重播到另一条线上,而合并则将端点合并在一起。

更有趣的变基

还可以将变基回放到除了变基目标分支之外的其他地方。例如,考虑一个像这样的历史:从另一个主题分支分出的一个主题分支。例如,从一个主题分支(server)分出一个分支,为项目添加了一些服务器端功能,并提交了一个提交。然后,从该分支分出一个分支(client)来进行客户端更改,并进行了几次提交。最后,回到了服务器分支并进行了几次提交。

假设决定要将客户端的更改合并到主线以进行发布,但想等到服务器端的更改经过进一步测试。可以使用git rebase的--onto选项,将客户端上不在服务器上的更改(C8和C9)重播到主分支上:

$ git rebase --onto master server client

这基本上是在说:“获取客户端分支,找出自从它与服务器分支分叉以来的补丁,并在客户端分支上重播这些补丁,就好像它直接基于主分支。” 这有点复杂,但结果非常酷。

现在可以将主分支快进(参见主分支快进以包含客户端分支的更改):

$ git checkout master

$ git merge client

假设决定同时合并服务器分支。可以在无需首先检出它的情况下,通过运行git rebase <基础分支> <主题分支> 将服务器分支变基到主分支上 - 这会检出主题分支(在本例中是服务器分支)并将其重播到基础分支(主分支)上:

$ git rebase master server

这会将服务器工作重播主分支工作之上

然后,可以快进基础分支(主分支):

$ git checkout master

$ git merge server

可以删除客户端和服务器分支,因为所有工作都已集成,不再需要它们,使得整个过程的历史记录看起来像是最终提交历史:

$ git branch -d client

$ git branch -d server

变基的危险

但是变基的喜悦并不是没有缺点的,可以用一句话概括:

不要变基已经存在于存储库之外的提交,可能有人基于这些提交进行工作。

如果遵循这个准则,那么一切都会很好。如果不遵循,人们会讨厌women ,会受到朋友和家人的蔑视。

当重新定位工作时,会放弃现有的提交并创建新的提交,这些提交类似但有所不同。如果推送提交到某个地方,其他人将其拉取下来并基于其进行工作,然后用git rebase重写这些提交并再次推送它们上去,那么合作者将不得不重新合并他们的工作,当试图将他们的工作拉回我们的工作时,事情会变得混乱。

让我们看一个例子,说明如何对已经公开的工作进行变基可能会导致问题。假设从一个中央服务器克隆,然后对其进行一些工作。提交历史如下所示:

现在,其他人做了更多的工作,其中包括一个合并,并将该工作推送到中央服务器。 获取了它并将新的远程分支合并到您的工作中,使历史看起来像这样:

接下来,推送合并工作的人决定返回并重新定位他们的工作; 他们执行git push --force以覆盖服务器上的历史记录。 然后,从该服务器获取,将新的提交拉取下来。

现在你们两个都陷入了困境。 如果你执行git pull,将创建一个合并提交,其中包含两行历史记录,你的存储库将如下所示:

如果在我们历史记录呈现此样式时运行git log,将看到两个提交具有相同的作者、日期和消息,这将令人困惑。此外,如果将此历史记录推送回服务器,将重新引入所有这些已重新定位的提交到中央服务器,这可能会进一步使人困惑。可以相当肯定地假设另一个开发人员不希望C4和C6出现在历史记录中;这就是他们首先进行重新定位的原因。

重新定位时进行重新定位

如果发现自己处于这种情况,Git 还有一些进一步的魔法可能会帮助您解决问题。如果团队中的某人强制推送了覆盖我们基于其进行工作的更改,我们挑战就是找出哪些是我们的,哪些是他们重新编写的。

事实证明,除了提交的 SHA-1 校验和之外,git 还计算了一个仅基于引入的补丁的校验和。这被称为“补丁 ID”。

如果拉取了被重写的工作,并将其重新定位到我们的合作伙伴的新提交之上,git 通常可以成功地确定哪些是我们独有的,并将它们应用到新分支的顶部。

例如,在先前的场景中,如果我们在当我们在有人推送重新定位的提交时,放弃了我们基于其进行工作的提交时,我们运行 git rebase teamone/master,git 将会:

确定哪些工作是我们分支独有的(C2、C3、C4、C6、C7)

确定哪些不是合并提交(C2、C3、C4)

确定哪些没有被重写到目标分支中(仅 C2 和 C3,因为 C4 与 C4' 是相同的补丁)

将这些提交应用到 teamone/master 的顶部

因此,我们不会像在“再次合并相同的工作以生成新的合并提交”中看到的结果那样结束,而是会得到类似“在被强制推送的重新定位工作之上重新定位”的结果。

这只有在合作伙伴制作的 C4 和 C4' 几乎完全相同的补丁时才有效。否则,重新定位将无法确定它是重复的,并将添加另一个类似于 C4 的补丁(这可能会导致应用失败,因为更改已经存在)。

还可以通过运行 git pull --rebase 而不是普通的 git pull 来简化此过程。或者,在这种情况下,也可以手动执行 git fetch,然后执行 git rebase teamone/master。

如果使用 git pull 并希望将 --rebase 设置为默认值,可以使用类似 git config --global pull.rebase true 的命令来设置 pull.rebase 配置值。

如果只重新定位从未离开过计算机的提交,那么一切都会很好。如果重新定位已经推送过的提交,但没有人基于这些提交创建新的提交,那么一切也会很好。如果重新定位已经公开推送的提交,而且人们可能已经基于这些提交进行了工作,那么可能会遇到一些令人沮丧的麻烦,并且会受到队友的责备。

如果我们或合作伙伴在某个时候发现有必要这样做,请确保每个人都知道运行 git pull --rebase 来尝试使发生这种情况后的痛苦变得简单一些。

重新定位 vs. 合并

现在已经看到了重新定位和合并的实际操作,可能想知道哪个更好。在我们回答这个问题之前,让我们稍微退后一步,谈谈历史意味着什么。

对此的一种观点是,存储库的提交历史记录是实际发生的事情的记录。它是一份历史文档,本身就有价值,不应该被篡改。从这个角度来看,更改提交历史几乎是亵渎的;那么如果有一系列混乱的合并提交怎么办?这就是实际发生的事情,存储库应该为后人保留下来。

相反的观点是,提交历史记录是项目是如何制作的故事。不会发布一本书的初稿,那么为什么要展示混乱工作呢?当在项目上工作时,可能需要记录所有错误和死胡同,但是当准备向世界展示我们工作时,我们可能希望讲述如何从 A 到 B 的更连贯的故事。在这个阵营中,人们使用像重新定位和 filter-branch 这样的工具,在将其合并到主干分支之前重新编写他们的提交。他们使用重新定位和 filter-branch 这样的工具,以最适合未来读者的方式讲述故事。

现在,关于合并和重新定位哪个更好的问题:希望能看到这并不简单。git 是一个强大的工具,可以让我们对历史进行许多操作,但每个团队和每个项目都是不同的。现在我们知道这两个工作原理了,就由我们自己来决定哪个对特定情况更好。

可以两全其美:在推送本地更改之前重新定位以清理您的工作,但不要重新定位已经推送到其他地方的任何内容。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 一个有关类模板、构造函数、析构函数、拷贝构造、重载等的数组案例分析

文章目录 概要根据代码和输出进行分析&#xff08;看注释和图示&#xff09;个人小结 概要 案例描述: 实现一个通用的数组类&#xff0c;要求如下&#xff1a; 可以对内置数据类型以及自定义数据类型的数据进行存储&#xff1b;将数组中的数据存储到堆区&#xff1b;构造函数…

QT-编译报库错误(LF/CRLF)

QT-安装后环境问题记录 版本和环境问题 版本和环境 QT5.15.2 Windows10 QT Creator 问题 在QT夸端开发的项目中 &#xff0c;使用QTCreator打开项目pro文件&#xff0c;编译报出很多系统库 及本地文件中的一些问题&#xff0c;具体如图&#xff1a; 后续&#xff0c;我以为…

【b站李同学的Lee】Part 2 模块化开发 NodeJS+Gulp基础入门+实战

课程地址&#xff1a;【NodeJSGulp基础入门实战】 https://www.bilibili.com/video/BV1aE411n737/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 4 Node.js模块化开发 4.1 JavaScript开发弊端 4.1.1 文件依赖 4.1.2 命名冲突 4.2 生活中的…

Midjourney常见玩法及prompt关键词技巧

今天系统给大家讲讲Midjourney的常见玩法和prompt关键词的一些注意事项&#xff0c;带大家入门&#xff5e;&#xff08;多图预警&#xff0c;建议收藏&#xff5e;&#xff09; 一、入门及常见玩法 1、注册并添加服务器&#xff08;会的童鞋可跳过&#xff5e;&#xff09; …

DC-9渗透测试复现

DC-9渗透测试复现 目的&#xff1a; 获取最高权限以及flag 过程&#xff1a; 信息打点--sql注入- 文件包含漏洞-Knockd开门开启ssh连接-hyjra爆破-sudo提权(文件追加) 环境&#xff1a; 攻击机&#xff1a;kali(192.168.85.137) 靶机&#xff1a;DC_3(192.168.85.141) …

GPT状态和原理 - 解密OpenAI模型训练

目录 1 如何训练 GPT 助手 1.1 第一阶段 Pretraining 预训练 1.2 第二阶段&#xff1a;Supervised Finetuning有监督微调 1.3 第三阶段 Reward Modeling 奖励建模 1.4 第四阶段 Reinforcement Learning 强化学习 1.5 总结 2 第二部分&#xff1a;如何有效的应用在您的应…

【Linux】Linux信号

目录 信号的概念 生活中的信号 Linux中的信号 kill命令 kill 命令的使用 常见的信号 命令行代码示例 注意事项 信号的处理方式 产生信号 信号的捕捉 信号捕捉示意图 内核如何实现信号捕捉 信号的捕捉与处理 小结 阻塞信号 信号在内核中的表示图 信号集操作函数…

如何学习嵌入式Linux?

如何去学习嵌入式 Linux 呢&#xff1f;嵌入式底层开发毫无疑问是一项极为关键重要的技术&#xff0c;其被广泛地应用于形形色色的嵌入式系统之中。伴随科技的迅猛飞速发展&#xff0c;嵌入式系统已然成为了我们生活中不可或缺的一个组成部分&#xff0c;这也极为凸显出了嵌入式…

基于 Bazel 的 iOS Monorepo 工程实践

在之前很长一段时间里&#xff0c;哔哩哔哩 iOS 工程是使用 Polyrepo&#xff08;或者说 Multirepo&#xff0c;即多仓库&#xff09;的传统模式进行开发。但是随着业务的发展&#xff0c;我们的代码仓库的数量也随之膨胀&#xff0c;我们慢慢发现 Polyrepo 模式并不一定是适合…

DDoS攻击愈演愈烈,谈如何做好DDoS防御

DDoS攻击是目前最常见的网络攻击方式之一&#xff0c;各种规模的企业包括组织机构都在受其影响。对于未受保护的企业来讲&#xff0c;每次DDoS攻击的平均成本为20万美元。可见&#xff0c;我们显然需要开展更多的DDoS防御工作。除考虑如何规避已发生的攻击外&#xff0c;更重要…

手机副业赚钱秘籍:让你的手机变成赚钱利器

当今社会&#xff0c;智能手机已然成为我们生活不可或缺的一部分。随着技术的飞速进步&#xff0c;手机不再仅仅是通讯工具&#xff0c;而是化身为生活伴侣与工作助手。在这个信息爆炸的时代&#xff0c;我们时常会被一种焦虑感所困扰&#xff1a;如何能让手机超越消磨时光的定…

关于Git的一些基础用法

关于Git的一些基础用法 1. 前言2. 使用GitHub/gitee创建项目2.1 创建账号2.2 创建项目2.3 下载仓库到本地2.4 提交代码到远端仓库2.5 查看日志2.6 同步远端仓库和本地仓库 1. 前言 首先说一个冷知识&#xff08;好像也不是很冷&#xff09;&#xff0c;Linux和git的创始人是同…

CC254X 8051芯片手册介绍

1 8051CPU 8051是一种8位元的单芯片微控制器&#xff0c;属于MCS-51单芯片的一种&#xff0c;由英特尔(Intel)公司于1981年制造。Intel公司将MCS51的核心技术授权给了很多其它公司&#xff0c;所以有很多公司在做以8051为核心的单片机&#xff0c;如Atmel、飞利浦、深联华等公…

C++:类型转换

目录 1、C语言中的类型转换 2、C的四种类型转换 2.1 static_cast 2.2 reinterpret_cast 2.3 const_cast 2.4 dynamic_cast 3 RTTI 1、C语言中的类型转换 如果 赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c;或者返回值类型与 接收返回值…

TexStudio + MikTex 手动安装宏包

遇到上面这个 “宏包安装” 提示窗口后&#xff0c;设置来源为本地&#xff0c;随后在这个网址 https://mirrors.ustc.edu.cn/CTAN/systems/win32/miktex/tm/packages/ 下载所需的宏包&#xff0c;放到本地仓库里&#xff0c;即可 有三个宏包是必须要有的&#xff0c;它们是索…

上下文输入无限制,谷歌发布Infini-Transformer

去年&#xff0c;百川智能发布号称全球最长的上下文窗口大模型Baichuan2-192K&#xff0c;一次性可输入35万字&#xff0c;超越GPT-4。 今年3月&#xff0c;Kimi智能助手宣布在上下文窗口技术上突破200万字。 紧追其后&#xff0c;国内各大互联网巨头纷纷布局升级自家大模型产…

JAVA基础08- 继承,重写,super以及this

目录 继承&#xff08;extends&#xff09; 定义 说明 作用 方法的重写 定义 重写关键点 方法重写与重载的区别 练习 练习1&#xff08;方法继承与重写的简单练习&#xff09; 练习2&#xff08;方法继承与重写的进阶练习&#xff09; This的使用 定义 作用以及注…

Postman之版本信息查看

Postman之版本信息查看 一、为何需要查看版本信息&#xff1f;二、查看Postman的版本信息的步骤 一、为何需要查看版本信息&#xff1f; 不同的版本之间可能存在功能和界面的差异。 二、查看Postman的版本信息的步骤 1、打开 Postman 2、打开设置项 点击页面右上角的 “Set…

MyBatis 源码分析 - SQL 的执行过程

MyBatis 源码分析 - SQL 的执行过程 * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程。该过程本身比较复杂&#xff0c;牵涉到的技术点比较多。包括但不限于 Mapper 接口代理类的生成、接口方法的解析、SQL 语句的解析、运行时参数的绑定、查询结果自动映射、延…

基于SpringBoot+Vue的二手车交易系统的设计与实现(源码+文档+包运行)

一.系统概述 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大&#xff0c;容错率低&…