使用git rebase 的前提是多人协作下的分支开发,如果是单人开发,那就没有必要使用它了,这是由git rebase 的作用所决定的,git rebase 有两大作用:一个是与主分支保持同步,一个是在合并分支之前清理commit 信息。先看第一个作用。
当多人协作进行开发的时候,通常都会有一个主分支,如master, 用于合并所有人的代码。而在本地开发的时候,每一个人都会开一个分支,进行分支开发。当我们新开一个分支的时候,就意味着,选择了主分支上的一个点作为开发的起点。如下图所示,
这时,本地开发的时候,我们每一个commit 都会提交到 new_feature 分支上, 同时,我们的同事也在开发功能, 他们开发完成后,都会把代码同步到master 分支上。我们从远程master 分支进行pull 操作,拉取到本地的master 分支上,随着时间的推移,就会形成如下状态,
现在怎么办?我们想使用master 分支上的新功能,你可能想到了merge, 但是new_feature 分支还没有开发完成,还没有到merge的时候,那就用git rebase 把。在 new_feature 分支上,使用git rebase master 命令就可以了。
使用git rebase 后,分支new_feature 以最新的master 作为了起点,这时就可以使用master 上的新功能了。rebase, re + base, 的意思,re 是再一次的意思, base 基的意思,再给它一个基础,就是改变以前的基础,改变分支以前的起点到新的起点上(change the starting point of your local branch)
但是有的时候,git rebase 会出问题,我们想回到rebase 之前的状态,怎么办?本地分支上的操作,可以使作git reset 进行回退,但是也要找到回退到的commit id. 这时使用git reflog 命令,如果使用的是git rebase, git reflog 打印出的日志就是显示rebase ......, 找到最后一个rebase 后面没有rebase 的id.
如上图所示,f883bbd, 就是 我们想要的id, 直接git reset --hard f883bdd 就可以了。
现在说第二个作用,清理commit 日志。我们再以master 为基础,新建一个分支,就叫new_feature 分支好了,再在该分支上随便提交两次代码,我一次增加了index.js 再一次增加了style.css 文件,
现在我们想把这个提交日志合并,然后再合并到master 分支上。使用的命令是git rebase --interactive master 然后弹窗一个vim 编辑器,上面就是提交的分支的日起,下面就是一个命令的说明。
你可以看到,它的日志排列正好和git log 相反, 最后提交的在最下面。合并使用的是squash 命令, 把pick 07ab50c 前面的pick 换成squash, 就是把下面07ab50c 提交日志,合并到fc26711 上。
然后按esc 键退出 编辑操作,然后再输入:wq , 退出这个弹窗,这时又跳出一个弹窗。
这个弹窗主要是告诉你git rebase 做了什么事情,直接 :wq 退出就可以了。
可以看到rebase 成功,同时git log 也可以看到 两条记录合并到一条记录上了。
这时,可以愉快地合并到master 分支上了。
git rebase 冲突解决
当使用rebase 的时候,有时会发生冲突,这主要是分支开发时间过长,而同事又大量的提交代码。最近我就遇到rebase 冲突的问题。
当时,我在开发一个功能模块,大约需要两周的时间,而同事呢,都在修复bug, 他们每修复一个bug, 就向远程仓库提交代码,导致我在新建分支开发功能的时候,在master上的起点,大大落后于远程仓库的head. 当开发完这个功能模块的时候,我还是向往常一样,切换到master 分支,从远程仓库拉取代码,然后再git rebase ,但是 rebase 失败,然后就发现我本地有几个文件也被删除掉了,我这里使用的是图形界面化工具进形的rebase, 这时, 我真的有点慌,不知道发生了什么,rebase 失败,怎么会把我本地的文件删除掉呢?胡乱操作了一个晚上,也不知道在操作什么,最终还是没有解决问题,
第二天,找了git的书籍关于git rebase 的内容又看了一遍,发现 我可以使用git reset --hard 进行回退,我晚上使用的git reset 没有加--hard 参数,所以工作区的内容没有发生变化。回退之后,我还要git rebase, 这时我想使用命令行的方式,进行rebase的操作. git rebase master,把master 分支上的内容合并到 我的开发分支上,同样你会现rebase 失败了。但是和图形化界面操作方式不同的是,它告诉你了冲突的文件,以及解决方式。这时看你的命令行中,你会发现(1/n), 到后来,我才发现这是在合并的时候,有n 个文件发生了冲突。我们现在正在解决第一个冲突,还有就是冲突的文件, 我这里是servcie/api.js, 最后是怎么操作, 有几个使用的命令, git add, git rebase --continue, git rebase --skipe, git rebase --abort。
我们来解决api.js中的冲突,冲突解决后,要使用git add, git add server/api.js 把它提交到暂存区,然后,再执行 git rebase --continue, 告诉git 继续rebase. 这时, git 会给出第2个冲突的地方,还是解决冲突,git add , 和git rebase --continue, git 会依次给出所有冲突的文件,直到你把所有冲突解决掉。有时,在解决冲突的时候,发现搞错了,这时 git rebase --abort, 终止rebase, 回到 rebase 之前的状态,就像回滚。这里一定要注意,使用git add的时候,一定不要使用git commit, git commit 不是git rebase 解决冲突的步骤,如果使用了, git 会因为你使用步骤之外的命令来终止rebase 操作。
现解决完冲突以后,我终于知道,为什么我使用图形化界面工具进行rebase的时候,会删除文件,因为有n个文件有冲突,然后,图形化界面工具一步到位,直接合并失败,没有多余的操作,所以就把有冲突的文件删除了。以后再使用rebase 命令的时候,很小使用图形化界面工具了。