git对象
每一个git对象都由3部分组成:类型(type)
、大小(size)
和内容(content)
大小就是内容的大小,内容取决于对象的类型,主要有4种类型 - blob
、tree
、commit
、tag
使用git cat-file -t hash
值可以查看文件类型
blob对象
用于存储文件数据。它通常是一个文件,注意它只包含文件内容并不包含文件名
tree对象
基本上就类似一个目录,它引用了一堆其他的tree
对象或者blob
对象,其实就是包含一些子目录及子文件
commit对象
指向一个tree
对象,它标记着项目在某个时间点的状态,即代表着项目的一个版本历史,多个commit
对象就形成了版本历史链条。
它包含了项目的一些元信息,比如时间戳、自上一次提交后所作更改的作者信息,一个指向上一次提交对象(parent)
的指针
对象示意图
对象关系图
圆形代表commit
对象,commit
对象指向tree
对象,而tree
对象又指向了其他的tree
对象和blob
对象。
多个commit
对象形成了一个有向无环图(DAG)
tag对象
通常用于标记一个特定的项目版本,它指向了一个commit
对象,并且指针不会移动,与commit
对象完全绑定,通过tag
标记对象可以将某个重要版本提取出来作为展示,也可以回退到该版本进行开发。
tag
分为两种:
一种轻量级的对象,只指明当前tag
名称,通过执行git tag "name"
命令,它实际上只生成了一个指针文件,保存在.git/refs/tags目录中。
另一种重量级的tag
对象,可以为当前tag
指定一些说明信息,通过执行git tag -a "name" -m "msg"
命令,它实际上也会生成一个指针文件,同时在objects目录下生成了一个tag
对象,并且tags目录的指针文件指向了该tag
对象
对象 & 引用
GIT对象是不可变的,也就是说它们永远不会被改变,对于文件的修改会以创建新的对象形式体现。
GIT中也包含了一些引用,与对象不同,引用可以不断变化,它们是指向特定commit对象的简单指针,类似tag,但是很容易移动,这些引用包含了Branches
(分支)、HEAD
、Remote branches
(远程分支)
对象与引用关系图
如图remote
和branch
分别代表远程分支引用,本地分支引用,分支引用都指向了一个commit
对象,但是指针可以移动。
HEAD
引用则指向了一个本地分支,tag
引用/对象始终与某个commit
对象绑定,不会移动。
事实上我们可以将一个commit
对象和其引用的tree
、blob
对象看作一个整体,方面从宏观上理解分支,如右图所示。
HEAD引用
使用cat
命令查看HEAD文件的内容,显示引用了refs目录下的一个master文件,refs目录下保存了heads和tags目录,这两个目录都是保存指向数据引用的文件,而文件保存的内容就是一个hash值,该hash值对应的是一个commit
对象
HEAD
代表了当前活动分支的引用,当前工作分支是哪个HEAD
就指向谁,一旦切换分支HEAD
又会移动到新的工作分支,
在我们初始化git仓库时,默认就会有一个master分支,所以HEAD
初始会指向master分支,即refs下的master文件。
使用git checkout -b "name"
命令创建并切换到指定分支后,再次查看HEAD
就指向了新的分支。
演示git对象
一次提交操作
创建一个文件,执行git add
操作和git commit
操作,在此过程中git分别做了什么,创建了哪些对象?
- 新建目录demo,新建readme.txt文件,随便写入一些内容。然后执行
git init
初始化本地仓库。
执行git add
操作,会对文件进行hash取值,将hash值前两个字符作为目录,后38个字符作为文件名,存放在git目录下的objects目录中,该文件仅仅保存文件内容,然后会在git目录下生成一个index文件,该文件就代表了暂存区,通过cat
命令可以看出暂存区保存了文件相关信息比如文件名。
- 执行
git commit
操作,首先会创建一个tree
对象,它指向了刚才创建的blob
对象,然后创建一个commit
对象,用于记录版本历史,它指向了刚才创建的tree
对象,即 commit --> tree --> blob
查看对象内容
blob
保存文件内容,tree
包含了blob对象hash值及文件名、权限等,commit
包含了commit对象和tree对象的hash值及提交作者和提交信息等。
查看blob对象:git show hash值
查看tree对象:git ls-tree hash值
查看commit对象:git show -s --pretty=raw hash值
命令中的hash值不用输入全部,只要能唯一区分就行
多级目录操作
有如下目录结构,根目录 - 2个子目录 - 3个子文件,文件都是有内容的且各不相同
执行git add .
和 git commit -m
操作后,一共生成了7个对象,其中1个commit
对象,3个tree
对象,3个blob
对象
它们的关系图如下