首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Git merge 各种参数以及与 rebase比较

Git merge 各种参数以及与 rebase比较

作者头像
麦克马
发布2025-05-14 11:33:17
发布2025-05-14 11:33:17
2560
举报
文章被收录于专栏:GitGit

--ff(Fast-forward)

Fast-forward 是指 Master 合并 Feature 时候发现 Master 当前节点一直和 Feature 的根节点相同,没有发生改变,那么 Master 快速移动头指针到 Feature 的位置,所以 Fast-forward 并不会发生真正的合并,只是通过移动指针造成合并的假象。

代码语言:shell
复制
git checkout master
git merge feautre556
Updating a1ec682..38348cc
Fast-forward
....... | 2+++
1 file changed, 2 insertions(+)

如果你注意上面的文字的话,你会发现 git 帮你自动执行了 Fast-forward 操作。分支变换过程如下:

合并前
合并前
合并后
合并后

通常功能分支(feature556) 合并 master 后会被删除,通过下图可以看到,通过 Fast-forward 模式产生的合并可以产生干净并且线性的历史记录

--no-ff(non-Fast-forward)

通常,当合并的分支跟 master 不存在共同祖先节点的时候,这时候在 merge 的时候 git 默认无法使用 Fast-forward 模式

举个例子,master 分支已经比 feature001 快了2个版本,master 已经没办法通过移动头指针来完成 Fast-forward,所以在 master 合并 feature001 的时候就不得不做出真正的合并,真正的合并会让 git 多做很多工作,具体合并的动作如下:

  • 找出 master 和 feature001 的公共祖先,节点 c1,c6, c3 三个节点的版本 (如果有冲突需要处理)
  • 创建新的节点 c7,并且将三个版本的差异合并到 c7,并且创建 commit
  • 将 master 和 HEAD 指针移动到 c7

补充:大家在 git log 看到很多类似:Merge branch 'feature001' into master 的 commit 就是 non-Fast-forward 产生的。

non-Fast-forward:合并前
non-Fast-forward:合并前
non-Fast-forward:合并后
non-Fast-forward:合并后

小结:

  • -ff 自动合并模式:当合并的分支为当前分支的后代的,那么会自动执行 。
  • --ff (Fast-forward) 模式,如果不匹配则执行 --no-ff(non-Fast-forward) 合并模式。
  • --no-ff 非 Fast-forward 模式:在任何情况下都会创建新的 commit 进行多方合并(即使被合并的分支为自己的直接后代)。
  • --ff-only Fast-forward 模式:只会按照 Fast-forward 模式进行合并,如果不符合条件(并非当前分支的直接后代),则会拒绝合并请求并且退出。
  • --squash 模式:当一个合并发生时,从当前分支和对方分支的共同祖先节点之后的对方分支节点,一直到对方分支的顶部节点将会压缩在一起,注意:这种方式不移动HEAD,不会提交。需要进行一次额外的commit来“总结”一下,然后完成最终的合并。
  • --no-commit 模式:会将两个分支的差异合并,但不会立即创建一个新的提交。这允许用户在合并后检查和调整合并结果,然后再决定是否提交。如果提交也需要额外的一次commit。

rebase

当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。

rebase合并过程
rebase合并过程
rebase结果
rebase结果

操作原理

  • 首先,它会找出当前所在分支和变基分支的共同Parent,即C2;
  • 然后,将当前分支中C2之后节点的快照暂存,即:C3,C4,C5;
  • 最后,将刚刚暂存的快照应用到基分支main的最新提交的后面,便得到了上图。

需要注意的是这里的第三步一般会产生冲突,这时候就不是简单的迁移了,而是先将待迁移节点(这里为C3,C4,C5)依次逐个与最新节点进行冲突合并。 比如这里第一次冲突是C3与最新节点C8冲突,解决冲突之后得到节点C3`,而得到的这个节点此时也成为了最新节点。之后继续拿C4,C5节点重复此动作依次得到最新的节点。

即便是这里不会发生冲突,迁移后的节点commit的哈希值也已经发生变化,所以相应的节点才叫C3`,而不是C3。

也正是出于这个原因,一般建议是在待合并分支上(此例中为feature)进行rebase操作,而不是在主分支上,最后切换到主分支merge过去即可。原因是有时候可能会通过HASH值去回溯节点,如果在主分支进行了此操作,则HSAH值会发生变化,不利于回溯。

其实在使用者的视角里这里的整个过程说白了就像是把你feature分支上的节点依次重新更新到主分支上一样。

rebase 比较 merge

异同

  首先二者都具备整合分支间变更的能力,但二者的实现手段却大不相同。git merge总是在推进提交历史,并不会影响提交的原始状态,而git rebase整合变更的方式则是对提交历史进行重写,但从结果上看,最后git rebase形成的节点C5`与git merge形成的节点C9完全相同。

优点

rebase不产生新节点,当然也不会产生新的commit日志,但是merge过程中会产生一条几乎“无用”的Merge日志。使用rebase操作的最大好处在于你可以让项目提交历史变得非常干净整洁。首先,它消除了git merge操作所需创建的没有必要的合并提交。其次,rebase会造就一个线性的项目提交历史——也就是说你可以从feature分支的顶部开始向下查找到分支的起始点,而不会碰到任何历史分叉。

rebase产生冲突并合并冲突发生在你操作git rebase时,而合并冲突这个操作是你自己进行的;但是你提交合并申请的时候一般情况下会有评审,由评审者解决冲突,开发者人多的情况下工作量可想而知。

缺点

rebase操作产生冲突需要依次逐个进行解决,重写提交历史可能引起混乱,对新手使用也不是很友好。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • --ff(Fast-forward)
  • --no-ff(non-Fast-forward)
  • rebase
  • rebase 比较 merge
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档