.git文件夹

前言

.git文件夹存储Git管理项目仓库的所有信息,其中:

  • hooks文件是存储客户端或者服务器的hook 脚本。
  • description文件是专用于GitWeb程序。
  • config文件是关于仓库的配置文件
  • info文件是设置全局的忽略指定模式的文件。

除此之外,下列几个文件是非常重要的:

  • HEAD文件: 存储当前检出分支的信息。
  • index文件:存储暂存区的信息。
  • objects文件夹:以键值对的形式存储所有对象(blob、tree、commit、tag)信息,可以看做是key-value型数据库。
  • refs文件夹:存储指向对象的指针信息。
     

git 对象

git所有类型的对象都存储在objects目录下,对于任意类型的信息,经过SHA1算法后,会生成一个唯一的id值,该id值作为键、对应内容作为值,存储在objects目录中。初始化的.git/objects包括两个文件夹——“pack、info”。pack文件夹是用于将多个文件打包成单个二进制文件滴,包含packfile与idxfile,packfile收集所有对象的内容,idxfile指明对象在文件中的位置。
 

blob对象

对于一个普通文件,git使用SHA-1算法计算文件内容,并返回hash值。将hash值作为键,内容作为值,存储在objects目录中。blob对象仅存储了文件的内容,并未存储文件名。

对一个文件的所有版本进行控制,可以通过记住该文件的所有版本对应的id值,然后通过cat-file命令即可切换到不同的版本内容,可是记住所有的id值不现实。

tree对象

一个项目中往往包含多个文件,但blob对象并未存储文件名称,如果想通过识别所有的对象id来辨别文件是非常困难的。git引入tree对象来存储对象id与名称的映射关系,tree对象可以看做是一个文件集合。

对比unix系统,tree对象相似于目录对象,而blob对象相似于文件节点对象,一个tree对象中存储了多个blob对象及子tree的模式、类型、SHA1值、文件名等。tree对象的模式为“040000”,blob对象有三种常见的模式,“100644”代表普通文件,100755表示可执行文件,120000表示符号链接。tree对象是根据暂存区的内容创建的。

commit对象

tree对象管理一组文件的版本,但在项目的多次迭代更新中,仅通过tree对象的的id值来辨别是哪次版本是困难的。因此git引入commit对象,commit对象不仅包含tree对象的id信息,同时包含提交的说明信息、以及提交的作者等信息。commit对象是指向tree对象的,commit对象是根据tree对象生成的。
 

git 引用

可以将git中的引用理解为“别名、链接”。git中的引用类似于标签、链接,当git命令需要提供相应对象的id时,可以通过记住所有的id值,然后提供给命令,但这是相当困难的。因此git在.git目录下创建refs目录,该目录中的文件仅记录SHA-1值,其文件名在git中就相当于那个被记录SHA-1的别名或者链接,这样就可以直接使用文件名来代替SHA-1值。git中的引用信息基本都存储在refs文件夹下。
 

refs/heads

在一个初始化的git仓库中,refs目录是空的,但是包含两个文件夹“heads、tags”, heads管理分支的引用,tags管理标签的引用。使用git branch <branch-name> 本质就是调用git update-ref refs\heads\<reference> <id>, 将所在分支最后一次提交的校验和存储到指定的命名文件下,则可以直接使用那个命名文件的名称来引用对象。
 

refs/tag(标签引用)

tag对象与commit对象十分相似,都是为了解决记忆SHA-1值的问题,并提供一些补充说明信息。与commit对象不同的是,commit对象是指向tree对象的,而tag对象是指向commit对象的。
 
另外branch分支本质就是一个别名,该别名指向“一连串工作中的最后一个提交对象”。tag与分支也很相似,只是分支对应的refs目录下的命名文件中的内容是可更新的,而tag是不可移动的,它以一种更友好的简称来引用提交对象。
 
tag对象有两种类型,轻量型的与标注型的,轻量型的本质就是一个别名,该别名对应refs/tags下的一个命名文件,命名文件中存储的是commit对象的SHA-1值。而标注型的标签是一个独立的对象,需要使用git tag -a命令创建。对于标注型的标签,refs/tags下的命名文件存储的是标注型标签对象的SHA-1值,该值会链接到对应的commit对象,而不是直接存储commit对象的SHA-1值。
 

refs/remotes(远程引用)

git中有三类引用,前两类对应refs/heads与refs/tags,这两个文件夹在初始化git仓库时就会自动创建,但第三类远程引用refs/remotes需要为本地仓库添加远程仓库后才会创建。
 
远程引用不同于分支引用(refs/heads)的最大点在于,“refs/remotes”下的文件是仅可读的,可以把这些文件内容当做书签,记录着git已知某个远程仓库的状态,当需要上传或者下载时,会将书签中的状态与远程服务器中的状态进行对比,从而得知本地仓库与远程仓库之间的差异。
 

