除了使用合并(merge)集成2个分支之间的更改,还有另外一种称为rebase的方法。
分支总是基于另一个分支,创建一个分支时,分支就从原分支某个地方(基点)分出去。
例如,在Git – 合并分叉分支示例中,我们在master分支的某个提交处,创建dev分支,然后在master和dev分支上各自都提交了一些更改。
当一个分支与它所基于的分支分离,想将最新的更改集成回当前分支时,rebase提供了一种比merge更简洁的方法。
rebase 命令:
git rebase <基础分支>
正如我们所看到的,合并引入了合并提交,2个合并分支的最后提交,在合并提交中再次集成。
与合并不同,rebase的作用是改变基点。rebase把当前分支的基点,由与基础分支的共同祖先处,移动到基础分支的头部位置处,然后以新基点为基础,重新提交当前分支中的更改。
让我们试用一下rebase,加深理解。
试用 rebase
试用 rebase 步骤:
- 切换到
master
分支,然后基于它创建/签出一个新分支dev3
,添加文件test3.txt
并提交。 - 切回到
master
分支,修改test1.txt
并提交。就像在Git – 合并分叉分支示例中一样,这2个分支的提交记录,在一个共同祖先处分叉,如下图所示。
- 切换到
dev3
分支,使用rebase把master
分支中的更改集成到当前分支dev3
中,执行rebase命令:Kevin@qikegu MINGW64 /g/project/git-demo (dev3) $ git rebase master First, rewinding head to replay your work on top of it... Applying: add test3.txt
该命令输出告诉我们rebase背后进行的操作。
rebase 背后
HEAD是指向当前分支头部位置(最新提交)的指针。
rebase启动之前,HEAD指向分支dev3的头部位置。rebase启动后,HEAD首先移动回公共祖先的位置,然后移动到基础分支:master的头部。
HEAD从0cfc1d2 commit移动到master头部的7639f4b commit。
然后rebase将dev分支上的每个提交,基于新基点重新提交。
更确切地说,git在返回到分支的公共祖先之后所做的是,保存当前分支中的每个提交内容(更改的diff、提交文本、作者等),然后以基础分支master的最新提交为基础,把前面保存的提交内容重新提交。
因此,通常的理解,在rebase之后,0cfc1d2提交不再指向公共祖先,而是指向master的头部。事实上,0cfc1d2提交已经没有了,dev3分支从一个新的0ccaba8提交开始,它的父提交是master的最新提交。
dev3分支看起来像是基于master的最新版本,而不是master的旧版本,rebase重写了分支的提交历史。
rebase是一个非常强大的工具,使用rebase,可以经常集成其他人所做的更改,同时保持清晰的线性历史记录,在将工作放入共享分支时可进行快速合并。
保持线性历史记录也使得(尝试git log --graph
)提交日志更清晰,比使用合并提交(通常仅使用默认文本)的历史记录更有用。