git rebase 合并提交与避免分叉合并

2023-11-09

本文让你熟练使用 rebase,学会以下两种操作,从此拒绝杂乱无章的 git 提交。

目录

用法一: 合并当前分支的多个commit记录

你可能出现过对同一处代码进行多次处理的场景。这会导致如下提交记录:

$ git log --pretty=format:'%h: %s'
d2399da: feat: modify c
0134695: feat: modify b
eb63848: feat: modify b
51c0bca: feat: modify b
4cb600e: feat: modify a
d29f331: Initial commit

其实,中间的对 b 的3次提交完全可以合并成一次 commit,这个时候 rebase 就很有用了。

step1. 找到想要合并的 commit, 使用 rebase -i

git rebase -i 4cb600e

注意 git rebase -i [startPonit] [endPoint]

  • 前开后闭 区间 这里的 [startPonit] 是指需要合并的 commit 的前一个 commit (即当前示例中的 “4cb600e: feat: modify a”)。 因为, 三个 commit 肯定要基于上一个 commit 合并成了新的 commit。
  • 谨慎使用[endPoint] 省略, 即默认表示从起始 commit 一直到最后一个,但是一旦你填写了, 则表示 [endPoint] 后面的 commit 全部不要了!

step2. 进入 Interact 交互界面

进入 Shell 终端选择交互界面,让你进行变基选择操作:
在这里插入图片描述

说明

  • 最上面三行, 就是刚刚选中的三个 commit, 按时间顺序依次往下排序(和 git log 的展示顺序是反的, 大家查看的时候要注意)
  • 前面的三个 Pick 其实就是下面 Commands 展示的7种命令中的第一个p, 也就是使用 commit。

step3. 使用 s 命令 合并到上一个 commit

  1. i 进入操作, 将第二、三个 commit 的 pick 改成 s
  2. Esc 退出操作
  3. 输入:wq保存并退出
    在这里插入图片描述

step4. 修改 commit 记录

接下来会弹出第二个页面, 分别展示三个 commit 的提交信息:
在这里插入图片描述

这里三个信息都是一样的,我们选用第一个的提交信息,将其余的全部注释掉,重复上述步骤, 保存退出即可。
在这里插入图片描述

step5. 查看最新合并情况

会发现原三个一样的提交现在合并成了一个新的 commit 。在这里插入图片描述

rebase 的其他用法

命令 缩写 含义
pick p 保留该 commit
reword r 保留该 commit,但需要修改该 commit 的注释
edit e 保留该 commit, 但我要停下来修改该提交(不仅仅修改注释)
squash s 将该 commit合并到前一个 commit
fixup f 将该 commit合并到前一个 commit,但不要保留该提交的注释信息
exec x 执行 Shell 命令
drop d 丢弃该 commit

用法二: 避免出现分叉合并

接下来,我将用实际示例和场景,来分析 rebase 是如何解决分叉合并的,在此之前, 我先做如下规定:

  1. 有两个分支: develop(主分支)、feature(需求分支);
  2. 新需求按时间顺序ab、…等(a 需求最早, b 其次, 以此类推);
  3. 原 commit a 变基之后(hashId 改变) 叫 a'

场景1: 合并时, 最舒服的情况

在这里插入图片描述
此时的合并有两点好处:

  1. 没有冲突
  2. 没有多余的 commit 提交
    其实这种情况下, rebase 和 merge 的效果是一样的。

请大家记住这个场景, 后面所有的 rebase 都是奔着这个目标来的。

场景2: 各分支都有自己新的 commit

develop 新增需求 a: “feat: a”

feature 新增需求 b: “feat: b”在这里插入图片描述

● develop 直接 merge feature

在这里插入图片描述
会出现以下结果:

  1. develop 会保留 feature 的所有 commit(hashId不变);
  2. 按提交顺序排序;
  3. 产生新的 commit 点(Merge branch ‘XXX’ into develop)
    在这里插入图片描述
● develop 直接 rebase feature

