本文介绍Git的分支。
目录
分支
Git里的分支用于开始一条独立的开发路径。分支是从一种统一的状态”分裂”出来的,这让分支和主干(其实Git没有绝对的主干,一切都是分支)可以独立开发,不受相互影响。当然,分支开发到一定阶段之后通常会”合并”到主干上。
Git里的分支非常轻量级,而且Git的合并(merge)也非常强大,因此在日常开发里用户会经常创建、合并和删除分支。比如我们修复一个小的bug,就可能创建一个分支,修复代码测试通过后就和合并到主分支上,然后再把这个分支删除掉。
为什么要使用分支
-
分支可以用来做发布
- 比如我们要开发包含新功能的1.1,但是有的用户需要停留在稳定的1.0版,这个时候就可以使用到分支。
-
分支可以封装开发的不同阶段
- 比如原型阶段、beta阶段、稳定阶段
-
分支可以用来开发一些实验性的代码
- 通过单独的分支来避免这些代码干扰稳定的代码。
-
分支可以用来代表一个人的工作
- 每个开发者用自己的分支来区分各种的工作
Git里把上面的这些分支叫做主题(topic)分支或者开发(development)分支,而与之相对的是tracking分支,它是为了追踪clone源分支而存在的,后面在介绍远程分支时会介绍tracking分支。
分支名
分支名除了某些字符的限制之外,没有任何约束。一个repo的默认分支是master,大部分开发者把稳定的代码保留在这个分支上。”master”这词没有任何特殊之处,我们完全可以删除它。它只是在git init之后默认创建的分支,不过最好还是不要删除它。有的开发团队为了组织方便,会在分支名里引入”/”从而”看起来”好像有层次结果,比如”bug/pr-1023”和”bug/pr-17”,不过git并不认为”/”有什么特殊含义。
分支名的一些限制:
-
我们可以用”/”来创建人类读起来有层次的分支名,但是分支名不能以”/”结尾,也就是说”/”不能是分支名的最后一个字符。
-
分支名不能以”-“开头
-
”/”后面不能是”.”,因此”feature/.new”不是合法的分支名
-
分支名不能包含连续的两个点,也就说不能包含”..”(可以包含一个”.”)
-
分支名还不能包括:白空格(空格和tab等)、~、^、:、?、*和[,此外还有一下控制字符是不允许的
使用分支
在某个时刻,一个repo可能包含多个分支。但是在一个时刻,只有一个分支是活跃的(active),工作目录包含的就是这个活跃分支的内容(当然如果工作目录是dirty的,则它也包含了对这个分支的修改)。活跃分支通常是很多git命令的默认参数,比如merge的目标分支。默认的活跃分支是master,当然我们可以使用git checkout任何其它分支。
分支允许repo的内容往不同的方向发展,每个分支是一个方向。一旦一个repo多余一个分支,则每个提交都是应用到当前活跃的这个分支上。
每个分支都有一个本repo唯一的名字,它总是引用当前分支最新的一个提交。一个分支最新的提交叫做tip或者head。
Git不会记录一个分支是从哪里fork出来的,分支名字会随着这个分支的新提交而不断改变。而之前老的提交可以用它的HASH或者相对名字(比如dev~2)。如果你想永久的标识一个提交,则可以使用tag。
如果你想知道某个分支是从哪个提交fork出来的,则可以使用如下命令:
$ git merge-base original-branch new-branch
其中original-branch是原始的分支名,而new-branch是fork出来的分支名,git会通过图的算法确定fork的提交。
但用git merge时,git会把被合并的分支合并到目标(target)分支上,但是被合并的分支并不会发生任何改变。分支名可以看做一个指向某个提交的指针,通过这个指针可以回溯这个分支所以的历史(一直回溯到初始提交)。
比如下图,dev分支指向Z这个提交,如果你想重构repo在Z的状态,那么所有从Z可以回溯到的提交都是需要的。也就是除了S、G、H、J、K和L,其它所有的提交都是Z的历史。
你的repo里的所有分支名以及提交都是local的,如果想要让他人看到,则需要发布(publish),后面介绍的git push可以把你修改的内容发布出去。其他人也可以是用git pull来获得你的修改。此外如果使用git clone时也会拷贝你的整个repo从而获得所有的内容。
