前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >.git 目录的内部结构

.git 目录的内部结构

作者头像
后端云
发布2023-02-10 19:30:35
7100
发布2023-02-10 19:30:35
举报
文章被收录于专栏:后端云

本篇不是讲git的使用,也不是讲git的源码,但阅读本篇有助于理解git的底层逻辑设计。本篇讲的是一个文件夹,具体就是git分布式仓库中的本地仓库的隐藏文件夹.git

.git目录的结构

代码语言:javascript
复制
[root@iZ23nrc95u7Z ~]# mkdir git-dir
[root@iZ23nrc95u7Z ~]# cd git-dir/
[root@iZ23nrc95u7Z git-dir]# git init
Initialized empty Git repository in /root/git-dir/.git/
[root@iZ23nrc95u7Z git-dir]# ls -a
.  ..  .git

该隐藏文件夹有以下文件夹和文件:

hooks:是存储git钩子的目录,钩子是在特定事件发生时触发的脚本。比如:提交之前,提交之后。

代码语言:javascript
复制
[root@iZ23nrc95u7Z git-dir]# cd .git/hooks/
[root@iZ23nrc95u7Z hooks]# ls
applypatch-msg.sample  commit-msg.sample  post-update.sample  pre-applypatch.sample  pre-commit.sample  prepare-commit-msg.sample  pre-push.sample  pre-rebase.sample  update.sample

objects:是存储git各种对象及内容的对象库,包含正常的和压缩后的。

文件名称是git管理的workspace文件内容的SHA-1 hash校验和,有40位,取前两位作为文件夹名称,后38位作为文件名。前2位作为文件夹是为了快速索引。

因为是根据文件内容做的校验和,所以.git目录不会重复保存,比如基于某个分支新创建一个分支,重复的文件不会重复保存,修改文件也是保存的增量信息。

目录objects里的文件保存的信息有几类,commit,tree(workspace的文件夹信息),blob(workspace的文件信息)。

refs:是存储git各种引用的目录,包含分支、远程分支和标签。

refs目录下面有几个目录:heads,remotes,tags

heads目录保存的是本地分支head信息,本地有几个分支就几个分支名称对应的文件,文件内容是该分支head对应的commit id。

remotes是远程仓库的分支和head信息

tags目录保存的是本地仓库的tag和head信息。一个tag对应一个和tag同名的文件,文件内容是该tag对应commit id。

config:是代码库级别的配置文件。

该文件的信息和 git config –local -l 命令显示的信息是完全一致的。

通过 git config –local 命令配置的信息,会添加到该文件中。比如 git config --local user.name "Your Name Here"

通过修改该文件,可以实现同 git config –local 命令配置 一样的效果。

HEAD:是代码库当前指向的分支。

该文件记录当前所处的分支信息,比如 ref: refs/heads/main

若用 git checkout 命令切换分支,该文件存储的信息会跟着变。

若修改该文件,一样可以达到和 git checkout 命令一样的切换分支的效果。

description:这个文件用于GitWeb。

GitWeb 是 CGI 脚本(Common Gateway Interface,通用网关接口,简单地讲就是运行在Web服务器上的程序, 但由浏览器的输入触发),让用户在web页面查看git内容。如果我们要启动 GitWeb 可用如下命令:

git instaweb –start

服务并打开浏览器 http://127.0.0.1:1234,页面直接显示当前的 git 仓库名称以及描述,默认的描述如下:

Unnamed repository; edit this file ‘description’ to name the repository.

上面这段话就是默认的 description 文件的内容,编辑这个文件会让 GitWeb 描述更友好。

常用操作后.git目录的objects文件夹变化

增加一个文件到暂存区,objects文件夹的变化

代码语言:javascript
复制
[root@iZ23nrc95u7Z git-dir]# ls
[root@iZ23nrc95u7Z git-dir]# tree .git/objects/
.git/objects/
├── info
└── pack

2 directories, 0 files
[root@iZ23nrc95u7Z git-dir]# echo "this is file1" > file1.md
[root@iZ23nrc95u7Z git-dir]# ls
file1.md
[root@iZ23nrc95u7Z git-dir]# cat file1.md
this is file1
[root@iZ23nrc95u7Z git-dir]# git add file1.md
[root@iZ23nrc95u7Z git-dir]# tree .git/objects/
.git/objects/
├── 43
│   └── 3eb172726bc7b6d60e8d68efb0f0ef4e67a667
├── info
└── pack

3 directories, 1 file
[root@iZ23nrc95u7Z git-dir]# git ls-files --stage
100644 433eb172726bc7b6d60e8d68efb0f0ef4e67a667 0	file1.md
[root@iZ23nrc95u7Z git-dir]# git cat-file -t 433eb172726bc7b6d60e8d68efb0f0ef4e67a667
blob
[root@iZ23nrc95u7Z git-dir]# git cat-file -p 433eb172726bc7b6d60e8d68efb0f0ef4e67a667
this is file1

增加一个文件夹和在该文件夹新建一个文件,并保存到暂存区,objects文件夹的变化