在这里插入图片描述
会出现以下结果:

  1. develop 分支的 a 会被排在合进来的 feature 分支 b 的上面(尽管 a 是先完成的)
  2. develop的原 commit a 被移除 产生了新的 commit a’(hashId 已变)
  3. 从 feature 合进来的 b 不变 (不会对合进来的 commit 进行变基)
    在这里插入图片描述
● rebase 终极版

上述两种操作虽然都能完成合并,但是结果却不是我们想要的。直接 merge 会产生多余提交,而直接 rebase 虽不会产生多余提交,但是会改变自身原有的 commit,这对上游的主分支来说是灾难性的。试想一下,如果上游的 master 主分支被你悄悄修改了 commit,而其他所有人还是基于原来的 commit 进行的开发,可想而知,到时候合代码就会如同车祸现场一样,遍地冲突…

所以,正确的操作是:先提前将 master 主分支的新代码 rebase 到自己的分支,再在主分支上 merge 自己的分支。

这样有两点好处:

  • rebase 的时候,虽然自己的新 commit,但是我们还没有提交上去,所以 commit 的变动对我们没有影响;
  • 如果有冲突,可以提前在自己的分支解决掉, 不会带到主分支上。

我们来看下完整示例:

step1: feature rebase develop
# feature分支
git fetch origin
git rebase develop

# 或者 直接一个命令
git pull develop --rebase

在这里插入图片描述
会出现以下结果:

  1. develop 的新需求 a 会先排在 b’ 的前面(a 先提交上去了嘛);
  2. feature 的 commit b 会重新排在第一个 变成 b’(a 插队了嘛,顺序就变了)。

到这里, 你应该有所察觉了!: 没错! 这一步相当于 回到了场景1的模式, 我当前的 feature 相当于先把需求b 拎出来, 同步完最新的 develop, 再把需求b放在了最后面。

所以, 接下来 merge 的时候 就很舒服了~!

step2: develop merge feature
# develop分支
git merge rebase_new

在这里插入图片描述
在这里插入图片描述
而这, 也是 rebase 为什么不会产生多余的 commit 记录的原因了。

rebase时如何解决冲突

  1. 先解决冲突 再保存
  2. git add .
  3. git rebase --continue
    注意! 不是commit ! 不是commit ! 不是commit !

使用 rebase 的注意点

警告!

先引用官网上的一段话:

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。

如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。

因为变基最强大也是最危险之处, 就在于, 它能改变原 commit 的 hashId, 而一旦你对历史提交做出改变, 那么 从变基那个节点开始往后的所有节点的 commit id 都会发生变化。 这对线上环境来说, 是不可控的!

注意一:不要基于 rebase 的分支 切新分支

在这里插入图片描述
如果 feature 在写完新需求 b 后,切了新分支 feature_B,然后又 rebase 了 develop,那么新分支feature_B 无论是合进 develop 还是 合进 feature 都会有冲突, 出现重复的 b(其实是 b 和 b’)
在这里插入图片描述在这里插入图片描述
除非 你能百分百确保 你的分支已经完成新需求, rebase 操作结束之后, 再切新分支, 这时 他们才是同步的。

注意二:不要对已经合并到主分支的本地修改进行变基

首先, 自己的分支, 如果想对已经推送的 commit 进行修改, 可以在修改完后, 使用 git push -f 强行 push 并覆盖远程对应分支。

但是如果这些修改 已经被合到了其他分支(比如主分支),那又会出现冲突,因为其他分支保存的是你 rebase 之前 合进去的 commit。
在这里插入图片描述

注意三:不要在预发布、正式分支上使用 rebase -i

从变基那个节点开始往后的所有节点的 commit id 都会发生变化。这个就不再赘述了。
所以可以想象一下, master上有100个 commit,你悄悄改了第50个 commit,那从 50—100 的所有 commit 全部改变了, 这时, 别人的分支合进来, 就会有51个冲突, 解决完冲突之后, 就会产生 51*2 个相同的提交记录, 恐怖如斯!

总结

git rebase 是一条集增删改查于一体的强大命令,它既可以对自己的分支进行修修剪剪,也可以在合并其他分支的时候缝缝补补,让我们的 commit 提交看上去干净清爽。

记住一条原则:只对尚未推送或未分享给别人的本地修改执行变基操作,清理历史, 从不对已推送至别处的提交执行变基操作

