关于Git rebase你必需要知道的几件事

DevUI是一支兼具设计视角和工程视角的团队,服务于华为云 DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师。
官方网站: devui.design
Ng组件库: ng-devui(欢迎Star)
官方交流群:添加 DevUI小助手(微信号:devui_official)进群

引言

使用git参与多人之间的合做开发大概有三年的时间,大多数场景下使用的git命令一只手多一点就能数的过来前端

git add, git commit, git push, git merge, git pull, git loggit

理论上来讲,只要能合理管理项目分支,这几个命令已经足以应付全部的平常开发工做。可是若是咱们偶尔看一下本身的git graph,个人天呐,为何会这么乱。github

鉴于分支管理的混乱(或者根本就没有进行过度支管理),咱们常常遇到一些意想不到的问题,所以须要使用不少面生的git命令来解决咱们的问题,好比说本文讲到的git rebase。vim

Git rebase 和git merge

Git rebase 的中文名是变基,就是改变一次提交记录的base。在这一环节,咱们不妨带着这样一个假设:git rebase ≈ git merge,并用两种命令实现同一工做流来对比他们之间的异同。segmentfault

回想咱们平常的工做流,假设a和b两人合做开发,三个分支:develop, develop_a, develop_b。两我的分别在develop_a和develop_b分支上进行平常开发,阶段性地合入到develop,那么从a的角度来看,可能的工做流是这样的:微信

(1)我的在develop_a分支上开发本身的功能前端工程师

(2)在这期间其余人可能不断向develop合入新特性fetch

(3)我的功能开发完毕后经过merge 的方式合入别人开发的功能网站

图1 平常merge 工做流ui

图1对应的git操做命令以下:

git checkout develop_a
// 本地功能开发...
git pull origin develop = git fetch origin develop + git merge develop

一样走完这样一个工做流若是咱们使用git rebase来实现,结果以下:

图2 git rebase 以前

图3 git rebase 之中

图4 git rebase 以后

图2-4对应的git操做命令以下:

git checkout develop_a
// 本地功能开发...
git fetch origin develop
git rebase develop
git checkout develop
git merge develop_a
git br -d develop_a

因而可知,git rebase 和git merge的异同之处以下:

(1)二者均可以用于本地代码合并

(2)git merge 保留真实的用户提交记录,且在merge时会生成一个新的提交

(3)git rebase 会改写历史提交记录,这里的改写不只限于树的结构,树上的节点的commit id也会别改写,所以图3和图4用e'表明图2的e',收益是能够保证提交记录很是清爽

如何使用git rebase -i 修改历史提交记录

git rebase -i,中文名叫交互式变基。意思就是在变基的过程当中是能够掺入用户交互的,经过交互过程咱们能够主动改写历史提交记录,包括修改、合并和删除等。咱们以上面使用rebase后获得的提交记录为例,来进行历史提交记录的修改,在修改以前,提交记录是这个样子的。

使用git rebase -i 修改历史提交的过程主要包含三步:

(1)列出一个提交记录的范围,并指出你在这个范围内须要对哪些记录进行什么样的修改

(2)以次执行上述的修改,若是遇到冲突须要解决

(3)完成rebase 操做

以上面截图中的提交记录为例,来对历史提交的commit msg进行修改,操做步骤以下:

// 查看最近6次提交记录,选择对哪一条记录进行修改
git rebase -i HEAD~6

执行完上述命令后,会以vim的方式打开一个文件,文件中显示了最近6次的提交信息,从上到下,由远到近。

从下面的注释能够看到,咱们分别把每一行前面的pick修改为r, s, d的方式就能够实现对历史记录的修改,合并和删除。首先咱们尝试修改提交信息,把第二行前面的pick改为r,保存退出。当前页面关闭的同时会打开一个新的页面,让你对选中的提交信息进行编辑。

