Git常用命令rebase

Git常用命令rebase

1、git常用命令rebase

rebase 会把你当前分支的 commit 放到公共分支的最后面,所以叫变基,就好像你从公共分支又重新拉出来这个

分支一样。

例如如果你从 master 拉了个 feature 分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西

合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的

话,就会把你当前的几个 commit,放到那个人 commit 的后面。

具体操作:

首先 master 也需要拉取到最新版本,然后是切换到 branch 分支,在branch分支执行 git rebase master,表

示 branch 上新提交的 commit 节点会在 master 上的最新提交点后重新设立起点重新执行,若是有冲突则解决冲

突,没有冲突执行 git add,然后执行 git rebase --continue。最后切换到 master 分支,执行 git merge

master

git merge 会将两个分支的最新提交点进行一次合并,形成一个新的提交点,最终形成树状的提交记录,但是有些

人并不是喜欢 merge,觉得 merge 之后出现的分叉会难以管理,那么可以选择 rebase 操作来替代 merge。

git rebase 操作是将要 rebase 的分支最新提交点作为新的基础点,将当前执行 git rebase master 的分支的新

commit 点重新生成 commit hash 值,rebase 完后再次切换到另一条分支进行合并,就可以保证线性的 commit

的记录。

最后只选择 merge 还是 rebase 取决于个人和时机情况,假如你想提交记录呈现线性整洁那么选择 rebase,否则

选择 merge,实际情况也有可能是这样的,每个人本地开发,可能会提交非常的多次,有些提交可能是修一些简

单的 bug,那么最后的提交只想做一次完整、正确的提交,那么也可以使用 rebase。

2、git rebase的两种用法

2.1 合并当前分支的多个commit记录

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

# 新建文件
touch README.md
touch a.txt
touch b.txt
touch c.txt

# 新建文件和本地提交
git add .
git commit -m "Initial commit"

# 修改和提交
echo a > a.txt
git add a.txt
git commit -m "modify a"

# 修改和提交
echo 1 > b.txt
git add b.txt
git commit -m "modify b"

# 修改和提交
echo 2 > b.txt
git add b.txt
git commit -m "modify b"

# 修改和提交
echo 3 > b.txt
git add b.txt
git commit -m "modify b"

# 修改和提交
echo c > c.txt
git add c.txt
git commit -m "modify c"
$ git log --pretty=format:'%h: %s'
2eeb74a: modify c
5d340c4: modify b
e51aaca: modify b
16aee3f: modify b
58c8fed: modify a
f6f3452: Initial commit

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

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

寻找合并 commit 的下一个。

$ git rebase -i 58c8fed

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

前开后闭区间,这里的 [startPonit] 是指需要合并的 commit 的前一个 commit (即当前示例中的 58c8fed ),因

为三个 commit 肯定要基于上一个 commit 合并成了新的 commit。

谨慎使用 [endPoint],该参数省略即默认表示从起始 commit 一直到最后一个,但是一旦你填写了,则表示

[endPoint] 后面的commit全部不要了。

2.1.2 进入Interact交互界面

终端会进入选择交互界面,让你进行变基选择操作:

在这里插入图片描述
最上面三行,就是刚刚选中的三个 commit,按时间顺序依次往下排序(和 git log 的展示顺序是反的, 大家查看的时

候要注意)。

前面的三个 Pick 其实就是下面 Commands 展示的7种命令中的第一个 p,也就是 use commit。

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

按 i 进入操作,将第二、三个 commit 的 pick 改成 s,按 Esc 退出操作,输入 :wq 保存并退出。

在这里插入图片描述

2.1.4 修改commit记录

接下来会弹出第二个页面,分别展示三个commit的提交信息:

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

在这里插入图片描述

# 执行结果
$ git rebase -i 58c8fed
[detached HEAD 792e41c] modify b
 Date: Tue Mar 14 12:28:51 2023 +0800
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.

2.1.5 查看最新合并情况

会发现原三个一样的提交现在合并成了一个新的commit 。

$ git log --pretty=format:'%h: %s'
e6c4bbd: modify c
792e41c: modify b
58c8fed: modify a
f6f3452: Initial commit

2.1.6 rebase的其他用法

命令缩写含义
pickp保留该commit
rewordr保留该commit,但需要修改该commit的注释
edite保留该commit,但我要停下来修改该提交(不仅仅修改注释)
squashs将该commit合并到前一个commit
fixupf将该commit合并到前一个commit,但不要保留该提交的注释信息
execx执行shell命令
dropd丢弃该commit

