git rebase的时候捅娄子了,怎么办?在线等……

大家在使用git的过程当中有闯过祸吗?
我闯过 , 我闯的第一个祸就是使用git rebase造成的 , 虽然后来最终还是解决了 , 但是还是给我吓得不轻 。 当时的事情是这样的 。
我们来看下这张图:
git rebase的时候捅娄子了,怎么办?在线等……文章插图
简单解释一下这张图当中的内容 , C1节点是所有分支的最小公共祖先 。 可以理解成是最早的master版本 , 之后我们checkout出来了两个分支 , 分别是bugFix和feature 。 其中feature是我们新开发的分支 , 而bugFix是修复bug的分支 。
当我们把bugFix了之后就赶紧merge master发布了 , 当我们发布了之后发现bugFix当中有一点小问题 。 比如说把不应该提交的文件提交了上来 , 再加上我们不是用rebase的形式合并的 , 所以看起来commit记录有一点点乱 。 于是我决定使用rebase修复一下提交记录 , 搞完了之后使用git push -f强行更新了远程分支 。
因为我们之前已经push过了 , 想要用新的commit记录覆盖掉旧的就必须要使用-f强行推送 。 这些操作都是常规的操作 , 但是我无意之间犯了一个大问题 , 差点导致了后面的悲剧 。
我先卖个关子 , 大家先用几秒钟时间想一下 , 这里藏着的问题是什么?
rebase的禁忌这里藏着的问题就是feature分支 , 我们从图中可以看到feature分支是merge了C5节点的 。 但是当我们rebase push -f了之后 , C5节点其实就不存在了 。 我们把图画出来给大家看一下就明白了 , 这个是rebase之前的依赖树:
git rebase的时候捅娄子了,怎么办?在线等……文章插图
我们rebase之后依赖树变成了这样:
git rebase的时候捅娄子了,怎么办?在线等……文章插图
由于feature之前曾经merge过master并且依赖了C5节点 , 而master在rebase强行push之后整个链路当中已经没有C5节点了 。 也就是说feature分支依赖了一个已经不存在的节点 , 这个时候还不算太遭 , 因为feature分支还没有更新 , 如果feature分支pull一下 , 那么整个分支会变成这样:
git rebase的时候捅娄子了,怎么办?在线等……文章插图
也就是说同样的代码在feature分支当中保存了两个版本 , 并且如果feature合并进master之后 , 会发现之前push -f强行抛弃的那些提交又被合并了进来 , 并且整个commit的log会变得非常非常混乱 , 难以看懂 。
【git rebase的时候捅娄子了,怎么办?在线等……】如果这些分支都是自己的 , 那么自己捏了鼻子也就算了 , 如果这些分支是团队当中其他人的 , 那么捅个篓子基本上是避免不了的 。 如果组里有一个Git大佬知道这种情况该怎么解决还好 , 否则的话 , 想要完全复原非常困难 , 很有可能一通操作完全不知道偏差到哪里去了 , 也不知道如何找回来 。
我当时还好 , 捅娄子的时候已经学过了这种情况应该怎么处理 , 虽然还是没能避免踩坑 , 但好在及时从坑里出来了 。 在我们来看脱坑的方法之前 , 先来思考一个问题 , 对于rebase造成混乱的根源究竟是什么 , 我们应该怎么避免?
解决rebase的只有rebase为什么我们刚才在C8节点一旦pull就会导致本地的错乱呢?因为我们之前也介绍过 , 当我们执行pull的时候 , 其实是执行了git fetch和git merge两个步骤 。 所以相当于我们把master分支的改动又merge了一次 , 我们本地依赖了rebase之前的改动 , 这样一merge自然就把两个版本的改动merge在一起了 。
要解决这个问题 , 我们就不能在C8节点的时候进行pull操作 , 因为pull操作包含merge , merge会导致错误 。 要解决这个问题其实也不难 , 我们可以rebase到master上 。 当我们执行rebase的时候 , git会找出我们当前分支独有而master分支上没有的改动 , 将这些改动提取出来应用在master上得到一个新的结果 。
git rebase的时候捅娄子了,怎么办?在线等……文章插图
这样我们的记录当中就不会把C2和C5带进来了 。
发散思考我们贯通思考一下上面的过程 , 会得到一个什么结论?
其实结论很简单 , 就是rebase虽然很好用也很方便 , 但是它也有适用的条件 , 其中最大的条件就是如果还有其他分支依赖了当前分支 , 我们这时候不可以使用rebase , 否则一定会引起错乱 。
那引起错乱的原因又是什么呢?本质上是我们rebase的时候修改了commit的记录 , 关于这一点不同的人有不同的观点 。 有一派人认为git的提交记录是不可以篡改的 , 它存在的意义就是记录repo当中所有发生过的改动 。 如果使用rebase等操作进行了篡改 , 那么我们就不能很好地追溯之前的改动和版本了 。 还有一派人不这么看 , 他们觉得如果记录的改动非常混乱非常不方便使用者阅读 , 这时候使用一些方法对它进行修整就是非常有必要的事情 。 工具发明出来就是为了使用的 。