『Git』rebase or merge

Git 是 Linus Torvalds 除了 Linux 之外,对人类的又一大贡献。作为一名开发者,相信大家也或多或少接触过 Git。当然,我平时也用,但只能说『能用』,谈不上熟练,每次要合并、撤销的时候,都心惊胆战的,这些都源于对 Git 的不熟悉。终于,决定从头梳理一遍 Git 的用法,感谢@小锅的悉心教导。前段时间在组内做 Git 分享的时候,几个开发小组都再说自己的 Git 远程 log 太乱,乱到没眼看的那种,终于 iOS 组决定先试试水,看看完全一条线的 Git log 有什么优劣势。

以下便是我的调研结果,以及我组现在的 Git 实践。

环境信息:
Git 2.8.4
Mac OS X 10.11.6

正文

Rebase 与 Merge 简介

在合作开发时,分支一旦多了,直接采用 merge 看起来非常乱,而采用 rebase,则会整洁很多:

     

但是什么导致的?什么时候用 rebase?什么时候用 merge?rebase 和 merge 应该怎样分工?感觉没有标准答案,还是先一步一步分析看看。

导致 Merge branch commit 的原因

如果 master 领先 dev 三个 commit,而 dev 此时也有新的 commit,那么,树状图应该是这样:

如果此时 merge,那么会产生新的 merge branch commit。

# 当前在 master 分支
git merge dev

解决 merge branch commit

如果要解决 merge branch commit,那就需要用到 rebase。

# 当前在 dev 分支
git rebase master

rebase 命令会将之前的三个 commit,移到 master 的前面。准确来说,应该是新建的三个 commit,这三个 commit 的 id 和以前都是不一样的。现在 master 与 dev 都在一条线上了,这个时候再去 merge 就不会有问题了:

# 当前在 dev 分支
git checkout master
git merge dev

Rebase 与 Merge 优劣势

先来看看 rebase 与 merge 的优劣势,然后再进行合理选择。下面的优劣势摘自 SourceTree 官方博客Merge or Rebase?

Merge 优势

  • 简单易读。
  • 保留了最原始的提交顺序。
  • 在当前分支上,不会包含其他分支的提交。这个特点,在有多个开发分支的时候比较显著。比如有作为新需求迭代的 feature 分支、有用于解决 bug 的 bug 分支等,能做到互不干扰。
  • 已存在的 commit 不会再变。

Merge 劣势

  • 会产生 merge branch commit。

Rebase 优势

  • 历史提交看起来很漂亮。
  • 多人协作开发时,能很直观很清晰的看出每个人的 commit。

Rebase 劣势

  • 当出现冲突时,要比 merge 复杂。在 rebase 每个 commit 的时候,出现冲突便会中断 rebase,在解决后,需要继续 rebase。
  • 会重写 commit 历史,这也就打乱了原本的 commit 顺序。

Git 实践

前文也谈到很多关于 rebase 与 merge 的优劣势,不同公司、不同开发小组之间,采用的合作开发模式也是不同的。关于这个,SwiftGG 中也专门发起了讨论。大致几种方式如下:

  1. 没有 rebase,全采用 merge(绝大多数都是这种)
  2. commit 数量比较少的时候,用 rebase,多的时候用 merge
  3. 在开发独立功能时,用 rebase,当要合并到主分支上时,用 rebase

调研一圈,都没发现有人像我司这样拉成一条线的 Git log。实行小一月,还未发现问题。下面来介绍下合作流程吧!

假设当前正在开发 6.4.0 版本,那么我会有三个分支:

  • origin/6.4.0:远程 6.4.0
  • 6.4.0:本地与远程想关联的 6.4.0
  • dev:本地的开发分支

假设当前在在开发分支上,有新的 2 个功能开发完成,而在 dev 上有两个新的 commit。而 origin/6.4.0 上,同事也提交的自己 commit。

# 当前在 dev 上,并且有 2 个 commit
# 此时 6.4.0 是落后 dev 的

git checkout 6.4.0 # 先切到与远程关联的 6.4.0 上,准备更新远程代码
git pull --rebase origin 6.4.0 # 将远程代码拉到本地,因为 pull 命令是 fetch + merge,不加 --rebase 可能会造成 merge branch commit

git checkout dev # 切到 dev 上,准备将 dev 中的 2 个 commit,移到 6.4.0 前面
git rebase 6.4.0 # 将 dev 的两个 commit,移到 6.4.0 前面,即将自己的两个 commit,作为最新 commit

# 如果出现冲突,则解决冲突,然后:
# git add .
# git rebase --continue

git checkout 6.4.0 # 切到 6.4.0
git merge dev # 让 6.4.0 分支,追上 dev(dev 因为两个 commit 而领先)

# push
git push origin 6.4.0

# 回到 dev 分支上继续埋头码
git checkout dev

最后

具体怎样选择使用 merge 与 rebase,还是要看团队具体怎样协作。欢迎大家 share 自己团队的协作方式。

关于 rebase 与 merge 的理解,这篇文章也不错,值得一看。

发表评论

电子邮件地址不会被公开。