当前位置:   article > 正文

在开发过程中使用 git rebase 还是 git merge,优缺点分别是什么?_git rebase 和 merge 用哪个好

git rebase 和 merge 用哪个好

在开发过程中使用 git rebase 还是 git merge,优缺点分别是什么?

在开发过程中使用 git rebase 还是 git merge,优缺点分别是什么? - 知乎 (zhihu.com)

作者:一个小号
链接:https://www.zhihu.com/question/36509119/answer/1990894567
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

rebase 和 merge 根本不是二选一的关系,要协同使用。如果你听到任何人说我只用 rebase/merge 那一定是他不懂。

一个最简单的模型,从 master 分支 checkout 出几个本地 feature 分支,你或者你的团队在协同开发某个 feature-a 时,可能别人已把 feature-b 的代码 merge 回 master 了,所以应该及时将 master 的改动 rebase 到你的本地分支,顺便 fix conflicts。即:

  1. $ git switch feature-a
  2. $ git rebase master
  3. fix conflicts...
  4. $ git rebase --continue

当你开发完成 feature-a 时,应该将改动 merge 回 master。即:

  1. $ git switch master
  2. $ git merge --no-ff -m "Merge branch 'feature-a'" feature-a

在本地分支中使用 rebase 来合并主分支的改动,是为了让你的本地提交记录清晰可读。(当然, rebase 不只用来合并 master 的改动,还可以在协同开发时 rebase 队友的改动。)

在主分支中使用 merge 来把 feature 分支的改动合并进来,是为了保留分支信息。

如果全使用 merge 就会导致提交历史繁复交叉,错综复杂。如果全使用 rebase 就会让你的 commits history 变成一条光秃秃的直线。

一个好的 commits history,应该是这样的:

  1. * e2e6451 (HEAD -> master) feture-c finished
  2. |\
  3. | * 516fc18 C.2
  4. | * 09112f5 C.1
  5. |/
  6. * c6667ab feture-a finished
  7. |\
  8. | * e64c4b6 A.2
  9. | * 6058323 A.1
  10. |/
  11. * 2b24281 feture-b finished
  12. |\
  13. | * c354401 B.4
  14. | * 4bfefb8 B.3
  15. | * eb13f72 B.2
  16. | * c2c62b9 B.1
  17. |/
  18. * bbbba82 init

而不是这样的:

  1. * 9f0c13b (HEAD -> master) feture-c finished
  2. |\
  3. | * 55be61c C.2
  4. | * e18b5c5 merge master
  5. | |\
  6. | |/
  7. |/|
  8. * | ee549c2 feture-a finished
  9. |\ \
  10. | * | 51f2126 A.3
  11. | * | 72118e2 merge master
  12. | |\ \
  13. | |/ /
  14. |/| |
  15. * | | 6cb16a0 feture-b finished
  16. |\ \ \
  17. | * | | 7b27b77 B.3
  18. | * | | 3aac8a2 B.2
  19. | * | | 2259a21 B.1
  20. |/ / /
  21. | * | 785fab7 A.2
  22. | * | 2b2b664 A.1
  23. |/ /
  24. | * bf9e77f C.1
  25. |/
  26. * 188abf9 init

也不是这样的:

  1. * b8902ed (HEAD -> master) C.2
  2. * a4d4e33 C.1
  3. * 7e63b80 A.3
  4. * 760224c A.2
  5. * 84b2500 A.1
  6. * cb4c4cb B.3
  7. * 2ea8f0d B.2
  8. * df97f39 B.1
  9. * 838f514 init

就这么简单。

编辑于 2021-07-11 09:42

​赞同 102​​5 条评论

​分享

​收藏​喜欢收起​

更多回答

知乎用户

638 人赞同了该回答

搞清楚这个问题首先要搞清楚merge和rebase背后的含义。

先看merge,官方文档给的说明是:

git-merge - Join two or more development histories together

顾名思义,当你想要两个分支交汇的时候应该使用merge。

根据官方文档给的例子,是master merge topic,如图:

  1. A---B---C topic
  2. / \
  3. D---E---F---G---H master

然而在实践中,在H这个commit上的merge经常会出现merge conflict。为了避免解决冲突的时候引入一些不必要的问题,工程中一般都会规定no conflict merge。比如你在github上发pull request,如果有conflict就会禁止merge。

所以才会有题主问的问题:在当前的topic分支,想要引入master分支的F、G commit上的内容以避免merge conflict,方便最终合并到master。

这种情况下用merge当然是一个选项。用merge代表了topic分支与master分支交汇,并解决了所有合并冲突。然而merge的缺点是引入了一次不必要的history join。如图:

  1. A--B--C-X topic
  2. / / \
  3. D---E---F---G---H master

其实仔细想一下就会发现,引入master分支的F、G commit这个问题上,我们并没有要求两个分支必须进行交汇(join),我们只是想避免最终的merge conflict而已。

rebase是另一个选项。rebase的含义是改变当前分支branch out的位置。这个时候进行rebase其实意味着,将topic分支branch out的位置从E改为G,如图:

  1. A---B---C topic
  2. /
  3. D---E---F---G master

在这个过程中会解决引入F、G导致的冲突,同时没有多余的history join。但是rebase的缺点是,改变了当前分支branch out的节点。如果这个信息对你很重要的话,那么rebase应该不是你想要的。rebase过程中也会有多次解决同一个地方的冲突的问题,不过可以用squash之类的选项解决。个人并不认为这个是rebase的主要问题。


 

综上,其实选用merge还是rebase取决于你到底是以什么意图来避免merge conflict。实践上个人还是偏爱rebase。一个是因为branch out节点不能改变的情况实在太少。另外就是频繁从master merge导致的冗余的history join会提高所有人的认知成本。

发布于 2016-11-16 11:48

​赞同 638​​31 条评论

​分享

​收藏​喜欢收起​

Elpie Kay

调参码农

110 人赞同了该回答

编辑说明:这个答案目前还有人点赞,所以想要完善下,之前的答案有些问题。添加上图片,让说明更加直观。截图来自于网站Learn Git Branching因为Git是分布式的并且本地仓库和远程仓库可以看作一个整体,所以将本地分支和服务器上的分支显示在同一张图上做说明。本地分支是master,服务器分支是server_ma。

不管用什么风格的操作流程来整合你的本地分支,最终,服务器上的目标分支是要和本地分支做一次类似于fast-forward merge的合并的。

通常情况下有这么两种情形:

1. 本地分支是C0-C1-C2-C3,服务器上是C0-C1。这时候直接push,服务器上也会变成C0-C1-C2-C3,这种是快进式合并。结束后,历史树是一条线。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/345096
推荐阅读
  

闽ICP备14008679号