Home Git 对象
Post
Cancel

Git 对象

.git

这个隐藏文件夹可以视为 git 的本地仓库,其内部文件主要由以下部分组成,有些是文件有些是文件夹。

└── .git

├── COMMIT_EDITMSG # 保存最新的commit message

├── config # 仓库的配置文件

├── description # 仓库的描述信息,主要给 gitweb 使用

├── HEAD # 指向当前分支

├── hooks # 存放一些shell脚本,可以设置特定的git命令后触发相应的脚本,.sample 后缀的脚本文件不会被执行

├── index # 二进制暂存区(stage)

├── info # 仓库的其他信息

│ └── exclude # 本地的排除文件规则,功能和 .gitignore 类似,区别在于 .gitignore 会被提交到版本库中,info/exclude 文件中的排除规则不会被提交到版本库

├── logs # 保存所有更新操作的引用记录,主要用于 git reflog 等

├── objects # 所有文件的存储对象,以 hash 值最为目录名,前两位 hash 值作为父目录

└── refs # 具体的引用,主要存储分支和标签的引用,是提交对象(commit object)的指针,把 hash 映射为 branch name

其中四个条目很重要:HEAD 文件、index 文件,objects 目录、refs 目录。

  • HEAD 文件通常是一个符号引用(symbolic reference),指向目前所在的分支。某些情况下,HEAD 文件可能会包含一个 git 对象的 SHA-1 值,譬如 checkout FETCH_HEAD 后。

  • index 文件保存暂存区信息
  • objects 目录存储所有数据内容
  • refs 目录存储指向数据(分支、远程仓库和标签等)的提交对象的指针

对象

git 内部有三类对象,数据对象、树对象和提交对象。

  • 数据对象(blob object),只存文件内容
  • 树对象(tree object),组织结构并存储文件名
  • 提交对象(commit object),包含提交信息和树对象

git对象存储

向 Git 仓库提交的所有对象都会有个头部信息一并被保存。

头部信息内容为:类型(blob、tree、commit) + 文件长度 + null

每次我们运行 git add 和 git commit 命令时,Git 所做的工作实质就是将被改写的文件保存为数据对象,更新暂存区,记录树对象(index 文件),最后创建一个指明了顶层树对象和父提交的提交对象。

底层工具

git 附带了一些底层工具,可以进行一些诸如 hash 计算等的底层操作,实际上 git 的各个命令也都是利用底层工具实现的。

  • git hash-object 计算 hash 键值。 -w 会指示该命令不要只返回键,还要将该对象写入数据库中。

    1
    2
    
    # 对一个文件进行 hash 计算, 并写该文件到 git 库
    $ echo  'test content' | git hash-object -w --stdin  
    
  • git cat-file 显示文件内容

    1
    2
    3
    4
    
    # 显示文件内容
    $ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
    # 显示文件类型
    $ git cat-file -t d670460b4b4aece5915caf5c68d12f560a9fe3e4
    
  • git update-index 创建暂存区

    1
    2
    3
    4
    
    # 从 git 库创建暂存
    $ git update-index --add --cacheinfo 100644 `blob hashcode` test.txt
    # 从工作区创建暂存
    $ git update-index --add new.txt    
    
  • git write-tree 生成树对象

    1
    2
    
    # 从暂存区生成树对象
    $ git write-tree  
    
  • git commit-tree 生成提交对象

    1
    2
    3
    4
    
    # 首次提交,无父提交
    $ echo 'first commit' | git commit-tree `tree hashcode`
    # 非首次提交,有父提交
    $ echo 'second commit' | git commit-tree `tree hashcode` -p `parent commit hashcode`
    
This post is licensed under CC BY 4.0 by the author.