IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> Git 笔记 - git rebase -> 正文阅读

[开发工具]Git 笔记 - git rebase

提醒:不要在多人合作的公共分支里使用 rebase,自己的开发分支除外。 在公共分支里使用 rebase 的话可能会影响其他小伙伴的工作噢!

01 基本用法

描述git rebase 可以理解为 重新设置基线 ,即 将当前分支重新设置开始点

原理解释:它需要基于一个分支(后面称该分支为公共分支)来设置当前分支的基线,将当前分支的开始时间轴 向后移动到 公共分支的最新跟踪提交最后面 ,这样当前分支就是公共分支的最新跟踪分支了。

白话文解释:rebase 会把当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像从最新公共分支又重新拉出来这个分支一样~

举个例子:现有一个 master 主分支,小明要开发新需求从 master 拉取并创建了名为 dev 的新分支。而当小明开发完后需要合并到 master,但发现 master 相比之前多了一些变更。这时想要同步 master 的改动应该怎么办呢?如下图所示:

dev
master
创建新分支 dev
G
F
B
E
D
C
A

讨论小剧场 01 ~
————
同学A:使用 git merge 就能解决这个问题。
小明:但提交记录会很乱,而且若之后要回滚这部分的代码还得考虑是否混杂涉及了别人的提交。
————
同学B:若只复制一两个提交到其他分支,建议使用更简单的命令 git cherry-pick
小明:没错!不过我的提交很多,还有没有其他方法呢?
————
同学C:别犹豫小伙!git rebase 欢迎你~
小明:对!就是它!

执行 git rebase master 之后,如图所示:

dev
master
小明 dev 复制版
创建新分支 dev
G
F
B
E
D
C
A
F1
G1

02 应用场景

2.1 合并子分支到主分支

$ git rebase <想要同步的分支名>

情景:你从主分支 master 切出分支 dev 进行开发。在你开发的过程中,你的小伙伴将他的修改早已合到 master 中,导致你的分支 dev 落后于 master ,这时想要同步 master 的改动。

操作说明👇👇👇

第 1 步,先查看下 master 和 dev 分支的提交记录:

# master 分支的提交( one 和 two 是小伙伴的提交)
$ git log --oneline
--->>
9ed2610 (HEAD -> master) calculate(two) # 2022-01-10 10:00
4803bd9 calculate(one)# 2022-01-05 17:00
819a8ce update 
69322b6 init
---<<

# dev 分支的提交 ( step 1/2/3/4 是自己的提交)
$ git log --oneline
--->>
a3154c7 (HEAD -> dev) step 4 # 2022-01-10 19:00
15135ef step 3 # 2022-01-06 10:00
3aad796 step 2 # 2022-01-04 16:00
a061fb6 step 1 # 2022-01-04 9:00
819a8ce update
69322b6 init
---<<

第 2 步,在 dev 分支里使用 rebase:

# 在 dev 分支里使用 rebase
$ git rebase master
--->>
Successfully rebased and updated refs/heads/dev.
---<<

第 3 步,再次查看 dev 分支里的提交,同步成功!!!

# 再次查看 dev 分支里的提交,确认是否同步成功
$ git log --oneline
--->>
4163d09 (HEAD -> dev) step 4 # 最新时间
6a48001 step 3 # 最新时间
4a1beb1 step 2 # 最新时间
fe0f3fc step 1 # 最新时间
9ed2610 (master) calculate-two # 2022-01-10 10:00
4803bd9 calculate-one # 2022-01-05 17:00
819a8ce update
69322b6 init
---<<

同步后提交记录示意图如下:

使用 rebase 同步 master 后的提交记录
step 4
step 3
step 2
step 1
calculate-two
calculate-one
update
init

试想:如果使用 git merge 最后打印出来的提交记录是什么样的呢?

首先,通过注释里的提交时间能够发现它们是交叉的,所以采用 git merge 的话,提交记录会不清晰,且若需要回滚涉及到合并节点也会很麻烦!

# 在 dev 分支里使用 merge
$ git merge master
 --->>
Merge made by the 'recursive' strategy.
 change.js | 3 +++
 hello.js  | 3 ++-
 2 files changed, 5 insertions(+), 1 deletion(-)
 ---<<
 
