什么是git分支?
什么是git分支?首先让我们回顾一下提交对象,一个提交对象(commit objects)包括:
一系列文件在某个时间的快照。
一系列指向父提交对象的索引。
一个SHA-1名字,这个名字40个字符长,是独一无二的。
作者的姓名和邮箱,以及提交时对提交的描述。
事实上,“一系列文件在某个时间的快照”并不是直接存在于提交对象。在git中,blob对象保存着文件的快照,树对象保存着目录结构和blob对象的索引,而提交对象保存指向树对象的指针。下图是一个这三者关系的示意图:
三个对象及其关系
那么git中的分支是什么呢?
git中的分支就像是你的文件的一份副本,你可以在需要的时候拷贝一份出来,这样你就得到了一个“分支”,你可以在上面修改,修改完成之后再合并回去。在一些版本控制软件中实际情况确实是这样,然而在git中并非如此。
在git中,对分支的操作大部分只是在修改指向提交对象的heads。我们知道,heads是一个指向提交对象的指针,分支操作中的大部分操作只需要修改heads的指向,即向heads文件中写入41个字符即可(40个SHA-1字符串和1个换行符)。与其他一些版本控制软件采用的复制文件策略相比较,git分支操作与文件大小无关,操作迅速快捷。
指向提交对象的heads
创建分支
现在先来看看我们在哪个分支,使用命令查看当前分支,命令选项显示分支指向提交对象的校验和及其描述:
从结果中看到,现在只有一个分支,叫做。表示当前所在的分支,即HEAD的指向。
用图简略表示如下:
仅有master分支
现在创建一条分支,使用命令:
现在有了两条分支:和,目前我们在分支。图示如下:
创建一条dev分支
可见,事实上只是创建了一个指向图中提交对象的指针,使用可以查看heads的指向:
、远程的和指向提交对象,指向。
切换分支
现在切换到分支,使用命令,在切换前请确保你的工作目录是干净的:
这样就切换到了分支,查看一下:
可以看到我们确实在分支,确实指向了分支。在切换分支时,git会将分支所指向的提交对象的文件快照检出到工作目录,并且更改的指向。目前分支情况图示如下:
切换到dev分支
可以创建分支并且切换到它,相当于执行下面两条命令:
“快进”合并
现在在分支,我们创建一个文件并且提交:
查看一下各个分支所指:
前进了一个提交对象,指向,其他分支并没有更改,图式如下:
dev新提交
现在切换到,使用命令,会指向,工作目录中的文件将会被替换:
切换回master
合并分支使用命令,这个命令将分支合并到当前分支,现在我们在分支,执行下面的命令将分支合并到分支:
git告诉我们此次合并的方式是(快进),此时分支情况如下:
合并dev分支
现在分支已经被合并到分支了。从上图可以看出git仅仅是简单的更新了和的指向,这是由于合并前指向的直接上游,这种合并方式叫做快进(Fast-forward)。
可以使用选项避免使用“快进”合并,这样会形成一个新的合并提交,类似下节讲到的分之合并:
现在分支已经充分得发挥了自己的作用,让我们删除它:
如果一个分支没有完全合并到当前分支,那么git会阻止你删除它,如果确实要删除它,使用命令选项:
如果想要知道那些分支被合并了或者没有合并,使用下面的命令:
目前分支情况如下:
删除dev分支
本文所讲的例子整体过程图示如下:
快进合并
分支合并
现在创建一个分支并且切换到该分支:
添加并提交,修改并提交:
回到分支并且修改:
现在两条分支在分叉后都有新的提交:有两个新的提交,有一个新的提交。怎样在命令行查看呢?
可以看到,在分支分叉,之后进行了两次提交,进行了一次提交,目前我们在分支。图示如下:
合并提交1
现在将分支合并到分支:
现在git帮我们合并了和,并且生成了一个新的提交(你可能需要填写提交描述),这个新提交的SHA-1校验和前七位是8425ef2。
git能够帮我们自动合并,而不会产生冲突的原因是我们在不同的分支中修改了不同的文件,此时git会参考两个分支所指的快照(的和的)和两个分支的共同祖先(),自动合并。参考的三个快照分别相当于下图的C6、C7和C4.
新生成的提交叫做合并提交,相当于下图的C8.这个新提交拥有两个父提交。
合并提交2
好了,现在删掉分支吧:
本文所讲的分支合并的整体过程图示如下:
分之合并
冲突解决
如果在不同分支中同一个文件的同一个地方做了修改,git就无法干净利落地合并它们。
创建一个新的分支,在分支中将修改如下并且提交:
切换到分支,将修改如下并且提交:
现在将分支合并到分支:
git告诉我们说自动合并失败,原因是在文件中有冲突,并且提醒我们解决冲突后提交结果。
也就是说,git在遇到冲突时,并不会创建一个合并提交,而是暂停下来,等用户解决冲突之后,由用户提交。
含有冲突的文件被标记为“未合并”(unmerged)状态,随时可以使用来查看:
现在让我们解决中的冲突,首先来看一看git刚刚所做的工作:
其中的一部分是git为我们标记的冲突的部分:
在的上半部分的是分支中的文件内容,在其下半部分的是分支中文件的内容。
现在让我们将这部分修改如下:
这表示将丢弃中的修改,当然你可以根据自己的喜好更改,你可以改成任意你需要的内容。
现在将文件添加到暂存区,并且查看状态:
可见,一旦冲突文件被添加到暂存区,它的“未合并”状态就会被解除,即表示冲突已经解决。
现在提交即可:
最后删除分支:
储藏与清理
git在切换分支时必须保证当前工作目录是干净的,如果现在做了一点更改,不至于提交一次新的更新,但是却必须更换到另一条分支上,怎么办呢?
git为我们提供了(储藏)工具。
现在在分支上对作一些更改,并且将它储藏起来:
在运行之后工作目录就变干净了,现在就可以切换到其他分支工作啦。
在其他分支工作完之后,又回到,怎样继续工作呢?
使用命令可以查看储藏的列表:
使用即可应用,如果为空,则会应用最新的储藏:
我们的更改又回来了,使用删除相应的储藏,如果为空,则会删除最新的储藏:
可以使用直接应用最新的储藏,同时删除该储藏。
在git中,可以进行多次储藏,也可以在不同的分支应用储藏。
领取专属 10元无门槛券
私享最新 技术干货