使用场景
- 实现代码合并,避免使用 merge 合并分支时产生的 merge commit 污染分支历史记录。最常见的使用场景是在个人分支上开发完想要合并到主分支上前,使用 rebase 操作将主分支新的 commit 作为基底,避免使用 merge 多产生一个无用的 commit。
- 将最近的几次提交合并,保持分支的整洁。最常见的使用场景就是开发一个功能过程中有多个 commit,最后提交时合并成一个总的 commit。
原理
变基前:
变基后:
这里 master 是基分支,feature 是待变基分支,当执行 rebase 操作时,git 从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。rebase 叫做变基意思就是待变基分支的基底变成基分支的最新节点,这里就表现为 feature 分支的基底变成 master 分支的 M 节点。
这里要注意新产生的 C' 和 D' 节点和原先的 C 和 D 节点是不同的(git 中两个节点的 commitid 不同两个节点就看作不同)。
命令
代码合并
git checout feature
git rebase master
git rebase master feature
两个命令效果是相同的,效果对应上面的例子。
合并多个 commit 为一个 commit
git rebase -i [startpoint] [endpoint]
其中-i
的意思是--interactive
,即弹出交互式的界面让用户编辑完成合并操作,[startpoint]
、 [endpoint]
则指定了一个编辑区间,如果不指定[endpoint]
,则该区间的终点默认是当前分支HEAD
所指向的 commit(注:该区间指定的是一个前开后闭的区间)。
执行命令后会进入 vim 界面修改 commit 记录:
pick 91398f93 d1
pick 65efc762 d2
pick b82e050d d3
# Rebase 4652f96d..b82e050d onto 4652f96d (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
pick:保留该 commit(都可以用首字母缩写代替,除了 exec 用 x)
reword:保留该 commit,但我需要修改该 commit 的注释
edit:保留该 commit,但我要停下来修改该提交(不仅仅修改注释)
squash:将该 commit 和前一个 commit 合并
fixup:将该 commit 和前一个 commit 合并,但我不要保留该提交的注释信息
exec:执行 shell 命令
drop:我要丢弃该 commit
vim 界面输入 :wq
保存退出,会进入一个新的 vim 窗口,在此可以进一步编辑新的 commit message,保存后 rebase 即可生效。
将某一段 commit 粘贴到另一个分支上
留坑,暂时用不到,想到再写
git merge 和 git rebase 的优缺点
git merge
- 优点:不会破坏原分支的提交记录。
- 缺点:会产生额外的提交记录,并进行两条分支线的合并。
git rebase
- 优点:无需新增提交记录到目标分支,reabse 后可以直接将对象分支的提交历史加到目标分支上,形成线性提交历史记录,更加直观。
- 缺点:不能在一个共享分支上进行 reabse 操作,会带来分支安全问题。
git merge 和 git rebase 的正确使用
- 合代码到公共分支的时候使用 git merge,书写正确规范的 merge commits 留下记录。
- 合代码到个人分支的时候使用 git rebase,可以不污染分支的历史提交记录,形成简介的线性记录。
注意事项
Git 官方文档中说“一旦分支中的提交对象发布到公共仓库,就干万不要对该分支进行衍合操作。”
在公共分支上尽量不要用 rebase 操作,而应该使用 merge,因为你使用 rebase 改变了之前节点,而可能影响到同时在使用相同节点的人。
关键就在于 rebase 操作是对 commit 的改写,当 commit 还没有提交到公共仓库时,自己怎么改写都可以,一旦提交到远程仓库再改写 commit,就会与别人的 commit 历史不同,这时 push 时需要push --force
,这显然是不可接受的。
如果是只有自己使用的分支,因为对他人不会造成影响,rebase 后使用push --force
是可以接受的,只要自己清楚使用这个命令的后果。