探秘.git目录

准备素材

执行下面的命令,创建本次实验的仓库。

## 创建仓库目录
mkdir hello
cd hello/
touch hello.txt
mkdir subdir
touch subdir/index.txt

## 初始化仓库
git init
# Initialized empty Git repository in /tmp/hello/.git/

## 提交
git add .
git commit -m"init repo"
# [master (root-commit) d0d6ded] init repo
#  2 files changed, 0 insertions(+), 0 deletions(-)
#  create mode 100644 hello.txt
#  create mode 100644 subdir/index.txt

## 编辑 hello.txt 并提交
echo "hello git" > hello.txt 
git add hello.txt 
git commit -m"add content to hello.txt"
# [master 39f7840] add content to hello.txt
#  1 file changed, 1 insertion(+)

## 编辑 subdir/index.txt 并提交
echo "subdir index.text" > subdir/index.txt 
git add subdir/index.txt 
git commit -m"add content to subdir/index.txt"
# [master 5ddd6b1] add content to subdir/index.txt
#  1 file changed, 1 insertion(+)

## 再次编辑 subdir/index.txt 并提交
echo " how are you" >> subdir/index.txt 
git add subdir/index.txt 
git commit -m"append content to subdir/index.txt"
# [master 03bd509] append content to subdir/index.txt
#  1 file changed, 1 insertion(+)

## 再次编辑 hello.txt 并提交
echo "over" >> hello.txt 
git add hello.txt 
git commit -m"edit hello.txt file"
# [master 7f77dfe] edit hello.txt file
#  1 file changed, 1 insertion(+)

## 创建新分支 develop,并添加 readme.md 文件,并提交
git checkout -b develop
# Switched to a new branch 'develop'
touch readme.md
echo "readme.md" > readme.md 
git add readme.md 
git commit -m"add file readme.md"
# [develop 48baef3] add file readme.md
#  1 file changed, 1 insertion(+)
#  create mode 100644 readme.md

## 创建一个 tag 
git tag -a 03bd5095f79995ed4329ca2ba0545364dbe6f2ea -m "v1.0"

当前目录结构如下

hello/
├── hello.txt
├── readme.md
└── subdir
    └── index.txt

进入 .git 目录,列出.git 文件夹的内容。

ls -al
# drwxr-xr-x  8 xingmu docker 4096 10月 27 13:28 .
# drwxr-xr-x  4 xingmu docker 4096 10月 27 13:27 ..
# drwxr-xr-x  2 xingmu docker 4096 10月 27 13:09 branches
# -rw-r--r--  1 xingmu docker   19 10月 27 13:27 COMMIT_EDITMSG
# -rw-r--r--  1 xingmu docker   92 10月 27 13:09 config
# -rw-r--r--  1 xingmu docker   73 10月 27 13:09 description
# -rw-r--r--  1 xingmu docker  295 10月 27 13:28 gitk.cache
# -rw-r--r--  1 xingmu docker   24 10月 27 13:20 HEAD
# drwxr-xr-x  2 xingmu docker 4096 10月 27 13:09 hooks
# -rw-r--r--  1 xingmu docker  320 10月 27 13:27 index
# drwxr-xr-x  2 xingmu docker 4096 10月 27 13:09 info
# drwxr-xr-x  3 xingmu docker 4096 10月 27 13:15 logs
# drwxr-xr-x 25 xingmu docker 4096 10月 27 13:27 objects
# drwxr-xr-x  4 xingmu docker 4096 10月 27 13:09 refs

HEAD

HEAD 是我们经常使用的文件,来看一下HEAD 文件的具体内容是什么?

cat HEAD
# ref: refs/heads/develop

根据输出内容可以看出,HEAD 是一个引入,它指向了 refs/heads/develop

git branch -av
# * develop 48baef3 add file readme.md
#  master  7f77dfe edit hello.txt file

通过查看当前的分支信息,可以看到当前工作在 develop 分支上,那么 HEAD 和分支有什么联系?下面先来切换分支,再来看一下 HEAD 具体的内容。

