Git常用命令rebase

news2024/11/27 14:44:46

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个相同的提交记录。

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

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

相关文章

VScode添加右键运行、并设置每次运行前都清屏即去除之前的输出

一、添加右键运行 下载安装运行插件即可 二、运行前清屏 在运行插件中设置 找到Code-runner: Clear Previous Output,把√打上即可

同样都是PoE交换机,标准PoE交换机、非标准PoE交换机和非PoE交换机三者到底有啥区别?

网络交换机是企业和组织中构建局域网、企业网络和数据中心网络的重要组成部分。其中最常见的类型之一是PoE交换机。PoE交换机是一种允许通过网络线路提供电源和数据传输的交换机,这种技术可以为设备提供电力,避免了需要附加电源的麻烦。 本文将介绍PoE交…

从零制作操作系统——环境搭建以及HelloWorld

从零制作操作系统——环境搭建以及HelloWorld 起因 最近在学习操作系统,尝试自己照着书搓一个出来。 环境搭建 基础环境 我们的操作系统在x86平台的Linux下进行编写和运行。编辑器用的VIM。 我的系统是Fedora 36,当然你也可以使用Ubuntu或者其他Li…

码云(Gitee)与Git配置

前提 本文配置的前提是已经申请好了码云(gitee)的账号和电脑上已经安装好了git 1.配置gitee的ssh公钥 在gitee的个人设置里面配置ssh公钥 就是将公钥复制到右侧的框中, 并点击确定即可。 1.1生成ssh公钥 右键鼠标打开git bash here 输入如下命令,邮箱就填自己…

栈与队列的对决:如何用栈实现队列?

本篇博客会讲解力扣“232. 用栈实现队列”的解题思路,这是题目链接。 先来审题: 以下是输出示例: 以下是提示和进阶: 栈是一种后进先出的数据结构,而队列是一种先进先出的数据结构,如何用栈实现队列呢&…

chatgpt赋能Python-pingouin_python

了解Pingouin Python对数据分析和统计学的优势 介绍Pingouin Python Pingouin Python是一个强大的Python包,它提供了在数据分析和统计学中所需的一些主要函数。使用Pingouin Python可以方便地进行t-检验、方差分析、相关性等常用的数据分析和统计学任务。 此外&a…

Vue组件复杂表格高级编辑功能

Vue 组件复杂表格高级编辑功能 文章目录 Vue 组件复杂表格高级编辑功能1. sync 父子组件数据同步更新2. 在 el-table 中开发高级编辑表格功能3. 参考文献 在vue中组件的定义是希望组件可以做单一的功能,做到高复用,低耦合,所以父子组件之间的…

【每日一题/简单模拟题】2446. 判断两个事件是否存在冲突

⭐️前面的话⭐️ 本篇文章介绍【2446. 判断两个事件是否存在冲突】题解,算法标签:【模拟】,【字符串】,展示语言c/java。 📒博客主页:未见花闻的博客主页 🎉欢迎关注🔎点赞&#x…

某大学信息安全竞赛——栈迁移加强版——只溢出0x8,无限ROP

芝士题目: 链接:https://pan.baidu.com/s/1uwFlcSg94MuC2tPi-HCb9w 提取码:joj6 感悟: 之前我只做过溢出超过0x10这样的栈迁移,思路就是找机会去泄露栈空间的地址然后把栈迁移到我们可以控制的栈空间,亦…

Linux_证书_Openssl工具详解

文章目录 OpenSSLopenssl实现对称加密openssl生成密钥对、非对称加密、数字签名根据CA颁布证书生成ca私钥和ca证书根据ca生成证书 小结 OpenSSL OpenSSL 是一个开源项目,其组成主要包括一下三个组件: openssl:多用途的命令行工具 libcrypt…

【滤波专题-第7篇】“类EMD”算法分解后要怎样使用(3)——EMD降噪方法及MATLAB代码实现

使用EMD分解(以及其他“类EMD”分解方法,以下为了简便统称EMD)做信号降噪,是EMD的一个比较重要的应用方向。EMD可以将复杂的信号分解为一系列的固有模态函数(IMFs),每一个IMF都包含了信号的一部…

“源擎”攻破银行核心系统建设痛点

银行业作为操作密集、数据密集、风险密集的行业,在向云转型的过程中面临着诸多独特的挑战,如银行需要具备不间断的业务创新能力,而不被系统开发周期制约;单一系统的开发和升级方式,越来越难以满足日益综合化的业务创新…

chatgpt赋能Python-pycharm关联python

Pycharm关联Python的介绍 Pycharm是一种非常流行的Python集成开发环境,开发人员可以在其中编写、调试和运行Python代码。Pycharm具有许多有用的功能,这些功能可以大大提高代码的效率和质量。其中一个最重要的功能是Pycharm如何关联Python,这…

HTB靶机012-Valentine-WP

012-Valentine 靶机IP:10.10.10.79 Scan nmap端口扫描: ┌──(xavier㉿kali)-[~] └─$ sudo nmap -sSV -T4 10.10.10.79 -F Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-29 00:47 CST Nmap scan report for 10.10.10.79 Host is up (0.30s…

chatgpt赋能Python-pycharm和python关联

PyCharm与Python:超越代码编写的完美结合 如果你是一位Python开发者,那么你肯定需要一个好用的开发环境,以便快速且高效地完成代码任务。而PyCharm就是这样一个优秀的Python开发IDE。它专注于提高Python开发速度和质量,让Python编…

Flowable 生成的表都是干嘛的?(一)

一.简介 Flowable 默认一共生成了 79 张数据表,了解这些数据表,有助于我们更好的理解 Flowable 中的各种 API。 接下来我们就对这 79 张表进行一个简单的分类整理。 ACT_APP_*(5)ACT_CMMN_*(12)ACT_CO_*…

chatgpt赋能Python-pycharm取消所有断点

Pycharm取消所有断点:提高编程效率的必备技巧 Pycharm作为Python程序员必备的开发工具之一,其强大的调试功能广受好评。但是,在开发过程中,我们可能会设置过多的断点或者设置了错误的断点,这样会让程序的运行速度变慢…

Java面向对象程序设计实验报告(实验四 抽象类的练习)

✨作者:命运之光 ✨专栏:Java面向对象程序设计实验报告 ​ 目录 ✨一、需求设计 ✨二、概要设计 ✨三、详细设计 ✨四、调试结果 ✨五、测试结果 ✨附录:源程序代码(带注释) demo4类 Car类 Circle类 Shape…

谷歌chrome浏览器无法自动播放video标签视频的问题

问题根源详见:Chrome中的自动播放政策>> https://developer.chrome.com/blog/autoplay/ The Autoplay Policy launched in Chrome 66 for audio and video elements and is effectively blocking roughly half of unwanted media autoplays in Chrome. For t…

基于数组实现的顺序表(SeqList)

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 它的详细定义如下: 顺序表是一种数据结构,用于存储一组具有相同数据类型的元素,并按照元素在内存中的…