这样,你才能享受到两种方式(rebase 和 merge)带来的便利。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

git rebase 合并提交与避免分叉合并 的相关文章

  • 来自 eclipse 的部分 git 提交 (egit)

    假设我有一个有 2 个更改的文件 如何使用 egit 只提交其中之一 命令行版本可以在以下位置找到this https stackoverflow com questions 1085162 commit only part of a fi
  • 在 git 提交消息中使用任何 utf-8 字符是否安全?

    我发现使用 UTF8 字符 例如 很有用 请参阅here http www utf8icons com subsets dingbats 在提交消息中 重构 NewService 添加了更好的服务 OldServiceA 据我所见 它see
  • git 克隆错误:致命:git upload-pack:由于远程端可能的存储库损坏而中止

    我对 git 存储库具有读 写访问权限 但是当我尝试 git clone 时 出现以下错误 x ubuntu temp git clone email protected cdn cgi l email protection Corp ap
  • git for-each-ref - 按年龄过滤结果

    我正在使用以下命令here https stackoverflow com a 39251131 5812876 git for each ref format color cyan authordate format m d Y I M
  • 本地git,推送到tfs远程repo

    我厌倦了向我的队友解释使用 DVCS 相对于 CVCS 的好处 他们中的一些人害怕学习曲线 另一些人则看不出任何原因 因为对他们来说 这都是一样的 就我个人而言 我对 TFS 及其问题感到非常厌倦 每当我需要进行一些小的 修复 时 我都必须
  • 无法将 git add origin git@anything 与新的 git 目录一起使用

    我有一个项目 我正在生成许多提交 因此它占用的空间正在快速增长 由于我有一个 gitlab 页面来推送提交 因此我决定最好删除本地 git 目录中的这些旧提交 因为我始终可以从 gitlab 获取它们 为此 我只需删除本地 git 目录 然
  • 如何标记单个文件?或如何下载特定文件? - 胃肠道

    我想向文件添加标签以轻松下载该文件而不是整个分支 如何下载GIT中的特定文件 我不知道有什么方法可以标记特定文件git 对于第二个问题 如何下载特定文件git 仅当您的意思是 同时下载 时 以下内容才有效in a git存储库 这就是我理解
  • 当出现错误时如何删除远程分支?

    我尝试过以下命令 但失败了 git push origin next remote error denying ref deletion for refs heads next To blah git remote rejected nex
  • Eclipse 与外部 src 和 Web 内容文件夹链接或映射

    首先这不是问题但是我遇到的问题的解决方案浪费了4 5个小时来找到解决方案 请让我知道是否有更好的替代方法来使用 eclipse 项目管理外部 src 文件夹 我正在使用版本控制系统 GIT 来管理我的项目 还使用外部 Git 客户端 Sou
  • gitlab 上的权限被拒绝(公钥)

    我的问题是我无法从 GitLab 推送或获取 不过 我可以克隆 通过 HTTP 或通过 SSH 当我尝试推送时出现此错误 权限被拒绝 公钥 致命 无法从远程存储库读取 从我看过的所有线程中 这是我所做的 在我的计算机上设置 SSH 密钥并将
  • ssh 连接超时

    我无法在 git 中 ssh 到 github bitbucket 或 gitlab 我通常会收到以下错误消息 如何避免它 输出 ssh T email protected cdn cgi l email protection i ssh
  • 获取最新远程提交的 SHA1 [重复]

    这个问题在这里已经有答案了 可能的重复 git bash 如何检查是否有新的提交可用 https stackoverflow com questions 6006759 git bash how to check if theres a n
  • Visual Studio Code 内置故事,用于查看 git 提交历史记录并对其内容进行比较

    In this https stackoverflow com questions 37899765 how can i view the git history in visual studio code 60013101 noredir
  • 致命:无法将 HEAD 解析为有效引用

    我正进入 状态fatal Failed to resolve HEAD as a valid ref 每当我尝试承诺时 我努力了 echo ref refs heads master gt git HEAD 但它不起作用 也尝试过 git
  • 未能将一些参考推送至 [email protected]

    当我尝试推送到 Heroku 存储库时收到此错误 我已经设置了autocrlf false在gitconfig中 但这个问题仍然存在 我也尝试过这个解决方案here https stackoverflow com questions 566
  • 我在哪里? *(无分支)

    我已经熟悉了创建 合并和删除分支 我想知道我在哪里 这样我就不会将工作提交到错误的分支 我用git branch a看看我有哪些分支 我认为星号 显示我当前所在的分支 当我得到以下信息时 这意味着什么 no branch master or
  • Git post-receive - 如何检查推送的分支是否与主分支合并

    在我们的团队中 我们通常将所有任务推送到单独的分支中 然后发布经理审查这些分支并将它们合并到 主 分支中 有时团队成员忘记将他们的分支与主分支合并 在推送之前 所以我想做的是 在用户推送后输出一条消息 请与主分支合并 我想我需要检查一些内容
  • 从自己的 gitlab 服务器安装节点模块

    我想从我们的 gitlab 服务器安装节点模块 这是存储库的链接 http ABCD GITLAB myGroup myNodeModule git http ABCD GITLAB myGroup myNodeModule git 根据n
  • 自动同步两个 git 存储库

    是否可以保持同步两个 Github 存储库 远程 的特定文件夹 有两个 github 存储库 repoA 和 repoB 这两个存储库都有名为 ABC 的文件夹以及其他独特的文件夹 如果repoA的文件夹ABC中的任何文件有更新 我想自动更
  • 如何让 Gitlab 运行程序在成功构建时将代码合并到分支中

    嗯 标题几乎是不言自明的 总之 如果构建成功 我希望将一个分支 即开发 合并到另一个分支 即生产 我尝试了 jakub kania 解决方案 但我总是得到id rsa invalid format 我认为 gitlab 秘密变量以某种方式被

