美文网首页
Git底层原理

Git底层原理

作者: 伊凡的一天 | 来源:发表于2017-12-21 11:47 被阅读31次

        git本质上是一个内容寻址的文件系统,并在此基础上提供了一个版本控制系统的界面。

        一个已经初始化后的git目录结构如图:

    git目录结构

    其中我们需要重点关注以下四个文件:

    1. HEAD:保存了当前被检出的分支

    2. objects:存储所有的数据内容

    3. index:存储暂存区信息

    4. refs:存储指向commit对象的指针


    1. Git对象

        objects目录下存储了git中所有的数据对象,其目录结构如下:

    objects                                                                                                                                    0d                                                                             7f012a2181ab54c95b4078674da7b31b580bff                                                              1c                                                                                     c469fe42468071e2b1823650fb0a3206985281

        objects目录中存储的对象拥有一个40位的id,其中前2位作为文件夹名,后38位作为文件名,文件内容即为该对象的值。git中拥有四种对象类型:blob,tree,commit和tag。

    1.1 blob对象

        blob对象存储了用户工作区域内的文件内容。当执行git add命令时,objects下会生成新的blob对象,保存了add命令的文件内容。

        使用git cat-file命令可以从指定的对象中取得数据,加上-p选项

        git构造一个对象时,首先添加一个header,header以对象类型开头。下面的例子时git构造了一个内容为字符串"blob",类型为blob的对象。header首先以blob开头,然后添加一个空格,随后是数据内容的长度,最后是一个空字节。因此一个blob对象包含一个blob header和原始数据内容,其形式如下:

    >> header = "blob #{content.length}\0"

    => "blob 16\u0000"

        Git会将上述header和原始数据内容为这个blob对象计算出SHA-1校验和。此SHA-1校验和就是前文所说的40位长度的对象id。然后git根据此id值确定此对象的存储位置(前2位作为文件夹,后38位作为文件名),使用zlib压缩此blob对象然后存储到相应位置。

        commit对象,tree对象的文件header则以"commit"和"tree"开头。

    1.2 tree对象

        tree对象,顾名思义是一棵树,它的每个节点被称为tree entry。每个tree entry有一个指向blob对象或子树对象的SHA-1指针,以及相应的模式,类型,文件名信息等。例如,某个tree对象的信息如下:

    tree对象

        每一行代表此tree对象的一个节点,即tree entry。第一列代表文件模式,其中040000表示这是一个目录,而100644表示这时一个普通文件。第二列表示此节点的对象类型。第三类是此节点的对象SHA-1值,通过此SHA-1值来定位数据内容,可以通过git cat-file -p <SHA-1>来查看。第四列则代表了文件名。因此,此tree对象的树形结构图如下:

    tree对象

    tree对象同blob对象一样,拥有一个SHA-1值,并且通过SHA-1值来确定文件位置,并将添加了header的tree对象内容写入到objects目录下。

    1.3 commit对象

        一个commit对象保存了一次commit的信息,包括作者,提交注释,并且指向父commit对象和一个tree对象。这个tree对象是当前项目快照。如图所示:

    commit对象

    2. 再谈git文件夹结构

    2.1 index文件

        index文件实际上就代表了git中暂存区。它存储了一个tree对象,表示当前项目的快照。当运行git add命令时,首先在objects目录下生成一个新的blob对象,然后更新index文件中的tree对象。

        当运行git status命令时,git会对比工作区和暂存区的文件,具体流程如下:

    1. 首先比较文件的时间戳和长度,如果相同则认为文件没有改变。

    2. 如果发现时间戳不同,则比较文件内容,如果内容相同,则将工作区文件的时间戳更新到index文件(暂存区)中。

    3. 如果工作区文件和暂存区文件内容不相同,则提示有changes

        当运行git commit命令时,首先使用index文件中tree对象在objects目录下创建一个tree对象,然后在objects目录下创建一个commit对象,commit对象指向此tree对象以及父commit对象,最后更新.git/refs/heads/master(commit时的分支名)文件内容为此commit的SHA-1值。

    2.2 refs文件夹

        refs文件夹结构如下:

    refs文件夹结构

        其中子文件夹heads目录为每一个分支创建了一个文件,文件中只保存了在该分支下最近一次提交的commit id。

    refs/heads文件夹结构

        打开master文件,内容只是一个commit的SHA-1值。

    master文件内容

    2.3 HEAD文件

        HEAD文件指向当前活跃的分支。打开HEAD文件,文件内容如下:

    HEAD文件内容

        可以看到文件内容是本地的某一个代表了feture2分支的文件,而该分支文件的内容是最近的一次commit id。因此,我们常用的命令诸如 git reset HEAD等命令中出现的HEAD,能够正确的定位到具体的commit。

    相关文章

      网友评论

          本文标题:Git底层原理

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