Git分支合并是我们绕不过的坑,尤其是在多Topic分支同步开发中。作为Git仓库的Owner怎么样,更安全,更高效的完成Git分支的合并工作。
准备工作
我预先在GitHub上创建一个仓库GitBranchPractice。
分支说明:
- master:主分支,外发release分支;
- dev_share:开发分享功能的Topic分支;
- dev_im:开发即时聊天功能的Topic分支;
- dev_share_bak:作为dev_share分支的备份,以便演示;
- dev_im_bak:作为dev_im分支的备份,以便演示;
大家主要关注master,dev_im和dev_share分支,先看看分支关系图。
dev_im分支提交记录如下:
dev_share分支提交记录如下:
在dev_im和dev_share的修改记录中,同时修改common.txt文件,以创造合并冲突。
合并的目标是把分支dev_im的提交记录合并到分支dev_share上。
好的,现在准备开始合并dev_im和dev_share分支。
尝试合并
Git支持merge和rebase两种方式合并代码,两个方式各有利弊。今天我们的合并功能使用rebase方式完成,如果对rebase了解不是很深入,请详细阅读下参考文章中的文章。
第一步:rebase
切换到分支dev_share下,执行git rebase dev_im
命名。
和我们预想的一样,在rebase过程中发生了冲突。
第二步:解决合并冲突
rebase合并过程中,先后会产生两次冲突,具体冲突入下图:
以上两个冲突解决起来比较简单,最终合并好的common.txt内容如下:
本地分支dev_im合并到本地分支dev_share后,dev_share的提交记录如下图:
在此图中,完美的解释了rebase的工作原理。找到dev_im与dev_share的Parent节点,把dev_share的每个提交在dev_im上重衍。大家要注意dev_share的提交记录,在rebase前后的commit id 是不一致的。
这里推荐一个一个Git命令1
git merge-base commit1 commit2
使用此命令可以找到commit1与commit2的Parent节点。
第三步:远端分支同步
完成本地分支合并后,本地分支与远端分支的情况如下:
本地分支dev_share提交记录如下:
本地分支dev_share状态如下:
当完成本地分支dev_im合并到本地分支dev_share后,发现与远端分支dev_share产生分歧,提示git pull
完成同步。
使用git pull -rebase
与远端分支完成同步。
看到这个冲突,已经内牛满面,这个冲突命名之前已经解决过,现在为什么有出现啦?一个冲突解决两次这个不是我们所期望的。
大家已经注意到rebase后,本地分支dev_share之前的提交记录commit id已经发生了变化。本地分支dev_share和origin/dev_share 的Parent节点为分支master的最后一次提交,所以在git pull -rebase
时,会把dev_share的六个提交记录在origin/dev_share上重衍,所以会再次出现冲突。
最佳实践
在尝试合并中第三步远端分支同步后,会发生再次重衍。如果在合并dev_im和dev_merge时,发生冲突(有些冲突,开发中无法避免),那么如果绕过再次重衍的过程,就可以避免两次解决冲突的尴尬。
第一步:创建本地Merge分支
找到本地分支dev_im和dev_share的Parent节点,创建本地分支dev_merge,dev_merge的作用是dev_share的替代者。
在演示实例中,Parent节点恰好是master分支,当然我们可以通过git merge-base dev_im dev_share
找到Parent节点。
确定Parent节点为cbe416b36a6351c457b0e6bd5f965b037dd2780c
,通过Parent节点创建本地分支dev_merge。
确认dev_merge的最后一个commit id为cbe416b36a6351c457b0e6bd5f965b037dd2780c
。
第二步:合并分支
目标是把dev_im与dev_share的提交合并到dev_merge中。
在git rebase dev_share
和git rebase dev_im
后,dev_merge的提交记录如下:
在dev_merge分支上,可以看到从dev_im上合并的commit id未发生变化,从dev_share上合并的commit id同尝试合并一样,发生了变化。
第三步:同步到远端
在第一步:创建本地Merge分支中,已经提前指出dev_merge的作用是dev_share的替代者。在完成本地合并后,我们需要及时的同步到远端,以便其他小伙伴继续coding起来。1
git push origin dev_share
把本地的dev_merge推送到origin/dev_share分支,其他小伙伴只需在dev_share分支上git pull --rebase
便可以继续开发工作。
总结
在这里再次提醒下,我们合并的目标是把分支dev_im的提交记录合并到分支dev_share上。完成合并后,需要保证:
- dev_im的后续提交可以轻松的再次合并到dev_share中;
- dev_share的远端库可以轻松同步到其他小伙伴。
注意
按照最佳实践的方式,需要Owner与小伙伴及时沟通,保证小伙伴们在合并过程中不要把本地dev_share的的提交同步到远端,以避免在第三步:同步到远端时,丢失小伙伴的提交记录。