引言
正如之前的博客中提到的,Git区别于Svn的一个最明显的功能就是分支管理功能。
那么什么是分支?分支又能为我们的开发带来什么翻天覆地的变化呢?(为了使博客的内容更具权威性和专业性,以下部分内容摘自官方文档《Git - 分支简介》)。
什么是分支
分支,顾名思义,从主干分离的枝干。使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。
分支并不是Git特有的功能特性,但是相比于其他的版本控制系统,Git处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。与许多其他版本控制系统不同,Git鼓励在工作流程中频繁地使用分支与合并(branch 和 merge)。
理解和精通这一特性,我们便会意识到Git是如此的强大而又独特,并且从此真正改变我们的开发方式。
创建分支
创建分支的命令是git branch :
$ git branch testing
根据Git的工作原理(在此不做讨论,可以参见《起步 - Git基础》),上面这行命令会在当前所在的提交对象上创建一个指针。
此时,两个指向相同提交历史的分支,而Git又是如何知道当前在哪一个分支上呢?其实,Git中还存在一个名为HEAD的特殊指针。在Git中,HEAD指向当前所在的本地分支(将HEAD想象为当前分支的别名)。$ git branch命令仅仅会创建一个新分支,并不会自动切换到新分支中去。
可以使用$ git log 命令查看各个分支当前所指对象。
$ git log --oneline --decorate
f30ab (HEAD, master, testing) add feature #32 - ability to add new
34ac2 fixed bug #1328 - stack overflow under certain conditions
98ca9 initial commit of my project
可以看到,当前master和testing分支都指向校验和以 f30ab 开头的提交对象。
切换分支
更换到一个已经存在的分支,需要使用$ git checkout 命令。
$ git checkout testing
可以再次进行开发,并提交:
$ vim test.rb
$ git commit -a -m 'made a change'
执行完提交后,HEAD分支就会随着提交操作自动向前移动,如上图所示,testing 分支向前移动了,但是master分支却没有,它仍然指向运行 git checkout 时所指向的对象。
我们再次切换回 master 分支上:
$ git checkout master
checkout 时HEAD随之移动,这条命令完成了两件事:第一是将HEAD指向 master 分支,第二是将工作目录恢复成master 分支所指向的快照内容。也就是说,你现在做修改的话,项目将始于一个较旧的版本。本质上来讲,这就是忽略 testing 分支所做的修改,以便向另一个方向进行开发。
此时,如果我们不进行分支合并(merge操作),而是朝着另一个方向进行了修改,那么我们就会出现如下图所示的分支结构:
可以看到,项目的提交历史已经产生了分叉。因为刚才我们创建了一个新分支,并切换过去进行了一些工作,随后又切换回 master 分支进行了另外一些工作,上述两次改动针对的是不同的分支:你可以在不同分支间不断地来回切换和工作,并在时机成熟时将他们合并起来。
项目分叉历史
使用 $ git log命令查看分叉历史。它会输出你的提交历史、各个分支的指向以及项目的分支分叉情况:
$ git log --oneline --decorate --graph --all
* c2b9e (HEAD, master) made other changes
| * 87ab2 (testing) made a change
|/
* f30ab add feature #32 - ability to add new formats to the
* 34ac2 fixed bug #1328 - stack overflow under certain conditions
* 98ca9 initial commit of my project
Git的分支实质上仅包含所指对象校验和(长度为40的SHA-1 值字符串)的文件,所以它的创建和销毁都异常高效。因为创建一个新分支就相当于往一个文件中写入1个换行符和40个字符,因此十分迅速。
综上,就是Git的分支管理相关的概念和模型,如有疑问欢迎文末留言。
参考:
《Git - 分支简介》