git merge和git rebase

git merge

下述的功能需要新版本git支持,笔者实验版本为: git version 2.30.0.windows.2

git merge --ff (-ff可不写, 默认参数fast-forward )

Fast-forward (–ff) 是指 Master 合并 Feature 时候发现 Master 当前节点一直和 Feature 的根节点相同,没有发生改变,那么 Master 快速移动头指针到 Feature 的位置。
所以 Fast-forward 并不会发生真正的合并,只是通过移动指针造成合并的假象,这也体现 git 设计的巧妙之处。
在这里插入图片描述
如果merge成功会提示使用的模式是Fast-forward

合并前的分支情况:
在这里插入图片描述
这样子可以得到干净线性的git log
合并后的分支指针如下:
在这里插入图片描述

git merge --no-ff (non-fast-forward)

如果Master 合并 Feature 时候发现 Master 当前节点和 Feature 的根节点不相同时,则–ff模式会失效,git就会自动使用–no-ff这种合并方式,这种方式会生成一个新的合并节点。
即使Master 合并 Feature 时候发现 Master 当前节点和 Feature 的根节点相同时,如果显式使用–no-ff模式,git仍然会生成一个新的合并节点。
合并前两个分支的log:
在这里插入图片描述
将分支ba的修改合并到master分支上,并解决冲突:
在这里插入图片描述
使用节点图描述如下:
在这里插入图片描述
其中绿色线表示merge过来的节点以及此次合并的生成的一个新的节点

  • 所有节点均按提交时间顺序排列。
  • 如果需要回退本次的合并,只需回退到merge commit 节点前一个提交到master分支上的节点即可回退本次合并内容,则master分支又会回到合并前的状态。
  • 这种情况就无法得到干净且线性的log,多了之后就会造成git log的混乱。
  • 由于合并的commit不带有任何修改信息,不便于回溯问题。
  • 好处就是可以纪录每次的合并信息。
    在这里插入图片描述

git merge --ff-only (fast-forward-only )

为了追求干净线性 git 历史记录,则可以使用 git merge --ff-only 方式保持主线模式开发是一种不错的选择。在这种情况下,如果Master 合并 Feature 时候发现 Master 当前节点和 Feature 的根节点不相同时,则git merge会提示失败。
如下图所示:
在这里插入图片描述

git merge --squash

在git merge --ff-only失败的时候,这时候可以采用放弃feature分支上commit信息,重新提交一次修改。效果就是相当于在当前分支上做了feature分支上的所有修改。
在这里插入图片描述
这样子就可以保持主分支git纪录的干净和线性,但遗憾的是他会丢失这次的合并信息,因此在下次使用git merge时,仍会提示冲突。

git merge 小结

  • Fast-forward (–ff) 是指 Master 合并 Feature 时候发现 Master 当前节点一直和 Feature 的根节点相同,没有发生改变,那么 Master 快速移动头指针到 Feature 的位置,不会生成新的合并节点。
  • –no-ff (non-fast-forward): 如果Master 合并 Feature 时候发现 Master 当前节点和 Feature 的根节点不相同时,则–ff模式会失效,git就会自动使用–no-ff这种合并方式,这种方式会生成一个新的合并节点
  • –ff-only (fast-forward-only): 如果Master 合并 Feature 时候发现 Master 当前节点和 Feature 的根节点不相同时,则git merge会提示失败
  • –squash: 放弃feature分支上所有commit信息,重新提交一次修改。但遗憾的是他会丢失这次的合并信息,因此在下次使用git merge时,仍会提示冲突

延申一下,git pull的默认行为是git fetch + git merge,因此也能指定上述参数。

git rebase

rebase的含义是改变当前分支branch out的位置,即将当前分支修改的提交均以补丁的形式链在新的branch out根节点位置

最大的特性就是它可以修改重整提交纪录。git rebase 是一个危险命令,因为它改变了历史,我们应该谨慎使用。使用不当可能会导致历史丢失。

使用场景1: 合并分支(变基)

将master分支合并到ba分支上(此时ba 合并 master, 发现 ba 当前节点和 master 的根节点不相同,如果相同的话,效果相当于git merge --ff):
在这里插入图片描述
rebase的操作如下:

  1. git 会把 ba 分支里面的每个 commit 取消掉;

  2. 把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;

  3. 把 ba 分支更新到最新的 master 分支;

  4. 把上面保存的 patch 文件应用到 ba 分支上;

  5. 在 rebase 的过程中,也许会出现冲突 conflict。在这种情况,git 会停止 rebase 并会让你去解决冲突。在解决完冲突后,用 git add 命令去更新这些内容(当然也可以使用git mergetool来解决合并冲突)。

    注意,你无需执行 git-commit,只要执行 continue

    然后git rebase --continue
    这样 git 会继续应用余下的 patch 补丁文件链接到节点末端。

  6. 在任何时候,我们都可以用 --abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。

合并过程的节点图:
在这里插入图片描述

  • git rebase可以保持线性干净的提交纪录

  • 这时候会打破提交纪录的时间顺序,造成阅读混乱。可以使用git rebase --ignore-date参数进行合并,git则会自动将patch的commit修正为当前的时间。
    在这里插入图片描述

  • 同理,git pull --rebase 则使用git rebase来进行合并。

使用场景2: 合并多次提交纪录

当开发一个特性时,往往会多次提交修改。这时候为了保持干净的log,可以使用rebase合并提交:
在这里插入图片描述
第一次进入vi,编辑多次commit的pick or squash
在这里插入图片描述
这里一直不太明白的是,git为什么第一个commit信息必须是pick的,不能是squash的。否则会报错error: cannot ‘squash’ without a previous commit。这时候需要我们使用git rebase --edit-todo才能第二次进入vi。

如果没有这个报错的话,git会自动第二次进入vi,并且让我们编辑提交信息,修改完后,git会自动提交,生成一个新的commit id。

在报错error: cannot ‘squash’ without a previous commit的情况下。这时候我们使用git rebase --edit-todo再第一次第二次进入vi的时候,这时候才是我们会选取保留的一次commit纪录,同时可以修改commit信息。然后执行git rebase --continue完成合并
在这里插入图片描述

使用习惯

一般来说,在多人协作的开发分支或者发布分支上,我们会要求git的log纪录是线性干净的,方便回溯问题和回滚。

因此当在feature、bugfix或者个人dev分支上开发时,需要追踪主线分支的修改,便于我们开发完之后合并到主线分支的时候是no merge conflict。这时候建议使用 git rebase --ignore-date将 master 合并 到特性分支上(这时候可能会有一个问题,就是远程的分支log和本地的会出现对不上的问题,因为rebase会变基。所以需要强制提交,才能提交成功)。

然后使用 git merge 将特性分支合并到 master 分支上,此时应该是可以fase forward的,所以不会有生成新的合并节点。这时候也可以通过git rebase 合并多个commit,让你的开发分支保持干净简洁。

当需要将合并的主线分支推到服务器上时,由于是多人开发,有可能此时你的本地主线已经落后于服务器的主线分支了。因此需要将远程分支同步到本地分支上。这时候建议使用 git fetch && git rebase --ignore-date origin/master 来保证主线分支log的干净简洁以及时间顺序。

参考

git merge --ff/–no-ff/–ff-only 三种选项参数的区别
彻底搞懂 Git-Rebase
git rebase

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值