编辑完信息以后保存退出,就完成了对历史提交记录的修改。经过观察下图能够发现,develop_a的提交记录中的commit msg 仍然是feat_c,可是develop 分支中对应的提交记录,commit msg 已经变成了feat: c-update. 这里须要留意到的一个现象是develop 和develop_a 分支上相同提交的commit id 已经发生了变化,这个在后面会再次提到。

除了修改提交的commit msg 以外,咱们也能够经过把pick 改成e,结合git reset --soft HEAD^的方式对档次提交的改动内容进行修改。

合并与删除历史提交的操做步骤与编辑相似,只须要把pick分别改成s 和d 便可,各位看官能够自行尝试。若是在rebase的过程当中遇到了冲突,须要手工解决,而后使用git rebase --continue完成rebase 操做。git rebase 的提示仍是很是友好的,它会告诉你须要进行哪些操做解决当前的问题。

使用git rebase -i 必须遵循的规则是什么?

从修改历史提交记录这个功能来看,交互式变基是一个很是强大的功能。可是使用这个功能必需要遵循一个铁则:不要对线上分支的提交记录进行变基!

引用git 官方指导文档的话来讲大概是这样:

若是你遵循这条金科玉律,就不会出差错。 不然,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。

在说为何不能对线上提交执行交互式变基以前,先说一下若是要对线上功能执行这个操做要怎么作。

首先,你须要在本身本地变基成功,而后使用git push -f强行push 并覆盖远程对应分支,之因此须要执行覆盖式push 是由于若是你不覆盖,当前变基事后产生的新提交会与远程合并,致使你在本地的变基行为失去意义。由于咱们上面提到过,从变基那个节点开始日后的全部节点的commit id 都会发生变化。

一样的缘由,即便你使用git push -f使远程分支发生了变基,若是你的同事的开发分支中还存在你执行变基操做(不管是修改、合并仍是删除)时针对的那些分支,那么当你的同事merge 你的提交以后,你全部想使用变基改变的东西都回来了!

若是打破了git rebase -i 的使用规则应该如何补救

此处咱们尝试经过要点描述的方式,说明线上提交执行变基会致使什么结果以及如何避免这个结果:

(1)你在本地对部分线上提交进行了变基,这部分提交咱们称之为a,a在变基以后commit id 发生了变化

(2)你在本地改变的这些提交有可能存在于你的同事的开发分支中,咱们称之为b,他们与a的内容相同,commit id 不一样

(3)若是你把变基结果强行push 到远程仓库后,你的同事在本地执行git pull 的时候会致使a 和b 发生融合,且都出如今了历史提交中,致使你的变基行为无效

(4)咱们想要的是你的同事拉取线上代码时跳过对a 和b 的合并,只是把他本地分支上新增的修改合并进来

讲了这么多,最终的结论就是,使用变基解决变基带来的问题。即你的同事使用git rebase 的方式把他本地的修改rebase 到远程你执行过rebase 的分支上。

简言之,就是你的同事使用git pull --rebase而不是git pull来拉取远程分支。在这个操做的过程当中,git 会对咱们上面提到几个要点的信息进行检查并把真正属于同事本地的修改合入远程分支的最后。

文字描述可能有些乏力,更多详细信息能够参考这里:https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%8F%98%E5%9F%BA

因此咱们应该如何使用git rebase

鉴于上面描述的git rebase 可能带来的问题,最后要回答的一个问题是咱们应该如何在平常工做中使用git rebase,一样借用git 官方文档中的一句话:

总的原则是,只对还没有推送或分享给别人的本地修改执行变基操做清理历史, 从不对已推送至别处的提交执行变基操做,这样,你才能享受到两种方式(rebase 和merge)带来的便利。

加入咱们

咱们是DevUI团队,欢迎来这里和咱们一块儿打造优雅高效的人机设计/研发体系。招聘邮箱:muyang2@huawei.com。

文/DevUI 少东

往期文章推荐

《手把手教你如何使用象限图组件》

《Web界面深色模式和主题化开发》

《手把手教你搭建一个灰度发布环境》