# 再次查看 dev 分支里的提交,确认是否同步成功
$ git log --oneline
--->>
99e4368 (HEAD -> dev) Merge branch 'master' into dev
a3154c7 step 4 # 2022-01-10 19:00
9ed2610 master calculate-two # 2022-01-10 10:00
15135ef step 3 # 2022-01-06 10:00
4803bd9 calculate-one # 2022-01-05 17:00
3aad796 step 2 # 2022-01-04 16:00
a061fb6 step 1 # 2022-01-04 9:00
819a8ce update
69322b6 init
---<<

同步后提交记录示意图如下:

使用 merge 同步 master 后的提交记录
step 4
calculate-two
step 3
calculate-one
step 2
step 1
update
init

2.2 将某段提交复制到另个分支上

$ git rebase <start_commitId> <end_commitId> --onto <branch_name>
# start_commitId 和 end_commitId 会指定的是一个前开后闭的区间
# 如果使用^ ,则包含 start_commitId,即 start_commitId^
# --onto 是将该指定的提交复制到 branch_name 分支上

情景:项目会存在多个分支,这时需要将某个分支中的某一大段提交应用到其他分支中。(若只有某一二三个提交,可以使用 cherry-pick 噢)

操作说明👇👇👇

第 1 步,先查看下 master 和 dev 分支的提交记录:

# dev 分支的提交
$ git log --oneline
--->>
4163d09 (HEAD -> dev) step 4 
6a48001 step 3
4a1beb1 step 2
fe0f3fc step 1
9ed2610 (master) calculate-two
4803bd9 calculate-one
819a8ce update
69322b6 init
---<<

# master 分支的提交
$ git log --oneline
--->>
9ed2610 (HEAD -> master) calculate(two)
4803bd9 calculate(one)
819a8ce update 
69322b6 init
---<<

现在想将 dev 中的 step 1 ~ step 3 的提交复制粘贴到 master 中

第 2 步,切换到 master 分支:

$ git checkout master

第 3 步,使用 rebase 命令进行复制粘贴:

$ git rebase fe0f3fc^ 6a48001
--->>                                         
Current branch 15135ef is up to date.
---<<

第 4 步,检查 master 记录,成功啦!

# master 分支的提交
$ git log --oneline   
--->>                                         
15135ef (HEAD -> master) step 3
3aad796 step 2
a061fb6 step 1
9ed2610 calculate(two)
4803bd9 calculate(one)
819a8ce update
69322b6 init
---<<

2.3 合并多个提交为一个提交

git rebase -i  <start_commitId> <end_commitId>
# -i(--interactive),参数含义是弹出交互式的界面让用户编辑完成合并操作
# start_commitId 和 end_commitId 会指定的是一个前开后闭的区间(使用^ 同理)
# 如果不指定 end_commitId,则该区间的终点默认是当前分支 HEAD 所指向的 commitId

情景:提交多次后,想让推送到远程仓库的提交记录简洁明了。

操作说明👇👇👇

第 1 步,先查看下 dev 分支的提交记录:

# dev 分支的提交
$ git log --oneline
--->>
a3154c7 (HEAD -> dev) step 4 
15135ef step 3
3aad796 step 2
a061fb6 step 1
819a8ce update
69322b6 init
---<<

现在将 step 1 ~ step 4 的提交合并为一个,且注释为 " add step all "

第 2 步,执行 rebase 命令:

$ git rebase -i a061fb6^ a3154c7
# -i 会唤起用户交互界面~

第 3 步,刚回车完 rebase 命令之后,会默认打开 vim,我们需要对未注释的行进行操作,即对本次 rebase 包含的所有提交进行操作,如下所示:

--->>
pick a061fb6 step 1
pick 3aad796 step 2
pick 15135ef step 3
pick a3154c7 step 4

# Rebase 5be4f27..a3154c7 onto 5be4f27 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
---<<

补充知识👇
p / pick:保留该 commit
r / reword:保留该 commit,但要修改该 commit 的注释
e / edit:保留该 commit, 但要停下来修改该提交,不只是修改注释
s / squash:将该 commit 和前一个 commit 合并
f / fixup:将该 commit 和前一个 commit 合并,但不保留该提交的注释信息
x / exec:执行 shell 命令
d / drop:丢弃该 commit

第 4 步,修改后的信息如下,如下所示:

--->>
pick a061fb6 step 1
s 3aad796 step 2
s 15135ef step 3
s a3154c7 step 4
...(在此省略注释部分)
---<<

