写点什么

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

发布于: 3 小时前
🏆【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-1test-1 独立,变成两个互不相干的分支,这种情况下可以使用 git rebase --onto main test-1 test-1-1

可以看到这种情况下 test-1-1test-1 已经互相独立互不相干了,而且 test-1-1 的记录线已经跟 main 在同一条线上了 * *不过在正常开发情况下应该避免这种情况发生,因为test-1-1中已经包含了一部分的 test-1 变更,所以当 test-1 分支再合并主干的时候,可能会有许多冲突

我们在使用 git rebasegit 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,我们会看到如下页面:



指令说明:

p 或 pick 		使用该commit,不做修改(默认指令)r 或 reword 	使用该commit,但是修改它的commit信息e 或 edit 		使用该commit,但是要停下来修改(commit信息和提交内容)s 或 squash 	使用该commit,但是将此条commit融入之前的commitf 或 fixup 	跟squash一致,跟前一条commit合并,但是丢弃该commit的日志消息 x 或 exec 		运行shell命令(该行的其余部分)b 或 break  	到此为止(稍后继续使用 'git rebase --continue' 进行rebase)d 或 drop		丢弃该commitl 或 label		使用label标记当前HEADt 或 reset		将HEAD重置到label标记m 或 merge 	[-C <commit> | -c <commit>] <label> [# <oneline>]						 使用原始合并提交的消息(或单行,如果未指定原始合并提交)创建合并提交。             使用 -c <commit> 改写提交消息。复制代码
复制代码

在该页面点击i键进入编辑页面,即可在指令模块编辑,编辑完成后点击esc然后输入:wq保存并退出进入下一步操作。

一般来说,除默认的pick之外,最常用的就是rewordeditsquashfixup这几个命令了,这里就只详细的讲解以上命令。

4.1 reword

如果我们想要修改 commit-1-5 这条 commit 的提交信息,只需在该条之前写明 rreword 方法:



保存退出之后进入 commit 编辑页面:



修改并保存之后,在提交记录里可以看到本地 commit-1-5 记录已经被修改成了 commit-1-5-reword,如果后面还有分支存在修改,则使用 git rebase --continue 命令进行之后的修改,待所有 commit 都修改完成之后再使用 git push -fgit 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 进行继续编辑。


发布于: 3 小时前阅读数: 2
用户头像

🏆2021年InfoQ写作平台-签约作者 🏆 2020.03.25 加入

👑【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 我们始于迷惘,终于更高水平的迷惘

评论

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