## 首先退出 .git路径
cd ..
## 切换分析
git checkout master
# Switched to branch 'master'
cat .git/HEAD 
# ref: refs/heads/master

当切换分支到master之后,HEAD 的值就指向了 master ,由此可见 HEAD 是保存了始终指向当前最工作分析的引用。

refs

先来看一下 refs 的结构

.git/refs/
├── heads
│   ├── develop
│   └── master
└── tags
    └── v1.0

可以看到 heads 下面存储了两个文件,分别对应当前分支的名字,现在通过 cat 命令来看下master 文件的具体内容。


然后通过 git cat-file -t 来查看下 7f77dfebffb72d7bd9a5401ae85a0f0f50df4f30 到底是什么?它又保存了什么样的内容。

git cat-file -t 7f77dfebffb72d7bd9a5401ae85a0f0f50df4f30
# commit
git cat-file -p 7f77dfebffb72d7bd9a5401ae85a0f0f50df4f30
# tree 00be1bd3fdfdea8aed1345cf0ca3390410f3afce
# parent 03bd5095f79995ed4329ca2ba0545364dbe6f2ea
# author daihaoxin <daihaoxin@126.com> 1572153583 +0800
# committer daihaoxin <daihaoxin@126.com> 1572153583 +0800
# 
# edit hello.txt file

由此可见heads 文件中的hash 类型是commit ,而 commit 中的除了提交信息之外,又包含了一个类型tree 的引用(tree 00be1bd3fdfdea8aed1345cf0ca3390410f3afce) 。

git cat-file 是一个用来查看 hash 的命令,-t 用来查看类型,-p 用来查看 hash 对应的内容

下面再来看一下 tags 下面存储了什么内容。

git cat-file -t 306e24f066c5d31e9617b6e339af64515ba988f4
# tag
git cat-file -p 306e24f066c5d31e9617b6e339af64515ba988f4
# object 03bd5095f79995ed4329ca2ba0545364dbe6f2ea
# type commit
# tag v1.0
# tagger daihaoxin <daihaoxin@126.com> 1572156754 +0800
# 
# v1.0 msg

## 查看下具体的 commit 信息
git cat-file -t 03bd5095f79995ed4329ca2ba0545364dbe6f2ea
# commit

通过上面的内容可以发现,原来 heads 下面的文件存储是类型为 commit 的哈希值;

tags下面的文件存储的是类型为 tag 的哈希值,只是这个tag 指向的具体内容又包含了一个commit 的指向。

objects

上面看到了两种类型的hash最终指向的内容,都是存储在 objects 里面,只是objects 里面存储的对象类型不是两种,而是四种(下面的内容来自《GIt版本控制管理》一书)。

git 在版本库中主要维护两个数据结构,对象库(object store)和 索引 (index)。

  1. 块(blob

    文件的每一个版本表示为一个块,blob是二进制大对象的缩写,用来代指某些可以包含任意数据的变量或者文件。一个blob保存一个文件的数据,但不包含任何关于这个文件的元数据,甚至连文件名也没有。

  2. 目录树(tree

    一个目录树对象代表一层目录信息,它记录blob表示、路径名和在一个目录里所有文件的一些元数据。它可以递归引用其他目录或子树对象,从而建立一个包含文件和子目录的完整层次结构。

  3. 提交(commit

    一个提交对象保存版本库中每一次变化的元数据,包括作者、提交者、提交日期和日志消息,每一个提交对象指向一个目录树对象,这个目录树对象在一张完整的快照中捕获提交时版本库的状态。最初的提交是没有父提交的

  4. 标签(tag

    一个标签对象分配一个任意的且人类可读的名字给一个特定的对象,通常是一个提交对象,虽然 4d002e6a304c71b8c8ac02372552b80f9e132f93 指的是一个确切且定义好的提交,但是一个更易读的标签名(如 test 1.0.1)会更有意义

随着时间的推移,所有信息在对象库中都会变化和增长,为了有效的利用磁盘空间和带宽,git 把对象压缩并存储在打包文件里,这些文件也在对象库中。

通过使用 git cat-file -tgit cat-file -p 来查看objects 下面的对象,就可以探索出 committreeblob 之间的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值