Smiling & Weeping

                  ---- 在街上看到长得和你相似的人时

                        我心中的那股雀跃

                       请你至少同情一下吧

第五章 Git 内部原理

5.0 引言

本章相对独立,从底层出发带你了解Git内部是如何运作的。

你应该注意到本地仓库下有个名为 .git 的隐藏目录,本章将带你了解这个目录下的文件结构和内容。

命令操作说明:

  • 本章演示的命令是使用win10环境下的git bash工具;
  • '$' 符号所在行是演示命令;
  • 如有内容输出,会在'$' 符号所在行的下面输出。

5.1 .git 的目录结构

创建一个名为 test 的新仓库

$ mkdir test
$ cd test
$ git init
 

新仓库会自动创建一个 .git 目录,该目录包含了几乎所有 Git 存储和操作内容。若想备份或复制一个版本库,只需将该目录拷贝至另一处即可。

目录结构如下(后续章节会对 *开头 的目录详细介绍):

├── *config               配置信息(比如本地repo是否大小写敏感, remote端repo的url, 用户名邮箱等)
├── description 无需关心(仅供GitWeb程序使用)
├── *HEAD 目前被检出的分支
├── index 保存暂存区信息


├── hooks/ 钩子脚本(执行Git命令时自动执行一些特定操作)
├── info/ 包含一个全局性排除文件
│ └── exclude 放置不希望被记录在 .gitignore 文件中的忽略模式
├── logs/ 记录所有操作
├── *objects/ 存储所有数据内容
│ ├── SHA-1/ 保存git对象的目录(三类对象commit, tree和blob)
│ ├── info/
│ └── pack/
└── *refs/ 存储指向数据(分支、远程仓库和标签等)的提交对象的指针
├── heads/
├── remotes/
└── tags/
 

5.2 objects目录 —— 对象存储

初始化仓库后:objects目录下只有子目录 pack 和 info ,但均为空。

运行以下命令,创建两个文件并提交

# 创建了 blob1
$ echo "version1" > test.txt
$ git add . # 创建了 blob2
$ mkdir folder1
$ echo "file inside folder1" >folder1/file.txt
$ git add . # 创建了 tree1, tree2和commit
$ git commit -m "test"
[master (root-commit) 67f0856] test
2 files changed, 2 insertions(+)
create mode 100644 folder1/file.txt
create mode 100644 test.txt
 

此时查看objects目录,会发现新增了5个子目录。

.git/objects
├── 40
│ └── fa006a9f641b977fc7b3b5accb0171993a3d31
├── 5b
│ └── dcfc19f119febc749eef9a9551bc335cb965e2
├── 67
│ └── f0856ccd04627766ca251e5156eb391a4a4ff8
├── 87
│ └── db2fdb5f60f9a453830eb2ec3cf50fea3782a6
├── ac
│ └── f63c316ad27e8320a23da194e61f45be040b0b
├── info
└── pack
 

让我们来学习一些知识点,来解答以下疑问。

- 这些长串数字代表什么意思?
- 为什么突然多了5个子目录,分别代表什么呢? (info和pack目录将在下一小节介绍)
 

知识点

1. 什么是对象?

objects目录下存储三种对象:数据对象(blob),树对象(tree)和提交对象(commit)。

5个子目录的含义如下图所示:2个blob, 2个tree和1个commit

2. Git如何存储对象?

  • Git会根据对象内容生成一个 SHA-1 哈希值(称为该文件的校验和)

    例如:40fa006a9f641b977fc7b3b5accb0171993a3d31

  • 截取校验和的前两个字符 => 用于命名子目录

    例如:40

  • 校验和余下的 38 个字符 => 用于文件名

    例如:fa006a9f641b977fc7b3b5accb0171993a3d31

  • 将对象内容存储在 子目录/文件名 内

3. [小拓展] 如何查看对象的存储内容

可以根据校验和,查看存储的内容及对象类型

# 查看文件类型
$ git cat-file -t 40fa006a9f641b977fc7b3b5accb0171993a3d31
blob # 查看文件内容
$ git cat-file -p 40fa006a9f641b977fc7b3b5accb0171993a3d31
file inside folder1
 

5.3 objects目录 —— 包文件的存储机制

Git默认保存文件快照,即保存每个文件每个版本的完整内容。但假设只更改了某大文件中的一个字符,保存两次全部内容是不是有点低效?

Git最初向磁盘存储对象时采用"松散"对象格式;但为了节省空间和提高效率,Git会时不时将多个对象打包成一个称为"包文件"。

当版本库中有太多的"松散"对象,或者手动执行 git gc 命令,或者向远程服务器执行推送时,Git 都会进行打包。

运行以下命令,手动打包

$ git gc
Enumerating objects: 113, done.
Counting objects: 100% (113/113), done.
Delta compression using up to 8 threads
Compressing objects: 100% (92/92), done.
Writing objects: 100% (113/113), done.
Total 113 (delta 15), reused 102 (delta 13), pack-reused 0
 