第 5 步,保存上一步修改的内容后,会自动到下一个交互阶段,如下:

--->>
# This is a combination of 4 commits.
# This is the 1st commit message:
step 1
# This is the commit message #2:
step 2
# This is the commit message #3:
step 3
# This is the commit message #4:
step 4
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date:      Mon Jan 24 20:40:38 2022 +0800
#
# interactive rebase in progress; onto 5be4f27
# Last commands done (4 commands done):
#    squash 15135ef step 3
#    squash a3154c7 step 4
---<<

第 6 步,修改后的信息如下:

--->>
...(在此省略注释部分)
add step all
...(在此省略注释部分)
---<<

第 7 步,保存后则会退出 vim 界面,展示下面的信息:

--->>
[detached HEAD 44c49f2] add step all
 Date: Mon Jan 24 20:40:38 2022 +0800
 2 files changed, 9 insertions(+), 1 deletion(-)
Successfully rebased and updated detached HEAD.
---<<

第 8 步,但此时咱们的这些修改还处于游离状态,可以简单的理解为只是复制粘贴到了 剪切板,还有真正的复制粘贴到 dev 分支中,所以需要先切换到 dev 分支~

$ git checkout dev
--->>
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  44c49f2 add step all

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 44c49f2

Switched to branch 'dev'
---<<
# 有人会疑惑,咱们一开始不就是在 dev 分支进行操作的吗,为啥还要切呢?
#答案是:在你进行 rebase 命令的时候,咱们相当于就游离在外啦,简单的说就是备份切换到了一个 临时分支(简单的理解就是 剪切板),所以想要复制粘贴到 dev 分支,就得先切回去啦~
#你看执行完 checkout,命令行就提醒我们需要去处理下 剪切板 里的信息呀

第 9 步,现在将 dev 分支的指针指向咱们最新的地方吧!(指针应该指向哪里呢?大家仔细看看上一步的 checkout 之后的提醒,有一个 commitId 在等着呢 👉 44c49f2)

$ git reset --hard 44c49f2
--->>
HEAD is now at 44c49f2 add step all
---<<

第 10 步,最后咱们看下 dev 分支的提交记录~成功!!!

$ git log --oneline
--->>             
44c49f2 (HEAD -> dev) add step all
819a8ce update
69322b6 init
---<<

2.4 rebase 过程中有冲突,如何解决

rebase 过程中发生代码冲突,可以采用以下配置项:

  • --continue :解决代码冲突后,需要将修改的文件加入暂存区 git add .,再执行 git rebase --continue,让 rebase 继续进行。

  • --abort:发生代码冲突后,放弃 rebase,回到操作前的样子。

  • --quit :发生代码冲突后,退出 rebase,但是不回到操作前的样子。

2.5 rebase 成功后,如何撤销

情景:从 master 分支拉取一个新的分支 dev,而后 master 新增两个提交 " change one " 和 " change two ",dev 分支新增一个提交 " change ",后来想让 dev 分支同步下 master 最新的改动就执行了 git rebase master ,现在希望能够撤销这次 rebase 操作。

第 1 步,执行 git reflog,查看所有操作日志:

$ git reflog
--->> 
3d399a5 HEAD@{0}: rebase (finish): returning to refs/heads/dev
3d399a5 HEAD@{1}: rebase (pick): change
74a3fd7 HEAD@{2}: rebase (start): checkout master
5a0c99c HEAD@{3}: commit: change
5be4f27 HEAD@{4}: checkout: moving from master to dev
---<<

第 2 步,从第 1 步打印出来的记录可以得到 rebase (start/pick/finish),而我们想要回到 rebase 之前的状态,就得回到 rebase (start) 之前,即回到节点 5a0c99c HEAD@{3}: commit: change

第 3 步,执行命令 git reset --hard 回到之前的状态:

# 方式 1 使用 commitId
git reset --hard 5a0c99c
# 方式 2 使用 HEAD@{n}
git reset --hard HEAD@{3}

要记得,最后需要使用 git log 打印提交记录来验证一下是否成功噢!

注意git reflog + git reset --hard 可以撤销任何命令,并回到想要的节点,所以请谨慎操作噢!? ????

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 19:08:14  更:2022-01-30 19:08:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 10:48:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码