15分钟了解Git对象和引用(3)

简介: 15分钟了解Git对象和引用

Git 引用 (Git Reference)

OID, 即40位的16进制字符串表示(SHA-256则为64位), 毫无疑问让我们非常晦涩难记。 Git 引用 (References 或 Refs) 就是为此而生的, 引用是一个逻辑概念, 其并非Git所独创, 很多的VCS工具都有类似的概念和设计, 但是基本通过不同的物理方式实现。

Git 引用的存储方式

Git 引用存储的文件可以在我们仓库中轻松找到, 并且其存储的内容结构也非常简易。 Git refs通常会 松散存储 在仓库的 .git/refs/ 目录下 (实际上也可以“打包”), 我们可以在此前的仓库中执行 find 命令:

 find .git/refs

.git/refs

.git/refs/heads

.git/refs/heads/master

.git/refs/tags

.git/refs/tags/v2.0

.git/refs/tags/v1.0

其中 .git/refs/heads 和 .git/refs/tags 等目录是用来让 Git 区分不同引用类型, 其中包括:

常见仓库内建引用目录标识

· .git/refs/heads/ : 分支引用(Branches);

· .git/refs/tags/ : 标签引用(Tags);

· .git/refs/remotes/<origin>/<ref> : 远端引用(Remotes Refs);

· .git/refs/stash/ : 暂存引用(保存还未提交的对象信息);

· .git : 符号引用(例如: HEAD等);

· .git/refs/meta/config : Gerrit 用于保存仓库信息和用户权限等用到的特殊引用;

分支和标签引用

分支(Branches) 是 Git refs 最常见的引用之一, 我们可以通过 cat 命令直接查看我们在 test.git 仓库中已经默认创建的 master 分支:

 cat .git/refs/heads/master

6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f

 git cat-file -p 6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f

tree 2e6cdc032db0ecfa4e3e898b8f8551acce10db11

parent 3de31e208ae26c6b44d9e6c4a3f0adb32d0c68b6

author Dyrone Teng <tenglong.tl@alibaba-inc.com> 1633681481 +0800

committer Dyrone Teng <tenglong.tl@alibaba-inc.com> 1633681627 +0800

 

COMMIT B

 

Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

可以看到, 在引用文件 .git/refs/heads/master 中保存了 6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f , 这个 OID 就是我们刚才创建的 COMMIT B 的对象。 同理, 我们可以查看 .git/refs/tags/v1.0 的引用存储的信息, 我们可以执行:

 cat .git/refs/tags/v1.0 | xargs git cat-file -p

tree 2e6cdc032db0ecfa4e3e898b8f8551acce10db11

parent 3de31e208ae26c6b44d9e6c4a3f0adb32d0c68b6

author Dyrone Teng <tenglong.tl@alibaba-inc.com> 1633681481 +0800

committer Dyrone Teng <tenglong.tl@alibaba-inc.com> 1633681627 +0800

 

COMMIT B

 

Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

符号引用

了解 符号引用(Symbolic Reference) 之前, 我们先在 test.git 目录中执行 git log 子命令:

 git log

commit 6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f (HEAD -> master, tag: v2.0, tag: v1.0)

Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>

Date:   Fri Oct 8 16:24:41 2021 +0800

 

   COMMIT B

 

   Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

 

commit 3de31e208ae26c6b44d9e6c4a3f0adb32d0c68b6

Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>

Date:   Fri Oct 8 15:45:01 2021 +0800

 

   COMMIT A

 

   Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

git log 子命令用于查看 提交历史, 这里我们没有指定任何一个选项或者参数, 这中情况下子命令会为我们展示 当前所在引用(the branch currently on) 分支 的最新提交历史, 那么Git是如何知晓我们当前引用是哪个呢? 原因就在于符号引用。

Git使用 .git/HEAD 文件来保存你当前所在分支引用的信息, 与分支引用和标签引用相比不同的是, 后者存储的是引用对象的信息, 而前者保存的是 引用的引用 , 我们执行 :

 cat .git/HEAD

ref: refs/heads/master

除了 HEAD 之外, 实际上我们可以 symbolic-ref 子命令更新和获取, 自定义名称的符号引用:

 git symbolic-ref MARK refs/heads/master

 test.git git:(master) cat .git/MARK

ref: refs/heads/master

Remotes引用

Remotes引用, 通常用来存储 已经存在于远程存储库中的对象 信息, 例如在执行 git push 子命令后进行维护. 我们此前介绍的内容都是基于本地仓库, 并不涉及与远端仓库的协作. 如果我们添加一个远端仓库 (remote) 的地址并将新的提交执行推送 (push) ,Git 便会将上次推送的对象的值存储在 refs/remotes 目录中的对应分支中。例如,您可以添加一个名为 origin 的远程信息并将master推送上去:

  git remote add origin https://codeup.aliyun.com/rdc2020/dyrone.git

  git push origin master

Enumerating objects: 9, done.

Counting objects: 100% (9/9), done.

Delta compression using up to 8 threads

Compressing objects: 100% (3/3), done.

Writing objects: 100% (9/9), 754 bytes | 754.00 KiB/s, done.

Total 9 (delta 1), reused 0 (delta 0), pack-reused 0

To https://codeup.aliyun.com/rdc2020/dyrone.git

* [new branch]      master -> master

 cat .git/refs/remotes/origin/master

6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f

现在我们可以看到, 在 .git/refs/remotes/origin/master 引用中记录了我们上一次 push 到名为 origin 的远端仓库上的对象信息。

引用维护

了解了引用的存储方式以后, 我们可以通过直接创建文件的方式, 创建一个仓库中的引用:

 git log --graph

