保姆级教程 | Merge Request 分支合并申请

What is it ?

首先我想先来讲讲什么是分支合并申请Merge Request(也可叫Pull Request,下文中全用Merge Request或其缩写MR指代),以及它有什么作用(如果你对此概念有所理解,你齐全能够跳过What is it)。

MR(或者PR)就是指将你开发的代码的内容以一种申请合并的形式来合并到它想去的分支上,这个申请的接管人(Reviewer)个别是我的项目、团队的负责人或者其余成员。

一般来讲,开发团队都对Code Review(代码复审/审查/检视)的器重水平比拟高。因为Code Review的的确可能晋升代码的品质以及缩小BUG的产生率。

Merge RequestCode review中就是重要的一环。如果应用MR来发动合并申请,那么在代码审查时就齐全能够以你本次申请的合并内容为单元进行代码审查,如果审查通过那么就胜利合并。审查交由Reviewer进行,他能够是申请的接管人。如果团队多个成员坐在一起来看你的本次合并内容,那么天然Reviewer就是这些人了。一份代码通过多人的审查,代码问题发生率天然会升高,开发者在开发时也会保持良好的编码习惯,毕竟没人想被他人指导本人的代码。

不过有些团队可能并不器重Merge Request,最多也就是在dev分支(大家共用的开发分支)上检出一个新分支,而后在新分支上进行开发,而后commit -> push最初mergedev 分支上就完事了。

上面咱们将以Merge Request为指标,从建设仓库开始讲述一个残缺的git工作流以及其中的git操作。

How to do?

接下来咱们从0开始,以Gitee(码云)代码托管和研发合作平台为例,来讲讲如何在失常的git工作流程中应用Merge request

1.创立一个近程仓库,默认创立master分支

2. 创立本地仓库,并关联近程仓库

初始化本地仓库后,轻易创立一个文件,而后提交到近程仓库的master分支。

git inittouch README.mdgit add README.mdgit commit -m "first commit"git remote add origin https://gitee.com/yaodao666/git-merge-requet.gitgit 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 deverror: pathspec 'dev' did not match any file(s) known to git

会报错如上。因为该命令是只是切换分支,而此时并没有dev分支,天然无奈切换过去会报错。

OK,当初咱们创立了本地dev分支,当初咱们让他关联上近程仓库的dev分支吧。(只有这样能力进行pullpush操作啊!)

git branch --set-upstream-to=origin/dev

这样子就好啦!

执行上面的命令

git pullAlready 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 devgit pull

用上面的命令创立一个新的个性分支,咱们就命名为feature-beer吧。

git checkout -b feature-beer

6. 在feature-beer分支上开发,并推送到近程。

轻易在readme.md文件上改点货色。而后执行:

git add -Agit 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 devgit pull                # 在合并前同样先pull一下devgit 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 -Agit commit -m "这是第二次在feature-beer上的开发的第一次提交。"# 改点内容:这是我第二次在feature-beer上进行开发工作,当初是早晨十一点五十二分了。git add -Agit commit -m "这是第二次在feature-beer上的开发的第二次提交。"git push

这样近程上的分支就能看到这次开发的两次提交啦。

Gitee上提供了Pull Request操作来实现Merge Request。

在创立的Pull Request中,你必须选中源分支、指标分支。还能看到提交记录和文件改变信息。

点击创立后,Beer Bear成员就会收到这个申请。

他能够在提交和文件中看到提交的内容。审查通过后,就能够合并了。在后面创立时咱们勾选了删除提交分支(不过截图中未勾选,实际操作上是勾选了的),合并后就没有这个分支了

这时候再看分支和分支内容,发现feature-beer没了,dev中有了合并过去的内容。

9. 删除本地分支和近程分支

这个时候咱们就应该删除这个本地分支了。

git checkout dev            # 先切换到dev分支git pullgit 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 devgit 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 stashgit stash pop

那么本地更改将笼罩掉dev的批改,即dev上也是上面的信息了。

就像该问题结尾说的那样,如果你在dev上写了不少货色了,那么就先pull一下最新的代码,而后检出到新分支上持续开发就能够了。

你能够在任意工夫回到dev上间接进行discard changed(回滚到最后的未修改的版本)操作。

如果切实不释怀就等新分支代码都写完了提交了你再到dev上删除。

2. 如果我在新分支上有很屡次提交,我是否能够合并这些提交到一个提交上再提交

这是能够的,并且很多时候咱们举荐这么做,比方一个模块须要三天去实现,这三天你可能提交了六七次,而实际上你只是实现了一个新模块的开发而已。

如果在你的几次提交中,有人往dev推送了代码,那么当你最初向dev发动合并申请并且胜利通过后,commit的记录会是怎么呢?上面一起来试一下。

咱们先把Question1中的在dev分支上的批改discard changes一下(回到未修改的状态,即上一个版本),而后删除刚刚那个分支并创立一个新分支feature-many-commits

# use "git checkout -- <file>..." to discard changes in working directory 这是官网提醒git checkout -- README.md        # 该文件回到未修改的状态
git branch -d feature-new-beergit checkout -b feature-many-commits

当初咱们在新分支上轻易写点内容并提交。

# 轻易加一行:我在 feature-many-commits 分支上写货色。当初是早晨22:25,写完这行立马提交。git add -Agit commit -m"feature-many-commits,早晨22:25"

当初咱们再到dev分支上写点货色并提交和push(模仿这是另一个人提交上来的代码),不过为了防止抵触,咱们就不在README文件中写了,新建一个txt文件。

当初咱们再回到新分支上轻易写点内容并提交,而后push到近程,并去Gitee上进行MergeRequest

# 轻易加一行:我在 feature-many-commits 分支上写货色。当初是早晨22:34,写完这行立马提交。git add -Agit 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 -Agit commit -m"feature-many-commits,早晨22:43"# 轻易加一行:我在 feature-many-commits 分支上写货色。当初是早晨22:44,写完这行立马提交,心愿这个提交最初会与之前的commit被合并到一个commit中。git add -Agit 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,不就达不到这种成果了么?

须要阐明的一点是,实际上像GiteeGitlab这种代码托管平台是都具备这种性能的,所以如果在它们的平台上通过Merge Request(或Pull Request)去做的话,肯定能实现这种成果。

但如果我不去代码托管平台发动合并申请呢?我就想本地开发完了,而后合并到dev上(再由本地dev分支push到近程dev分支),那该怎么做呢?这时候一个git rebase命令就跃然纸上了。

这个命令的作用就是将某个分支的屡次commit合并成一个commit,而后在merge到另一个分支上的时候就会只有一个提交啦。

这个过程是这样的(示例是将feature-many-commits分支内容合并到dev上):

# 假如当初开发结束 并且曾经在feature-many-commits上提交了屡次git checkout devgit pull            # dev放弃最新的代码git checkout feature-many-commitsgit 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的办法合并到近程分支。:

  1. 切换到dev分支

    git checkout dev
  2. 更新dev分支代码

    git pull
  3. 在dev分支的根底上,检视出一个新分支feature-beerbear

    git checkout -b feature-beerbear
  4. 进行开发并提交你的代码

    git add -Agit commit -m"xxxxxx"
  5. 将本地feature-beerbear分支推送到近程

    git push -u origin feature-beerbear  # 会创立一个近程feature-beerbear分支

    如果不是第一次推送,能够间接应用

    git push

    4、5步骤将在理论的开发工作中反复执行。

  6. 开发工作实现后,到代码托管平台上进行Merge Request(或Pull Request)操作。
  7. 合并申请通过后。就能够删除本地分支。

    git branch -b feature-beerbear
  8. 新的工作来了,从1再来。

在第六步时,可能会产生以下状况:

① 如果不通过,那么持续从4开始执行,不过不再须要新提出一个新的MR(Merge Request)了。

这时候可能会疑难,为啥不须要从新提一个了呢?

因为这个合并是指分支之间的合并,当你的近程feature-beerbear分支发生变化时,MR会感知到做出相应变动的。

实际上,如果你要新建的MR的源分支和指标分支和之前的MR中的雷同,这样的话是创立不了的。

你必须敞开掉之前的那个,当然齐全没这个必要。

② 发生冲突

尽管你在创立新分支时pull了一下dev分支,而后在此基础上创立新分支了,但毕竟你的MR可能是好几天后收回的,dev分支必定不是原来的状态了。所以就会导致在创立MR时揭示抵触。那当提醒发生冲突的时候,怎么办呢?只需以下几个命令即可:

git checkout devgit pullgit checkout feature-many-commitsgit merge dev                        # 如果在这一步发生冲突,那么手动解决抵触即可git push

实际上就是将dev代码更新,而后将dev上的代码合并到feature-many-commits上来。

其实咱们齐全能够在提交MR之前就将下面的几行命令走一遍,这样就不会再提MR的时候报出抵触了。

总不至于你刚执行完下面的命令,在你筹备提出MR时,就又有人往dev上提交了代码,又恰好导致抵触了吧——如果有,能够买张刮刮乐试试运气了。

Thanks

这篇对于Merge Request的文章到此就算完结了!首先,谢谢你看完这篇文章!

其次,我非常心愿这篇文章能对你有所帮忙,或者帮忙不是很大。如果你喜爱这篇文章或者真的有一些播种,请也点赞或者珍藏,最好是在评论区留言通知我!

尽管付出了挺多精力来写这篇文章,但毕竟咱程度个别、能力无限,所以必定会有一些语句不畅、表意不明甚至谬误的中央。

如果你能指出问题、不吝赐教,我将非常感激,你的倡议和指教也将催促我始终欠缺此文!欢送敌对交换!