管理引用信息

.git文件夹下有logs文件夹,logs下会保存“HEAD”文件与“refs”文件夹,其中“HEAD”记录HEAD指针每次移动的情况,refs下的记录各个分支的每次变化的情况,如果需要查看“引用”信息,可以人工到logs目录下查找。
 
当然git中也提供了相应的命令——“git reflog”,该命令有几个子命令,其中默认子命令为“show”,show子命令的调用格式为:git reflog [show] [log-options] [<ref>],不指定“ref”参数值时,默认为“HEAD”。其选项与git log的选项保持一致。git reflog会议更加可读性的方式呈现logs文件夹下的信息。
 

注意事项

当本地仓库逐渐变大时,git会自动调用gc命令,gc不仅会打包压缩objects目录,还会打包refs目录,这可能会造成refs目录下的命名文件被合并到一个叫做“packed-refs”文件中,该打包的文件包含之前所有的引用信息。当后续再更新“引用”时,git并不会直接更新“packed-refs”文件,而是直接在refs目录下新建命名文件,当需要使用引用时,git先到refs目录下查找,如果查找不到再去“packed-refs”打包文件查找。如果refs文件夹为空,可能就需要在.git目录下查找“packed-refs”文件。
 

git HEAD

HEAD用于解决让git知道你当前所在的分支,当使用git branch 创建新分支时,默认会将所在分支的最后一个提交对象的校验和存储到新的分支名命名文件下,但git怎样知道当前分支是哪个。HEAD文件就是用来解决此问题的。
 
通常情况下,HEAD文件下存储一个“符号引用”,符号引用不是一个单纯的别名,而是ref:ref的形式,即一个引用指向另一个引用。但是在某些情况下,即使用checkout命令检出“commit、tag、remote branch”时,git就会处于“detached HEAD”状态,此时HEAD文件下存储的是git对象的SHA-1值。
 

git refspec

当为本地仓库添加远程仓库时,会在.git/config文件下配置远程仓库的信息,默认包括远程仓库的名称、url、fetch命令中本地分支与远程分支的映射——也就是refspec
 
refspec的格式为[+]sur:dst,“+”表示即便不是“fast-forward”也更新数据,sur是远程分支的ref引用名称的模式,dst是存储在本地记录远程分支引用名称的模式。这些配置信息在调用git remote add <remote>后会自动写进config文件。如果不需要更新所有匹配的分支,仅更新特定的分支,比如master分支,可以修改fetch行的配置信息,比如+ refs/heads/master: refs/remotes/origin/master可以根据需要自定义refspec,只要符合上述格式就可以,注意可以指定多行的refspec,并且支持glob模式匹配。
 
除了为fetch配置refspec,还可以为push配置refspec,但注意格式是反的,push时候,本地分支的引用名在前,远程分支的引用名在后,+ refs/heads/master: refs/heads/master,注意后面的dst没有remote和origin的远程标识,直接使用的是远程仓库中分支的引用名。
 

附录:plumbing命令

git hash-object
git hash-object [-t <type>] [-w]  [--stdin] [--] <file>

根据SHA-1算法,计算给定的内容,返回id值。

  • w选项: 将对象写进.git/objects目录中。
  • t选项:指定对象的类型,默认为blob类型。
     
git cat-file
git cat-file [-t |-s |-e|-p] <object>

输出对象的content、size、type。

  • p选项:会以优化的格式输出信息。
     
git update-index
git update-index [<options>] [--] [<file>...]

将工作区的文件添加到暂存区,该命令主要是为生成tree对象服务,因为tree对象主要是根据暂存区的内容创建的。

  • add选项:若文件不在暂存区,则将其添加到暂存区。默认方式是忽略新文件的。
  • cacheinfo ,, 选项:直接将指定的信息插入暂存区。
     
git write-tree

调用方式git write-tree,将当前暂存区的内容写进tree对象。
 

git read-tree

调用方式git read-tree,将tree对象的信息读入暂存区。
 

git commit-tree

调用方式git commit-tree <sha1>,输入tree对象的校验和,生成一个新的提交对象。
 

git update-ref
git update-ref  <ref> <newvalue> [<oldvalue>] 

更新存储在.refs目录中对象的名字

 

git symbolic-ref
git symbolic-ref  <name> <ref>

读取、修改、删除符号链接,本质是以安全的方式修改或者查看HEAD文件中的内容。
 

git verify-pack

查看objects/pack目录下的packfile文件内容。
 

git fsck

调用git fsck --full,检查git仓库数据库对象的有效性与完整性,可用于找回丢失的commits对象。
 

参考资料

  1. 《Progit》
  2. https://git-scm.com/docs/git-reflog
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值