git核心

分支概念

  1. 版本控制系统中,都有一个概念,叫做分支,就是同样的一份儿代码,可以拉取多个分支,每个分支的代码刚开始都是一样的,然后不同的人可以基于不同的分支去开发,然后开发完之后,再将多个分支的代码合并在一起

  2. git里面,每次git init之后,默认初始就创建一个分支,叫做master分支,我们每次写代码,然后git commit提交,都会形成一次新的commit,然后默认就是在master分支对应的代码拷贝上,进行代码修改和提交的

    .git文件夹

  3. 这个文件夹一般会在git初始化的时候创建出来,后续所有版本管理相关的数据都会存在这个文件夹里面 | 文件/文件夹 | 作用 | | —- | —- | | config | 文本文件,保存当前项目特有的配置项,通过git config —local进行配置 | | HEAD | 文本文件,指针,指向当前正在工作的分支 | | description | 文本文件,描述当前仓库的一些信息,只有GitWeb会用到该文件 | | refs | 文件夹,里面包含所有分支以及tag指向的commit信息 | | hooks | 文件夹,包含有在执行一些 Git 命令后,git 命令调用的脚本 | | info | 文件夹,存储有一些该仓库中记录的其他信息。例如,exclude 文件中要存储 需要被排除在外的文件名,类似于 .gitignore 文件,和gitignore 不同的是exclude并不会把自己也提交到git仓库中 | | objects | 文件夹,git commit建立的所有的commit和文件快照信息都会保存在这里 |

核心对象

  1. git有几个最核心的对象,git所谓的版本控制实际就是增删改查这几个核心的对象 | 对象名 | 作用 | | —- | —- | | blob | 存储真正的文件内容,比如我们的文本文件/图片等都会生成一个blob对象 | | tree | 存储目录结构和文件名(即blob的SHA1哈希值) | | commit | 存储提交的说明,比如提交作者/作者的邮箱/提交的时间等等,还有一个parent指针来指向上一个commit,最后还会指向一个tree构成我们的提交图谱 | | tag | 存储带注释的标签(tag) |

Object/References/Index

实体

  1. 实体就是我们上面的核心对象,仓库中的所有文件都会保存在.git/objects下面存储为实体

  2. 每一个实体以一个SHA1哈希值作为标识

引用

  1. 引用可以简单粗暴的理解为分支,不管是本地分支还是远程分支 亦是某一个tag都是一个引用

  2. 引用即字面意思 最终都会指向一个地方,git中的引用最终都会指向一个commit实体

  3. 引用是以文本文件的形式存储在.git/refs下面

索引

  1. 索引也就是我们常说的暂存区,以二进制文件的形式存储在.git/index下面

  2. git add 的时候先会把该文件的信息存储到索引中,git commit的时候仅提交索引文件中列出的文件

三者的关系

  1. 三者的关系如下图所示

image.png

举例说明

初始化新的代码仓库

  1. 重新初始化一个仓库

    1. [root@ipa ~]# git init git-test

    image.png
    image.png

  2. 可以看到初始化了.git目录,HEAD目前指向refs/heads/master

    添加新文件

  3. 添加一个新文件,此时可以看到.git/objects文件夹里多个一个目录和文件即blob实体,并且也创建出了index文件

    [root@ipa git-test]# echo "Hello Git" >> README
    [root@ipa git-test]# git add README
    

    image.png
    image.png

  4. 顺便说一下,objects中生成的对象的名称是以SHA1哈希值前两位做目录名 后38位做文件名,如图片所示我们在objects目录里生成了一个子目录(9f)和文件(4d96d5b00d98959ea9960f069585ce42b1349a),那么这个对象的SHA1哈希值就为9f4d96d5b00d98959ea9960f069585ce42b1349a

  5. 同时我们也可以使用命令进行类型的查看和内容的查看 ```shell

    查看某个对象的类型,SHA1哈希值可以只取前几位,能够唯一标识即可

    git cat-file -t 9f4d96d

查看某个对象的内容

git cat-file -p 9f4d96d

![image.png](https://cdn.nlark.com/yuque/0/2022/png/2463114/1641015581646-36eac51b-a51e-40b3-8e7a-f491c0c1d358.png#clientId=u1be09c11-f8b0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=162&id=ud3065309&margin=%5Bobject%20Object%5D&name=image.png&originHeight=162&originWidth=2539&originalType=binary&ratio=1&rotation=0&showTitle=false&size=14211&status=done&style=none&taskId=ufcb55222-8cf8-472d-9ee1-1f81c82c721&title=&width=2539)


<a name="jhBEE"></a>
### 首次提交

1. 将README文件从暂存区提交至本地git仓库,可以看到创建了master引用以及多了两个实体对象
```shell
[root@ipa git-test]# git commit -m 'first commit'

