本篇主要总结的是Git中的分支管理
分支是什么
在Git中,一个强大的功能就是分支
由前面的学习可以知道,当我们每次进行commit
的时候,Git都会把这些commit
的操作穿成一个时间线,而这个时间线就可以理解为是一个分支,在我们前面的操作中,只有一个时间线,换而言之,只有一个分支,这个分支就叫做主分支,也叫做master
分支
上一篇在介绍Git的基本操作中讲到,Git中含有HEAD
指针,可以借助它来完成对于版本的回退,这里再次明确概念,这个HEAD
指针所指向的内容是master
而不是具体的commit记录,而master
所指向的内容才是提交的内容,也就是说,HEAD
指向的是当前分支,而分支指向的是具体的master
提交记录,用下面一张图来表示:
提交线上的每一个圆圈,代表的都是每一次提交,而master
指向的是最新的一次提交,用户本身利用HEAD
指针就可以通过master
的指向回退或快进到某一个版本,随着不断提交,这个分支会不断变长,但只要HEAD
一直指向的是master
分支就可以指向当前的分支
下面通过一些实验来看上面的理论:
上图中使用了一些命令来查看当中的commit
相关信息,从中可以看出每一次提交的信息都有记录,并且也会记录它的上一次提交的相关信息,依据这些信息都可以在这条master
分支线中找到相应的信息
创建分支
既然分支是Git中的一大重要操作,那么创建多分支并使用多分支进行管理项目也是必不可少的操作,那么如何新建分支?
这里提供两个命令
# 查看本地所有分支 git branch # 新建分支dev git branch dev
其中,*
表示的内容是,当前Git所控制的分支,以上图为例,当前HEAD
所指向的分支其实是master
,同时上面也表明了在Git中如何创建一个分支
下图表示了分支的存在证明:
在我们创建了分支后,此时的refs
路径下heads
所包含的内容就不仅仅是master
了,换句话说,HEAD
可以指向其他内容了
分支切换
在Git中提供了切换分支的操作:
# dev表示要切换的分支名称 git checkout dev
利用上面的命令,将Git的分支实现了切换,下图为实践图
而切换分支的操作,实际上就是将HEAD
指针所指向的分支做修改的一个过程:
从上图中可能还有疑问,为什么dev
创建后的分支默认是指向最新提交处?后面会进行实验证明
那么切换完分支后,就可以进行一些操作验证分支的特性了
从上图的实验中可以看出,在没有进行合并分支的前提下,在不同的分支下进行的commit
操作是不可以互通的,都是单独的时间线,也就是单独的分支,从commit id
的视角下观察这个结论
从上面的实验中可以几点:新建的分支确实是在当前所指分支的开始新建的,并且新建后的分支内容和旧的分支内容并不互通,也就是说,此时的状态可以用下面的状态图表示
合并分支
那么如何进行分支合并?Git中也提供了相关的命令:
# 要切换到master分支下 git merge dev
当在master
分支下使用指令合并分支后,test
中的内容就被合并到master
中了,此时master
就重新指向了最新的分支节点
Fast-forward
代表快进模式,也就是直接把master
指向dev
的当前提交
删除分支
分支使用后要进行删除,避免占用过多资源:
git branch -d dev
此时就删除掉了分支:
那创建分支合并分支删除分支有什么作用?
Git建议使用分支后再删除,这样比较安全
合并冲突
看下面的场景:
上面所演示的过程就是合并冲突的原理,两个分支都进行了一些操作,此时想要进行合并Git不知道该如何合并,该合并哪个部分,因此Git给出的解决方案是两个版本都进行保留,由用户自己来决定如何管理
用下图来表示这个冲突的过程:
因此,当手动删除了部分内容后并进行提交,就可以解决这个冲突问题,此时就可以把状态转换为:
Git的可视化流程图
在Git命令中也是可以把上面的这个流程图进行可视化的,使用到的命令是git log
git log --graph --pretty=oneline --abbrev-commit
合并模式
在merge
的过程中,有两种合并模式,前面已经提到过一种合并模式是Fast-forward
模式,这个模式的特点是直接将dev
分支中的信息合并到master
分支内,但如果这里我想在合并的这个过程也产生一次commit
来表示,这里确实发生过一次merge
该如何处理?Git中也提供了对应的命令选项:
# branch表示合并的分支名称 git merge --no-ff -m "merge with no-ff" [branch]
那么下面用实验来对比一下这两个方法合并模式对应的效果演示
首先看fast-forward
模式
上面演示的就是fast-forward
下的各项操作,下面演示no fast-forward
的操作结果
从中可以看出,使用no-ff
模式下的合并方法可以显示出merge
的具体commit id
等信息,这样有利于在追溯代码的时候找到在哪里产生问题等,在实际开发中也多建议使用no-ff
模式而不是ff
模式
分支策略
在实际开发中,进行分支管理应该要遵循下面的几个原则
master
版本是一个非常稳定的版本,这个分支是主分支,上面只是用来发布新的版本,在平时的开发过程中应该要自己创建分支,在自己的分支上完成操作- 在自己的
dev
分支上完成自己的工作任务后,每个人都有自己的分支,完成后向master
分支合并就可以了
因此整个合并的流程可以表示为下面的图
每个人都有自己的分支,分支写好后统一合并到master
分支上,以确保master
分支上都是稳定的代码
bug分支
现在有这样的场景,假设你正在dev
的分支上进行开发,突然,master分支上发现了一个bug
,现在这种修改master
分支上的bug
,应该如何解决?
在Git中,每一个bug
都可以通过一个新的临时分支来进行修复,修复后合并分支,再将临时分支删除即可,但是对于上面的情况,dev
的代码正在开发,但是master
有问题,现在还无法提交,对于这种情况该如何解决?
针对这种情况,在Git中提供了一种叫做git stash
的命令,这个命令的作用就是可以让当前的工作区的信息进行存储,在未来的某个时刻再把信息拿出来
git stash
使用该指令可以让工作区中的代码暂时存起来,因此使用stash
指令查看就会发现此时工作区中是没有内容的,此时就可以单独拉一条fix_bug
专用的分支进行修复代码,修复后的代码再提交到master
分支内,此时master
分支就是一个稳定的,没有bug
的一份代码
那么下面就要解决的问题是,如何把我写了一半的代码和新的没有bug
的代码合在一起
此时就完成了基本目标:既把master
分支的bug
改完了,又把dev
分支下的内容更新完,并且dev
下的内容是没有bug
的,那么如何把dev
的文件上传到master
主线上?其实直接上传即可,但这里不推荐这样,原因如下:
原因是,解决合并冲突的时候,是由dev
的用户自己进行手动的删除解决的,这当中可能会出现一些问题,因此这样的方法是有可能会出现错误的:
那么最标准的方法是,应该先拉取master
上的代码与dev
合并,在dev
分支下看看能不能正常运行,如果可以再将代码整体合并到master
分支上,以确保master
分支上都是可跑的,没问题的代码
强制删除分支
Git默认的删除分支的前提是路径要进行合并后才能进行删除,但如果是没有进行合并,只是单纯想把路径删除?
Git中提供了对应的选项
# dev表示要删除的分支 git branch -D dev