文章目录
- [第四章 变基操作及相关案例](#第四章 变基操作及相关案例)
-
- [4.0 变基简介](#4.0 变基简介)
- [4.1 将 `commit` 版本变基到另一分支](#4.1 将
commit
版本变基到另一分支) - [4.2 在版本冲突的情况下执行变基](#4.2 在版本冲突的情况下执行变基)
- [4.3 对指定版本执行交互式变基](#4.3 对指定版本执行交互式变基)
第四章 变基操作及相关案例
【相关主题】
- 将
commit
版本变基到另一分支- 在版本冲突的情况下执行变基
- 对指定版本执行交互式变基
- 利用交互式变基聚合版本
- 利用交互式变基变更提交者
- 自动聚合版本
4.0 变基简介
变基(Rebasing
)是 Git 具备的一个异常强大的特性。变基是这样一类操作:假如一个 commit
A 最早是基于 commit
B 的;那么将 A 变基到 C ,就是将 A 变为基于 C 的操作。
在接下来的演示案例中,你会发现变基操作往往并不像看上去那么容易。
4.1 将 commit
版本变基到另一分支
先来看看最简单的一类变基操作。相关准备工作:引入一个新文件、提交、变更内容、再提交。这样本地就有了两次 commit
版本。
还是以 jgit
库为例:
bash
# Clone jgit repo into chapter4
$ git clone https://git.eclipse.org/r/jgit/jgit chapter4
$ cd chapter4
# Checkout a new branch
$ git checkout -b rebaseExample --track origin/stable-3.1
# Create the 1st commit
$ echo "My Fishtank
Gravel, water, plants
Fish, pump, skeleton" > fishtank.txt
$ git add fishtank.txt
$ git commit -m "My brand new fishtank"
# Create the 2nd commit
$ echo "mosquitos" >> fishtank.txt
$ git add fishtank.txt
$ git commit -m "Feeding my fish"
# Rabase to stable-3.2
$ git rebase origin/stable-3.2
Successfully rebased and updated refs/heads/rebaseExample.
变基前:
变基后:
git rebase
的执行过程:
- 找到
HEAD
与变基指向的目标分支之间的公共版本(merge-base
); - 基于
merge-base
,找出目标分支上所有缺少的版本; - 尝试将缺少的版本逐一应用到目标分支上。
4.2 在版本冲突的情况下执行变基
如果将一个 commit
版本或一个 branch
分支变基到不同的 HEAD
上,很可能会出现版本冲突。此时必须解决完冲突,并运行命令 git rebase --continue
,方可完成变基。
本节示例将演示如何在有冲突的情况下完成变基。沿用 4.1 节中演示的最终结果,此时 rebaseExample
分支已经变基到 stable-3.2
分支。示例将从 stable-3.1 重新检出新分支,并添加一个和 rebaseExample
分支同名但内容不容的文本文件 fishtank.txt
:
bash
# Checkout rebaseExample2
$ git checkout -b rebaseExample2 --track origin/stable-3.1
# Add a new commit
$ echo "My Fishtank
Pirateship, Oister shell
Coconut shell
">fishtank.txt
$ git add fishtank.txt
$ git commit -m "My brand new fishtank"
# Rebase conflicting branches
$ git rebase rebaseExample
Auto-merging fishtank.txt
CONFLICT (add/add): Merge conflict in fishtank.txt
error: could not apply 24f9bf1ef... My brand new fishtank2
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 24f9bf1ef... My brand new fishtank2
$ subl fishtank.txt
冲突情况如下:
改为如下内容后保存、关闭:
添加合并好的文件,继续变基:
bash
$ git add fishtank.txt
$ git rebase --continue
hint: Waiting for your editor to close the file...
打开的编辑器如图所示:
确认、保存并关闭,将看到提示变基成功:
bash
$ git rebase --continue
[detached HEAD 9911772b3] My brand new fishtank2
1 file changed, 2 insertions(+), 3 deletions(-)
Successfully rebased and updated refs/heads/rebaseExample2.
# Check new status via gitk
$ gitk
详情如下:
可见,本次变基,只将旧分支有、而新分支没有的版本变基过来(即新增 commit
)。
在首次变基中断的 git 提示信息中,还能看到两个备选项:
-
git rebase --abort
:如字面含义,中断变基 -
git rebase --skip
:跳过冲突直接变基,这将导致rebaseExample2
放弃新增的commit
,直接并入rebaseExample
,变基后指向的父级,和rebaseExample
一致:
4.3 对指定版本执行交互式变基
本例以 4.1 中的 rebaseExample
分支为基础,演示如何利用 --interactive
标记,将 4.1 中变基的两个 commit
重新变基到远程跟踪分支 stable-3.1
上:
bash
$ git checkout rebaseExample
Switched to branch 'rebaseExample'
Your branch is ahead of 'origin/stable-3.1' by 109 commits.
(use "git push" to publish your local commits)
$ git rebase origin/stable-3.1
此时在新弹出的编辑器中会展示一个 commit 列表,范围是 rebaseExample
与 stable-3.1
之间的、所有可以变基到 stable-3.1
的 commit
记录。保留示例中新增的两个 commit
,其余全部删除(即第 89 行及以前的内容):
保存后退出编辑器可以看到如下输出:
bash
$ git rebase --interactive origin/stable-3.1
Successfully rebased and updated refs/heads/rebaseExample.
# Check in gitk view:
结果如下:
示例拓展
本例还可以通过一个命令快速实现既定效果:
bash
$ git rebase --onto origin/stable-3.1 origin/stable-3.2 rebaseExample
Successfully rebased and updated refs/heads/rebaseExample.
变基前后示意图如下: