深入浅出git(一)——数据模型

自2005年诞生以来,git 已经在开源世界中大受欢迎,我们中的许多人也在我们的工作岗位上使用它。 它是一个很棒的VCS工具,具有很多优点,但易于学习并不是其中之一。 对于 git 如果只会死记硬背命令那么要不了多久你就会忘记,然后一而再而三的背诵,无疑让人很受打击,在我看来,熟悉使用 git 甚至开始喜欢它的唯一方法是了解它如何在内部工作。

git 命令只是对数据存储的抽象,如果不了解 git 的工作原理,无论我们在笔记中记忆或存储了多少 git 命令或技巧我们仍然会对git的使用感到困惑.而git则是通过抽象的命令来暴露它的数据结构的使用方法.

所以这边文章我们更多的要关注 git 的内部关系-数据模型,当然这篇文章不会涉及到 git 的源码.

准备工作

初始化仓库

为了讲解数据模型,我们首先要在自己的工作目录下初始化一个空的 git 仓库

git init

git会告知我们已经在当前的目录下创建了一个 .git 目录,我们来看看这个 .git 长什么样子.

$ tree .git/
.git
|-- HEAD
|-- config
|-- description
|-- hooks
|   |-- applypatch-msg.sample
|   |-- commit-msg.sample
|   |-- fsmonitor-watchman.sample
|   |-- post-update.sample
|   |-- pre-applypatch.sample
|   |-- pre-commit.sample
|   |-- pre-push.sample
|   |-- pre-rebase.sample
|   |-- pre-receive.sample
|   |-- prepare-commit-msg.sample
|   |-- update.sample
|-- info
|   |-- exclude
|-- objects
|   |-- info
|   |-- pack
|-- refs
    |-- heads
    |-- tags

8 directories, 15 files

其中一些文件和目录是不是看着有些熟悉,现在我们主要还是看objects这个目录,现在它是空的,但是一会儿我们就会改变它.

提交文件

首先我们创建一个Main.java文件

touch Main.java

然后输入一部分内容

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

然后以同样的方式在准备一个README.md文件

touch README.md

向文件中输入以下内容

this is my first java project!

现在add并且commit他们到仓库

git add .
git commit -m 'Initial Commit'

模型的创建

现在看上去没啥特殊的,现在我们回过头来在看看.git/objects目录下已经存在了一些子文件夹以及文件了

.git/objects
|-- 84
|   -- 705622ee44f2afbb21087ca7d81fda01fccded
|-- 95
|   -- fc1236534b6f73930367f02895467040f47d4a
|-- b0
|   -- 81e51f448387e72a3e3551ba8610eedc172e60
|-- f1
|   -- a8b89f50a2fd8287578daa2b0374adf3cad8aa
|-- info
|-- pack
6 directories, 4 files

需要注意的是在你的电脑上目录和文件名称和我这里是不一样的.

blob object的创建

.git/objects下我们注意到每个目录的名称只有2个字符长度,Git为每个对象生成一个40个字符的校验和(SHA-1)哈希,该校验和的前两个字符用作目录名,另外38个字符用作文件(对象)名。
当我们提交一些文件时,git创建的第一类对象是blob object,在我们的例子中是两个,每一个blob object对应我们提交的每一个文件:

blob-object

blob object包含文件的快照以及拥有文件校验和.

tree object的创建

git创建的另外一种对象是tree object,在我们的例子中只有一个,它包含我们项目中所有文件的列表,其中包含分配给它们的blob object的指针(这就是git如何将文件与blob object相关联)

tree-object

commit object的创建

最后git还创建了一个commit object,该对象具有指向它的tree object的指针(以及一些其他信息)

commit object

)

这个时候在来看以下objects目录下的结构就清晰多了

.git/objects
|-- 84
|   -- 705622ee44f2afbb21087ca7d81fda01fccded
|-- 95
|   -- fc1236534b6f73930367f02895467040f47d4a
|-- b0
|   -- 81e51f448387e72a3e3551ba8610eedc172e60
|-- f1
|   -- a8b89f50a2fd8287578daa2b0374adf3cad8aa
|-- info
|-- pack

