版本库,也就是git的分支库,实际上是git最核心的部分。当咱们提到git时,其实就是在说git分支。若是你是一个我的开发者,你的项目只有一我的在开发,永远只有一个master分支,那么你可能永远接触不到分支的内容,你对git的了解会永远停留在「了解」这一阶段。git
版本库这个名称来源,就是它管理的是一个个「版本」。segmentfault
版本库是由分支组成的,分支则是由commit组成的。commit就是版本库的基本单位。svn
在git中,每一个都commit有一个独一无二的「commit id」,也就是说经过这个id你能够精肯定位到某一个commit上。spa
因此,为何git要求每次commit的时候必须为commit添加明确的commit message,而且要专门开辟出stage暂存区来管理每一次commit的内容(svn就没有暂存区),就是为了可以随时进行commit(代码版本)层面的操做,明确每一次commit,保证出现问题时能快速定位,以及完成版本回退等操做。3d
简单的说,分支就是由commit串成的一条时间线,就是这样子的:指针
上面的每一个圈圈都是一次commit。code
在新建git仓库时,git会自动给你建立一条分支,叫master,你以后所作的全部操做都是在这个master分支上操做。不过,并不要把一个分支就理解为是这样的一条时间线。这里可能有点绕,也是git中最抽象的一个点之一。就是:对象
master分支实际上是一个指针,它指向一个commit,表明了在这条时间线上,master指针指向的那个commit时间点的代码状态。可能对于指针概念有基础的同窗会更好理解一点。以下图:blog
当咱们创建一个分支时,使用两种方式:开发
这样子创建的分支指针会指向目前你所在的那个分支(master),假如咱们建立了一个分支叫dev,那么咱们的时间线就变成了这个样子:
能够看到,时间线仍是那条时间线,不过已经有两条分支同时存在了,只是这两条分支都指向同一个commit,因此两条分支内容彻底相同,git也就只会指一下指针,不会对代码和时间线作任何操做。可是,抽象来看,你能够把这两条分支看做是两条线。
而咱们怎么肯定哪一条分支是咱们当前的分支呢?也是指针,不过是一个指向指针的指针,叫作HEAD。HEAD指针在git中算是个关键字,HEAD就是当前指向当前分支的指针的意思。咱们只用git branch dev
建立分支时,HEAD指针不会作改变,当前分支依然是master分支,当前状态如图所示:
当咱们在当前这种状态下,将暂存区中的内容进行一次提交时,会将时间线向前推动,生成一个commit,而后把当前分支master指向最新的commit。如图所示:
当切换分支时,咱们会使用git checkout <branch name>
,将HEAD指针指向切换过去的那个分支名。
咱们是否是见到了老朋友checkout!
在前面的暂存区我讲过,checkout做为检出操做是将暂存区中的内容同步到工做区的方法。这里的checkout依然是检出的意思,只不过检出的对象变成了相应分支的文件。
其实咱们能够把暂存区想象成一个分支,暂存区的内容就是commit的内容,这两种操做的意义就保持一致了,只不过检出分支时HEAD指针会移动。checkout文件会修改工做区。因此,执行git checkout dev
后,分支状态就变成了这样:
而上面说过,checkout会修改工做区,因此你磁盘上的文件就变成了dev分支上那次commit时的样子。而在建立时提到的git commit -b <branch name>
则同时完成了「建立分支」和「检出分支」两个操做,方便得很。
使用git branch -av
就能够查看全部分支的信息了(a是all,v是verbose)。
涉及操做:git branch <branch name>
, git checkout <branch name>