首页 存档 技术 查看内容

探索.git目录,让你真正了理解git

2018-3-30 13:00 |来自: 互联网 259 0

摘要: “哇欧,我才读了 git 的快速入门指南就觉得它简直酷毙了,现在使用起 git 来感觉超舒服,妈妈再也不担心我会捅出什么篓子了。” 某位无名英雄曾曰过 新人刚使用 git 的时候,就像去到一个既不识当地文字也不会说当 ...

“哇欧,我才读了 git 的快速入门指南就觉得它简直酷毙了,现在使用起 git 来感觉超舒服,妈妈再也不担心我会捅出什么篓子了。” 某位无名英雄曾曰过


新人刚使用 git 的时候,就像去到一个既不识当地文字也不会说当地语言的陌生的国家。只要你知道你在什么地方、要去哪里,一切都 OK,而一旦你迷路,麻烦就来了。


网上已经有许多关于学习基本的 git 命令的文章,但是本文不属于这一类,而是尝试另辟蹊径。



新手总是被 git 吓到,事实上也很难不被吓到。可以肯定的是 git 是很强大的工具但还不够友好。大量的新概念,有些命令用文件做参数和不用文件做参数各自执行的动作截然不同,还有隐晦的回馈等…


我以为克服第一道难关的方法就是不仅仅是使用 git commit/push 就完了。如果我们花点时间去真正了解到底git是由什么构造的,那将会省去不少麻烦。


初探 .git


那么我们开始吧。当你创建一个仓库的时候,使用 git init 指令, git 将会创建一个神奇的目录:.git。这个目录下包含了所有 git 正常工作所需要的信息。说白一点,如果你想从你的项目中删除 git 但是又要保留项目文件,只需要删除 .git 文件夹就可以了。但是,你确定要辣么做?


├── HEAD

├── branches

├── config

├── description

├── hooks

│ ├── pre-commit.sample

│ ├── pre-push.sample

│ └── ...

├── info

│ └── exclude

├── objects

│ ├── info

│ └── pack

└── refs

├── heads

└── tags


这就是你第一次提交之前 .git 目录的样子:


  • 这个我们稍后会讨论

  • 这个文件包含你仓库的设置信息。例如这里会放你远程仓库的 URL,你的 email 地址,你的用户名等…。 每次你在控制台使用“git config…”指令时,修改的就是这里。

  • gitweb(可以说是 github 的前身)用来显示仓库的描述。

  • 这是一个有意思的特性。Git 提供了一系列的脚本,你可以在 git 每一个有实质意义的阶段让它们自动运行。这些脚本就是 hooks,可以在 commit/rebase/pull…. 的前后运行。脚本的名字表示它什么时候被运行。例如一个有用的预推送 hook 可能会测试关于保持远程仓库一致性的式样原则。

  • 你可以把你不想让 git 处理的文件放到 .gitignore 文件里。那么,exclude 文件也有同样的作用,不同的地方是它不会被共享,比如当你不想跟踪你的自定义的 IDE 相关的配置文件时,即使通常情况下 .gitignore 就足够了(如果你用到了这个请在评论中告诉我)。

commit 的真相


每一次你创建一个文件并跟踪它会发现,git 会对其进行压缩然后以 git 自己的数据结构形式来存储。这个压缩的对象会有一个唯一的名字,即一个哈希值,这个值存放在 object 目录下。


在探索 object 目录前,我们先要问自己 commit 到底是何方神圣。commit 大致可以视为你工作目录的快照,但是它又不仅仅只是一种快照。


实际上,当你提交的时候,为创建你工作目录的快照 git 只做了两件事:


  • 如果这个文件没有改变,git 仅仅只把压缩文件的名字(就是哈希值)放入快照。

  • 如果文件发生了变化,git 会压缩它,然后把压缩后的文件存入 object 目录。最后再把压缩文件的名字(哈希值)放入快照。


这里只是简单介绍,整个过程有一点复杂,以后的博客里会作说明的。


一旦快照创建好,其本身也会被压缩并且以一个哈希值命名。那么所有的压缩对象都放在哪里呢?答案是object 目录。


├── 4c

│ └── f44f1e3fe4fb7f8aa42138c324f63f5ac85828 // hash

├── 86

│ └── 550c31847e518e1927f95991c949fc14efc711 // hash

├── e6

│ └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 // hash

├── info // let's ignore that

└── pack // let's ignore that too


这就是我创建一个空文件 file_1.txt 并提交后 object 目录看起来的样子。请注意如果你的文件的哈希值是“89faaee…”,git 会把这个文件存在 “89” 目录下然后命名这个文件为 “faaee…”。


你会看到3个哈希。一个对应 file_1.txt ,另一个对应在提交时所创建的快照。那么第三个是什么呢?其实是因为 commit 本身也是一个对象并且也被压缩存放在 object 目录下。


现在,你需要记住的是一个 commit 包含四个部分:


  • 工作目录快照的哈希

  • 提交的说明信息

  • 提交者的信息

  • 父提交的哈希值


如果我们解压缩一个提交,你自己可以看看到底是什么:


// by looking at the history you can easily find your commit hash

// you also don't have to paste the whole hash, only enough

// characters to make the hash unique

git cat-file -p 4cf44f1e3fe4fb7f8aa42138c324f63f5ac85828


这是我看到的


tree 86550c31847e518e1927f95991c949fc14efc711

author Pierre De Wulf

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类