这才是真正的 Git:Git 内部原理揭秘!
设为 “星标”,每天带你逛 GitHub!
本文以一个具体例子结合动图介绍了 Git 的内部原理,包括 Git 是什么储存我们的代码和变更历史的、更改一个文件时,Git 内部是怎么变化的、Git 这样实现的有什么好处等等。
视频链接: https://www.bilibili.com/video/av77252063
PPT 链接: https://www.lzane.com/slide/git-under-the-hood
前言
Git 是怎么储存信息的
$ git init
$ echo '111' > a.txt
$ echo '222' > b.txt
$ git add *.txt
.git/
目录下,如果你此时去查看
.git/objects
目录,你会发现仓库里面多了两个 object。
$ tree .git/objects
.git/objects
├── 58
│ └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
├── c2
│ └── 00906efd24ec5e783bee7f23b5d7c941b0c12c
├── info
└── pack
$ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
xKOR0a044K%
git cat-file [-t] [-p]
,
-t
可以查看 object 的类型,
-p
可以查看 object 储存的具体内容。
$ git cat-file -t 58c9
blob
$ git cat-file -p 58c9
111
58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c,作为这个 object 在 Git 仓库中的唯一身份证。
$ git commit -am '[+] init'
$ tree .git/objects
.git/objects
├── 0c
│ └── 96bfc59d0f02317d002ebbf8318f46c7e47ab2
├── 4c
│ └── aaa1a9ae0b274fba9e3675f9ef071616e5b209
...
cat-file
命令,我们看看它们分别是什么类型以及具体的内容是什么。
$ git cat-file -t 4caaa1
tree
$ git cat-file -p 4caaa1
100644 blob 58c9bdf9d017fcd178dc8c0... a.txt
100644 blob c200906efd24ec5e783bee7... b.txt
$ git cat-file -t 0c96bf
commit
$ git cat-file -p 0c96bf
tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
author lzane 李泽帆 1573302343 +0800
committer lzane 李泽帆 1573302343 +0800
[+] init
$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
0c96bfc59d0f02317d002ebbf8318f46c7e47ab2
git tag -a
)的时候会新建,这里不详细介绍,有兴趣的朋友按照上文中的方法可以深入探究。
Git 的三个分区
工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。
索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次 commit 被提交到 Git 仓库。
Git 仓库( git repository ):由 Git object 记录着每一次提交的快照,以及链式结构记录的提交变更历史。
echo "333" > a.txt
将 a.txt 的内容从 111 修改成 333,此时如上图可以看到,此时索引区域和 git 仓库没有任何变化。
git add a.txt
将 a.txt 加入到索引区域,此时如上图所示,git 在仓库里面新建了一个 blob object,储存了新的文件内容。并且更新了索引将 a.txt 指向了新建的 blob object。
git commit -m 'update'
提交这次修改。如上图所示
Git 首先根据当前的索引生产一个 tree object,充当新提交的一个快照。
创建一个新的 commit object,将这次 commit 的信息储存起来,并且 parent 指向上一个 commit,组成一条链记录变更历史。
将 master 分支的指针移到新的 commit 结点。