什么是Git
Git是一种分布式的版本控制。版本控制,即是一种记录一个或若干文件内容的变化,以便将来查阅特定版本的修订情况的系统。在Git之前,也是由一些集中式的版本控制,比如SVN等,而为什么出现Git呢,主要是由于Git有以下几个优势:
分布式 :Git与传统的版本控制最大的区别即是在于其分布式,分布式意味着Git在每个人的本地维护者一个仓库,而不像集中式版本控制,本地不会有仓库;Git由于其分布式的特性,其可以在任意时刻提交你的代码,有无网络皆可,当有网络的时候则可将本地仓库的代码推送到远程仓库,而集中式的版本控制则不行;
直接记录快照:什么意思呢?Git保存的是当前提交的一个快照。而不是基于上次提交的差异性比较,假设你对你工作区的文件A进行了修改,但B没有修改,提交之后,Git将记录的是A文件与B文件的在当前提交的一个快照,而传统的集中式版本控制,则只会记录B文件修改过后的内容;
Git由于其上重要的两个特性,使得大多数的操作都可以在本地完成,即将代码提交到本地仓库,之后再将代码推送到远程仓库
Git基本操作
下面对Git的一些操作进行说明,以便更好的理解Git的工作原理。
初始化仓库
初始化仓库的命令是git init,如果安装好Git,配置好环境变量后,在一个目录下运行git init命令,则会发现,在这个文件夹下出现了个.git/的隐藏目录,进入到该目录下,可以看到,其中的内容为
HEAD文件指示出目前被检出的分支,即当前分支
config文件中包含一些配置项
description供gitweb使用
hooks目录包含服务器端或客户端的钩子脚本
info目录包含一些全局性的排除文件
objects目录存储所有的数据内容
refs目录存储只想数据(分支)的提交对象的指针
注意:最开始初始化仓库的时候,并没有index文件,只有当你将文件添加到暂存区时,index文件则会自动生成
更新到仓库
在将将代码更新到仓库之前,首先先将下Git环境下文件的三种状态,即分别是已提交、已暂存和已修改。三种状态对应Git的工作区域,已提交的文件一般在Git仓库中,会将信息保存在.git的目录下,而已暂存,对应Git的暂存区,也叫index区域,其内容在.git目录下的index文件保存,而修改的文件对应你的工作区域,一般就是你的文件夹目录下。
已修改:就是对文件进行了修改
在Git的工作目录下,新建了一个a.txt的文件,这时使用git status查看状态,这时a.txt文件就处于已修改的状态
已暂存:就是将修改的文件从修改状态改变为到暂存区,一般使用的是add命令,此时使用git status查看状态,即
已提交:就是将文件从暂存区提交到本地仓库,一般使用的是commit命令,此时查看状态,即
此时工作区是干净的。
而相对应的,对一个文件来说,其有两种状态:一是未追踪,一是已追踪。在对一个文件进行修改了但还未纳入到暂存区的时候,这是使用git status查看的时候,会看到untracked files,表明此文件是没有被版本库追踪的,只有使用add命令会,该文件才会被追踪。
Git引用
Git引用,出现的原因就是因为40位的SHA-1值不太好记。在Git中40位的SHA-1值主要是为了保证数据的完整性,而在你每次提交的过程中,Git都会将这些信息记录下来,记录这些信息的主要就是使用SHA-1值。而由于该值不太好记,所以就可以使用Git引用。引用的本质是一个文件,其文件的内容就是SHA-1值。
在Git中主要有两种引用,一类是HEAD引用,HEAD引用只想目前所在的分支,其在.git/HEAD。
一类是标签引用,标签引用指向的是一个提交对象,里面包含一些标签信息。
Git对象
Git中的对象主要有四种,分别是数据对象(Blob),树对象(tree),提交对象(commit)和标签对象(tag),下面分别对此进行介绍。
数据对象(Blob)
Git的数据对象,只是记录文件的内容,而不会记录文件名。
树对象(tree)
树对象主要是记录文件名,其可以将多个文件组织在一起,可以将树对象理解为目录,其中包含子目录信息和文件信息。
可以使用git cat-file -t SHA-1可以查看某个SHA-1是什么对象
使用git cat-file -p SHA-1查看该对象里面的具体内容,若为数据对象,则显示文件内容,若为树对象,则显示目录下的信息
提交对象(commit)
提交对象表示当前项目的快照信息,里面包含着提交/作者信息
标签对象(tag)
Git中标签分为两种,一种是轻量标签,直接使用git tag 标签名,创建即可,轻量标签只是一个特定提交的引用,其本质是将提交校验和存储到一个文件中,没有保存任何其他的信息;一种是附注标签,带上参数-a 即可,附注标签是存储到Git数据库中一个完整的对象,其包含的内容比较多。
Git分支
在进行提交的时候,Git一般会保存一个提交对象,该提交对象会保存一个指向暂存内容的快照指针。Git分支的本质,是指向提交对象的可变指针。
分支的创建与切换
创建分支:git branch 分支名,会在当前提交对象上创建一个指针
切换分支:git checkout 分支名,其会将HEAD内容修改为切换后的分支
分支合并
在工作中,会进行大量的分支的创建,分支的合并等。分支的合并一般使用merge,在对分支进行合并的过程中,会有两种情况:
当在当前分支master合并hotfix分支的内容时,使用merge出现Fast-forward,即表示该合并方式是‘’‘快进’。出现这种情况是由于master分支所指向的提交是当前提交的直接上游,所以Git只是简单的移动指针。换句话说,当试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么Git在合并两者的时候,只会简单的将指针向前推进,这种情况下,合并操作没有需要解决的分歧,即“Fast-forward”
master分支时hotfix分支的直接上游,所以直接使用快进合并,只是指针简单的移动,如下图
另一种情况如下,在C2提交点的时候,分支进行了分叉,master的提交为C2,C4这条路径,而iss53分支提交的为C2,C3,C5这条路径,此时master进行合并issue53。此时的合并进行的三方合并的方式,即找到master和iss53所指的末端分支(C4和C5),在找到两个分支的第一个工作祖先(C2),将三者进行合并并生成新的提交