保姆级教程 | Merge Request 分支合并请求
保姆级教程 | Merge Request 分支合并请求
What is it ?
首先我想先来讲讲什么是分支合并请求Merge Request
(也可叫Pull Request
,下文中全用Merge Request
或其缩写MR
指代),以及它有什么作用(如果你对此概念有所了解,你完全可以跳过What is it
)。
MR
(或者PR
)就是指将你开发的代码的内容以一种请求合并的方式来合并到它想去的分支上,这个请求的接收人(Reviewer
)一般是项目、团队的负责人或者其他成员。
一般来讲,开发团队都对Code Review
(代码复审/审查/检视)的重视程度比较高。因为Code Review
的确实能够提升代码的质量以及减少BUG
的产生率。
Merge Request
在Code review
中就是重要的一环。如果使用MR
来发起合并请求,那么在代码审查时就完全可以以你本次请求的合并内容为单元进行代码审查,如果审查通过那么就成功合并。审查交由Reviewer
进行,他可以是请求的接收人。如果团队多个成员坐在一起来看你的本次合并内容,那么自然Reviewer就是这些人了。一份代码经过多人的审查,代码问题发生率自然会降低,开发者在开发时也会保持良好的编码习惯,毕竟没人想被别人指点
自己的代码。
不过有些团队可能并不重视Merge Request
,最多也就是在dev
分支(大家共用的开发分支)上检出一个新分支,然后在新分支上进行开发,然后commit -> push
最后merge
到 dev
分支上就完事了。
下面我们将以Merge Request
为目标,从建立仓库开始讲述一个完整的git
工作流以及其中的git
操作。
How to do?
接下来我们从0开始,以Gitee
(码云)代码托管和研发协作平台为例,来讲讲如何在正常的git
工作流程中使用Merge request
。
1.创建一个远程仓库,默认创建master分支
文章图片
2. 创建本地仓库,并关联远程仓库
初始化本地仓库后,随便创建一个文件,然后提交到远程仓库的master分支。
git init
touch README.md
git add README.md
git commit -m "first commit"
git remote add origin https://gitee.com/yaodao666/git-merge-requet.git
git push -u origin master
git push -u
的作用就是关联并推送内容到上远程仓库的分支。(后面还有别的关联远程分支的方法。)3. 以master分支为起点创建一个dev分支
我们后面就将以
dev
分支作为开发分支(仓库成员共用的一个分支)。文章图片
4. 仓库中再添加另一个成员
该成员将在后面作为
Reviewer
来处理自己的Merge Request
,看我们的提交内容,从而达到代码审查的目的。文章图片
文章图片
然后为该用户设置为代码审查人员:
文章图片
以上的操作都在
Gitee
仓库的管理设置选项中。
4. 本地切换到dev分支,并连接远程dev分支此时本地是没有dev分支的。可以用
git branch -a
命令来查看所有分支。
文章图片
现在就用
git checkout -b dev
来创建一个dev的本地分支。如果此时执行该命令时没有加-b参数:
git checkout dev
error: pathspec 'dev' did not match any file(s) known to git
会报错如上。因为该命令是只是切换分支,而此时并没有dev分支,自然无法切换过来会报错。
文章图片
OK,现在我们创建了本地dev分支,现在我们让他关联上远程仓库的
dev
分支吧。(只有这样才能进行pull
、push
操作啊!)git branch --set-upstream-to=origin/dev
这样子就好啦!
执行下面的命令
git pull
Already up to date.
出现上述信息,说明链接上远程的
dev
了。其实还有一种链接远程仓库分支的方式,比如我们又在远程仓库上以
dev
分支为起点,创建了test
分支,那么我们在本地创建test
分支时,就可以执行:git checkout -b test origin/test
创建本地
test
分支的同时又链接到远程的test
分支上。文章图片
在后文中
5. 新建一个feature(特性)分支
中还会有另一种方式来连接远程仓库分支。5. 新建一个feature(特性)分支
在实际开发中,我们往往会新建一个特性分支,该分支专门为你服务,并且它专门用于处理某个bug,或者开发某个新的功能。即当有个新功能需要开发或者有bug以及优化重构部分代码时,我们就应该单独拿出一个新分支来专门处理这些事情。
与上面创建dev的方式相同,不过我们这次不先在远程仓库创建分支了,而是在本地直接创建分支后,再将该分支推送到远程。
我们先切换到dev分支,正常工作中,你必须要pull一下,保证你之后写的代码将是建立在
dev
上最新的代码的基础上,以避免一些不必要的麻烦。git checkout dev
git pull
用下面的命令创建一个新的特性分支,我们就命名为
feature-beer
吧。git checkout -b feature-beer
6. 在feature-beer分支上开发,并推送到远程。
随便在
readme.md
文件上改点东西。然后执行:git add -A
git commit -m "这是我第一次在feature-beer分支上提交。"
最后将内容推送到远程的仓库上,
git push -u origin feature-beer
这时候再去远程仓库上看,就会有
feature-beer
分支了,并且提交内容也有了。所以git push -u
的作用不仅仅是关联并推送内容到上远程仓库的分支,当没有远程分支时还会创建该分支!文章图片
7. 直接合并到dev上。
很多时候,有些开发团队根本就在乎使用Merge Request来在合并时进行Code review,那么他们就会直接合并代码到
dev
分支。切换到
dev
分支执行merge
命令。git checkout dev
git pull# 在合并前同样先pull一下dev
git merge feature-beer# 这里的合并是本地合并,将feature-beer中的内容合并到dev中
git push# 将本地内容推送到远程仓库
文章图片
此时再去远程
dev
分支上看一下:文章图片
我们在
feature-beer
上的修改内容已经放在dev
上了。8. Merge Request
不过这种简单粗暴的方式往往会带来很多问题,比如没有人去注意你往
dev
上合并了什么内容,这种没人关注自己写的代码
情形往往就会导致开发人员在开发时不注意代码规范,甚至会提交上很明显的bug,也懒得去测试,更有甚者则会上传使得项目启动失败的代码。这时候如果能有一个人来帮你再把把关,看看你写的代码咋样,则会促使自己写代码时更加注意代码规范和代码健壮性,毕竟谁也不想被别人批评,要是因为代码写的好被表扬就更好了。而
Merge Request
就可以达到这种效果。现在,我们就模拟启动一个
Merge Request
的过程。重新切换到
feature-beer
分支上写点内容,并分两次提交,并push
到远程分支上。git checkout feature-beer
# 改点内容:这是我第二次在feature-beer上进行开发工作,现在是晚上十一点五十一分了。
git add -A
git commit -m "这是第二次在feature-beer上的开发的第一次提交。"
# 改点内容:这是我第二次在feature-beer上进行开发工作,现在是晚上十一点五十二分了。
git add -A
git commit -m "这是第二次在feature-beer上的开发的第二次提交。"
git push
这样远程上的分支就能看到这次开发的两次提交啦。
文章图片
Gitee上提供了
Pull Request
操作来实现Merge Request。文章图片
在创建的
Pull Request
中,你必须选中源分支、目标分支。还能看到提交记录和文件改动信息。文章图片
点击创建后,
Beer Bear
成员就会收到这个请求。文章图片
他可以在提交和文件中看到提交的内容。审查通过后,就可以合并了。在前面创建时我们勾选了删除提交分支(不过截图中未勾选,实际操作上是勾选了的),合并后就没有这个分支了。
文章图片
这时候再看分支和分支内容,发现feature-beer没了,dev中有了合并过来的内容。
9. 删除本地分支和远程分支
这个时候我们就应该删除这个本地分支了。
git checkout dev# 先切换到dev分支
git pull
git branch -d feature-beer
如果这个命令报错,往往是
- 很有可能是你正处于该分支上。
- 该分支包含了还未合并的工作,可以先合并或者使用 -D参数强制删除。
Merge Request
通过时就一起删除了),可以使用:git push origin --delete feature-beer
当然你也可以登录到
Gitee
的网页上删除远程分支。为啥要删除呢?继续用不行么?
其实可以继续用,但是不推荐,因为我们创建这个分支的目的就是为了开发一个新模块或者修复一个BUG,当开发工作完成后删除该分支,处理别的事情时再新建一个就好了。
Some Questions 1. 如果本地dev有修改内容,是否可以把这些修改内容带到新分支上
比如有一天,你困意十足,打开编译器直接开始干活了,干了半天才发现这是dev分支,这时候已经有很多代码的改动了,咋整?
现在我们在
dev
分支上新增一行,不提交。文章图片
然后切换到新分支:feature-new-beer.
git checkout -b feature-new-beer
再打开文件会发现会有这行信息的。所以这个未提交的信息是可以带过来的。
那我要是不想带过来怎么办?我们先删除这个分支换一个分支看一下如何做到不带过来。
git checkout dev
git branch -d feature-new-beer
我们使用
git stash
将dev分支上的内存暂存起来,这时dev上就看不到这一行了。
然后我们再次切换到新分支:feature-new-beer.
git checkout -b feature-new-beer
这个时候该分支上也不会有这一行信息了。但如果此时执行:
git stash pop
会发现那一行又出现了,并且再切换到
dev
时,dev
上也又出现这一行了。为啥会出现上面的现象呢,其实是因为
git
中存在工作区和暂存区,这两个区都是被所有本地分支共享的。当有内容修改时,修改信息就会放在工作区中,此时如果直接检出一个新的分支,就会把工作区的内容都带过去。
而如果把修改信息暂存(stash)到暂存区时,都暂存起来了自然就不会带过去,但是由于该区也是共享的,当pop出暂存内容时,所有分支又同时恢复了这些修改内容。
如果我在
dev
上进行stash
后,检出新分支,又加了一行,再pop
会怎样呢?文章图片
git stash pop
文章图片
会提示报错:你的本地更改(新分支上的更改)会被覆盖。
这个时候如果:
git stash
git stash pop
那么本地更改将覆盖掉
dev
的修改,即dev
上也是下面的信息了。文章图片
就像该问题开头说的那样,如果你在
dev
上写了不少东西了,那么就先pull
一下最新的代码,然后检出到新分支上继续开发就可以了。你可以在任意时间回到
dev上
直接进行discard changed
(回滚到最初的未修改的版本)操作。如果实在不放心就等新分支代码都写完了提交了你再到
dev
上删除。2. 如果我在新分支上有很多次提交,我是否可以合并这些提交到一个提交上再提交
这是可以的,并且很多时候我们推荐这么做,比如一个模块需要三天去完成,这三天你可能提交了六七次,而实际上你只是完成了一个新模块的开发而已。
如果在你的几次提交中,有人往
dev
推送了代码,那么当你最后向dev
发起合并请求并且成功通过后,commit
的记录会是怎样呢?下面一起来试一下。我们先把
Question1
中的在dev
分支上的修改discard changes
一下(回到未修改的状态,即上一个版本),然后删除刚刚那个分支并创建一个新分支feature-many-commits
。# use "git checkout -- ..." to discard changes in working directory 这是官方提示
git checkout -- README.md# 该文件回到未修改的状态
git branch -d feature-new-beer
git checkout -b feature-many-commits
现在我们在新分支上随便写点内容并提交。
# 随便加一行:我在 feature-many-commits 分支上写东西。现在是晚上22:25,写完这行立马提交。
git add -A
git commit -m"feature-many-commits,晚上22:25"
现在我们再到
dev
分支上写点东西并提交和push
(模拟这是另一个人提交上来的代码),不过为了避免冲突,我们就不在README
文件中写了,新建一个txt
文件。文章图片
现在我们再回到新分支上随便写点内容并提交,然后
push
到远程,并去Gitee
上进行MergeRequest
。# 随便加一行:我在 feature-many-commits 分支上写东西。现在是晚上22:34,写完这行立马提交。
git add -A
git commit -m"feature-many-commits,晚上22:34"
git push -u origin feature-many-commits
文章图片
文章图片
文章图片
这里提供两个选项,一个是合并分支一个是扁平化分支。看看解释应该能猜出啥意思,第一个的意思是指直接合并,后者则是先把
feature-many-commits
上的提交合并成一个新的commit
——这就是我们想要的目标,然后再合并到dev上。不过我们先来看一下直接合并:
文章图片
现在我们根据该图显示的提交记录就可以回答开头的那个问题了:“如果在你的几次提交中,有人往
dev
推送了代码,那么当你最后向dev合并并成功后,commit
的记录会是怎样呢?”。正如图中展示的那样,
dev
的提交记录夹在了新分支上的两次的提交记录中间,这样确实凌乱、不美观。所以我们在很多时候应该采用扁平化分支的方式来合并。
写点内容提交,再用扁平化的方式试一次:
# 随便加一行:我在 feature-many-commits 分支上写东西。现在是晚上22:43,写完这行立马提交,希望这个提交最后会与接下来的commit被合并到一个commit中。
git add -A
git commit -m"feature-many-commits,晚上22:43"# 随便加一行:我在 feature-many-commits 分支上写东西。现在是晚上22:44,写完这行立马提交,希望这个提交最后会与之前的commit被合并到一个commit中。
git add -A
git commit -m"feature-many-commits,晚上22:44"
git push
文章图片
文章图片
文章图片
文章图片
发现确实成功将那两次
commit
合并成一个了!并且提交的时间就是通过Merge Request(Pull Request)
的时间。总结一下这个问题:直接合并分支会让两个分支的每一次提交都按照
commit
的时间进行排序,这样看起来会比较凌乱。我们可以通过gitee
上扁平化分支的方式通过MR
。3. 除了Merge Request通过后合并时选择扁平化分支(将多次提交合并成一个commit)还有啥方法也能实现这个效果么
确实,这个将多次提交合并为一个提交的操作是在
gitee
上进行的,那要是我不去gitee
上进行Pull Request
,直接在本地进行merge
,不就达不到这种效果了么?需要说明的一点是,实际上像
Gitee
、Gitlab
这种代码托管平台是都具备这种功能的,所以如果在它们的平台上通过Merge Request
(或Pull Request
)去做的话,一定能实现这种效果。但如果我不去代码托管平台发起合并请求呢?我就想本地开发完了,然后合并到
dev
上(再由本地dev
分支push
到远程dev
分支),那该怎么做呢?这时候一个git rebase
命令就呼之欲出了。这个命令的作用就是将某个分支的多次
commit
合并成一个commit
,然后在merge
到另一个分支上的时候就会只有一个提交啦。这个过程是这样的(示例是将
feature-many-commits
分支内容合并到dev
上):# 假设现在开发完毕 并且已经在feature-many-commits上提交了多次
git checkout dev
git pull# dev保持最新的代码
git checkout feature-many-commits
git rebase dev# 将feature-many-commits上所有的commit,重新在新的dev的HEAD上commit一遍
git checkout dev# 再次切换到dev上
git merge feature-many-commits # 将feature-many-commits上的内容合并到dev上
git push# 推送即可
这个过程还是比较简单的,很多人也在这样去做,在此就不演示了。
Summary 现在让我们再来梳理一下整个
MR
的关键流程。假设dev分支就是大家共用的分支,我们要在此基础上检视出新分支进行开发工作,最后通过
Merge Request
的方法合并到远程分支。:- 切换到dev分支
git checkout dev
- 更新dev分支代码
git pull
- 在dev分支的基础上,检视出一个新分支
feature-beerbear
git checkout -b feature-beerbear
- 进行开发并提交你的代码
git add -A git commit -m"xxxxxx"
- 将本地
feature-beerbear
分支推送到远程
git push -u origin feature-beerbear# 会创建一个远程feature-beerbear分支
如果不是第一次推送,可以直接使用
git push
4、5步骤将在实际的开发工作中重复执行。
- 开发工作完成后,到代码托管平台上进行
Merge Request
(或Pull Request
)操作。 - 合并请求通过后。就可以删除本地分支。
git branch -b feature-beerbear
- 新的任务来了,从1再来。
① 如果不通过,那么继续从
4
开始执行,不过不再需要新提出一个新的MR(Merge Request)
了。这时候可能会疑问,为啥不需要重新提一个了呢?
因为这个合并是指分支之间的合并,当你的远程
feature-beerbear
分支发生变化时,MR
会感知到做出相应变化的。实际上,如果你要新建的
MR
的源分支和目标分支和之前的MR
中的相同,这样的话是创建不了的。你必须关闭掉之前的那个,当然完全没这个必要。
② 发生冲突
虽然你在创建新分支时
pull
了一下dev
分支,然后在此基础上创建新分支了,但毕竟你的MR
可能是好几天后发出的,dev
分支肯定不是原来的状态了。所以就会导致在创建MR
时提醒冲突。那当提示发生冲突的时候,怎么办呢?只需以下几个命令即可:git checkout dev
git pull
git checkout feature-many-commits
git merge dev# 如果在这一步发生冲突,那么手动解决冲突即可
git push
实际上就是将
dev
代码更新,然后将dev
上的代码合并到feature-many-commits
上来。其实我们完全可以在提交
MR
之前就将上面的几行命令走一遍,这样就不会再提MR
的时候报出冲突了。总不至于你刚执行完上面的命令,在你准备提出
MR
时,就又有人往dev
上提交了代码,又恰好导致冲突了吧——如果有,可以买张刮刮乐试试运气了。Thanks 这篇关于
Merge Request
的文章到此就算结束了!首先,谢谢你看完这篇文章!其次,我十分希望这篇文章能对你有所帮助,或许帮助不是很大。如果你喜欢这篇文章或者真的有一些收获,请也点赞或者收藏,最好是在评论区留言告诉我!
虽然付出了挺多精力来写这篇文章,但毕竟咱水平一般、能力有限,所以肯定会有一些语句不畅、表意不明甚至错误的地方。
【保姆级教程 | Merge Request 分支合并请求】如果你能指出问题、不吝赐教,我将十分感谢,你的建议和指教也将敦促我一直完善此文!欢迎友好交流!
推荐阅读
- 2.6|2.6 Photoshop操作步骤的撤消和重做 [Ps教程]
- jhipster|jhipster 升级无效问题
- CET4听力微技能一
- 【生信技能树】R语言练习题|【生信技能树】R语言练习题 - 中级
- 二十年后的家乡
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- 唐嫣可真会穿,西装搭牛仔裤都能穿出高级感,一双大长腿太抢镜
- gitlab|Gitlab升级(12.2.1到14.6.4)
- 2018.03.18
- 幸福是个比较级