git rebase
rebase 是一个……我觉得很麻烦的指令,不过没办法,公司算是有个软规定必须要使用 rebase。
rebase 的功能和 merge 很像,不过它能够保持一个相对干净的历史,继续举个例子,假设现在有一个新的功能开发好了,需要将新功能合并到 main 中。
---
title: Merge Example
---
gitGraph
commit
commit
branch feature-merge
commit
commit
checkout main
commit
commit
checkout feature-merge
merge main
commit
checkout main
commit
checkout feature-merge
merge main
checkout main
merge feature-merge
这是开发 A 决定做的事情,ta 总共从 main 上拉了两次,每次产生 conflict 之后都是用 merge 解决的问题,产生了 2 个 merge commits,最后将所有的功能推到了 main 上。
在这个过程中,A 虽然自己实现了 3 个 commits,不过因为 2 次 merge 造成的 commits,ta 一共向 main 提交了 5 个 commits。
---
title: Rebase Example
---
gitGraph
commit
commit
branch feature-rebase
commit
commit
checkout main
commit
commit
commit
merge feature-rebase
开发 B 决定使用 rebase,ta 虽然也产生了 merge conflicts,不过 ta 使用了 rebase 重写了历史,因此在提交上去的时候值提交了 2 个 commits。
看起来好像很方便,但是它造成了一个问题:feature-rebase 上的历史被重写了。
真实发生的小故事
下面这是一个之前碰到的真实事情……
---
title: Rebase Example
---
gitGraph
commit
commit
branch feature
checkout feature
commit
commit
branch feature2
checkout feature2
commit
commit
checkout main
commit
commit
checkout main
merge feature
feature 已经开发了两个月了,所以老板决定将 feature 合到 main 上,并且使用 rebase 清理历史……这个就是我近期内的噩梦的开始……
因为我在实现 feature2……
rebase 之后 feature 上的历史倒是干净了,但是因为 feature 历史被改变了,单独落在 feature2 上的我其实失去了所有在 feature 上的 commits 历史。换言之,feature 上本来的历史在我现在的分支上是不存在的(hash 不一样),所以我需要一一比对原本在我这个分支上 commits……
下面是之前同事的一个 commits:
注意这三百多个文件,其中很多配置文件会反复出现……所以在尝试了 rebase 两三次,花了一个下午,大概只过了十几条 commits 之后,愤然创建了一个 draft,手动一个个 cv 文件,用时两天……
我们团队是 6 个人的团队,一两个月的时间里面就有了这么多的 commits,假设团队的数量再大一些,或者团队对于每个 PR/MR 的 commits 没什么限制……
所以我个人的建议就是,如果你的 commits 已经推到了云端,并且有已经被其他的同事所使用,那么就别 rebase 了……一旦 rebase 会对别的同事产生影响,同时搞乱他们本地的时间线。
但是如果你在本地做一个功能,并且你每天都从主分支上拉最新的变化,那么这个时候就可以使用 rebase,保持当前历史分支干净清爽,别一天创建 3 个 merge commits,但是 3 天才写一个功能 commit……
最后,有一个可互动的 rebase 指令是 git rebase -i <commit>
,看了一下使用方法,会出现 squash、pick、reword 这些选项让你重新修改过去的 commit history:
大致效果如下: