git rebase 通常有两个作用,一个是合并 commit,一个是合并分支。
最近看了一篇文章讲解的很清楚了:git-rebase.io/
先说合并 commit:
在合并 commit 的时候,git rebase 最好在 feature 分支或者 hotfix 分支上做,并且这个分支是不和其他人共用的:也就是说其他人不会 pull 你这个分支并且在这个分支上修改内容;并且这个分支最好还没有推送到远程仓库。
以上是前提,然后说下场景。
第一个场景就是修改最后一次提交,直接在最后一次提交的基础上修改内容,然后用 git rebase -a --amend 就可以修改最后一次的提交。
第二个场景是修改更早之前的提交,比如你分别 commit 了2次:a, b。但是你发现在 a 的时候你的修改不完善,你又不想直接在 b 的基础上对 a 进行修改。那么比较原始的办法是,你需要回退到 a 修改的更加完善,然后再 commit a,再在这个基础上 commit b。这样的好处就是你只有两次提交,而不是通过新增一个 a' 的方式来给 a 打补丁,因为这种会产生 3 个 commit,对于代码洁癖的人来说是有问题的。这种场景下,有个好办法。直接在 b 的基础上给 a 打补丁,然后生成 a' 的 commit。然后输入命令 git rebase -i HEAD~3,在交互模式下做如下操作。
pick 8d3fc77 commit a
fixup 0b9d0bb commit a'
pick 2a73a77 commit b
这里有两个操作,第一个是把 a' 挪动了位置,从最下面的第三行移动到了第二行,放在 a 下面。第二个操作是将 a' 前面的内容从 pick 改成了 fixup。保存当前的交互。然后提交就会变成 a, b 两个,并且给 a 打上了 a' 的补丁。
这里多说一句,很多时候我们都是 git add files,然后再 git commit -m 'message',但是有时可以直接用 git commit -a -m 'message' 的方式合并这两步操作。当然其实我还是觉得分开执行比较好,看的更清楚一些。-a 表示 automatically stages (i.e. git add's) all files that git already knows about。我还是不推荐这种方式使用,但是你需要知道这个是什么意思。
第三个场景是合并多次提交,这个其实很多人提到了,而且目前市面上的大部分描述场景也都是这个。细节我不详述了。只说一点,就是修改的时候是把 pick 改成了 squash,这个和上面讲的 fixup 的不同在于,squash 会保留 comimt,而 fixup 不会保留。因此 squash 之后还会有第二步,就是给这次 rebase 做一次新的 commit message 的修改。
第四个场景是拆分一个大的 commit,这个我目前没有使用场景,所以不做了解。
第五个场景是修改 commit 的顺序,这个很简单就是直接在交互模式下修改 commit 的位置就可以了。这个 rebase 你可以理解为一次回放。从这个角度来讲的话,你就能理解交互模式的这个修改为什么能重新排序 commit 了。
第六个场景是从远程 pull 内容,通常情况下我们采用的都是 git pull 命令。这个命令相当与两个命令的集合,就是 git fetch origin <branch> 和 git merge origin/<branch>,但是这个命令方式会产生一条新的 pull 记录。那么我们可以通过 git pull --rebase 的命令实现不产生记录,并且其实这个是大多数情况下我们想要的效果,commit 的历史是更加整洁的。
第七个场景就是我们所说的分支 rebase,而实际上这个才是 rebase 真正的初心。这个不多说了,这个也是中文博客和内容里最多提到的使用方式,经常是和 merge 进行比较。
关于 rebase 和 merge 的争论一直存在,而这个网站感觉会有很多可以学习的内容。www.atlassian.com/blog/git/gi…