Git 原理初步探索

Git 是一个分布式版本控制系统

  • 本上来讲 Git 是一个寻址 (content-addressable文件系统,并在此之上提供了版本控制系统的用户界面

一,Git 对象

数据对blob object)

先引入几个命令:

  • git init  上层命令,一个目录转一个 Git 仓库
  • git hash-object  底层命令,用于向Git数据库中写入数据
  • git cat-file  底层命令,用于查看Git数据库中数据

1,在 git-learning 目录下执行命令 git init ,查看 .git 目录结构

$ git init
Initialized empty Git repository in D:/tools/git-learning/.git/

$ find .git
.git
.git/config
.git/description
.git/HEAD
.git/hooks
.git/hooks/applypatch-msg.sample
.git/hooks/commit-msg.sample
.git/hooks/fsmonitor-watchman.sample
.git/hooks/post-update.sample
.git/hooks/pre-applypatch.sample
.git/hooks/pre-commit.sample
.git/hooks/pre-merge-commit.sample
.git/hooks/pre-push.sample
.git/hooks/pre-rebase.sample
.git/hooks/pre-receive.sample
.git/hooks/prepare-commit-msg.sample
.git/hooks/update.sample
.git/info
.git/info/exclude
.git/objects
.git/objects/info
.git/objects/pack
.git/refs
.git/refs/heads
.git/refs/tags

  • hooks 客户服务子脚本(hook scripts
  • info 一个global exclude文件 , 用以置那些不希望记录.gitignore 文件中的略模式(ignored patterns
  • config 文件目特有的置选项
  • description 文件GitWeb 使用,我
重点是下面这几个:
  • objects 存储所有数
  • refs 存储向数支、远程仓库和) 的提交
  • HEAD 文件指向目前被检出的
  • index 文件存暂存区信
2,利用底层命令 git hash-object 向 git 数据库中写入一些内容
 
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4
  • git hash-object 接受你传它的东西它只可以存储Git 仓库中的唯一键
  • -w 选项会指该命令不要只,还要该对
  • --stdin 选项该命令 从标准输入定此选项则须在命令存储文件
此命令 出一个 度为 40 字符
这是一个 SHA-1 希值 —— 一个 存储 的数 据外 加一个 息 (header )一起 SHA-1 得的
 
$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
这就是开始时 Git 存储内 容的方式 —— 一个 文件 条内 容, 以该 容加上特定 一起的 SHA-1 文件 命名
校验和 的前 字符 用于命名 下的 38 字符则 用作 文件
 
3,查看数据类型和内容 git cat-file
 
$ git cat-file -t d670460b4b4aece5915caf5c68d12f560a9fe3e4
blob

$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
你将内 存储 在了对 中,那 可以 cat-file 命令 Git 据, -t 查看类型, -p 查看内容
 
4,同样可以这些用于文件中的内容
 
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt
83baae61804e65cc73a7201a7252750c76066a30

$ find .git/objects -type f
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
到此,文件 名并没有 —— 仅保存了文件的内容 。 上 述类型 的对 之为 数据对象(blob object)
 
 

树对象(tree object

  • Git利用树(tree)对象解决了文件名保存的问题,将多个文件组织在一起
  • Git通过树(tree)对象将数据(blob)对象组织起来,这很类似于一种文件系统——blob对象对应文件内容,tree对象对应文件的目录和节点
  • 一个树(tree)对象包含一条或多条记录,每条记录含有一个指向 blob 对象或 tree 对象的SHA-1指针,以及相应的模式、类型、文件名
  • Git根据某一时刻暂存区所表示的状态创建并记录一个对应的树对象,如此重复便可以依次记录一系列的树对象
  • Git的暂存区是一个文件——.git/index

同样,我们引入几个命令:

  • git update-index     底层命令,用于创建暂存区
  • git ls-files --stage   底层命令,用于查看暂存区内容
  • git write-tree           底层命令,用于将暂存区内容写入一个树对象

1,创建暂存区 git update-index

$ find .git/index
find: ‘.git/index’: No such file or directory

$ git update-index --add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

我们注意 .git/index 文件的变化。在添加 test.txt 到暂存区前,index 文件并不存在,这说明暂存区还没有创建。添加 test.txt 到暂存区的同时,index 文件被创建

2,查看暂存区内容 git ls-files --stage

$ git ls-files --stage
100644 83baae61804e65cc73a7201a7252750c76066a30 0       test.txt
  • 100644 文件模式,表明这是一个普通文件。 其选择如100755一个可执行文件
  • 83baae... 向数或者SHA-1
  • 0 这个指的是什么?
  • test.txt 文件名

3,写入树对象 git write-tree

$ git write-tree 83baae61804e65cc73a7201a7252750c76066a30
d8329fc1cc938780ffdd9f94e0d364e0ea74f579

$ find .git/objects -type f
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579

$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
tree

$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30    test.txt
  • 100644 文件模式,表明这是一个普通文件。 其选择如120000一个符号链
  • blob 文件类型
  • 83baae... 向数或者SHA-1
  • test.txt 文件名

在执行 git write-tree 之后,git数据库中多出了一条新的记录,键值为 d8329fc1cc938780ffdd9f94e0d364e0ea74f579

git 数据库中新增加的记录是一个 tree 对象,该 tree 对象指向一个blob对象,hash键值为 83baae61804e65cc73a7201a7252750c76066a30,文件名为 test.txt

至此,在 git 数据库中,我们可以完整的记录文件的状态、文件夹的状态;并且可以把多个文件或文件夹组织在一起,记录他们的变更过程

接下来,我们只要把数据库中各个版本的时序关系记录下来,再把对每一个版本更新的注释记录下来

这就要引入另一个 git 数据对象——提交对象(commit object)

 

提交对象(commit object)

  • commit 对象能够帮你记录什么时间,由什么人,因为什么原因提交了一个新的版本,这个新的版本的父版本又是谁
  • Git 提供了底层命令 commit-tree 来创建提交对象(commit object)
  • 我们需要为这个命令指定一个被提交的树对象的 hash 键值,以及该提交对象的父提交对象(如果是第一次提交,不需要指定父对象)
$ git write-tree
d8329fc1cc938780ffdd9f94e0d364e0ea74f579

$ git commit-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 -m "first commit"
8c14d0e26c4baded3ad6bbf88cb40660bd3544d0

$ git cat-file -t 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
commit

$ git cat-file -p 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author maling <744632504@qq> 1610162941 +0800
committer maling <744632504@qq> 1610162941 +0800

first commit



$ echo "version 2" > test.txt

$ git update-index test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

$ git write-tree
2f39845a4a2c3ad86adebb00b1ddabd959c131c4

$ git commit-tree 2f39845a4a2c3ad86adebb00b1ddabd959c131c4 -p 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0 -m "second commit"
f5a3262459510d25c013e3ffeb3cf83fe60ca416

$ git cat-file -t f5a3262459510d25c013e3ffeb3cf83fe60ca416
commit

$ git cat-file -p f5a3262459510d25c013e3ffeb3cf83fe60ca416
tree 2f39845a4a2c3ad86adebb00b1ddabd959c131c4
parent 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
author maling <744632504@qq> 1610163455 +0800
committer maling <744632504@qq> 1610163455 +0800

second commit

$ find .git/objects/ -type f
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/2f/39845a4a2c3ad86adebb00b1ddabd959c131c4
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/8c/14d0e26c4baded3ad6bbf88cb40660bd3544d0
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
.git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579
.git/objects/f5/a3262459510d25c013e3ffeb3cf83fe60ca416

$ git log f5a3262459510d25c013e3ffeb3cf83fe60ca416
commit f5a3262459510d25c013e3ffeb3cf83fe60ca416
Author: maling <744632504@qq>
Date:   Sat Jan 9 11:37:35 2021 +0800

    second commit

commit 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
Author: maling <744632504@qq>
Date:   Sat Jan 9 11:29:01 2021 +0800

    first commit

小结

1,Git 对象有:blob,tree,commit

blob 如:

$ git cat-file -t 83baae61804e65cc73a7201a7252750c76066a30
blob

$ git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30
version 1

暂存区(index)如:

$ git ls-files --stage
100644 83baae61804e65cc73a7201a7252750c76066a30 0       test.txt

tree 如:

$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579
tree

$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
100644 blob 83baae61804e65cc73a7201a7252750c76066a30    test.txt

commit 如:

$ git cat-file -t 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
commit

$ git cat-file -p 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author maling <744632504@qq> 1610162941 +0800
committer maling <744632504@qq> 1610162941 +0800

first commit


$ git cat-file -t f5a3262459510d25c013e3ffeb3cf83fe60ca416
commit

$ git cat-file -p f5a3262459510d25c013e3ffeb3cf83fe60ca416
tree 2f39845a4a2c3ad86adebb00b1ddabd959c131c4
parent 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
author maling <744632504@qq> 1610163455 +0800
committer maling <744632504@qq> 1610163455 +0800

second commit

2,工作区与暂存区

直观上看,.git 目录外的部分是工作区

.git/index 文件为暂存区

3,目前已经介绍了

  • objects 存储所有数
  • index 文件存暂存区信
 
还有个问题是 SHA-1 值的问题,看某个提交日志的时候(git log),不好准确记住 SHA-1 值,所以介绍下面两个:
 
  • refs 存储向数支、远程仓库和) 的提交
  • HEAD 文件指向目前被检出的

二,Git 引用

  • git update-ref
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f

$ git update-ref refs/heads/master f5a3262459510d25c013e3ffeb3cf83fe60ca416

$ cat .git/refs/heads/master
f5a3262459510d25c013e3ffeb3cf83fe60ca416

HEAD 引用

  • HEAD 为当前支的
$ cat .git/HEAD
ref: refs/heads/master
Git 支的本一个提交
 

标签引用

  • 前面我讨论Git 三种主要的对象类型( 数据对象 blob树对象 tree 提交对象 commit ,然而实上还有第四
  • 标签对象( tag  非常类似于一个提交——它包一个标者信、一个日、一,以 及一个指
  • 主要的区在于,标象通向一个提交不是一个
  • 它像是一个动的分支——远指向同一个提交,只不过这个提交加上一个更的名
$ git update-ref refs/tags/v1.0 f5a3262459510d25c013e3ffeb3cf83fe60ca416

$ cat .git/refs/tags/v1.0
f5a3262459510d25c013e3ffeb3cf83fe60ca416

$ git log v1.0
commit f5a3262459510d25c013e3ffeb3cf83fe60ca416 (HEAD -> master, tag: v1.0)
Author: maling <744632504@qq>
Date:   Sat Jan 9 11:37:35 2021 +0800

    second commit

commit 8c14d0e26c4baded3ad6bbf88cb40660bd3544d0
Author: maling <744632504@qq>
Date:   Sat Jan 9 11:29:01 2021 +0800

    first commit

三,参考资料(推荐电子书 progit

PS:这个工具好用!

$ tree . -al
.
|-- .git
|   |-- HEAD
|   |-- config
|   |-- description
|   |-- hooks
|   |   |-- applypatch-msg.sample
|   |   |-- commit-msg.sample
|   |   |-- fsmonitor-watchman.sample
|   |   |-- post-update.sample
|   |   |-- pre-applypatch.sample
|   |   |-- pre-commit.sample
|   |   |-- pre-merge-commit.sample
|   |   |-- pre-push.sample
|   |   |-- pre-rebase.sample
|   |   |-- pre-receive.sample
|   |   |-- prepare-commit-msg.sample
|   |   `-- update.sample
|   |-- index
|   |-- info
|   |   `-- exclude
|   |-- logs
|   |   |-- HEAD
|   |   `-- refs
|   |       `-- heads
|   |           `-- master
|   |-- objects
|   |   |-- 1f
|   |   |   `-- 7a7a472abf3dd9643fd615f6da379c4acb3e3a
|   |   |-- 2f
|   |   |   `-- 39845a4a2c3ad86adebb00b1ddabd959c131c4
|   |   |-- 4b
|   |   |   `-- 825dc642cb6eb9a060e54bf8d69288fbee4904
|   |   |-- 83
|   |   |   `-- baae61804e65cc73a7201a7252750c76066a30
|   |   |-- 8c
|   |   |   `-- 14d0e26c4baded3ad6bbf88cb40660bd3544d0
|   |   |-- d6
|   |   |   `-- 70460b4b4aece5915caf5c68d12f560a9fe3e4
|   |   |-- d8
|   |   |   `-- 329fc1cc938780ffdd9f94e0d364e0ea74f579
|   |   |-- f5
|   |   |   `-- a3262459510d25c013e3ffeb3cf83fe60ca416
|   |   |-- info
|   |   `-- pack
|   `-- refs
|       |-- heads
|       |   `-- master
|       `-- tags
|           `-- v1.0
`-- test.txt

20 directories, 30 files

windows 系统需要额外工具来执行 tree 命令

https://blog.youkuaiyun.com/qq_36852780/article/details/104447068

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值