• git原理浅析


    1.git概念

    在这里插入图片描述

    我们的项目一般由文件夹和文件组成,在文件系统中,基本都是树形结构, 在git中,文件夹称为 “tree” ,文件称为 “blob” ,顶层文件夹称为 “top-level tree” 。下方的目录结构是个例子而已:

    . (top-level tree)
    ├── humx.txt (blob,内容为“111”)
    └── test (tree)
        └── humx1.txt (blob,内容为“222”)
        └── humx2.txt (blob,内容为“222”)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    整个树形结构我们称为"commit", 在git 系统中, 就是众多commit构成的

    11316@DESKTOP-SMV4E4J MINGW64 /f/idea
    $ mkdir test
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea
    $ cd test
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test
    $ git init
    Initialized empty Git repository in F:/idea/test/.git/
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ cd .git/
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test/.git (GIT_DIR!)
    $ tree
    .
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-commit.sample
    |   |-- pre-push.sample
    |   |-- pre-rebase.sample
    |   |-- pre-receive.sample
    |   |-- prepare-commit-msg.sample
    |   `-- update.sample
    |-- info
    |   `-- exclude
    |-- objects
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        `-- tags
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    .git目录下结构功能:

    • HEAD 文件:指向当前所在分支。
    • config文件:包含了一些git的配置。
    • description文件:只有在GitWeb项目中才会用到,所以不用关注这个文件。
    • hooks文件夹:包含了一些钩子脚本, 触发某些特定事件触发
    • info文件夹:包含了.gitignore 文件中的信息, 忽略某些文件用的
    • objects文件夹:存放object的数据库,存放整个项目的所有数据。
    • refs文件夹:存放了指向objects的指针(如branches,tags,remotes等)

    首先,我们先创建一个文件humx.txt 并写入111的内容,并执行git add ,得出以下:

    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ echo '111' > humx.txt
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ git add .
    warning: LF will be replaced by CRLF in humx.txt.
    The file will have its original line endings in your working directory
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ tree .git/
    .git/
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-commit.sample
    |   |-- pre-push.sample
    |   |-- pre-rebase.sample
    |   |-- pre-receive.sample
    |   |-- prepare-commit-msg.sample
    |   `-- update.sample
    |-- index
    |-- info
    |   `-- exclude
    |-- objects
    |   |-- 58
    |   |   `-- c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        `-- tags
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    可以看到,在objects文件夹下多了一个58文件夹和一个名叫c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c文件,把两者看成一个整体就是一个git object,而且我们将它们的名字拼接起来就能得到一个40位的hashId,这个hashId是这个object的唯一标志符,git通过这个hashId来查找这个object。不过不能直接cat,因为文件是经过压缩的,不能直接阅读。通过 git cat-file命令查看可得到 111 的内容 和blob 的类型。并且多了index文件,这是我们git 的暂存区存放的文件,内容为(mode) (object) (stage) (file).

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ git commit -m"first commit"
    [master (root-commit) a4f7afb] first commit
     1 file changed, 1 insertion(+)
     create mode 100644 humx.txt
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ tree .git/
    .git/
    |-- COMMIT_EDITMSG
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-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
    |   |-- 56
    |   |   `-- 63e48c7b2bc80c2cdc2990d11ba8594a87ba0f
    |   |-- 58
    |   |   `-- c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
    |   |-- a4
    |   |   `-- f7afb5eda5f66b249171a744feebf9a754a7ea
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        |   `-- master
        `-- tags
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    接下来提交文件,我们发现又多了两个object,其中:
    56:(tree)
    在这里插入图片描述
    a4:(commit)
    在这里插入图片描述
    仔细观察,commit指向tree, tree指向blob,可以得出:
    在这里插入图片描述

    然后在创建一个test文件夹,文件夹下新建humx1.txt humx2.txt 内容分别为222 333

    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test/text (master)
    $ echo '222' > humx1.txt
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test/text (master)
    $ echo '333' > humx2.txt
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test/text (master)
    $ cd ..
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ git add .
    warning: LF will be replaced by CRLF in text/humx1.txt.
    The file will have its original line endings in your working directory
    warning: LF will be replaced by CRLF in text/humx2.txt.
    The file will have its original line endings in your working directory
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ git commit -m"second commit"
    [master 8b2580a] second commit
     2 files changed, 2 insertions(+)
     create mode 100644 text/humx1.txt
     create mode 100644 text/humx2.txt
    
    11316@DESKTOP-SMV4E4J MINGW64 /f/idea/test (master)
    $ tree .git/
    .git/
    |-- COMMIT_EDITMSG
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-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
    |   |-- 30
    |   |   `-- ed92ac0fa69377e0f25cb339e1e5676a300c5a
    |   |-- 55
    |   |   `-- bd0ac4c42e46cd751eb7405e12a35e61425550
    |   |-- 56
    |   |   `-- 63e48c7b2bc80c2cdc2990d11ba8594a87ba0f
    |   |-- 58
    |   |   `-- c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
    |   |-- 8b
    |   |   `-- 2580a781611d1e7be39e42ab8bbf88181103bf
    |   |-- a4
    |   |   `-- f7afb5eda5f66b249171a744feebf9a754a7ea
    |   |-- c2
    |   |   `-- 00906efd24ec5e783bee7f23b5d7c941b0c12c
    |   |-- df
    |   |   `-- 15a9f7eb285f1384886435bf4055f12d1bb93a
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        |   `-- master
        `-- tags
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    30:(tree)
    在这里插入图片描述
    55:(blob)
    在这里插入图片描述
    8b:(commit)
    在这里插入图片描述
    c2:(blob)
    在这里插入图片描述
    df:(tree)
    在这里插入图片描述
    我们可以发现:hashId为df的tree是新生成的,是因为根目录下的文件/文件夹列表发生了变化。git并没有直接在56 的tree中直接修改,是因为如果我们需要跳回第一次commit的内容时,直接使用56的tree就可以了,这样就很方便。
    还有值得注意的是:由于humx.txt文件内容未改变,df tree直接引用了58这个object,这样的策略可以为.git目录节省很大的空间,如下图:
    在这里插入图片描述

    2.Reference

    git是通过hashId来查找某个commit的,这对于计算机来说是件非常简单的事,但对于人来说,要记住这么长的hashId,真不是件容易的事。如果能给这些hashId取一些“简单的名字”(比如master、dev、HEAD等),那就非常容易记忆了。在git术语中,这些“简单的名字”被叫做 “reference” 。这些reference主要保存在.git/refs文件夹中

    2.1 Branch
    这里我们新建一个名为test1的仓库,并创建humx3.txt文件,进行commit后,cd 到.git/refs/head路径下,会有一个master文件,直接查看文件可以得到这个commit的hashId,可以直接找到这个提交,下面清楚的标记了这次提交的 tree ,作者信息,并且类型为 commit。git管理的项目原本没有master分支,当我们提交第一个commit后,git会自动给我们创建master分支,并将它指向第一个commit。
    在这里插入图片描述

    .
    |-- COMMIT_EDITMSG
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-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
    |   |-- ce  
    |   |   `-- 013625030ba8dba906f756967f9e9ca394464a
    |   |-- e2
    |   |   `-- 244575c8f723ffb6de45fac2b34391cc1b074d
    |   |-- fb
    |   |   `-- e2b124907eb30c097cec796f60dfb9c18df8ff
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        |   `-- master
        `-- tags
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    ce:
    在这里插入图片描述

    e2:
    在这里插入图片描述

    fb:
    在这里插入图片描述
    在这里插入图片描述
    这里我们修改一下开始文件的内容,追加“world”进去,发现新的提交指向了新的地址,但文件名还是之前的文件名。
    在这里插入图片描述

    .git/
    |-- COMMIT_EDITMSG
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-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
    |   |-- 47
    |   |   `-- 0b84f11fafd7e2a29a54d9cefd9fa199b9f3d3
    |   |-- 94
    |   |   `-- 954abda49de8615a048f8d2e64b5de848e27a1
    |   |-- b7
    |   |   `-- e48a1342abdc6c13ff4c10993625d6a60d836e
    |   |-- ce
    |   |   `-- 013625030ba8dba906f756967f9e9ca394464a
    |   |-- e2
    |   |   `-- 244575c8f723ffb6de45fac2b34391cc1b074d
    |   |-- fb
    |   |   `-- e2b124907eb30c097cec796f60dfb9c18df8ff
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        |   `-- master
        `-- tags
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    47:
    在这里插入图片描述

    94:
    在这里插入图片描述

    b7:
    在这里插入图片描述

    接下来,我们在切换分支,并新增humx4.txt文件写入内容hahaha
    在这里插入图片描述

    .git/
    |-- COMMIT_EDITMSG
    |-- HEAD
    |-- config
    |-- description
    |-- hooks
    |   |-- applypatch-msg.sample
    |   |-- commit-msg.sample
    |   |-- fsmonitor-watchman.sample
    |   |-- post-update.sample
    |   |-- pre-applypatch.sample
    |   |-- pre-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
    |           `-- text
    |-- objects
    |   |-- 44
    |   |   `-- 5a69c00e48288ac420a2ead9ae5a1cb4cd36d4
    |   |-- 47
    |   |   `-- 0b84f11fafd7e2a29a54d9cefd9fa199b9f3d3
    |   |-- 94
    |   |   `-- 954abda49de8615a048f8d2e64b5de848e27a1
    |   |-- b7
    |   |   `-- e48a1342abdc6c13ff4c10993625d6a60d836e
    |   |-- bf
    |   |   `-- 06cff14be1e67be65b50f333cbf1d13270662e
    |   |-- ce
    |   |   `-- 013625030ba8dba906f756967f9e9ca394464a
    |   |-- dc
    |   |   `-- 55dcba685e66992a5379e393a4fb2de1738d92
    |   |-- e2
    |   |   `-- 244575c8f723ffb6de45fac2b34391cc1b074d
    |   |-- fb
    |   |   `-- e2b124907eb30c097cec796f60dfb9c18df8ff
    |   |-- info
    |   `-- pack
    `-- refs
        |-- heads
        |   |-- master
        |   `-- text
        `-- tags
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    44:
    在这里插入图片描述
    bf:
    在这里插入图片描述
    dc:
    在这里插入图片描述
    在这里插入图片描述

    HEAD文件保存着当前所在分支的路径,git通过这个路径访问到对应分支文件,然后通过这个分支文件保存的hashId就能获取到对应commit,这样git就能构建出当前commit对应的目录结构,如图:
    在这里插入图片描述

    3.总结

    • objects文件夹是git最重要的数据库,所有的文件内容,及各个版本的内容,都保存在objects文件夹中。
    • objects文件夹中主要保存三类object:commit、tree、blob,它们都由一个文件夹和文件组成,文件夹和文件的名字拼接成40位的hashId,这个hashId就是这个object的唯一标识符,git通过这个hashId来查找某个object。另外,这些文件都是经过压缩的,不能直接供人阅读,需要通过git cat-file指令查看。
    • 每一个commit都对应一个top-level tree,以top-level tree为根节点,可以构造出当前版本的目录结构,通过访问blob类的object,就能读取到对应文件的具体内容。另外,多个版本之间的文件如果是完全相同的,git只会生成一个blob对象,多个版本引用同一个blob对象,这可以大大节省磁盘空间。
    • referrence都是基于commit来实现的。
  • 相关阅读:
    安全认证框架Shiro入门学习(shiro概述和shiro入门小案例);后续整合SpringBoot,应用程序安全;
    Session会话追踪的实现机制
    基于matlab的神经网络设计,深度神经网络代码matlab
    SSH连接MobaXterm
    从react源码看hooks的原理
    【蜂鸟E203内核解析】Chap.3 自定义指令与协处理器设计
    CSS:line-height是什么?,height是什么?
    学习C++语言可以适用于哪些方面
    14SpringMVC中的默认的异常解析器,以及如何基于XML和注解的方式配置自定义异常解析器
    【区块链 | 多签】知识普及:什么是多重签名钱包?
  • 原文地址:https://blog.csdn.net/qq_44778109/article/details/128178741