2.2 避免出现分叉合并

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

1、有两个分支:develop(主分支) 和 rebase_new(feature分支)

2、新需求按时间顺序叫 a 、b、... 等 ( a 需求最早,b 其次,以此类推)

3、原 commit a 变基之后(hashId改变) 叫 a'

2.2.1 先初始化信息

# 新建文件本地提交
touch README.md
git add README.md
git commit -m "Initial commit"

# 新建文件本地提交
touch first.txt
git add first.txt
git commit -m "first commit"

# 新建文件本地提交
touch rebase.js
git add rebase.js
git commit -m "feat rebase.js"

# 修改当前分支名master为develop
$ git branch -m master develop

$ git branch
* develop

# 新建分支
$ git branch rebase_new

$ git branch
* develop
  rebase_new
$ git log --pretty=format:"%h: %cd %s" --graph
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit
$ git checkout rebase_new
Switched to branch 'rebase_new'

$ git log --pretty=format:"%h: %cd %s" --graph
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

2.2.2 develop新增文件

# develop分支下操作
$ touch a.txt

$ git add a.txt

$ git commit -m "feat a"
[develop ea2b178] feat a
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a.txt
 
$ git log --pretty=format:"%h: %cd %s" --graph
* ea2b178: Tue Mar 14 14:07:18 2023 +0800 feat a
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

2.2.3 feature新增文件

# rebase_new操作
$ touch b.txt

$ git add b.txt

$ git commit -m "feat b"
[rebase_new 9a6ddc7] feat b
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt

$ git log --pretty=format:"%h: %cd %s" --graph
* 9a6ddc7: Tue Mar 14 14:08:30 2023 +0800 feat b
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

2.2.4 develop直接merge feature

$ git checkout develop
Switched to branch 'develop'

$ git merge rebase_new
Merge made by the 'recursive' strategy.
 b.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt
 
$ git log --pretty=format:"%h: %cd %s" --graph
*   185c7fc: Tue Mar 14 14:12:57 2023 +0800 Merge branch 'rebase_new' into develop
|\
| * 9a6ddc7: Tue Mar 14 14:08:30 2023 +0800 feat b
* | ea2b178: Tue Mar 14 14:07:18 2023 +0800 feat a
|/
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

会出现以下结果:

1、会保留所有的commit(hashId不变)

2、按提交顺序排序

3、产生新的commit点 (Merge branch ‘rebase_new’ into develop)

2.2.5 develop rebase feature

$ git checkout develop
Switched to branch 'develop'

$ git rebase rebase_new
First, rewinding head to replay your work on top of it...
Applying: feat a

$ git log --pretty=format:"%h: %cd %s" --graph
* d60a365: Tue Mar 14 14:27:06 2023 +0800 feat a
* 9a6ddc7: Tue Mar 14 14:08:30 2023 +0800 feat b
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

会出现以下结果:

develop 分支的 a 会被排在合进来的 feature 分支 b 的上面(尽管a是先完成的)

develop 的原 commit a 被移除产生了新的 commit a’ (hashId已变)

从 feature 合进来的 b 不变 (不会对合进来的 commit 进行变基)

2.2.6 rebase两步走完整版

step1:feature 先 rebase develop

# rebase_new分支
$ git checkout rebase_new
Switched to branch 'rebase_new'

# 从分支上拉取
# 拉取的是两个分支都没有提交过的
$ git fetch origin

$ git rebase develop
First, rewinding head to replay your work on top of it...
Applying: feat b

$ git log --pretty=format:"%h: %cd %s" --graph
* c2b5c6c: Tue Mar 14 15:02:02 2023 +0800 feat b
* ea2b178: Tue Mar 14 14:07:18 2023 +0800 feat a
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit
# 上面的命令比较繁琐,也可以直接执行下面的命令
# rebase_new分支
$ git checkout rebase_new
Switched to branch 'rebase_new'

$ git pull develop --rebase

会出现以下结果:

feature 的 commit b 会在重新排在第一个变成 b’

这一步可以理解为,当前的 feature 相当于先把需求 b 拎出来,同步完最新的 develop,再把需求 b 放在了最后

面。

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

step2:develop 再 merge develop

# develop分支
$ git checkout develop
Already on 'develop'

$ git merge rebase_new
Updating ea2b178..c2b5c6c
Fast-forward
 b.txt | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 b.txt
 
