我们已经了解了git非常重要的三个组件:blob、commit、tree,这三个组件都是以二进制的方式存储的,
而且都是用hash码作为主键的唯一名称。
接下来我们将详细的介绍git的分支。
分支在项目的开发过程中是非常重要的,分支旨在解决版本管理之中的冲突问题。分支的使用一定要在整个项目团队中达成一致,否则分支太多,最后合并的时候会存在一大堆的问题,目前已经有了一套成熟的分支管理体系git-flow,这套体系我们会在以后详细介绍,这一次我们主要介绍git和分支相关的各种命令。
1、首先建立自己的git目录。进行如下操作:
D:\test\git>git init
Initialized empty Git repository in D:/test/git/.git/
***完成工厂的创建
D:\test\git>echo a > a.txt
D:\test\git>git add .
D:\test\git>git commit -m "add a.txt"
[master (root-commit) df11b43] add a.txt
1 file changed, 1 insertion(+)
create mode 100644 a.txt
***完成第一版本的提交
D:\test\git>echo a1 > a1.txt
D:\test\git>git add .
D:\test\git>git commit -m "add a1.txt"
[master e5fb3fb] add a1.txt
1 file changed, 1 insertion(+)
create mode 100644 a1.txt
***完成第二个版本的提交
D:\test\git>git log
commit e5fb3fba474eaa5e429bd51945caeae29b46e7b9
Author: pm <pm@gmail.com>
Date: Sat Dec 31 22:08:23 2016 +0800
add a1.txt
commit df11b43c129bd3761b0855ef146d0a8a9f9183a6
Author: pm <pm@gmail.com>
Date: Sat Dec 31 22:02:43 2016 +0800
add a.txt
***通过git log发现已经存在两个版本了。
通过以上操作基本完成了项目的初始化操作,这里我们建立了两个版本。
2、接下来我们使用下一个命令来创建一个分支。
git branch b1
这样就创建好了一个分支b1,可以通过:
git branch
查询所有的分支:
我们发现有两个分支,一个是master,另外一个是刚才创建的b1,master是绿色的并且前面有个*,表示
我们目前处于master分支。
现在的状态:
有两个分支,有两个文件a.txt和a1.txt。
3、下一步我们需要转换到b1这个分支中,使用下面的命令:
git checkout b1
此时就可以转换到b1的分支中,同样我们也可以通过如下命令完成分支的创建和转换:
git checkout -b b2
这将会创建一个分支b2,并且切换到分支b2中
4、我们就在b2分支中进行一些修改,并且完成一次版本的提交。
此时在b2分支中就有了三次提交,而且有了三个文件。
我们再切换回分支master看看情况:
我们发现master分支看不到b2分支的任何信息,而且文件也没有在b2分支中添加的b2.txt。
我们继续在master分支中添加一个文件m.txt。然后完成版本的提交:
此时在master中有3个文件:a.txt,a1.txt,m.txt,其中m.txt是在分支创建之后才创建,而且目前master分支
也有三个commit,切换回b2分支,查询文件:
我们发现在b2上并不存在master在创建分支之后的信息,此时master分支的修改不会在b1或者b2中
有所呈现。
我们继续如下操作,选择b2分支,然后再次创建一个分支b2_1:
此时需要注意的是我们是在b2分支上创建的分支b2_1,所以b2_1分支仅仅只能看到b2分支上的东西,
这里就得出了一个结论,在某个分支上创建的分支是以该分支为基础的。此时在b2_1中添加文件并且完成
提交。并且切换到b1中进行一次版本的提交,再在b2中进行一次版本提交,执行的命令如下:
D:\test\git>git checkout b2_1
Already on 'b2_1'
D:\test\git>echo b2 > b2_1.txt
D:\test\git>git add .
D:\test\git>git commit -m "b2_1 add b2_1.txt"
[b2_1 29f4946] b2_1 add b2_1.txt
1 file changed, 1 insertion(+)
create mode 100644 b2_1.txt
***在b2_1分支完成b2_1.txt的添加、提交
D:\test\git>git checkout b1
Switched to branch 'b1'
D:\test\git>echo b1 > b1.txt
D:\test\git>git add .
D:\test\git>git commit -m "b1 add b1.txt"
[b1 4a3143a] b1 add b1.txt
1 file changed, 1 insertion(+)
create mode 100644 b1.txt
*** 在b1分支完成b1.txt的添加、提交
D:\test\git>git checkout b2
Switched to branch 'b2'
D:\test\git>echo b2 >> b2.txt
D:\test\git>git add .
D:\test\git>git commit -m "b2 update b2.txt"
[b2 7911400] b2 update b2.txt
1 file changed, 1 insertion(+)
***在b2分支完成b2.txt的修改、提交
查看当前每个分支的情况,可以使用如下命令让git log 在一行显示:
git log --pretty=oneline
有没有发现,现在分支已经开始混乱了,我们简单分析下分支目前的状态:
我们最早的master分支有两次提交,之后创建了b1和b2分支,并且分别完成了一次提交,然后在master上也完成了一次提交,在b2分支上又创建了新的分支b2_1,然后完成了一次提交。大家有没有发现不管怎么分析,当分支变多之后也很难进行管理,这也就是为什么我们要确定分支管理思路的原因,很幸运,git-flow为我们定义了一套合理的分支管理流程,我们将会在后面来进行介绍。
现在我们已经了解了分支的创建操作,之后我们需要对分支进行合并,刚才我们的操作是人为避开了冲突,我们先了解分支合并步骤,之后再来看产生冲突之后的情况。分支的合并非常的简单,只要在需要合并的分支上使用git merge 要合并的分支
就完成了。
5、下面的操作完成了在master分支上合并b1:
git checkout master
git merge b1
合并非常的顺利,但是注意,合并完成之后,会产生一个新的commit组件,通过cat-file查询这个组件,
我们会发现该组件有两个parent,看看这两parent的id,就是原来的master的最新版本id和b1的最新
版本的id。我们发现一个版本是可能存在多个parent的,只要分支进行合并之后,parent指向了它的
上一个版本。
接着我们来合并b2分支,b2分支有些特殊,因为b2分支上还存在b2_1分支。
git merge b2
我们发现合并非常的顺利,git并不会将b2_1的内容合并进来,我们可以继续执行git merge b2_1
完成合并,也同样顺利完成,git log --pretty=oneline
查询,我们发现每次合并都产生了新的commit组件:
我们发现git的分支合并非常的灵活高效,在合并完分支之后我们就需要删除多余的分支,
使用-d
参数完成删除:
git branch -d b1
使用以上命令就完成了对b1分支的删除,之后我们来删除b2分支,我们发现b2分支的删除也非常的顺利,而且删除完成之后b2_1分支依然存在。我们发现虽然b2_1是在b2的基础上创建的,但两者之间的关联其实并不密切(后面我们会了解到分支的名称仅仅只是那个hashid的标示,删除了分支,其实版本依然是存在的)。而且,我们发现b2_1上的parent依然是我们删除了b2分支的版本。
但是此时执行git branch -d b2_1
,我们发现报了一个错误。他告诉我们b2_1并没有被完全合并,由于它是在b2上衍生出来的分支,应该要先合并到b2中,但是此时b2已经被删除了,我们可以使用git branch -D b2_1
强行删除分支。所以虽然git对分支的合并的管理非常灵活,但是在实际使用中,如果在某个分支上创建了子分支,依然应该先完成子分支的合并再将其合并到master中。
6、下面我们演示一个带冲突的分支合并,当两个分支同时修改某个文件的相同行时就会发生这个冲突。
我们会执行如下一组命令:
D:\test\git>echo co > co.txt
D:\test\git>git add .
D:\test\git>git commit -m "master add co.txt"
[master 318f7ac] master add co.txt
1 file changed, 1 insertion(+)
create mode 100644 co.txt
D:\test\git>git checkout -b bc
Switched to a new branch 'bc'
D:\test\git>echo changeByBc > co.txt
D:\test\git>git add .
D:\test\git>git commit -m "bc update co.txt in first line"
[bc 9f961c6] bc update co.txt in first line
1 file changed, 1 insertion(+), 1 deletion(-)
D:\test\git>git checkout master
Switched to branch 'master'
D:\test\git>echo changeByMaster > co.txt
D:\test\git>git add .
D:\test\git>git commit -m "master update co.txt in first line"
[master a4bb91b] master update co.txt in first line
1 file changed, 1 insertion(+), 1 deletion(-)
此时两个版本中co.txt的内容不一样,而且是在同一行,我们进行一下合并:
git checkout master
git merge bc
我们发现产生冲突了,在co.txt中显示了冲突的位置,当发生这个冲突,我们只能在团队的内部进行协调
解决这个冲突,这是分支合并时修改了相同文件,带来的必然结果,只能人工解决或者通过SourceTree之类的工具选择使用那个版本。所以分支虽然给我们带来了很多便利,但是一定要合理的规划好分支的使用策略才能让分支发挥出最大的功效,接下来将介绍基于git-flow的分支管理策略。