美文网首页
底层命令与文件结构

底层命令与文件结构

作者: 一江碎月 | 来源:发表于2018-03-12 16:06 被阅读0次

    Git 实质

    参考

    Git 是一个内容寻址文件系统。 这意味着,Git 的 核心部分是一个简单的键值对数据库。 你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索(retrieve)该内容。


    底层命令

    涉及到的底层命令有:

    命令 解释
    cat-file 获取指定 Git 对象的信息
    ls-files 显示暂存区的信息
    ls-tree 显示指定结点的 tree 对象
    hash-object 用于计算文件的 sha-1 值
    update-index 更新暂存区
    write-tree 将暂存区中的文件写成 tree 对象
    read-tree 把树对象读入暂存区
    commit-tree 根据指定的树对象创建一个提交对象
    rev-parse 解析分支名或标签名对应的提交对象的 sha-1 值

    Git 所做的实质工作 —— 将被改写的文件保存为数据对象(hash-object),更新暂存区 ( update-index ),记录树对象(write-tree),最后创建一个指明了顶层树对象和父提交的提交对象(commit-tree)。


    ls-tree

    用于显示指定结点对应的 tree 对象中的内容。

    它会展示所有的文件(即 blob 对象)。

    $ git ls-tree -r HEAD
    100644 blob 34f7ae03cc475d78515719c5b6f8c34e46002f7f    aa
    100644 blob c93ab02d540e388e1b83e23bbd8b49cb97c4b4ce    bb
    100644 blob 837df2b7ed69104790e279524d51880324064492    cc
    100644 blob 9b5cf45dcf51d69998fc7cdab86ea8afb2905047    cid.java
    100644 blob 79f6e4824f9578f237633353e8d6939c8bffcca1    dd.txt
    100644 blob 7f1021754129446ecef3fecab549015ccbe5e59f    ee
    100644 blob f0e0aa843620d42bb1e72f4949001d0ca4173dc1    i/i.txt
    100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    i/ii/xx.txt
    100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    new
    100644 blob 59f2c499c12c1385dd0ff1131a50820e7f6a618c    test.html
    100644 blob d6459e005434a49a66a3ddec92279a86160ad71f    xxx.xxx
    

    从输出可以看出,其中有几个文件是子目录下的文件,它也会直接列出来。


    rev-parse

    解析分支、标签等指向的提交对象的 sha-1 值。

    如:

    $     git rev-parse master
    9b335a39f65dff232f239c08baeeb9f7d27f193a
    $     git tag t1
    $     git rev-parse t1
    9b335a39f65dff232f239c08baeeb9f7d27f193a
    $     git rev-parse HEAD
    9b335a39f65dff232f239c08baeeb9f7d27f193a
    

    master 与 HEAD 为分支名, t1 为标签名。


    ls-files

    用于获取暂存区的信息。

    其常用的几个选项有:

    -c : 在输出中显示暂存的文件。默认值。此选项只会输出文件名。

    --stage : 显示文件的详细信息。包括文件名,sha-1 值,文件模式等。

    $ git ls-files --stage
    100644 6b20baa0a072d5c9578e024942c6ce1d42cf5a2a  0          a.txt
    100644 24e27b2a30edadba619d26e2d3662ec307cdddb2 0   test.html
    100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   xx
    

    上述命令显示当前暂存区中暂存的有三个文件。


    hash-object 命令

    计算文件的 sha-1 值,并可选地根据该文件创建一个 blob 对象。

    注意:该命令只适用于文件,不能用于目录

    选项 解释
    -w 不加该选项则不会生成 blob 对象,反之则会生成
    --stdin hash-object 命令会从标准输入读取内容
    -- <path> 指定 hash-object 操作的文件的路径

    注意:如果使用 --stdin 选项,就需要指定文件路径。

    如:

    $ find .git/objects/ -type f
    $ git hash-object -- ../appid.txt 
    a5a06de3b66ee3a609def184e78873c99d6b1221
    $ find .git/objects/ -type f
    $ git hash-object -w -- ../appid.txt 
    a5a06de3b66ee3a609def184e78873c99d6b1221
    $ find .git/objects/ -type f
    .git/objects//a5/a06de3b66ee3a609def184e78873c99d6b1221
    

    find 命令用于查找指定目录( .git/objects )目录下的所有文件( 通过 -type f 限定 )。

    从上可以看出,起初 objects 目录下并没有文件。hash-object 不加 -w 操作后,目录下依旧没有文件,只不过输出了指定文件的 sha-1 值。

    加上 -w 选项后,objects 目录下多了一个父目录为 a5 的文件。Git 会截取 sha-1 值的前两个字符生成目录名,将剩余的部分做为文件名。因此,objects 目录下会有一个 a5 目录。


    cat-file

    获取指定的 Git 对象的内容等信息。

    其常用的选项如下:

    选项 解释
    -p 后跟 sha-1 值,则 cat-file 会返回该 sha-1 值的内容
    -t 获取指定对象的类型
    -s 获取指定对象的大小

    在使用时,可以通过 > <path> 后缀,将 cat-file 的输出内容输出到指定的文件中。如 git cat-file -p bf43b62de7d99fa2c427dcc82257d81431ba816f > xxx.xxx 就会将内容输出到同目录下的 xxx.xxx 文件中。

    如 -p 选项的使用:

    $ git cat-file -p 9daeafb9864cf43055ae93beb0afd6c7d144bfa4
    test
    

    其中 test 为该对象的内容。

    如 -t 选项的使用:

    $ git cat-file -t ee1a8365ec2baa3e5a97cb6e44d8d8b5c553fb30
    blob
    
    $ git cat-file -t 8bdb01d84c5ad6456acb4d8df8d82a0db5214972
    tree
    
    $ git cat-file -t bf43b62de7d99fa2c427dcc82257d81431ba816f
    commit
    

    Git 中一共有三种对象 :commit , tree 与 blob ,所以 -t 只会输出这三个值中的一个。


    update-index

    该选项用于更新暂存区。git addgit rm 等命令都是对该选项的封装。

    其常用的选项有:

    选项 解释
    <无> 更新已暂存的文件
    --add 将未跟踪的文件添加到暂存区中
    --cacheinfo 将已保存到本地仓库的文件加入到暂存区中
    --remove 将已删除的文件从暂存区中移除

    各个选项具体说明如下:

    1. --add : 如果文件从来没有添加到暂存区中,该选项表示将文件第一次添加到暂存区中

      $ git ls-files --stag
      100644 6b20baa0a072d5c9578e024942c6ce1d42cf5a2a 0   a.txt
      
      $ git hash-object yy
      e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
      $ git update-index --add yy
      $ git ls-files --stage
      100644 6b20baa0a072d5c9578e024942c6ce1d42cf5a2a 0   a.txt
      100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   yy
      

      初始时,暂存区中只有一个 a.txt 文件。使用 git update-index --add 命令后,暂存区中多了一个 yy 文件,并且 yy 文件与 update-index 指定的文件的 sha-1 值相同,所以该命令可以将指定的文件添加到暂存区中。

      再查看 .git/objects 目录下,可以发现多了一个文件(即 yy 文件)。

    2. --cacheinfo:如果要保存的文件已位于 git 仓库中,需要使用该选项。

      $ vim yy 
      $ git hash-object -w -- yy 
      9be86ae7054f7c477afabe3d971046032851b574
      
      $ git update-index --cacheinfo 100644 9be86ae7054f7c477afabe3d971046032851b574 yy 
      

      首先修改 yy 文件,并通过 hash-object 将文件存储到 git 目录中。所以更新暂存区时不需要 --add 选项。

      在使用 --cacheinfo 修改暂存区时,指定了文件的 sha-1 值,同时也指定了文件模式为 100644(即普通文件)。

    3. --remove:将指定的文件从索引中删除,该文件必须已经从工作目录中删除

      $ git ls-files --stage
      100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0   xx
      100644 9be86ae7054f7c477afabe3d971046032851b574 0   yy
      
      $ rm xx 
      $ git update-index --remove -- xx
      $ git ls-files --stage
      100644 9be86ae7054f7c477afabe3d971046032851b574 0   yy
      
      $ git update-index --remove -- yy 
      $ git ls-files --stage
      100644 9be86ae7054f7c477afabe3d971046032851b574 0   yy
      

      不删除文件直接使用 --remove 选项时,并不会删除相应的记录(如上例中的 yy 文件)。


    write-tree

    将暂存区内容写入一个树对象。

    通过 update-index 更新暂存区后,基本的文件并没有生成成 tree 对象。而 write-tree 可以根据暂存区生成一个树对象。

    $ git write-tree
    348eb10c8ce3e5a4561a38aa7e76e61013e153e1
    
    $ git cat-file -t 348eb10c8ce3e5a4561a38aa7e76e61013e153e1
    tree
    

    read-tree

    将指定的树对象读入到暂存区中。

    通过 --prefix=name 指定读入的树对象的名字。

    首先将一个树对象读入暂存区中,然后通过 write-tree 将暂存区中的内容写入一个树对象中。则新生成的树对象会包含一个指向通过 read-tree 读入的树对象的指针。

    $ git read-tree --prefix=namep 348eb10c8ce3e5a4561a38aa7e76e61013e153e1
    

    执行上述命令后,如果将当前暂存区生成一个 tree 对象后,该对象会包含一个名为 namep 的指针,它指向的是通过 read-tree 读入的树对象。


    commit-tree

    根据指定的树对象创建一个提交对象。

    通过 -p sha-1 指定当前对象的父对象

    $ echo "first commit" | git commit-tree 2aabf73883cc35cef05f3c7919274da2aaebf674
    cbc41af8ae9347c21299005f40ce998e58ab357e
    
    $ echo "third" | git commit-tree fa197580163fc711a76726db35488f433968699c -p cbc41af8ae9347c21299005f40ce998e58ab357e
    
    7e0792c1e2b634b4721edc6e3ff6f206d18298a2
    

    echo 指定的是本次提交的说明。

    上述命令新建了两个 commit 对象,并将第二个 commit 对象的父结点指向第一个对象。

    当在第二个 commit 对象处建立分支后,运行 git log 命令,可以发现有两条提交记录。


    目录

    Git 有几个非常重要的文件:

    1. objects 目录存储所有数据内容;

    2. refs 目录存储指向数据(分支)的提交对象的指针。

      1. refs/heads 存储的是当前的是各个分支,每一个文件记录了该分支最后一个提交结点的 sha-1 值。

      2. refs/tags 目录下记录的是各个标签。

      3. refs/remotes 存储当前仓库配置的远程服务器。其每一个子目录就对应着一个远程仓库 —— 子目录名字就是通过 git remote add <别名> url 中的别名。子目录下的各个文件指的是远程仓库的各个分支。

    3. HEAD 文件指示目前被检出的分支;

    4. index 文件保存暂存区信息。

    5. config 文件保存 --local 的配置信息。例如我们使用 git remote add <别名> url 命令时,会在 config 文件中添加如下信息。其具体信息可参考 remote一节:

      [remote "demo"]
          url = https://github.com/birdandcliff/gitdemo.git
          fetch = +refs/heads/re:refs/remotes/demo/devlocal
      

    相关文章

      网友评论

          本文标题:底层命令与文件结构

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