$ git log --pretty=format:"%h: %cd %s" --graph
* c2b5c6c: Tue Mar 14 15:02:02 2023 +0800 feat b
* ea2b178: Tue Mar 14 14:07:18 2023 +0800 feat a
* e3e3525: Tue Mar 14 13:58:03 2023 +0800 feat rebase.js
* f1801e7: Tue Mar 14 13:58:02 2023 +0800 first commit
* cf94b2d: Tue Mar 14 13:58:01 2023 +0800 Initial commit

而这,也是 rebase 为什么不会产生多余的 commit 记录的原因了。

不要基于 rebase 的分支切新分支:如果 feature 在写完新需求 b 后,切了新分支 feature_B,然后又 rebase 了

develop,那么新分支 feature_B 无论是合进 develop 还是合进 feature 都会有冲突,出现重复的 b (其实是b和

b’)。

除非你能百分百确保你的分支已经完成新需求,rebase 操作结束之后,再切新分支,这时他们才是同步的。

3、rebase的其它问题

3.1 rebase时如何解决冲突

1、先解决冲突再保存

2、git add .

3、git rebase --continue

注意不是commit。

如果 rebase 过程中,你想中途退出,恢复 rebase 前的代码则可以用命令 git rebase --abort

3.2 使用rebase的注意点

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

因为变基最强大也是最危险之处就在于它能改变原commit的hashId,而一旦你对历史提交做出改变, 那么从变基

那个节点开始往后的所有节点的 commit id 都会发生变化。这对线上环境来说,是不可控的。

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

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

盖远程对应分支。

但是如果这些修改已经被合到了其他分支(比如主分支),那又会出现冲突,因为其他分支保存的是你 rebase 之前

合进去的 commit。

3.4 不要在预发布/正式分支上使用rebase -i

从变基那个节点开始往后的所有节点的 commit id 都会发生变化。

所以可以想象一下,master 上有100个 commit,你悄悄改了第 50 个 commit,那从 50-100 的所有 commit 全

部改变了,这时别人的分支合进来,就会有51个冲突,解决完冲突之后,就会产生51*2个相同的提交记录。

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

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

相关文章

【C++】YY带你手把手掌握C++系列 (P2)未完结

前言 大家好,这里是YY的带你手把手掌握C系列。大部分知识点都含有【特性介绍】【使用场景】【注意要点】【易混淆点】【代码演示】【画图演示】由于C体系之庞大,所以该系列以分P形式更新!本篇博客为P2! 大家可以通过本篇博客查找C…

【鲁棒优化、机会约束】具有分布鲁棒联合机会约束的能源和储备调度研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

项目实现读写分离操作(mysql)

读写分离 1.问题说明 2.读写分离 Master(主库)----(数据同步)—> Slave(从库) Mysql主从复制 mysql主从复制 介绍 mysql主从复制是一个异步的复制过程,底层是基于mysql数据库自带的二进制日志功能。就是一台或多台…

算法套路十七——买卖股票问题:状态机 DP

算法套路十七——买卖股票问题:状态机 DP 状态机DP是一种将动态规划方法应用于有限状态机(Finite State Machine)的问题求解方法。 状态机DP(State Machine DP)是一种动态规划的思想,它通常用于解决一些具…

如何应用金字塔模型提高结构化表达能力

看一下结构化表达的定义: 结构化表达:是基于结构化思维,理清事物整理与部分之间关系、换位思考后,进行简洁、清晰和有信服力的表达,是一种让受众听得明白、记得清楚、产生认同的精益沟通方式。 结构化表达的基本原则是…

总结如何申请注册 GitHub 教师教育优惠 Benefits for Teachers 来免费使用 copilot

目录 1. GitHub 教师教育优惠有什么2. 如何申请教师教育优惠呢2.1 选择学校2.2 更改个人信息2.3 准备证明材料2.4 提交申请2.5 遇到的问题2.5.1 问题 12.5.2 问题 22.5.3 问题 3 3. 申请免费的 GitHub Copilot 学生注册不在此处赘述了,网上有很多教程可以参考。但是…

前端BFC

一、首先我们要先了解常见的定位方案,总共3种(普通流、浮动、绝对定位) 而BFC是属于普通流的 我们可以把BFC看作为页面的一块渲染区域,他有着自己的渲染规则 简单来说BFC可以看作元素的一种属性,当元素拥有了BFC属性…

Python os模块详解

1. 简介 os就是“operating system”的缩写,顾名思义,os模块提供的就是各种 Python 程序与操作系统进行交互的接口。通过使用os模块,一方面可以方便地与操作系统进行交互,另一方面页也可以极大增强代码的可移植性。如果该模块中相…

二叉堆讲解

