脑图1: README
GIT: 内容追踪器
1.1 content
/ -> + head: object type tag + content size + content = original object
| -> zlib 压缩 (deflated) = _compressed_ object
-> SHA-1 = 2 + 38 个 hex
| -> object name
|—— 1.2 object 可 指向 其他 object
-> 解引用 其 SHA-1
-> 可构建 `objects 体系(hierarchy)`
1. object database |
按 content 寻址
/ | object 的 SHA-1(即 path) 与 object content 的 SHA-1 匹配
| /
|—— 1.3 object 一致性检验
| \
| object -> 解压 ( inflates) -> bytes 流 <ascii tag without space> + <space> + <ascii decimal size> + <byte\0> + <binary object data>
|
| blob
| \ /
1.4 3种 object- tree: 按 filename+content 排序 => 2 个 tree 比较, O(n) n 是 diff 的 大小, 而非 tree 的 大小
| \
changeset / commit
Git |
2.1 按 name 排序
| /
| 2.2 随时 可被 update
|
\ 2. current directory cache |
即 .dircache/index
| 可 re-generate 其所 cache 的 full state: current directory cache -> 唯一 tree object
\ /
2.3 2个 属性
\
可 快速 找出 cached state 与 current state 的 diff
脑图2: 软件系统 & Git
设计思想 (第1版设计: 开山鼻祖)
/
/
软件
/ \
| 代码质量 (后续 迭代&维护: 锦上添花)
软件系统 & Git |
核心思想: 分布式, 3 种 object, 3个区
| /
/
| 第1版
\ 1) `异常处理` 不好, 常出现 `SegmentFault`
| / \ /
/ 代码质量 |— 2) `内存泄漏`: 如 write-tree.c -> main -> buffer
| / \
\ / 3) `读 index` 中 `变更文件信息` 用 `array` 存储 -> 较多 申请释放操作 -> 优化: `链表` 存储
Git
\
\
杀手锏: 分支策略 / 远程仓库 / 日志系统 / git hooks 是后续 逐步迭代出来的
脑图3: Git 第1版 设计思想
工作区 / workspace / working directory
/
/
1. 3个区 —— 暂存区 / index / staging area
/ \
/ \
| 版本库 / commit history / local repo
已提交 data
|
blob object
| / `文件 snapshot (快照)`
/
| 2.1 3 种 —— tree object
/ \ `目录结构` + `blob object 索引`
| | \
设计思想 commit object
| | `所在 tree commit` + `parent commit 指针` + `提交信息`
|—— 2. object |—— 2.2 `存储目录` 默认为 .dircache/objects (最新版 git 中 是 .git/objects), 也可用 环境变量 SHA1_FILE_DIRECTORY 指定
.dircache/objects 目录结构 查询: linux 命令 $ tree .dircache/objects
| \
2.3 sha1 值 9a860ccaa5f7d7e207e932ce2d4d1c72489ea83e = 前 2个 hex 值 是 目录 / 其余为 name
| => object path: .dircache/objects/9a/860ccaa5f7d7e207e932ce2d4d1c72489ea83e
|—— 3. 哈希算法: Git 用 `OpenSSL 库` 中 `sha1 算法`
| staging area
\ /
\ / (1) 32Byte head
4. .dircache/index (二进制)文件 /
\ / 32Byte
\ / /
结构 —— (2) 文件1信息 64Byte |—— 8Byte
\ |—— 20Byte(40hex): sha-1
\ |—— 2Byte : namelen
\ \ 不定长 : name
\ hexdump -C 的 print 右侧能看出 相应 name (相应 file_name)
\
(3) 文件2信息 64Byte + ...
脑图4: Git 第 1版 7 个底层 可行性文件
可执行文件 git 命令 说明
init-db git init . 初始化仓库
update-cache git update-index --add ... 添加 文件 或 目录
show-diff git diff 查 diff 内容
cat-file git cat-file -t 读 object 文件
read-tree git cat-file -p 读 tree
write-tree git write-tree 写到 tree
commit-tree git commit -tree [-p] 提交 tree
脑图5: Git 第 1版涉及 Linux 命令
1. cat ./< original object 文件名 > => 查 original object 的 content
/
|—— 2. 查看目录结构
$ tree -h
| $ tree . -a
linux 命令 |—— 3. Ubuntu 下 怎么 `显示隐藏文件 (夹)`
Ctrl+H
| 4. 查 二进制 文件 内容
hexdump
| hexdump -C .dircache/index
\
5. echo 将 file content(如 commit 的 comment)写入 file
$ echo "second commit" > changelog
脑图6: Git 第1版源码 框架: 底层7条命令 & 机制
1. $ ./init-db 1.1 功能
/ 初始化仓库
|
1.2 实现
| 创建目录
.dircache // Git 工作目录, 最新为.git/
| objects
00 ~ ff // 256个目录
| 1.3 调用
$ init-db
|
|—— 2. $ ./update-cache <file> ... 2.1 功能
提交 `工作区` 修改文件 到 `暂存区`
|
2.2 实现
| 遍历
(1) `变更 文件` -> 压缩 -> blob object -> sha1
|
(2) ctime mtime dev info mode uid gid size sha-1
| 构成 `变更 文件信息`
-> 写入 index 文件: .dircache/index
|
初始化 repo 时, 自动创建 index 文件
|
2.3 调用
| (1) 新增 文件 README.md + 文件夹及文件
$ echo "hello git" > README.md
| $ echo "folder1 file1" > folder1/file.c
| (2) 提交 到 staging area
$ ./update-cache README.md
|
(3) ubuntu 下 显示隐藏文件 index
| Ctrl+H
| (4) 查看 二进制文件 index
$ hexdump -C .dircache/index
|
|—— 3. $ ./cat-file <sha1> 3.1 功能:
据 sha1 -> object 的 有效 content -> 写到 临时文件 temp_***
| -> print <临时文件名>: <object type>
| 3.2 实现
sha1 -> object 文件 -> 解压
| -> original object = object type tag + content size + content
-> 解析 content -> 写到 临时文件 temp_*** -> print tempFileName
| -> 解析 object type -> print
| 3.3 调用
(1)cat-file <sha1>
| $ ./cat-file <sha1>
temp_git_file_***: blob
|
(2) 查 tempFile 内容
| $ cat ./temp_git_file_***
hello git!
Git 底层命令 |
|—— 4. show-diff 4.1 功能
查 `工作区` 和 `暂存区` 中 `文件差异`
|
4.2 实现
| 循环遍历
`变更 文件信息`
| -> 与 `index 文件` 中相应 `文件信息`
-> 有差异
| -> 输出 file content diff
| 先比 file info (=> fast) -> 有差异 -> 才比 file content => fast
| 4.3 调用
(1) 改 README.md
| $ echo "hello" > README.md
| (2) 查 diff
$ ./show-diff
|
|—— 5. write-tree 5.1 功能
解析 index 文件, 生成 tree object
|
5.2 实现
| index 文件 -> 提取 各变更文件/目录 (即 blob / tree object ) info 中的 mode/name/sha-1 -> tree original object -> 压缩 -> tree object
| 5.3 调用
(1)
| $ write-tree
treeSha1
|
(2)
| $ cat-file <treeSha1>
tempFile
|
(3)
| $ cat ./<tempFile>
tree object 有效 content
|—— 6. read-tree <treeSha1> 6.1 功能
解析 tree object, 输出 tree object 所含 blob/tree object 的 mode + name (即 path) + sha1
|
6.2 实现
| treeSha1 -> tree object -> 解压 -> 所含 blob/tree object 的 mode+name+sha-1
| 6.3 调用
(1)
| $ write-tree
treeSha1
|
(2)
| $ read-tree <treeSha1>
tree 有效 content
|
\
7. commit-tree <treeSha1> < changelog 7.1 功能
基于 tree sha1, 生成 commit object
7.2 实现
建 array -> 写入 tree:<tree_sha1> + 获取 & 写入 parent:<parent_sha1> + author/commiter 信息 + comment
-> 填 head -> 压缩 -> commit object
7.3 调用 $ commit-tree <sha1> [-p <sha1>]* < changelog
(1) write-tree
$ write-tree
treeSha1
(2) first commit-tree
$ echo "first commit" > changelog
$ commit-tree <treeSha1> < changelog
commitSha1/commitId
$ cat-file <cmmoitSha1>
tempFileName
$ cat <tempFileName>
commit object 有效 content
(3) 更改 README.md
$ echo "hello second commit" > README.md
(4) 提交 到 staging area
$ ./update-cache README.md
(5) write-tree
$ write-tree
treeSha1
(6) second commit-tree
$ echo "second commit" > changelog
$ commit-tree <treeSha1> < changelog
commitSha1/commitId
Git 底层命令关系.png
blob object.png
tree object.png
commit object.png
index 文件.png
1 获取 git 源码
Git 第1版 源码 仅约 1000 行
Git 是世界上使用最广泛的 VCS
https://github.com/git/git.git
从自己的 gitee 账户导入, 再从 gitee 仓库 clone
# clone git 源码
$ git clone git@gitee.com:liyu_mypassion/git_first_ver.git
# 查看 第1个提交
$ git log --date-order --reverse
commit e83c5163316f89bfbde7d9ab23ca2e25604af290
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date: Thu Apr 7 15:13:13 2005 -0700
Initial revision of "git", the information manager from hell
# 变为第1个提交, 用 commit-id
$ git reset --hard e83c5163316f89bfbde7d9ab23ca2e25604af290
2 文件结构
image.png手动删 隐藏文件夹 .git
image.png
# linux 下
$ tree -h
.
├── [2.4K] cache.h
├── [ 503] cat-file.c
├── [4.0K] commit-tree.c
├── [1.2K] init-db.c
├── [ 957] Makefile
├── [5.5K] read-cache.c
├── [8.2K] README
├── [ 986] read-tree.c
├── [2.0K] show-diff.c
├── [5.3K] update-cache.c
└── [1.4K] write-tree.c
0 directories, 11 files
# 统计 代码行数: 共 1076
$ find . "(" -name "*.c" -or -name "*.h" -or -name "Makefile" ")" -print | xargs wc -l
23 ./cat-file.c
51 ./init-db.c
248 ./update-cache.c
43 ./read-tree.c
66 ./write-tree.c
93 ./cache.h
81 ./show-diff.c
40 ./Makefile
172 ./commit-tree.c
259 ./read-cache.c
1076 total
3 编译
#1 直接编译, 找不到 <openssl/sha.h>
$ make
gcc -g -c -o update-cache.o update-cache.c
In file included from update-cache.c:1:
cache.h:13:10: fatal error: openssl/sha.h: No such file or directory
13 | #include <openssl/sha.h>
| ^~~~~~~~~~~~~~~
compilation terminated.
make: *** [<builtin>: update-cache.o] Error 1
#2 安装ssl开发库, ubuntu下
sudo apt-get install libssl-dev -y
$ make
gcc -g -c -o update-cache.o update-cache.c
In file included from update-cache.c:1:
cache.h:14:10: fatal error: zlib.h: No such file or directory
14 | #include <zlib.h>
| ^~~~~~~~
compilation terminated.
make: *** [<builtin>: update-cache.o] Error 1
#3 安装 zlib
apt-get install zlib1g-dev
#4 修改 Makefile,生成 可执行文件
LIBS=-lssl
改为
LIBS=-lcrypto -lz
#5 make
编译生成 `7 个 可执行文件`
见 脑图 4
image.png
4 Git 第1版 设计思想
Write programs to work together.
—— Unix philosophy
Git 是 `分布式`: 每个 developer `本地工作区` 都是 `完整 的 版本库`
见脑图 3
image.png
// .dircache/objects 目录结构:
$ tree .dircache/objects
.dircache/objects
├── 5d # tree
│ └── 323ceef3152979ef4b50bf20e4a72468b7abee
├── 82 # blob (README.md 第 1 次 提交到 暂存区)
│ └── f8604c3652fa5762899b5ff73eb37bef2da795
├── 9a # commit
│ └── 860ccaa5f7d7e207e932ce2d4d1c72489ea83e
├── d1 # blob (README.md 第 2 次 提交到 暂存区)
│ └── 411423ff8cd2481a52ee2a96a999bf676d6242
5 Git 第1版 源码分析(框架): 底层7条命令 & 机制
Write programs that do one thing and do it well.
——Unix philosophy
1. init-db
$ ./init-db
image.png
# 查看初始化后的目录结构
$ tree . -a
.
├── cache.h
├── cat-file
├── cat-file.c
├── cat-file.o
├── commit-tree
├── commit-tree.c
├── commit-tree.o
├── .dircache # git 工作目录
│ └── objects # objects 文件 目录
│ ├── 00
│ ├── 01
│ ├── 02
│ ├── 03
...
│ └── ff
├── init-db
├── init-db.c
├── init-db.o
├── Makefile
├── read-cache.c
├── read-cache.o
├── README
├── read-tree
├── read-tree.c
├── read-tree.o
├── show-diff
├── show-diff.c
├── show-diff.o
├── update-cache
├── update-cache.c
├── update-cache.o
├── write-tree
├── write-tree.c
└── write-tree.o
258 directories, 26 files
2. update-cache
$ ./update-cache <file> ...
# (1) 新增 README.md 文件
$ echo "hello git" > README.md
# (2) 提交
$ ./update-cache README.md
(3) Ubuntu 下 怎么 `显示隐藏文件 (夹)`
Ctrl+H
image.png
image.png
#(4) 查看 index 文件
$ hexdump -C .dircache/index
00000000 43 52 49 44 01 00 00 00 01 00 00 00 60 31 dd b9 |CRID........`1..|
00000010 04 4d a6 8d 23 46 14 37 74 d5 97 0a b7 7a ac b4 |.M..#F.7t....z..|
00000020 41 ce f3 60 4c 83 df 35 41 ce f3 60 4c 83 df 35 |A..`L..5A..`L..5|
00000030 05 08 00 00 38 0e 12 00 b4 81 00 00 e8 03 00 00 |....8...........|
00000040 e8 03 00 00 0b 00 00 00 82 f8 60 4c 36 52 fa 57 |..........`L6R.W|
00000050 62 89 9b 5f f7 3e b3 7b ef 2d a7 95 09 00 52 45 |b.._.>.{.-....RE|
00000060 41 44 4d 45 2e 6d 64 00 |ADME.md.|
00000068
// => 变更文件 README.md 的 sha1 值
82f8604c3652fa5762899b5ff73eb37bef2da795
3. cat-file
$ ./cat-file <sha1>
// (1)
$ ./cat-file 82f8604c3652fa5762899b5ff73eb37bef2da795
temp_git_file_1ZeoRy: blob
// (2) 查看 temp_git_file_1ZeoRy 文件内容
$ cat ./temp_git_file_tBTXFM
hello git!
image.png
4. show-diff
$ show-diff
# (1) 当前无差异
$ ./show-diff
README.md: ok
# (2) 更改 README.md
$ echo "hello" > README.md
# (3) 查看 diff
$ ./show-diff
README.md: 82f8604c3652fa5762899b5ff73eb37bef2da795
--- - 2021-07-18 15:22:01.449806765 +0800
+++ README.md 2021-07-18 15:21:51.971496739 +0800
@@ -1 +1 @@
-hello git!
+hello
// 1)
$ ./update-cache README.md
// 2)
$ hexdump -C .dircache/index
00000000 43 52 49 44 01 00 00 00 01 00 00 00 1a 5c d0 b9 |CRID.........\..|
00000010 88 c3 53 b8 c0 7a a2 71 3f 02 b2 54 f4 e4 a1 0e |..S..z.q?..T....|
00000020 8f d6 f3 60 23 dd e7 39 8f d6 f3 60 23 dd e7 39 |...`#..9...`#..9|
00000030 05 08 00 00 38 0e 12 00 b4 81 00 00 e8 03 00 00 |....8...........|
00000040 e8 03 00 00 06 00 00 00 d1 41 14 23 ff 8c d2 48 |.........A.#...H|
00000050 1a 52 ee 2a 96 a9 99 bf 67 6d 62 42 09 00 52 45 |.R.*....gmbB..RE|
00000060 41 44 4d 45 2e 6d 64 00 |ADME.md.|
00000068
// 3)
$ ./cat-file d1411423ff8cd2481a52ee2a96a999bf676d6242
temp_git_file_q8qN7c: blob
// 4)
$ cat ./temp_git_file_q8qN7c
hello
image.png
前面 提交 到 暂存区 的 `变更文件 / objects 文件 / blob 对象` 仍保存在 原objects 目录下
image.png
5. write-tree
$ ./write-tree
# (1) 提交
$ ./write-tree
5d323ceef3152979ef4b50bf20e4a72468b7abee
# (2) 查看 `objects 文件 内容`
$ ./cat-file 5d323ceef3152979ef4b50bf20e4a72468b7abee
temp_git_file_oUiQV2: tree
$ cat ./temp_git_file_oUiQV2
100664 README.md�A#���H�R�*����gmbB
6. read-tree
$ ./read-tree <sha1>
# 读 tree object
$ ./read-tree 5d323ceef3152979ef4b50bf20e4a72468b7abee
100664 README.md (d1411423ff8cd2481a52ee2a96a999bf676d6242)
7. commit-tree
$ commit-tree <sha1> [-p <sha1>]* < changelog
$ echo "first commit" > changelog
$ ./commit-tree 5d323ceef3152979ef4b50bf20e4a72468b7abee < changelog
Committing initial tree 5d323ceef3152979ef4b50bf20e4a72468b7abee
9a860ccaa5f7d7e207e932ce2d4d1c72489ea83e
# 查看 commit obj 内容
$ ./cat-file 9a860ccaa5f7d7e207e932ce2d4d1c72489ea83e
temp_git_file_hHQULA: commit
$ cat ./temp_git_file_hHQULA
tree 5d323ceef3152979ef4b50bf20e4a72468b7abee
author mypassion2,,, <mypassion2@mypassion2-virtual-machine> Sun Jul 18 15:57:30 2021
committer mypassion2,,, <mypassion2@mypassion2-virtual-machine> Sun Jul 18 15:57:30 2021
first commit
image.png
禁止转载 或 用于其他用途
参考文章
https://developer.aliyun.com/article/772825?
网友评论