此时查看objects目录,会发现很多子目录不见了,而 info 和 pack 目录非空。

.git/objects
├── info
│ ├── commit-graph
│ └── packs
└── pack
├── pack-XXX.idx
└── pack-XXX.pack
 
  • 包文件pack-XXX.pack:包含了刚才从文件系统中移除的所有对象的内容;
  • 索引文件pack-XXX.idx:包含了包文件的偏移信息。通过索引文件可以快速定位任意一个指定对象

5.4 refs目录 —— 引用

Git把一些常用的 SHA-1 值存储在文件中,用文件名来替代,这些别名就称为引用。有三种引用类型:heads, remotes和tags。

运行以下命令,更新refs目录下的内容

# 基于当前commit创建新分支test
git branch test # 基于commit打tag
git tag -a v1.0 <commitId> # 连接远程仓库
git remote add origin https://github.com/datawhalechina/faster-git.git
git fetch # 本地修改文件,然后运行git stash
echo "version2" > test.txt
git stash
 

此时查看refs目录,内容如下

.git/refs
├── heads 记录本地分支的最后一次提交
│ ├── master
│ └── test
├── remotes 记录远程仓库各分支的最后一次提交
│ └── origin
│ └── main
├── tags
│ └── v1.0
└── stash
 

5.4.1 HEAD引用

HEAD引用有两种类型

  存储位置 指代内容 文件内容
