git rebase 一看就会,一上手就废我都用 git rebase了,为啥还会重复创建提交记录?而且还会有合并记录?
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 吧。
转载自:https://juejin.cn/post/7390340031036948516