zoukankan      html  css  js  c++  java
  • 一文了解git底层原理

    一、git相关区域

    工作区(Working Directory): 工作区是平时编写文本文件的地方

    暂存区(Stage/Index): 暂存区是提交文本文件到本地仓库的来源地,只有把工作区的文件添加至暂存区,才可以被提交至本地仓库。 (git add)

    本地仓库(Repository): 本地仓库是保存每次文件更新的记录,包括提交人,提交时间,提交的内容等详细信息,方便追溯历史版本。(git commit)

    远程仓库(Remote Repository):远程仓库算是本地仓库的一个副本,主要是方便合作伙伴之间的仓库文件同步。

    二、git各类对象

    blob:

         blob对象只跟文本文件的内容有关,和文本文件的名称及目录无关,只要是相同的文本文件,会指向同一个blob。

    tree:

         tree对象记录文本文件内容和名称、目录等信息,每次提交都会生成一个顶层tree对象,它可以指向其引用的tree或blob。

    commit:

         commit对象记录本次提交的所有信息,包括提交人、提交时间,本次提交包含的tree及blob。

    tag:

         标签引用,它指向某一个commit。

    三、验证git中三大对象commit、tree和blog之间的关系

    1. 本地初始化一个git仓库

    $ git init gittest

    执行后 ls -a 可查看到.git目录。

    2. 在.git同级目录下创建doc/readme.txt文件,内容为 hello world 

       执行 ls -a 查看到文件已新增

    $ ls -a
    .git doc/readme.txt

    3. 在还没有进行add的前提下,使用命令 git status 查看当前仓库的状态,可以看到创建的文件夹和文件还没有添加到暂存区,所以接着使用命令:find .git/objects -type f 看不到有什么结果。

    $ git status
    On branch master
    
    No commits yet
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
    
        doc/

    $ find .git/objects -type f

    4. git add 后,使用上述命令结果如下:

    $ git status 
    On branch master
    
    No commits yet
    
    Changes to be committed:
      (use "git rm --cached <file>..." to unstage)
    
        new file:   doc/readme.txt
    
    $ find .git
    /objects -type f .git/objects/3b/18e512dba79e4c8300dd

    $ git cat-file -t 3b18e512dba79e4c8300
    blob

    $
    git cat-file -p 3b18e512dba79e4c8300
    hello world
     

    使用 git cat-file -t ID号  查看object的类型,由上可知该object为blog,说明新的东西加入到暂存区,git会主动把暂存区的东西创建为blog。使用命令:git cat-file -p ID号  查看该blog的内容,可以得到内容就是readme中的内容。

    5. 执行如下命令commit该新增文件

    $ git commit -m "add readme"
    
    

    再通过 find .git/objects -type f 可查看到四个object对象

    $ find .git/objects -type f
    .git/objects/3b/18e512dba79e4c8300dd
    .git/objects/e7/a75e980c7adc0d5ab1c4
    .git/objects/2e/9e6cd9fef232a6f0ecab
    .git/objects/7a/802cad5138b242c5ee6b
    
    $ git cat-file -t 3b18e512dba79e4c8300
    blob
    
    $ git cat-file -p 3b18e512dba79e4c8300
    hello world
    
    $ git cat-file -t e7a75e980c7adc0d5ab1
    tree
    
    $ git cat-file -p e7a75e980c7adc0d5ab1
    100644 blob 3b18e512dba79e4c8300dd    readme.txt
    
    $ git cat-file -t 2e9e6cd9fef232a6f0ec
    tree
    
    $ git cat-file -p 2e9e6cd9fef232a6f0ec
    040000 tree e7a75e980c7adc0d5ab1    doc
    
    $ git cat-file -t 7a802cad5138b242c5ee
    commit
    
    $ git cat-file -p 7a802cad5138b242c5ee
    tree 2e9e6cd9fef232a6f0ecab
    author test <test@gmail.com> 1591054691 +0800
    committer test <test@gmail.com> 1591054691 +0800

    由上可以得出,一个commit里面含有一个tree(这次commit时期包含的文件内容)。一个tree下面确实包含有tree和blog。 

    进入到某一具体的blog进行查看,验证是否一个blog代表一个文件内容(进入到具体的blog下,有的blog能直接解析打开,如html,txt等,有的不能,如图片等)。如下可以直接看到该blog所对应的readme.txt的文件内容。

    6. 在.git 同级目录下新建second.txt文件,commit后得到3个新object如下:

    $ git commit -m "second commit"
    [master b0da7df] second commit
     1 file changed, 1 insertion(+)
     create mode 100644 second.txt
    
    $ find .git/objects -type f
    .git/objects/0c/e52f0e38439ed9833307
    .git/objects/3b/18e512dba79e4c8300dd
    .git/objects/b0/da7dfb5c1f09e5c0b618
    .git/objects/e7/a75e980c7adc0d5ab1c4
    .git/objects/e0/19be006cf33489e2d017
    .git/objects/2e/9e6cd9fef232a6f0ecab
    .git/objects/7a/802cad5138b242c5ee6b
    
    $ git cat-file -t 0ce52f0e38439ed983330d7
    tree
    
    $ git cat-file -p 0ce52f0e38439ed983330d7
    040000 tree e7a75e980c7adc0d5ab1    doc
    100644 blob e019be006cf33489e2d0    second.txt
    
    $ git cat-file -t b0da7dfb5c1f09e5c0b618 
    commit
    
    $ git cat-file -p b0da7dfb5c1f09e5c0b618
    tree 0ce52f0e38439ed98333077
    parent 7a802cad5138b242c5ee
    author test <test@gmail.com> 1591016659 +0800
    committer test <test@gmail.com> 1591016659 +0800
    
    second commit
    
    $ git cat-file -t e019be006cf33489e2d0
    blob
    
    $ git cat-file -p e019be006cf33489e2d0
    second

    当执行 git commit -m "second commit" 的时候就会在.git/objects/下新生成了1个tree对象和一个commit对象的文件夹(前两位为文件夹名称 -- 后38位为文本内容的哈希值)。对应上述的0ce52f0e38439ed98333077(tree对象), b0da7dfb5c1f09e5c0b61835e0ecc87877d0e853(commit对象)。

    只生成一个与commit对象一一对应的顶层tree对象。由于本次提交doc目录下的readme.txt内容没有变化,所以上图的0ce52f0e38439ed98333077(tree对象)还会指向e7a75e980c7adc0d5ab1(tree对象)。这个时候HEAD游标指向的是当前master分支的second commit(HEAD索引向前移动),second commit 会指向上一次的提交即 parent指向first commit。

    整个原理图如下:

    注意: blob对象只对文件的内容有关,和文件名称无关,如果不同的文件名称,内容相同只会有一个blob对象,生成的新tree对象会指向该blob对象。例如third commit和four commit的内容一样,所以不会生成新的blob对象,新的tree对象只会指向同一个blob。

     

     

  • 相关阅读:
    慕课网-安卓工程师初养成-3-2 Java中的算术运算符
    慕课网-安卓工程师初养成-3-1 什么是运算符
    慕课网-安卓工程师初养成-2-13 练习题
    慕课网-安卓工程师初养成-2-12 如何在Java中使用注释
    慕课网-安卓工程师初养成-2-11 Java常量
    慕课网-安卓工程师初养成-2-10 Java中的强制类型转换
    试把一个正整数n拆分为若干个
    求解两个给定正整数m、n的最大公约数(m、n)
    统计n!尾部零
    横竖折对称方阵
  • 原文地址:https://www.cnblogs.com/UniqueColor/p/13092192.html
Copyright © 2011-2022 走看看