🏆【Git 实战专题】你知道 git rebase 如何让代码提交变得清晰明白吗?

什么是 rebase
在介绍 rebase 之前,需要提前说明,rebase 是一个非常强大的功能,也正是因为它的强大,所以使用起来也有一定的隐患,一旦使用不好可能会对团队的代码造成非常大的问题。所以在使用前一定要了解其中的原理并小心谨慎的使用。
rebase 的功能可以简要的概述为对某一条线性提交分支上的记录进行编辑、删除、复制、粘贴、合并。合理使用 rebase 可以使团队的提交记录变的非常干净整洁。
注意:如非迫不得已不要通过 rebase 对任何已经提交到公共主干分支上的提交记录进行 commit!
使用 rebase 替代 merge 进行主干/开发分支合并
假设我们在开发的时候同时拉出来两个分支并行开发,然后有一条已经合并到主干分支 main 了,像这样:
这个时候我们想要把主干分支 main 的代码再合并到当前开发分支 test-1,然后再进行提交,如果使用 merge 会是这样:
如果当前分支有很多的子分支,到最后合并的时候就会出现像一开始那张图一样爆炸的情况。
而如果使用 git rebase main (或者 git pull --rebase origin main / git pull -r origin master )合并 main 分支,提交记录就会变成这样:
这样清晰明了。
注:使用 rebase 合并主干分支时,当前分支所做的修改永远会被认为是最新的,所以会导致在提交记录上就算
test-1分支一开始的提交时间在test-2之前,但是 rebase 之后 commit 记录也是最新的,这也是 rebase 的初衷之一,更清晰的显示出来在什么时候提交到主干的什么功能(因为按照提交时间来看,test-1分支的功能是在test-2分支功能合并到主干main分支后添加的)。⚠️ 正是因为它改变了历史,所以我们更应该谨慎使用 。
当然,如果该分支是测试环境或者预发环境分支,则一般需要使用git merge来合并。因为在这两个分支上会存在多个分支但是并没有合并到主干的修改。
再看一种情况:
如图所示,test-1-1 分支其实是从 test-1分支的 commit-1-3节点拉取出来的,而此时 test-1分支并没有合并到主干 main 分支,但是 main 分支上的功能要提前合并到test-1-1分支上,合并完成之后将 test-1-1 与 test-1 独立,变成两个互不相干的分支,这种情况下可以使用 git rebase --onto main test-1 test-1-1
可以看到这种情况下 test-1-1 与 test-1 已经互相独立互不相干了,而且 test-1-1 的记录线已经跟 main 在同一条线上了 *( *不过在正常开发情况下应该避免这种情况发生,因为test-1-1中已经包含了一部分的 test-1 变更,所以当 test-1 分支再合并主干的时候,可能会有许多冲突 ) 。
我们在使用 git rebase 或 git pull --rebase 合并的时候可能会有许多冲突
在发生冲突时,
git rebase将停止在第一个有问题提交,并在树上留下冲突标记。我们可以使用git diff定位标记(<<<<<<),并进行编辑以解决冲突。对于编辑的每个文件,需要告诉 Git 冲突已解决,通常使用
git add <filename>手动解决冲突并更新到对应的索引,之后,我们可以手动进行下一步进程
git rebase --continue我们也可以手动撤销 rebase
git rebase --abort
4. 使用 rebase 编辑 commit
rebase 最经典的功能,就是编辑 commit。比如在 pull requests(gitlab 为 merge request)中需要修改代码的时候,需要把修改的内容合并到已经提交的 commit 上。
这里我们可以使用 git rebase -i [startpoint] [endpoint]来编辑提交记录,其中-i的意思是--interactive交互的意思,即弹出交互式页面供使用者编辑。[startpoint]和[endpoint]指的是编辑的开始和结束节点(不包含[startpoint]节点,范围逻辑是[startpoint] < commits <= [endpoint]),如果不指定[endpoint]则结束节点会指向HEAD所对应的节点(一般使用的时候也不指定结束节点...)。
举个栗子:
此时我们想编辑test-1分支的最新三条历史记录,我们可以使用前面所说的
git rebase -i 39ce617 或者是 git rebase -i HEAD~3,我们会看到如下页面:
指令说明:
在该页面点击i键进入编辑页面,即可在指令模块编辑,编辑完成后点击esc然后输入:wq保存并退出进入下一步操作。
一般来说,除默认的pick之外,最常用的就是reword、edit、squash、fixup这几个命令了,这里就只详细的讲解以上命令。
4.1 reword
如果我们想要修改 commit-1-5 这条 commit 的提交信息,只需在该条之前写明 r 或 reword 方法:
保存退出之后进入 commit 编辑页面:
修改并保存之后,在提交记录里可以看到本地 commit-1-5 记录已经被修改成了 commit-1-5-reword,如果后面还有分支存在修改,则使用 git rebase --continue 命令进行之后的修改,待所有 commit 都修改完成之后再使用 git push -f 或git push --force 强制推送代码覆盖远端后,远端的提交记录就变成了:
可以看到提交记录已经被修改了。
4.2 edit
使用该方法之后,我们就可以修改想要修改的内容,修改完并执行 git add 之后,就可以调用
git commit --amend 来修改 commit 的记录内容,这里可以看到 edit 之后修改的文件是 README.md,
然后修改 commit 方式跟 reword一致,待所有 commit 都修改完成之后,使用 git push -f 强推至远程便可以实现记录内容的编辑修改了。
4.3 squash
字面意思,使用 squash 是将记录压缩到一起,一般用于一个大功能开发完成后合并提交到主干分支上使用,这里我们可以用 vue 的提交记录举例:
可以看的出来 fix(types): async Component types (#11906) 记录下合并了许多子记录,这样也可以清晰的表明一个迭代的功能及开发提交记录。
4.4 fixup
fixup 也是将代码进行保留并合并到上一条提交记录,唯一的区别就在于 fixup 的记录被删除,此方法适用于我们在 MR 时候的 comment 修改。
注:如果我们在 rebase 的过程中因为一些原因退出了终端中断了 rebase,我们可以回来继续使用git rebase --edit-todo 进行继续编辑。
版权声明: 本文为 InfoQ 作者【李浩宇/Alex】的原创文章。
原文链接:【http://xie.infoq.cn/article/5d060ce545ac140978893cc30】。文章转载请联系作者。











评论