在定制Spark源码内部功能的过程中,和其他Git托管项目一样,都会产生对同一个功能不断改进、多次远程提交生成commit记录的情况,为了保证一个功能点只有一条提交记录利于后续维护,需要利用git rebase命令对属于同一功能点的多条commit记录进行合并。
第一到四点适合merge request中最上面的几个commit都是自己的,需要简化为一个commit记录的情形。
第五点适合自己分支合入master最新代码,并且在merge request中依然commits中只包含自己提交记录的情况。
一、确定此次合并基于的base记录
在开发中提交与改进了共四次,生成了四条commit记录,用git log命令(上下键滚动、Q键退出)可以看到,蓝色高亮的“Support”那一行代表某功能点的第一次提交记录,如下图所示:
既然要合并“Support”那一条与它上面三条的总共四次commit记录,就要以“Support”那条第一次提交记录的再下面那条“Merge branch”记录,作为本次合并的base记录。这点容易理解,就像造房子需要在地基之上建,第一次提交记录的再之前一次记录就是本次“地基”。因此输入以下命令开始此次记录合并,commit id就是选取的base记录的id:
git rebase -i 4560d5dd728c627291201eb8c04041628de7d5e4
二、合并多个commit id
使用git rebase -i命令后,会进入Git内置的vim界面,如下图所示:
一开始四条commit记录都被标记为“pick”,意思是这四次提交都会被采用,并显示在Git的提交记录中。这四次提交涉及的代码改动都是需要的,但是只需要一条提交记录,因此先按“i”键进入INSERT模式,将后三次commit id前面的“pick”字样改为“s”,只有第一次的commit id前面是“pick”,然后按ESC键退出编辑模式,并输入:wq进行保存。注意如果是在Intellij IDEA的Terminal框里编辑rebase信息,那么在按ESC之后光标会回到代码区,此时输入的“:wq”会写到代码里,所以这种情况下按ESC键之后,要重新用鼠标点一下Terminal框里的区域,重新把光标定位回Terminal框中。
当然更好的方式是上图中后3条提交记录都从“pick”改成“f”,这样:wq保存后就不用进行下面第三步了,会自动并入第一条提交记录中。
三、去除多余的commit描述
在上一个pick与squash编辑界面用:wq保存后,会跳出最后的commit描述编辑界面,如下图所示:
这里按“i”键进入INSERT模式后,可以把不需要的后三条commit描述用“#”号注释掉,只留下第一次提交时那条蓝色高亮的“Support”描述,然后用ESC键退出编辑模式,再输入:wq进行保存。
四、远程强制提交
在经历上面两个rebase编辑步骤后,本地Git的commit记录已经成功合并,需要将合并好的单条记录覆盖掉远程GitLab上的四条记录,在命令行输入以下命令即可:
git push -f origin 分支名
如果本地分支与远程分支关联过,那么其中“origin 分支名”部分可以省略。提交后可以看到GitLab上关于该功能点只有一条commit记录了,下图中“Merge branch”那条记录的确在rebase的过程中充当了“地基”:
五、合入master最新代码且本地commit在最开头(可选)
有时候自己的本地分支落后远程master分支太久,需要返合回master最新代码避免提merge request时冲突,但是直接采用IDEA merge的方式,会导致自己的commit记录因创建时间早而沉到后面,且会导致提MR时改动记录包含其他无关的commit记录。
为了在提MR时,commits记录只包含自己的改动,且自己的commit信息显示到最前面,同时包含master分支最新代码,可以执行以下两个命令再push到远程gitlab:
git fetch
#从远程拉取master分支最新代码到本地分支
git merge origin/master
#将本地分支的历史改动对齐到最新master,这样自己功能的commit时间就在最新master时间之后
git rebase origin/master
#rebase master后的记录提交到远程
git push -f origin 本地分支名
不用上面的命令也可以直接使用IDEA的rebase合入功能,效果也一样,如下图所示: