🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油


1.理解分支

本章开始介绍 Git 的杀手级功能之一(注意是之一,也就是后⾯还有之二,之三……):分支。分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习 C++ 的时候,另一个你正在另一个平行宇宙⾥努力学习 JAVA。
如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了 C++ 又学会了 JAVA!

在这里插入图片描述

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就可以理解为是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即 master 分支。
再来理解⼀下HEAD,HEAD 严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD 指向的就是当前分支。

那么分支在git仓库里面是如何体现出来的呢?
在这里插入图片描述

其中间的关系就是
HEAD指向master
master指向最新一次的提交

在这里插入图片描述

我们的git的所有提交可以串成一条线,这个提交时间线就相当于我们的分支

在这里插入图片描述


2.创建分支

在创建分支之前,我们先来看看我们仓库是有哪些分支存在的
我们可以使用branch命令,他是可以显示出我们当前仓库有哪些分支的
这里可以看到我们有且只有一个分支,那就是master分支
在这里插入图片描述
在我们创建git仓库的时候,master分支就会默认创建

在这里我们解释一下我们之前讲过的HEAD指针
不是一直讲的都是HEAD指针指向master指针吗?
HEAD指针其实可以指向其它分支的,被指向的分支就是当前正在工作的分支
就是因为我们只有master分支所以HEAD只能指向master

我们接下来来创建我们的第一个分支
我们使用

git branch dev

就可以创建一个dev分支出来了
在这里插入图片描述
当我们创建新的分支后,Git 新建了⼀个指针叫 dev, * 表示当前 HEAD 指向的分支是 master 分支。
我们再来看一下git目录下的文件
在这里插入图片描述
我们会发现git里refs文件下heads里不在只有我们的master文件了,还有我们新创建的dev

另外,可以通过目录结构发现,新的 dev 分支:
在这里插入图片描述
发现目前 dev 和 master 指向同一个修改。并且也可以验证下 HEAD 目前是指向 master 的。
用图来帮忙我们理解:
在这里插入图片描述


3.切换分支

我们想要在我们的dev上操作,那我们就需要把我们的HEAD指向dev,这样才能把dev变成我们的当前的工作分支
那么我们如何做呢?
使用 git checkout 命令即可完成切换,⽰例如下:
在这里插入图片描述
我们来验证一下我们的HEAD指针
在这里插入图片描述
我们发现 HEAD 已经指向了 dev,就表⽰我们已经成功的切换到了dev 上!
接下来,在 dev 分支下修改 ReadMe 文件,新增⼀行内容,并进行⼀次提交操作:
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
现在,dev 分支的⼯作完成,我们就可以切换回 master 分支:
在这里插入图片描述
在这里插入图片描述
切换回 master 分支后,发现ReadMe文件中新增的内容不见了!!!
为什么会出现这个现象呢?我们来看看 dev 分支和 master 分支指向
在这里插入图片描述
这个时候我们可以看到两个指针指向的commit ID已经不在相同了
我们对dev指向的commit ID进行查看,可以看到记录就是我们刚刚对readme文件进行的修改操作,而且这里的parent指向的commit ID就是刚才刚出创建时的commit ID

因为我们是在dev分支上提交的,而master分支此刻的提交点并没有变,此时的状态如图如下所⽰。
在这里插入图片描述
当切换到 master 分⽀之时,HEAD 就指向了 master,当然看不到提交了!


4.合并分支

为了在 master 主分支上能看到新的提交,就需要将 dev 分支合并到 master 分支
git提供了merge指令
在这里插入图片描述
Fast-forward 代表“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度⾮常快。
当然,也不是每次合并都能 Fast-forward,我们后面会讲其他方式的合并。
我们来查看一下master指针的指向有没有改变
在这里插入图片描述
发生了改变,已经指向了我们在dev分支上对readme的修改
git merge 命令用于合并指定分支到当前分支。合并后,master 就能看到 dev 分支提交的内容了。此时的状态如图如下所示。
在这里插入图片描述

5.删除分支

其实我们在将dev与master分支合并后,dev分支就可以丢弃了,它已经完成它的任务了
那我们怎么进行删除呢?
在这里插入图片描述

注:我们在这里只能除了dev分支之外的分支对dev分支进行删除

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上⼯作效果是⼀样的,但过程更安全。

6.合并冲突

我们在合并两个分支的时候有可能会出现冲突的
比如说

