美文网首页
深入理解 Git: Git 第1版 源码 分析 (概述)

深入理解 Git: Git 第1版 源码 分析 (概述)

作者: my_passion | 来源:发表于2021-11-19 23:29 被阅读0次
    脑图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?
    

    相关文章

      网友评论

          本文标题:深入理解 Git: Git 第1版 源码 分析 (概述)

          本文链接:https://www.haomeiwen.com/subject/elfstrtx.html