阅读 149

git rebase的两种用法(最全)(git的rebase和merge的区别)

熟练使用rebase 拒绝杂乱无章的git提交

用法一: 合并当前分支的多个commit记录

你可能出现过对同一处代码进行多次处理的场景。这会导致如下提交记录:

$ git log --pretty=format:'%h: %s' d2399da: feat: modify c 0134695: feat: modify b eb63848: feat: modify b 51c0bca: feat: modify b 4cb600e: feat: modify a d29f331: Initial commit 复制代码

其实, 中间的对b的3次提交 完全可以合并成一次commit, 这个时候 rebase就很有用了。

1. 找到想要合并的commit, 使用rebase -i

git rebase -i 4cb600e 复制代码

注意 git rebase -i [startPonit] [endPoint]

  • 前开后闭 区间 这里的 [startPonit] 是指需要合并的commit的前一个commit (即当前示例中的 "4cb600e: feat: modify a")。 因为, 三个commit肯定要基于上一个commit合并成了新的commit。

  • 谨慎使用[endPoint] 省略, 即默认表示从起始commit一直到最后一个,但是一旦你填写了, 则表示 [endPoint]后面的commit全部不要了!

2. 进入Interact交互界面

终端会进入选择交互界面, 让你进行变基选择操作: Snipaste_2021-11-27_17-20-59.png

说明

  • 最上面三行, 就是刚刚选中的三个commit, 按时间顺序依次往下排序(和git log的展示顺序是反的, 大家查看的时候要注意)

  • 前面的三个Pick 其实就是下面 Commands展示的7种命令中的第一个p, 也就是使用commit。

3.使用s命令 合并到上一个commit

  1. i 进入操作, 将第二、三个commit的pick改成s

  2. Esc 退出操作

  3. 输入 :wq 保存并退出

Snipaste_2021-11-27_17-22-28.png

4.修改commit记录

接下来会弹出第二个页面, 分别展示三个commit的提交信息 在这里插入图片描述

这里三个信息都是一样的, 我们选用第一个的提交信息, 将其余的全部注释掉,重复上述步骤, 保存退出即可

Snipaste_2021-11-27_17-41-28.png

5.查看最新合并情况

会发现原三个一样的提交现在合并成了一个新的commit。 Snipaste_2021-11-27_17-24-26.png

6.rebase的其他用法

命令缩写含义
pickp保留该commit
rewordr保留该commit,但需要修改该commit的注释
edite保留该commit, 但我要停下来修改该提交(不仅仅修改注释)
squashs将该commit合并到前一个commit
fixupf将该commit合并到前一个commit,但不要保留该提交的注释信息
execx执行shell命令
dropd丢弃该commit

用法二: 避免出现分叉合并

接下来, 我将用实际示例和场景, 来分析rebase是如何解决分叉合并的, 在此之前, 我先做如下规定:

  1. 有两个分支: develop(主分支) rebase_new(feature分支)

  2. 新需求按 时间顺序ab、......等(a需求最早, b其次, 以此类推。)

  3. 原commit a 变基之后(hashId改变) 叫 a'

场景1: 合并时, 最舒服的情况

image.png

此时的合并有两点好处:

  1. 没有冲突

  2. 没有多余的commit提交

其实这种情况下, rebase和merge的效果是一样的。
请大家记住这个场景, 后面所有的rebase都是奔着这个目标来的。

场景2: 各分支都有自己新的commit

develop 新增需求a: "feat: a"
feature  新增需求b: "feat: b" 场景2准备.png

● develop 直接merge feature

image.png 会出现以下结果:

  1. 会保留所有的commit(hashId不变)

  2. 按提交顺序排序

  3. 产生新的commit点(Merge branch 'XXX' into develop)

image.png

● develop rebase feature

image.png 会出现以下结果:

  1. develop分支的 a会被排在 合进来的feature分支 b 的上面(尽管a是先完成的)

  2. develop的 原commit a 被移除 产生了新的 commit a' (hashId已变)

  3. 从feature合进来的 b不变 (不会对合进来的commit进行变基)

image.png

● rebase 两步走 完整版

step1: feature 先 rebase develop

image.png 会出现以下结果:

  1. 和场景2类似, feature的commit b 会在重新排在第一个 变成 b'

  2. develop的 新需求a 会排在 b' 的前面

到这里, 你应该有所察觉了!: 没错! 这一步相当于 回到了场景1的模式, 我当前的feature相当于先把需求b 拎出来, 同步完最新的develop, 再把需求b放在了最后面。
所以, 接下来merge的时候 就很舒服了~!

step2: develop 再 merge develop

image.png

image.png
而这, 也是rebase为什么不会产生多余的commit记录的原因了。

rebase时如何解决冲突

  1. 先解决冲突 再保存

  2. git add .

  3. git rebase --continue 注意! 不是commit ! 不是commit ! 不是commit !

使用rebase的注意点

警告!

先引用官网上的一段话:

如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。

不要基于rebase的分支 切新分支

image.png 如果feature在写完新需求b后, 切了新分支 feature_B, 然后又rebase了develop, 那么新分支feature_B无论是合进develop 还是 合进 feature 都会有冲突, 出现重复的b(其实是b和b') image.png image.png 除非 你能百分百确保 你的分支已经完成新需求, rebase操作结束之后, 再切新分支, 这时 他们才是同步的。

不要对已经合并到主分支的本地修改进行变基

首先, 自己的分支, 如果想对已经推送的commit进行修改, 可以在修改完后, 使用 git push -f 强行push并覆盖远程对应分支。 但是如果这些修改 已经被合到了其他分支(比如主分支), 那又会出现冲突, 因为其他分支保存的是你rebase之前 合进去的commit。 image.png

不要在预发布/正式分支上使用rebase -i

从变基那个节点开始往后的所有节点的commit id 都会发生变化。这个就不再赘述了。 所以可以想象一下, master上有100个commit, 你悄悄改了第50个commit, 那从50—100的所有commit全部改变了, 这时, 别人的分支合进来, 就会有51个冲突, 解决完冲突之后, 就会产生51*2个相同的提交记录, 恐怖如斯!

总结

总的原则是,只对尚未推送或未分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式(rebase 和merge)带来的便利。


作者:蓝屏的钙
链接:https://juejin.cn/post/7035512330662182920


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