【Git原理与使用】分支管理
分支管理
- 1.理解分支
- 2.创建分支
- 2.1创建分支
- 2.2切换分支
- 2.3合并分支
- 3.删除分支
- 4.合并冲突
- 4.分支管理策略
- 5.分支策略
- 6.bug分支
- 7.删除临时分支
- 8.小结
点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃
1.理解分支
Git 的杀手级功能之一(注意是之一,也就是后面还有之二,之三……):分支。
先从小一个小故事理解分支。
比如你出生一个在武侠村,这个武侠村现在要召开一个武林大会,凡是赢得人可以赢取村长女儿。现在距离无论武林大会还有三个月的时间。第一个月你先练基本功,第二个月和第三个月学习降龙十八掌,然后到时间参加比较。你可以做这些事情你的对手也可以做这些事情。如果你们学习能力差不多,天赋差不多,比赛你俩就五五开了。但是你有一个先天优势,你会分身术。在练习完基本功之后你创造了一个分身,这个分身去学习辟邪剑法,最后在比赛之前你让自己本体和分身进行一个合体,合体之后你就同时掌握了两门功法,所以参加比赛后你就把对手打得落花流水,最后赢得比赛之后赢取村长女儿。
其实Git也可以做到这一套,它也可以分身,也可以合体。
在之前说的版本库中有一个HEAD指针,它默认指向master分支。master里面其实存储的就是最近一个提交。
因此我们也可以串一条提交时间线出来,这个提交时间线我们可以称为主线,这主线就是 master主分支。
我们也可以在主分支上创建一个分支,然后合并分支。
2.创建分支
查看本地仓库的分支:
git branch
创建本地仓库的时候Git就会为我们自动创建master主分支
master 前面的 *,之前我们只知道HEAD指向master有这一个东西存在,但是对于HEAD指针我们并不了解它有什么功能。首先要明确HEAD不仅可以指向master分支,它也可以指向其他分支,被HEAD指向的分支就是当前正在工作的分支。
这里我们就知道为什么 * 在master前面,因为我们当前在master分支下工作。
2.1创建分支
git branch [分支名]
可以看到当前除了master分支,还有dev分支,当前HEAD还是指向master
并且我们可以看到,刚创建出来的dev分支和master主分支存放的最新提交的commit id是一样的。
我们创建新的分支是站在当前最新版本上创建的分支,所以dev分支指向了最新的提交
那如何切换到dev分支工作呢?
就是把HEAD指向dev,让dev成为当前工作的分支。
2.2切换分支
git checkout [分支名]
接下来我们就可以在dev分支进行工作了,我们进行一次提交
然后我们在切回master分支,然后打印ReadMe文件,发现新增的代码不见了。
我们在切回dev分支,发现这一行代码还在
我们查看到dev分支目前最新提交的commit id,打印一下发现它前一个commit id正好是我们刚创建dev里面的conmit id也是master最新提交的commit id。这是因为我们在这个提交线上又进行了一次提交。dev指向了最新的一次提交,而master没动。
那我们想在master分支下看到这一行代码怎么做呢?那就要将master分支和dev分支进行一次合并操作。
2.3合并分支
如果我们想要master分支合并dev分支,我们必须要先切到master分支,然后在合并。
git merge [分支名]
Fast-forward表示快进模式,下面在解释。然后还打印初ReadMe改变,一行插入。
现在打印ReadMe就可以在master分支上看到新增的一行代码。
合并后master分支和dev分支一样指向最新提交的commit id
Fast-forward快进模式,表示直接把master指向dev最新提交的commit id。所有看到合并是非常快的。
3.删除分支
目前我们已经成功创建了属于自己的本地分支并且完成了自己的工作,那么对于dev分支来说它的工作已经完成了,那dev分支就没有用了,我们如何将它删除呢?
但是要注意的是我们只能在其他的分支上才能删除你要删除的分支!
git branch -d [分支名]
因为创建、合并和删除分支非常快,所以Git鼓励你使用分只完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
4.合并冲突
在实际分支合并的时候,并不是想合并就能合并成功的,有时候可能会遇到代码冲突的问题。
比如说dev1分支和master分支都对当前ReadMe文件的一行代码进行了修改,此时就有合并冲突的问题。Git并不知道此时需要保留bbb还是ccc的代码,这都是开发人员自己写的是由开发人员自己决定的,所以就有合并冲突的问题。
这里我们在学一个命令,直接一条命令完成 ,创建 + 切换分支
git checkout -b [分支]
创建dev1分支,修改ReadMe文件aaa变成bbb,然后提交
切换到master分支,也去修改ReadMe文件aaa变成ccc,然后提交
下面是此时的仓库状态
然后我们让master合并dev分支,就会发生冲突。
合并ReadMe文件冲突,我们需要手动解决冲突然后将结果在进行提交。
进入ReadMe文件发现 <<<<< Head ====== >>>>> dev1,< 到 = 之间的代码是由当前master分支上的代码,= 到 > 是dev1分支上的代码。在 < 到 > 是冲突代码,表示bbb和ccc冲突了。Git没办法帮我们解决冲突,需要我们手动解决冲突,到底是保留bbb还是ccc,还是都保留,还是都删除,这都是由开发人员自己判断。
比如我们现在保留bbb代码,只需要把< 到 > 其他代码删掉即可。现在就不冲突了。然后将结果重新提交。
合并冲突之后,需要手动调整冲突代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘记)
用带参数的 git log也可以看到分支的合并情况
git log --graph --pretty=oneline --abbrev-commit
4.分支管理策略
到目前为止,我们已经使用过两次merge操作,一次是直接合并没有发生冲突,一次合并发生冲突解决冲突后在重新提交。 对于这两次merge操作其实分别对应了Git提供给我们两个merge模式。
通常合并分支时,如果可能,Git 会采用 Fast forward 模式。
可以清楚看到使用Fast - forward 快进模式 ,在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。
但在合并冲突部分,我们也看到通过解决冲突问题,会再进行一次新的提交,得到的最终状态为:
那么这就不是 Fast forward 模式了,这样的好处是,从分支历史上就可以看出分支信息。例如我们现在已经删除了在合并冲突部分创建的 dev1 分支,但依旧能看到 master 其实是由其他分支合并得到:
Git 支持我们强制禁用 Fast forward 模式,那么就会在 merge 时生成⼀个新的 commit ,这样,从分支历史上就可以看出分⽀信息。
git merge --no-ff -m "xxxx" [分支]
可以看到,不使用 Fast forward 模式,merge后就像下面这样,所以在合并分支时,加上 --no-ff 参数就可以用普通模式合并,合并后的历史有分支,能看出来曾
经做过合并,而 fast forward 合并就看不出来曾经做过合并。
合并我们建议不要使用Fast-forward,而使用no-ff。
5.分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
6.bug分支
假如我们现在正在 dev2 分支上进行开发,开发到一半,突然发现 master 分支上面有 bug,需要解决。注意不能在master主分支上进行代码修复,我们需要在本地创建一个专门修复master主分支上的bug,修复后,合并分支,然后将临时分支删除。如果在master主分支上进行代码修复,可能会造成一个更大的bug。
可现在 dev2 的代码在工作区中开发了一半,还无法提交,怎么办?
Git 提供了 git stash 命令,可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。
git stash
stash在refs下,注意stash里面存的是已经被Git追踪管理的文件,ReadMe已经被追踪管理了,所以对工作区ReadMe文件修改它是可以保存起来的。
接下来我们创建一个bug分支,对master出现的bug进行修复。
比如说ReadMe文件123后面少跟了456导致bug,现在我们加上,bug修完之后进行提交合并。
修复完bug之后,由于我们还在dev2下进行开发,所以还要在进行开发。但是发现开发的内容不见了,原因是因为修复bug之前把dev2开发的内容存储到stash里面了。
我们要重新开发,就要把存到stash里面的内容恢复过来。我们可以使用 git stash pop 命令,恢复的同时会把 stash 也删了。
git stash pop
不过恢复之前我们还可以查看一下stash里面存了那些东西
git stash list
目前我们看到确实是恢复过来了。但是123后面并没有跟456,也就是dev2这里并没有修复bug,原因是因为我们在创建dev2的时候是基于master的有bug的时候,所以dev2还是未修复bug的状态。不过它并不影响master主分支。
我们看此时仓库的状态就能明白刚才说的这一点,master 分支前最新的提交,是要领先于新建 dev2 时基于的 master 分支的提交的,所以我们在 dev2 中当然看不见修复 bug 的相关代码。
当dev2继续开发完成后,就可以在dev2分支上提交了
我们的最终目的是要让 master 合并 dev2 分支的,那么正常情况下我们切回 master 分支直接合并即可,但这样其实是有一定风险的。
是因为在合并分支时可能会有冲突,而代码冲突需要我们手动解决(在 master 上解决)。我们无法保证对于冲突问题可以正确地一次性解决掉,因为在实际的项目中,代码冲突不只一两行那么简单,有可能几十上百行,甚至更多,解决的过程中难免手误出错,导致错误的代码被合并到 master 上。此时的状态为:
解决这个问题的一个好的建议就是:最好在自己的分支上合并下 master ,再让 master 去合并dev ,这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响 master 。此时的状态为:
一般我们让master合并自己的代码之前,都建议这样做。
7.删除临时分支
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个分支,我们可以将其称之为 feature 分支,在上面开发,完成后,合并,最后,删除该 feature 分支。
可是,如果我们今天正在某个 feature 分支上开发了一半,被产品经理突然叫停,说是要停止新功能的开发。虽然白干了,但是这个 feature 分支还是必须就地销毁,留着无用了。这时使用传统的 git branch -d 命令删除分支的方法是不行的,因为它只适用于删除已经merge过的分支。对于没有merge过的分支要使用git branch -D 去删除。
git branch -D [分支]
8.小结
分支在实际中有什么⽤呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了⼀个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
并且 Git 无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。