我们在a分支上对readme文件进行了添加文件
同时b分支也没有闲着,也对readme文件进行了修改
当我们合并的时候,git如何知道这两个操作哪个保留下来呢?
这个问题就是合并冲突问题
话不多说,我们进行实操

在这里我们引入一个新的操作,可以将创建以及能转换分支变成一行代码
我们前面需要先git branch dev
然后再checkout dev
这样才完成了我们创建以及更换当前分支的行为
我们使用checkout -b可以直接进行创建且更换当前分支

在这里插入图片描述
我们来对readme文件进行一下修改
在这里插入图片描述
我们照常进行add以及commit操作
在这里插入图片描述
接下来我们切换到master分支再次进行操作
我们在master对readme文件添加一行为add aaaaaaa
在这里插入图片描述
进行add以及commit操作
在这里插入图片描述
这个时候我们git仓库的状态是这样的
在这里插入图片描述
我们这个时候来进行合并,通过我们上面的说辞是会发生冲突的
在这里插入图片描述
这里确实是爆出了错误,说自动合并失败,readme文件的合并出现了矛盾,我们需要改变一下结果并重新提交
我们进入readme文件编辑界面查看
在这里插入图片描述
发现多了不少东西
这些符号里面的就是我们的冲突代码
git无法帮我们进行操作,我们只能自己进行人为操作,谁去谁留
我们要想保留在dev修改的,那我们自己进行删除
将其余行都删掉
在这里插入图片描述
修复之后我们还要进行提交操作

在这里插入图片描述
我们在master最后进行的提交是对最终修改的提交
所以我们的master会指向我们刚刚合并后最后的提交,dev会指向在dev分支上的提交
这也很好理解

git log指令是可以看到我们对分支的操作情况的
在这里插入图片描述
最左边有一个小图可以看到我们对于分支的操作

7.分支管理策略

通常合并分支时,如果可能,Git 会采用Fast forward 模式。还记得如果我们采用 Fast forward 模式之后,形成的合并结果是什么呢?回顾⼀下
在这里插入图片描述
在这种 Fast forward 模式下,删除分支后,查看分支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的
但在合并冲突部分,我们也看到通过解决冲突问题,会再进行一次新的提交,得到的最终状态为:
在这里插入图片描述
那么这就不是 Fast forward 模式了,这样的好处是,从分⽀历史上就可以看出分⽀信息。
我们先创建一个分支dev1
再对readme文件进行修改操作以及add和commit操作
然后再对dev1和master进行合并
在这里插入图片描述
在这里插入图片描述
上面我们在合并的时候可以看到我们的模式是fast-forward模式
我们使用git log --graph --abbrev-commit
我们可以看到在这个模式下我们无法看到我们分支合并的相关操作
在这里插入图片描述
有的仅仅是一条最后合并的操作
–no-ff代表的是我们强制禁止fast-forward模式,后面的-m

我们输入

git merge --no-ff -m “merge dev1” dev1

请注意 --no-ff 参数,表⽰禁⽤ Fast forward 模式。禁⽤ Fast forward 模式后合并会创建⼀个新的 commit ,所以加上 -m 参数,把描述写进去。
可以看到,不使⽤ Fast forward 模式,merge后就像这样
在这里插入图片描述
所以在合并分⽀时,加上 --no-ff 参数就可以⽤普通模式合并,合并后的历史有分⽀,能看出来曾
经做过合并,⽽ fast forward 合并就看不出来曾经做过合并。

8.分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:
⾸先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,⽐如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本
你和你的⼩伙伴们每个⼈都在dev分支上干活,每个⼈都有⾃⼰的分支,时不时地往dev分支上合并就可以了。
在这里插入图片描述
所以,团队合作的分支看起来就像这样:

在这里插入图片描述

9.bug分支

假如我们现在正在 dev2 分支上进⾏开发,开发到⼀半,突然发现 master 分⽀上面有 bug,需要解决。在Git中,每个 bug 都可以通过⼀个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
我们创建一个dev2分支
在这里插入图片描述
在dev2分支上对readme文件进行添加数据
在这里插入图片描述

假设我们在开发过程中出现了bug
我们一开始的需求是在dev2上进行一系列的开发,并且我们的开发并没有完成,所以我们不能进行提交也就是add以及commit操作
同时不能在这个分支上解决bug
现在我们就需要另开一个分支来帮助解决bug
我们移动到master分支

在这里插入图片描述
这里也显示了,我们对readme文件有所修改
这个也是因为我们在dev2分支对readme文件修改后没有进行add以及commit操作
所以我们对于readme的修改是对所有分支都会有影响的,因为没有提交所以git没有对这个修改进行管理
我们在master分支上也可以看到
在这里插入图片描述

git stash

Git 提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在将来某个时间恢复出来。
在这里插入图片描述
那我们这个分支被保存在哪里呢?
我们可以看到在refs文件里多了一个stash文件,这就是储存地点
在这里插入图片描述
⽤ git status 查看⼯作区,就是⼲净的(除⾮有没有被 Git 管理的⽂件),因此可以放⼼地创建分⽀来修复bug。
在这里插入图片描述
储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复 bug,所以需要切回 master 分⽀,再新建临时分⽀来修复 bug
我们在master分支里看readme文件和原来的没有修改过的是一样的
在这里插入图片描述
我们在master分支新建分支
在这里插入图片描述
我们假设发现是readme文件里少了一个s
在这里插入图片描述
我们给加上
在这里插入图片描述
bug已经修复完毕了
将分支删除
在这里插入图片描述
我们还要接着进行开发
切换到dev2分支
我们需要将其隐藏的恢复出来

git stash list

我们可以先使用git stash list
查看我们的stash里面存储了哪些信息
这里只有我们刚刚对于readme进行的修改信息
在这里插入图片描述

git stash pop

我们将隐藏信息释放
指令为 git stash pop
在这里插入图片描述
我们打开看我们刚才修复的bug
在这里插入图片描述
但我们注意到了,修复 bug 的内容,并没有在 dev2 上显⽰
这是因为我们在创建这个分支的时候是没有加上那个s的
此时的状态图为:
在这里插入图片描述
Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以我们在 dev2 中当然看不⻅修复 bug 的相关代码。
我们的最终⽬的是要让 master 合并 dev2 分⽀的,那么正常情况下我们切回 master 分⽀直接合并即可,但这样其实是有⼀定⻛险的。
是因为在合并分⽀时可能会有冲突,⽽代码冲突需要我们⼿动解决(在 master 上解决)。我们⽆法保证对于冲突问题可以正确地⼀次性解决掉,因为在实际的项⽬中,代码冲突不只⼀两⾏那么简单,有可能⼏⼗上百⾏,甚⾄更多,解决的过程中难免⼿误出错,导致错误的代码被合并到 master 上。
此时的状态为:
在这里插入图片描述
解决这个问题的⼀个好的建议就是:最好在⾃⼰的分⽀上合并下 master ,再让 master 去合并dev ,这样做的⽬的是有冲突可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态为:
在这里插入图片描述
在这里插入图片描述
对应的实操演⽰如下,要说明的是,以下演⽰的merge操作,没有使⽤ --no-ff ,但上述的图⽰是
禁⽤ Fast forward 了模式后得出的,主要是为了⽅便解释问题
我们的开发完成了
在这里插入图片描述
再进行add以及commit操作
在这里插入图片描述
解决冲突并提交

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
切回master,并合并(这个时候就不会出现冲突)
在这里插入图片描述
最后删除开发的分支因为任务已经完成
在这里插入图片描述

10.删除临时分支

软件开发中,总有⽆穷⽆尽的新的功能要不断添加进来。
添加⼀个新功能时,你肯定不希望因为⼀些实验性质的代码,把主分⽀搞乱了,所以,每添加⼀个新功能,最好新建⼀个分⽀,我们可以将其称之为 feature 分⽀,在上⾯开发,完成后,合并,最后,删除该 feature 分⽀。
可是,如果我们今天正在某个 feature 分⽀上开发了⼀半,被产品经理突然叫停,说是要停⽌新功能的开发。虽然⽩⼲了,但是这个 feature 分⽀还是必须就地销毁,留着⽆⽤了。这时使⽤传统的 git branch -d 命令删除分⽀的⽅法是不⾏的。演⽰如下:

创建新分支,进行开发并实现提交

在这里插入图片描述

此时被叫停打算删除

我们切回master并删除
在这里插入图片描述
这个时候根据提示无法进行删除,需要使用git branch -D dev3
在这里插入图片描述

11.总结

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再⼀次提交,又存在丢失每天进度的巨大风险。
现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别⼈看不到,还继续在原来的分支上正常工作,而你在自己的分支上⼲活,想提交就提交,直到开发完毕后,再⼀次性合并到原来的分支上,这样,既安全,⼜不影响别⼈工作。
并且 Git 无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