验证模型的准确性

上面画出了模型图,但是你以为我这个模型是自己猜的吗?我又是如何确定哪个是blob object?哪个是tree object?哪个是commit object的呢?接下来就是见证奇迹的时刻了.

使用git log命令我们可以查看我们的提交历史

commit f1a8b89f50a2fd8287578daa2b0374adf3cad8aa (HEAD -> master)
Author: zhu.yang <zhu.yang@xxx.com>
Date:   Tue Jan 8 10:12:06 2019 +0800
    Initial Commit

根据我们前面说的命名约定,我们可以在objects中发现f1a8b89f50a2fd8287578daa2b0374adf3cad8aa这个对象.
想要查看文件内容我们不能简单的使用cat命令,因为这些不是纯文本文件,但是好在git给我们提供了一个cat-file命令

git cat-file commit f1a8b89f50a2fd8287578daa2b0374adf3cad8aa

可以通过它获取到commit object中的内容

tree 95fc1236534b6f73930367f02895467040f47d4a
author zhu.yang <zhu.yang@xxx.com> 1546913526 +0800
committer zhu.yang <zhu.yang@xxx.com> 1546913526 +0800
Initial Commit

从上面可以看到commit指向tree object并且我们可以使用git ls-tree命令来检查下其中的内容

git ls-tree 95fc1236534b6f73930367f02895467040f47d4a

正如我们说预料的一样,其中包含了指向blob object的文件列表

100644 blob 84705622ee44f2afbb21087ca7d81fda01fccded    Main.java
100644 blob b081e51f448387e72a3e3551ba8610eedc172e60    README.md

如果想要查看Main.java中的内容则使用cat-file命令即可

git cat-file blob 84705622ee44f2afbb21087ca7d81fda01fccded

我们可以看到其中返回了Main.java文件的内容

public class Main {
        public static void main(String[] args) {
                System.out.println("Hello World");
        }
}

上面就是当我们创建并提交了一些文件的时候就会发生的事情.同时也验证了我们模型的准确性.

修改文件时模型的改变

现在我们修改一下main.java然后重新提交一下

新增blob object

正如我们看到的一样,git以快照的方式为Main.java新建了一个blob object,由于README.md没有被修改,因此不会为其创建新的blob object.而且git会重用现有的blob object.

现在,当git创建一个tree object时,分配给Main.java的blob指针会被更新,并且分配给README.md的blob指针将保持与前一个提交树中的相同。

新增tree object

)

在最后,git创建一个commit object并指向它的tree object.同时还有一个指向它的父提交对象的指针(每个提交除了第一个提交至少还有一个父提交)

新增commit object

到现在为止我们已经知道了git是如何处理文件的新增以及编辑的,唯一还遗留的就是如何处理删除了,我们先删除Main.java:

删除文件

请注意上图中红色的连线,我们发现删除同样也是非常简单,只需要删除tree object指向blob object的指针即可.在这种情况下我们在新的提交中删除了Main.java,因此我们的提交的树对象不再具有指向表示Main.java的blob object的指针.

模型对文件夹的处理

我们提供的这个数据模型还有一个附加功能-tree object是可以被嵌套的(它们可以指向其他树对象),你可以这样想:每个blob object代表一个文件,每个树对象代表一个目录,所以如果我们有嵌套目录,我们就有嵌套的tree object.

由于上面的图已经是提交多次结果画出来的了,再在上面的基础上画结构就不是那么清晰了,这次我重新初始化一个仓库来演示,现在该仓库下存在存在的数据如下:

|-- README.md
`-- app
    `-- user.json

然后提交,最后可以看到如下的数据模型

tree object嵌套g

Git使用blob object以及tree object来重现项目的文件夹结构.到这里我相信你肯定对git的数据模型有了较为深入的了解,它真的是很简单,我相信基于它再去学习Git一定会是事半功倍.

总结

  1. 创建一个提交的时候git会新增blob object,tree object,commit object并会形成链路图
  2. 嵌套的tree object用来表示文件夹
  3. git从复用blob object
  4. 除了第一个提交之外,每一个提交都有一个父提交
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容