随机推荐

  • 面试高频:为什么不用定时任务实现关闭订单?

    在电商 支付等领域 往往会有这样的场景 用户下单后放弃支付了 那这笔订单会在指定的时间段后进行关闭操作 细心的你一定发现了像某宝 某东都有这样的逻辑 而且时间很准确 误差在1s内 那他们是怎么实现的呢 一般的做法有如下几种 定时任务关闭订单
  • pytest当中conftest.py的使用

    目录 一 规则 1 conftest py文件是单独存放的一个单独夹具文件 名称不可修改 2 用处可以在不同的py文件当中使用同一个fixture函数 3 原则conftest py 要和运行的用例放在同一层级 例如testcase包下面
  • centos7服务器升级harbor-2.0.6至2.7.0

    centos7服务器升级harbor 2 0 6至2 7 0 1 升级harbor 2 0 6至2 4 0 使用指南 由于2 0 6版本不能直接升级到2 7 0版本 所以需要先过渡到2 4 0版本 原因是PG版本升级不兼容 2 0 6使用P
  • 如何利用TL431设计一个可调电压源

    TL431是一个三脚电压可控的稳压器件 常用的封装有TO 92 SOT 23 SOT 89 电路符号是这个 TL431常被用在参考电压 基准电压电路 用来替代稳压管 其中1脚是reference 2脚是Anode 3脚是Cathode TL
  • ARP(地址解析协议)

    ARP Address Resolution Protocol 地址解析协议 可以在以太网上 根据已知的IP地址查找主机的硬件地址 一 ARP的工作原理 我们以以太网的工作环境作为背景来探讨这一协议 串行链路由于是点到点链路 故而不需要AR
  • 微信网页开发分享

    首先提供一个微信官方地址点击打开链接 早期web项目中经常用到微信分享功能 现在整理一下 供记忆与分享 开发环境为JAVA H5 1 微信的开发环境不在多说 大概为 使用已备案的域名 设置 公众号设置 的三项域名 设置开发者密码 AppSe
  • Java直接杀死线程方法_如何杀死一个线程?

    1 简介 在这篇短文中 我们将讲述一下java中如果结束一个线程 事实上 这并没有想象中的那么简单 因为 Thread stop 方法已经被废弃啦 根据Oracle的解释 stop 方法可以导致被监视对象遭受破坏 2 使用一个Flag 我们
  • DWT数字水印算法(Python)

    DWT数字水印算法的基本原理 结合Arnold变换的基于DWT的数字水印的嵌入 充分利用了小波变换的特点 采用Haar小波 把原始图像及水印图像进行三级小波分解 然后在多分辨率分解后的频段嵌入水印信号 得到嵌入水印的图像 数字水印最重要的性
  • Keil5识别不到ST-Link的解决办法

    刚开始还以为是pack的问题 下载好多pack也没解决 后来发现其实是驱动的问题 从官网上下载驱动 之后进行基本的配置 如下所示 点击魔术棒标志 然后 然后 点击settings 点击add 添加自己的芯片类型 选择erase full c
  • 基于BERT模型实现文本分类任务(transformers+torch)

    BERT的原理分析可以看这 BERT Pre training of Deep Bidirectional Transformers for Language Understanding 论文笔记 代码实现主要用到huggingface的t
  • 如何保证MQ不丢失信息

    为了保证消息队列 MQ 不丢失信息 有以下几种方法可以考虑 增加冗余 通过将数据存储到多个不同的地方来防止数据丢失 使用持久化存储 通过将数据存储到磁盘上 而不是内存中 以确保数据不会丢失 引入数据备份 定期对数据进行备份 以防止意外数据丢
  • 二. go 常见控制结构实现原理之 select

    目录 一 基础问题 select 与channel select 与 channel 二 实现原理 1 select 底层结构 2 select选择case的执行逻辑 一 基础问题 select是Golang在语言层面提供的多路IO复用的机
  • Vue基础--组件的创建和使用

    一 组件化思想 一个页面中所有的处理概述逻辑全部放在一起 处理起来就会变得非常复杂 不利于后续的管理以及扩展 但是 我们将一个页面逻辑复杂的页面拆分成一个个小的功能块 每个功能块只完成属于自己这部分独立的功能 把大功能拆分成一个个小的功能
  • 51单片机0-9数字LED灯循环输出

    代码 include
  • 703n的OpenWrt配置一:安装和基本设置

    OpenWrt支持的路由可以从官网查到 顺藤摸瓜也可以找到固件的下载地址 如果知道路由器的cpu也可以从这里分类查找路由器型号 对于703n的ar71xx就是点我里面搜索703n找到的那几个文件 挑最小的固件下载 这样可以剩下更多空间安装其
  • 【C++】类的默认成员函数——构造函数、析构函数、拷贝构造函数、赋值运算符重载

    文章目录 一 前言 二 构造函数 1 基本概念 2 初始化列表 3 自动生成的构造函数 三 析构函数 1 基本概念 2 自动生成的析构函数 四 拷贝构造函数 1 基本概念 2 自动生成的拷贝构造函数 五 赋值运算符重载 1 基本概念 2 自
  • 全面剖析PMD静态代码扫描工具

    PMD是使用JavaCC生成解析器来解析源代码并生成AST 抽象语法树 的 这两天对PMD及自定义规则做了调研及实验 部分说明来自官方说明文档 做了大部分参数的详细描述及测试 少数几个参数不明白含义 有了解的朋友欢迎讨论 1 调研对象 pm
  • 如何连接安卓手机到mac并传文件

    平时你有没有需求将文件拖拽到安卓手机文件夹下呢 我最近就需要安装许多插件包到我的手机上 今天就记录下我是如何做这个事情的 本文纯属自己记录自己的学习过程 下面交代下步骤 1 mac端下载HandShaker 2 安装HandShaker包
  • 2.1.cuda驱动API-概述

    目录 前言 1 Driver API概述 2 补充知识 总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程 之前有看过一遍 但是没有做笔记 很多东西也忘了 这次重新撸一遍 顺便记记笔记 本次课程学习精简 CUDA 教程 Dr
  • git rebase 合并提交与避免分叉合并

    本文让你熟练使用 rebase 学会以下两种操作 从此拒绝杂乱无章的 git 提交 目录 用法一 合并当前分支的多个commit记录 step1 找到想要合并的 commit 使用 rebase i step2 进入 Interact 交互