代码语言:javascript
复制
[root@iZ23nrc95u7Z git-dir]# ls
file1.md
[root@iZ23nrc95u7Z git-dir]# mkdir dir2
[root@iZ23nrc95u7Z git-dir]# echo "this is file2" > dir2/file2.md
[root@iZ23nrc95u7Z git-dir]# tree
.
├── dir2
│   └── file2.md
└── file1.md

1 directory, 2 files
[root@iZ23nrc95u7Z git-dir]# git add dir2
[root@iZ23nrc95u7Z git-dir]# tree .git/objects/
.git/objects/
├── 43
│   └── 3eb172726bc7b6d60e8d68efb0f0ef4e67a667
├── f1
│   └── 38820097c8ef62a012205db0b1701df516f6d5
├── info
└── pack

4 directories, 2 files
[root@iZ23nrc95u7Z git-dir]# git ls-files --stage
100644 f138820097c8ef62a012205db0b1701df516f6d5 0	dir2/file2.md
100644 433eb172726bc7b6d60e8d68efb0f0ef4e67a667 0	file1.md
[root@iZ23nrc95u7Z git-dir]# git cat-file -t 433eb172726bc7b6d60e8d68efb0f0ef4e67a667
blob
[root@iZ23nrc95u7Z git-dir]# git cat-file -p 433eb172726bc7b6d60e8d68efb0f0ef4e67a667
this is file1
[root@iZ23nrc95u7Z git-dir]# git cat-file -t f138820097c8ef62a012205db0b1701df516f6d5
blob
[root@iZ23nrc95u7Z git-dir]# git cat-file -p f138820097c8ef62a012205db0b1701df516f6d5
this is file2

提交内容:

git commit 将暂存区的内容提交到本地仓库。

代码语言:javascript
复制
[root@iZ23nrc95u7Z git-dir]# git commit -m 'add file1.md and dir2/file2.md'
[master (root-commit) b2d176a] add file1.md and dir2/file2.md
 2 files changed, 2 insertions(+)
 create mode 100644 dir2/file2.md
 create mode 100644 file1.md
[root@iZ23nrc95u7Z git-dir]# tree .git/objects/
.git/objects/
├── 01
│   └── 54de200dfc71f16a7847f293d79b42b43995e6
├── 20
│   └── d1d441485e8a194976cba515754890bffb32ad
├── 43
│   └── 3eb172726bc7b6d60e8d68efb0f0ef4e67a667
├── b2
│   └── d176a8c3f1d4f608b722cc3b79bdeeaebbdf06
├── f1
│   └── 38820097c8ef62a012205db0b1701df516f6d5
├── info
└── pack

7 directories, 5 files

发现经过了 git commit 命令,除了原来的两个文件blob对象,又多出了三个对象,分别是commit对象,该commit作为整体的tree对象,file2.md所在的文件夹dir2的tree对象。

代码语言:javascript
复制
[root@iZ23nrc95u7Z git-dir]# git cat-file -t 0154de200dfc71f16a7847f293d79b42b43995e6
tree
[root@iZ23nrc95u7Z git-dir]# git cat-file -p 0154de200dfc71f16a7847f293d79b42b43995e6
040000 tree 20d1d441485e8a194976cba515754890bffb32ad	dir2
100644 blob 433eb172726bc7b6d60e8d68efb0f0ef4e67a667	file1.md
[root@iZ23nrc95u7Z git-dir]# git cat-file -t 20d1d441485e8a194976cba515754890bffb32ad
tree
[root@iZ23nrc95u7Z git-dir]# git cat-file -p 20d1d441485e8a194976cba515754890bffb32ad
100644 blob f138820097c8ef62a012205db0b1701df516f6d5	file2.md
[root@iZ23nrc95u7Z git-dir]# git cat-file -t b2d176a8c3f1d4f608b722cc3b79bdeeaebbdf06
commit
[root@iZ23nrc95u7Z git-dir]# git cat-file -p b2d176a8c3f1d4f608b722cc3b79bdeeaebbdf06
tree 0154de200dfc71f16a7847f293d79b42b43995e6
author gitusername <gitusermail> 1674019979 +0800
committer gitusername <gitusermail> 1674019979 +0800

add file1.md and dir2/file2.md
[root@iZ23nrc95u7Z git-dir]# git log
commit b2d176a8c3f1d4f608b722cc3b79bdeeaebbdf06
Author: gitusername <gitusermail>
Date:   Wed Jan 18 13:32:59 2023 +0800

    add file1.md and dir2/file2.md
[root@iZ23nrc95u7Z git-dir]# cat .git/COMMIT_EDITMSG
add file1.md and dir2/file2.md

commit后,继续修改文件内容,或新增文件,文件夹。不管是内容修改还是新建,校验和变了,就会在.git/objects目录下多出对应的对象,再次commit,会多出commit对象和该commit的整个tree的对象。

所以即使有多个版本git不会保存多份相同文件内容,只会保存原始文件和增量内容,每一个commit版本都有清晰的结构快照,可以恢复到任意一次commit。新建分支,在其他分支的commit。通过分支信息文件,分支的HEAD信息文件,可以计算出不同分支的commit历史。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端云 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • .git目录的结构
  • 常用操作后.git目录的objects文件夹变化
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档