分支级别 .git/refs/heads目录下 本地分支的最后一次提交- 有多少个分支,就有多少个同名的HEAD引用 commitHash
代码库级别 .git/HEAD文件 指代当前代码所处的分支;拓展:也可指代commitHash(称为分离HEAD 符号引用 - 例如 ref: refs/heads/master

5.4.2 远程引用

  • 存储位置: .git/refs/remotes 目录下
  • 指代内容:远程仓库各分支的最后一次提交
  • 注意点:用于记录远程仓库;文件是只读的,乱改就崩了

5.4.3 标签引用

tag主要用于发布版本的管理:一个版本发布之后,我们可以为git打上 v1.0 v2.0 ... 这样的标签

  • 存储位置:.git/refs/heads 目录下
  • 指代内容:tag可以指向任何类型(更多的是指向一个commit,赋予它一个更友好的名字)
  • 文件内容:SHA-1值

5.4.4 stash

  • 存储位置:.git/refs/stash 文件
  • 指代内容:当你想转到其他分支进行其他工作,又不想舍弃当前修改的代码时 - stash可把当前的修改暂存起来

5.5 config文件 —— 引用规范

运行以下命令,连接远程仓库

git remote add origin https://github.com/datawhalechina/faster-git.git
git fetch
 

此时查看 .git/config 文件,会发现新添加了一段小节:

[remote "origin"]
url = https://github.com/datawhalechina/faster-git.git
fetch = +refs/heads/*:refs/remotes/origin/*
 

引用规范由 git remote add origin 命令自动生成

  • 获取远端 refs/heads/ 下的所有引用
  • 将其写入本地的 refs/remotes/origin/ 中
  • 更新本地的 .git/config 文件

一些常用命令:

  命令
连接远程仓库 git remote add <远端名origin> <url>
拉取分支 git fetch <远端名origin> <远端分支名>:<本地分支名>
将远程的 main 分支拉到本地的mymaster 分支 git fetch origin main:mymaster
将本地的master分支推送到远端的topic分支 git push origin master:topic
删除远端分支topic 法1:将<src>留空
git push origin :topic
法2:Git v1.7.0新语法
git push origin --delete topic

5.6 config文件 —— 环境变量

Git有三种环境变量:

1)系统变量

  • 适用范围:对所有用户都适用
  • 命令选项:git config --system

2)用户变量

  • 适用范围:只适用于该用户
  • 命令选项:git config --global

3)本地项目变量

  • 适用范围:只对当前项目有效
  • 命令选项:git config --local
  • 存储位置:.git/config

一些常用命令:

  命令
查看所有配置 git config --list
配置用户名 git config --global user.name "你的用户名"
配置邮箱 git config --global user.email "你的邮箱"

5.7 小练习

5.7.1 远端分支推送

Tom 想把自己的本地分支 feature1(当前也为 HEAD ),推送到远端分支的 feature,应当执行什么命令?

A. git push origin/feature1:feature
B. git push origin feature1:feature
C. git push origin HEAD:feature
D. git push origin :feature
 

5.7.2 邮箱配置

Tom工作在多个Git项目上,大部分属于公司的项目,都是使用他的工作邮箱提交。

今天他新建了一个私人项目,想使用私人邮箱进行提交。他运行什么命令更合适呢?

A. git config --system user.email "tom@私人邮箱"
B. git config --global user.email "tom@私人邮箱"
C. git config --local user.email "tom@私人邮箱"
D. 以上选项都可以
 

.

.

.

.

.

.

8.1 答案:B C

8.2 答案:C 只对当前项目有效

文章到此结束,我们下次再见

其实我心动了,但是赶路要紧,我没有说

Lecture5的更多相关文章

  1. Linear Algebra Lecture5 note

    Section 2.7     PA=LU and Section 3.1   Vector Spaces and Subspaces   Transpose(转置) example: 特殊情况,对称 ...

  2. cs231n spring 2017 lecture5 Convolutional Neural Networks听课笔记

    1. 之前课程里,一个32*32*3的图像被展成3072*1的向量,左乘大小为10*3072的权重矩阵W,可以得到一个10*1的得分,分别对应10类标签. 在Convolution Layer里,图像 ...

  3. cs231n spring 2017 lecture5 Convolutional Neural Networks

    1. 之前课程里,一个32*32*3的图像被展成3072*1的向量,左乘大小为10*3072的权重矩阵W,可以得到一个10*1的得分,分别对应10类标签. 在Convolution Layer里,图像 ...

  4. lecture15-自动编码器、语义哈希、图像检索

    Hinton第15课,本节有课外读物<Semantic Hashing>和<Using Very Deep Autoencoders for Content-Based Image ...

  5. GO語言視頻教程

    第1课:https://github.com/Unknwon/go-fundamental-programming/blob/master/lectures/lecture1.md Go开发环境搭建h ...

  6. SLAM(二)----学习资料下载

    有位师兄收集了很多slam的学习资料, 做的很赞, 放到了github上, 地址:https://github.com/liulinbo/slam.git ruben update 0823 2016 ...

  7. ra寄存器定位core

    $ra寄存器中存入的是pc的值(程序运行处的地址),调用函数时,在跳转前,必须保存当前地址(pc的值),以便后来返回.jal $ra 保存后跳转,jr $ra,返回到跳转前,通过$ra保存进入上层栈地 ...

  8. hash相关

    转译☞:https://www.cs.rice.edu/~as143/COMP441_Spring17/scribe/lect4.pdf 1 大规模图片检索问题 基于树模型的算法在分类跟聚类中很受欢迎 ...

随机推荐

  1. 百信银行基于 Apache Hudi 实时数据湖演进方案

    简介: 本文介绍了百信银行实时计算平台的建设情况,实时数据湖构建在 Hudi 上的方案和实践方法,以及实时计算平台集成 Hudi 和使用 Hudi 的方式. 本文介绍了百信银行实时计算平台的建设情况, ...

  2. DelegateCommand-最简单的合令调用。

    View代码 <StackPanel> <Button Content="方法一" Command="{Binding AddCommand}" ...

  3. Roslyn 分析器 EnforceExtendedAnalyzerRules 属性的作用

    在开始编写 dotnet 的 Roslyn 分析器项目时,会被 VisualStudio 通过 RS1036 要求在项目文件配置上 EnforceExtendedAnalyzerRules 属性,本文 ...

  4. dotnet 5 的 bin 文件夹下的 ref 文件夹是做什么用的

    本文来和大家聊聊在 dotnet 5 和 dotnet 6 或更高版本的 dotnet 构建完成,在 bin 文件夹下,输出的 ref 文件夹.在此文件夹里面,将会包含项目程序集同名的 dll 文件, ...

  5. Azure 无服务器 Function 函数计算服务 dotnet core 3.1 创建和部署入门

    本文用的是 世纪互联 的 Azure.cn 版本,这个版本因为是在国内,所以网速会快超级超级多.使用 世纪互联 的版本需要一块钱哦,用一块钱就能进入一个月的免费试用.本文主要告诉小伙伴如何使用 Azu ...

  6. kali linux 渗透测试 01 kali介绍

    安全问题的根源 分层思想------盲人摸象 只追求功能实现----比较片面 最大的安全威胁是人---- 安全目标 先于攻击者发现和防止漏洞出现 攻击型安全 防护性安全 渗透测试 尝试击破安全防御机制 ...

  7. linux文本三剑客之grep及正则表达式详解

    linux文本三剑客之grep及正则表达式详解 目录 linux文本三剑客之grep及正则表达式详解 1. grep命令详解 2. 正则表达式 2.1 基本正则表达式 2.2 扩展正则表达式 1. g ...

  8. 1.简单的C语言程序

    简单的C语言程序 什么是计算机程序? 什么是计算机语言? 所谓程序,就是一组计算机能识别和执行的指令. 什么是计算机语言? 机器语言(0,1 '低级语言'),汇编语言(符号化 '低级语言'),高级语言 ...

  9. 适用于任何设备的屏幕共享应用程序 – Mirroring360

    Mirroring360 适用于 Windows.Mac.iOS.Android 和 Chromebook 设备的屏幕镜像和屏幕共享,非常适合商务和教育! 屏幕共享应用程序可以帮助增强业务专业人员,讲 ...

  10. C#.Net筑基-模式匹配汇总

    01.模式匹配概述 从C#7开始支持的 模式匹配 语法(糖,挺甜),可非常灵活的对数据进行条件匹配和提取,经过多个版本的完善,已经非常强大了. C# 支持多种模式,包括声明.类型.常量.关系.属性.列 ...