git merge
在团队开发中,少不了需要合并分支代码,常规的命令都是使用git merge
来合并我们的代码,一般操作是:
- 本地分支 拉取 目标分支最新代码
- 切换到目标分支,拉取 本地分支代码
注意,这里的 拉取 ,我们用的是 VSCode 自带的 git 图形操作界面的 拉取 ,其实就是
git pull
指令,而git pull
背后就是git fetch
和git merge
的结合。
这种 git merge
的方式比较简单且常规,可能唯一有点影响的就是美观?因为你的 git 提交历史记录会出现大量的合并记录,同时会出现很多分支的分叉。
git rebase
如果想要保证自己的提交历史记录是线性的,就可以使用 git rebase
命令,效果如下图:
注意,git rebase
与 git pull --rebase
效果是一样的!
现在模拟一下,假设本地开发分支是 dev
分支,我们需要将最新的提交 B2
合并到 master
分支,我们在 dev
分支上执行 git rebase master
,会出现以下情况:
- 将
dev
分支上的提交节点B2
以补丁的形式保存起来,这里假设为B2'
,放到master
分支上最后一次提交。然后dev
分支上的HEAD
指针指向master
分支上的最新提交的补丁节点B2'
- 但是此时
master
分支上的HEAD
指针,还是指向自己分支最后一次提交,即B
节点 - 所以要切到
master
分支,需要进行拉取
我们的dev
分支,此时会进行fast forward
快进的一个操作,将HEAD
也指向最新的提交。
git rebase 的 "坑"
正常像上面合并是没有任何问题的,git 提交记录也会是线性的,但那是有一个前提条件的,即我们在合并 master
分支的时候, master
分支上不能有任何新的提交,这在实际开发中基本不可能!
假设我们 rebase
的时候,master
分支上有一次新的提交 C
,我们继续之前的操作 git rebase master
,会出现以下情况:
-
第一步没有变化,还是 将
dev
分支上的提交节点B2
以补丁的形式保存起来,这里假设为B2'
,放到master
分支上作为最后一次提交。然后dev
分支上的HEAD
指针指向master
分支上的最新提交的补丁节点B2'
-
但此时 VSCode 就会提示同步更改代码,即
pull
和push
本地分支。简单说,就是git rebase
会重新应用你的提交到最新的master
分支之上,这个过程会修改你的提交历史,你的本地分支dev
上的提交历史已经改变了,需要将这些更改同步到远程仓库。 但要命的是,如果你选择了同步更改代码,恭喜你,你的代码提交记录不再清爽了/(ㄒoㄒ)/~~ 会多了合并提交的记录,而且即使你删掉dev
分支,dev
分支合并进来的图谱还存在。 那该如何解决呢?让历史提交记录继续保持清爽的线性?不能点击同步更改,而是使用
git push --force
来强制推送本地分支到远程分支!
这时候就会有人说,强制推送,这在公司能随便用吗?不怕覆盖别人的历史提交记录?
稍安毋躁,git rebase
的最佳实践就是在自己的本地分支上执行,不能在公共分支上执行! 所以自己分支上执行强制推送,没有任何问题,因为覆盖的只有自己的提交记录。同时,你要是觉得不保险,还可以使用git push --force-with-lease
这种更安全的选项,它会在强制推送之前检查远程分支是否已经被其他人更新,防止意外覆盖。
- 跟之前一样。此时
master
分支上的HEAD
指针,还是指向自己分支最后一次提交,即B
节点 - 跟之前一样。切到
master
分支,需要进行拉取
我们的dev
分支,此时会进行fast forward
快进的一个操作,将HEAD
也指向最新的提交。最终就大功告成了,我们的提交记录又清爽了!
git rebase 注意点
git rebase
的最佳实践就是在自己的本地分支上执行,不能在公共分支上执行!- 执行
git rebase
的时候,一定要确保变基前服务区必须是干净的,不能有任何文件的更改。
- 要么使用
git commit
提交本地代码 - 要么使用
git stash
暂存本地代码
- 如果遇到冲突,有以下三个命令行可以来解决冲突:
git rebase -- skip
会丢弃掉当前补丁,以目标分支上的为准,丢弃掉本地分支上的修改git rebase --abort
会丢弃掉整个 rebase 操作,重新恢复到 rebase 之前的状态git rebase --continue
就是解决完一个冲突后,继续 rebase 下去
但实际开发中很少用命令行,直接在 VSCode 中,解决 rebase 合并冲突跟解决merge
合并冲突一样,正常解决即可 4. 在自己分支上 rebase 完之后,一定要手动执行 git push -f
强制推送!!
git rebase 高阶操作
如果 rebase 只是为了保证 git 提交历史记录的线性,那也太小看 rebase 的强悍之处。
交互式 rebase
执行git rebase -i HEAD~~
,这会打开一个交互式界面,一个~
代表压缩(或者说删除)一次提交,也可以用数字代表git rebase -i HEAD~2
,让你可以修改、合并、删除或重新排序最近的 2 个提交。
总结
因为 rebase 的时候要考虑的心智负担太重,如果我们用的是 VSCode 图形化界面操作 git,那本地分支最后还需要手动输入命令 git push -f
进行强制推送,不熟练的情况下还是比较繁琐的。除非公司有洁癖特别要求使用 rebase,大家还是老老实实使用 merge 吧。