* commit 6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f (HEAD -> master, tag: v2.0, tag: v1.0, origin/master)

| Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>

| Date:   Fri Oct 8 16:24:41 2021 +0800

|

|     COMMIT B

|

|     Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

|

* commit 3de31e208ae26c6b44d9e6c4a3f0adb32d0c68b6 (topic_aliyun)

 Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>

 Date:   Fri Oct 8 15:45:01 2021 +0800

 

     COMMIT A

 

     Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>

 echo 3de31e23de31e208ae26c6b44d9e6c4a3f0adb32d0c68b6 > .git/refs/heads/topic_aliyun

 git log --oneline refs/heads/topic_aliyun

3de31e2 (topic_aliyun) COMMIT A

首先我们找到仓库中的第一个提交, 随后基于第一个提交的OID创建一个名为 topic_aliyun 的分支引用, 随后执行 git log 子命令查看新分支的提交记录, 其中 --graph 选项可以在提交历史中附带输出文本形式的简易图形信息, --oneline 可以简化我们的输出信息, 只关注提交的 标题 和 简短形式的OID。

直接使用 echo 的方式去修改引用其实不是非常安全, 所以Git设计了 git update-ref 子命令专门用来维护引用的数据。 例如, 我们可以尝试将分支应用 refs/heads/topic_aliyun 更新为 COMMIT B 的提交对象:

 git update-ref refs/heads/topic_aliyun 6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f

 cat .git/refs/heads/topic_aliyun

6ae8bbeeb4dba091d3c6295d0b3d0f9a3863d32f

最后

本文花了一部分的篇幅用来介绍了Git的设计思路, 引出了Git是如何通过对象来完成版本控制数据的存储, 以及如何通过引用来方便的管理和使用这些对象, 希望这些内容对不太了解Git的同学能够小有帮助, 同时这也是继续学习Git的重要基础。

本文没有对所有深入的内容都深入介绍, 例如Git存储对象和引用的方式不光光包含松散存储的方式, 而这种方式往往方便演示, 感兴趣的同学可以边阅读边执行。

在视频中, 除了对象和引用之外, 还介绍了一些简单的运维仓库的方式, 这些内容将在后面的系列视频和文章中由我其他同事们继续深入介绍, 敬请期待。

关于我们

欢迎加入我们!

如果你是一个懂代码,爱Git,有技术梦想的工程师,并想要和我们一起打造世界NO.1的代码服务和产品!

请联系我吧!C/C++/Golang/Java 我们都要 ღ( ´・ᴗ・` )!

If not now, when? If not me, who?

— 简历投递: tenglong.tl@alibaba-inc.com

Last updated 2021-10-11 19:05:43 CST

目录
相关文章
|
3月前
|
存储 Java 开发工具
聊聊Git中的引用
这个 SHA-1 值就指向 Git 仓库中的某个提交对象 ID。既然能用 SHA-1 值来区分不同的提交对象,为何要创建一个存放 SHA-1 值的文件呢?因为 SHA-1 值过于长,而且没有规律,如果利用简单的文件名来引用对原来的提交对象,就不用记住复杂且无规律的 SHA-1 值了。 因此在 Git 中,**像这种只含有 SHA-1 值的文件,就是 Git 的引用(Reference)。而分支,就是一个指向某一系列提交之首的指针或引用**。
54 0
聊聊Git中的引用
|
5月前
|
存储 Unix 开发工具
15分钟了解Git对象和引用(2)
15分钟了解Git对象和引用
51 0
|
5月前
|
存储 算法 Unix
15分钟了解Git对象和引用(1)
15分钟了解Git对象和引用
85 0
|
3月前
|
存储 算法 开发工具
深入剖析Git对象底层原理
Git 在中间做了什么,它如何存储不同的文件和内容,以及如何区分不同分支下的文件版本呢?日常操作对这些自动的操作都是无感的。 但是如果哪天一旦上述操作中出现了错误,需要找回自己的代码时,如果不懂 Git 其内部存储原理,是没法找回的,因此为了避免这种情况,就有必要去了解其内部的存储——Git 对象的原理。
15 0
深入剖析Git对象底层原理
|
开发工具 git 索引
commit时Git都干了些啥?--- 提交对象
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 提交对象 一般我们平时有了需要提交的文件,都是2步走:add,然后commit add操作 第一步:添加文件 //添加文件到暂存区 git add test.
1276 0
|
开发工具 数据库 git
Git是如何保存文件名和目录关系的---树对象
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 树对象(tree)—— 保存文件名和目录关系 树对象主要解决2个问题,:文件名的保存和文件目录关系的保存 就像下面这样 下面我们就来模拟一下构建上面这颗树,也就是模拟保存这3个文件,其中的"bak"是一个目录,下面有一个文件 首先可以看到,我们一共需要保存的是3个文件,new.txt 、 内容为version 2的 test.txt 和内容为version 1的 test.txt。
773 0
|
数据库
Git.Framework 框架随手记--ORM查询返回实体对象
  使用ORM有一个优势,可以通过某种机制将数据库中的数据转化为自己想要的对象形式数据。本章记录一下如何使用Git.Framework返回实体对象     一. Git.Framework 中提供的方法     在Git.
1002 0
|
开发工具 Android开发 git
mac AndroidStudio git 引用失效
mac AndroidStudio git 引用失效
2695 0
|
存储 开发工具 git
Git 内部原理之 Git 对象哈希
在上一篇文章中,将了数据对象、树对象和提交对象三种Git对象,每种对象会计算出一个hash值。那么,Git是如何计算出Git对象的hash值?本文的内容就是来解答这个问题。
891 0
|
16天前
|
缓存 数据可视化 网络安全
Git命令大全
Git命令大全
46 1