二叉堆讲解 大顶堆和小顶堆 从二叉堆的结构说起,它是一棵二叉树,并且是完全二叉树,每个结点中存有一个元素(或者说,有个权值)。 堆性质:父亲的权值不小于儿子的权值(大根堆&#x…

什么是JS事件流

什么是JS事件流? 一&#xff1a;事件冒泡 <!DOCTYPE html> <html lang"en"> <head><title>事件冒泡例子</title> </head> <body><div id"box">点击我</div> </body> </html>上述的代…

利用暴力攻击破解登陆密码

长久以来&#xff0c;入侵远程计算机系统的工具和技术并没有发生翻天覆地的变化。例如&#xff0c;在许多情况下&#xff0c;普通用户只要知道了相关密码&#xff0c;就能立刻变身为管理员。虽然这些情形听起来不够曲折&#xff0c;但在大多数情况下&#xff0c;暴力攻击是通过…

css3 flex弹性布局详解

css3 flex弹性布局详解 一、flexbox弹性盒子 2009年&#xff0c;W3C 提出了一种新的方案----Flex 布局&#xff0c;可以简便、完整、响应式地实现各种页面布局。目前&#xff0c;它已经得到了所有浏览器的支持&#xff0c;这意味着&#xff0c;现在就能很安全地使用这项功能。…

【一起啃书】《机器学习》第五章 神经网络

文章目录 第五章 神经网络5.1 神经元模型5.2 感知机与多层网络5.3 误差逆传播算法5.4 全局最小与局部极小5.5 其他常见神经网络5.6 深度学习 第五章 神经网络 5.1 神经元模型 神经网络是由具有适应性简单单元组成的广泛并行互连的网络&#xff0c;它的组织能够模拟生物神经系统…

生产流程图怎么制作?思路提供

生产流程图是一种图表&#xff0c;用来展示生产流程中的各个环节及其顺序。这种图表可以帮助企业管理者更好地了解生产过程中的各个环节&#xff0c;从而更好地进行管理和优化。生产流程图通常包括各个生产环节的名称、所需时间、参与人员、设备和工具等信息。 在制作生产流程图…

七大软件架构设计原则详解

目录 1、概述 2、七大设计原则 2.1、开闭原则 2.2、里氏替换原则 2.3、依赖倒置原则 2.4、单一职责原则 2.5、接口隔离原则 2.6、迪米特法则 2.7、合成复用原则 3、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&…

基于jdk1.8的Java服务监控和性能调优

JVM的参数类型 X参数 非标准参数-Xint: 解释执行-Xcomp: 第一次使用就编译成本地代码-Xmixed: JVM自己来决定是否编译成本地代码 默认使用的是mixed mode 用的不多, 只需要做了解, 用的比较多的是XX参数 XX参数 非标准化参数相对不稳定主要用来JVM调优和Debug Boolean: …

【Vue3+TS项目】硅谷甄选day02--后台管理系统模板搭建/项目配置

1 项目初始化 一个项目要有统一的规范&#xff0c;需要使用eslintstylelintprettier来对我们的代码质量做检测和修复&#xff0c;需要使用husky来做commit拦截&#xff0c;需要使用commitlint来统一提交规范&#xff0c;需要使用preinstall来统一包管理工具。 1.1 环境准备 n…

阿里云u1服务器通用算力型CPU处理器性能测评

阿里云服务器u1通用算力型Universal实例高性价比&#xff0c;CPU采用Intel(R) Xeon(R) Platinum&#xff0c;主频是2.5 GHz&#xff0c;云服务器U1实例的基准vCPU算力与5代企业级实例持平&#xff0c;最高vCPU算力与6代企业级实例持平&#xff0c;提供2c-32c规格和1:1/2/4/8丰富…

elasticsearch结构化查询(一)

在上一篇中我们介绍了DSL相关的知识&#xff0c;接下来我们将会学习elasticsearch的结构化查询&#xff0c;同时也实践一下上一篇的DSL的查询用法 什么是结构化搜索? 从《Elasticsearch权威指南》上摘取部分解释如下: 结构化搜索是指查询包含内部结构的数据。日期&#xff0…

MATLAB 之 函数文件、特殊形式的函数和程序调试与优化

文章目录 一、函数文件1. 函数文件的基本结构2. 函数调用2.1 函数调用的格式2.2 函数的递归调用2.3 函数参数的可调性2.4 全局变量与局部变量 二、特殊形式的函数1. 子函数2. 内联函数3. 匿名函数 三、程序调试与优化1. 程序调试方法1.1 利用调试函数进行程序测试1.2 利用调试工…