image.png

  1. 按照前面的理论支持,我们可以猜到.git/refs/heads/master指向的是一个commit,可以看到下面输出的内容 commit对象实际上就是一个tree + 一些提交信息 ```shell

    查看master引用的内容是一个SHA1哈希值

    [root@ipa .git]# cat refs/heads/master 994f5181ddc4fdb5ed78f96fe58af0bac99249aa

查看该SHA1哈希值的类型是一个commit

[root@ipa .git]# git cat-file -t 994f5181 commit

查看该commit对象的内容

[root@ipa .git]# git cat-file -p 994f5181 tree 53d7660eebaafbee73095cd4cef68455d47fdb21 author tianbo tianbo1@yonghui.cn 1641015725 +0800 committer tianbo tianbo1@yonghui.cn 1641015725 +0800

first commit


3. 那么commit对象里面的tree又是什么呢?其实commit 里面的tree就是指向了我们的README文件的blob对象
```shell
[root@ipa .git]# git cat-file -t 53d7660e
tree

[root@ipa .git]# git cat-file -p 53d7660e
100644 blob 9f4d96d5b00d98959ea9960f069585ce42b1349a    README

image.png

修改一个文件

  1. 我们再把README文件修改一下,可以看到有新建了一个blob对象 并且index中也加入了这个对象 ```shell [root@ipa git-test]# echo “Hello BO.TIAN” >> README [root@ipa git-test]# git add README

查看下index文件中的内容

[root@ipa .git]# git ls-files —stage 100644 dd9178f85072dc73841d8de98167859065df25d7 0 README

查看下新加入对象的类型以及内容

[root@ipa .git]# git cat-file -t dd9178f8 blob

[root@ipa .git]# git cat-file -p dd9178f8 Hello Git Hello BO.TIAN

![image.png](https://cdn.nlark.com/yuque/0/2022/png/2463114/1641016758116-3bc7cf45-f5ef-42f8-92f7-23282167393c.png#clientId=u1be09c11-f8b0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=774&id=ub649f902&margin=%5Bobject%20Object%5D&name=image.png&originHeight=774&originWidth=2539&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42673&status=done&style=none&taskId=u38c1045a-8a18-404d-925d-36a186e9eb7&title=&width=2539)<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/2463114/1641016902884-6ed8b516-0a92-4ab8-8c36-e3e4e2f52a91.png#clientId=u1be09c11-f8b0-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=617&id=u192b9d11&margin=%5Bobject%20Object%5D&name=image.png&originHeight=617&originWidth=1062&originalType=binary&ratio=1&rotation=0&showTitle=false&size=23539&status=done&style=none&taskId=u7ce3f3f8-5dea-4b05-8ce4-a2c83be5244&title=&width=1062)
<a name="JDXq5"></a>
### 向子目录添加文件

1. 我们在创建一个子目录,并且在子目录中创建一个文件,此时就会更新index并且创建一个blob对象(4bf92f2)
```shell
# 创建相关文件
[root@ipa git-test]# mkdir src
[root@ipa git-test]# echo "CODEING..." >> src/code.txt
[root@ipa git-test]# git add .

# 查看下index文件中的内容
[root@ipa .git]# git ls-files --stage
100644 dd9178f85072dc73841d8de98167859065df25d7 0    README
100644 4bf92f2e900cb67b5a76ee0c02c6a9e01c706a76 0    src/code.txt

image.png

第二次提交

  1. 上面我们修改了README文件并且增加了一个文件夹src,在src文件夹里加入了code.txt文件,并且都加入暂存区

image.png

  1. 我们现在来进行第二次提交 ```shell [root@ipa git-test]# git commit -m ‘second commit’

查看master引用指向

[root@ipa .git]# cat refs/heads/master fd49b9fe6e8ec6f9ff3b8ea4d587d904c843f180

查看该实体的类型

[root@ipa .git]# git cat-file -t fd49b9 commit

查看commit实体的内容

[root@ipa .git]# git cat-file -p fd49b9

tree 97dd67d23a116a61f563096bc49c41d4b378d3cd parent 994f5181ddc4fdb5ed78f96fe58af0bac99249aa author tianbo tianbo1@yonghui.cn 1641017543 +0800 committer tianbo tianbo1@yonghui.cn 1641017543 +0800

查看该commit指向的tree

[root@ipa .git]# git cat-file -t 97dd67d tree

[root@ipa .git]# git cat-file -p 97dd67d 100644 blob dd9178f85072dc73841d8de98167859065df25d7 README 040000 tree 3f3ddf46810d1da2a635060ac0a0ace231675251 src

查看src tree

[root@ipa .git]# git cat-file -p 3f3ddf 100644 blob 4bf92f2e900cb67b5a76ee0c02c6a9e01c706a76 code.txt

``` image.png