Git Pinciple
Git使用命令有很多,参数也很多,如何把它迅速掌握?就应该从原理开始。从建立git跟踪文件到最后多次提交,内部文件数据结构是怎样的呢?结合Git Simple Tutorial的基本概念,本节将一步一步揭开它的不为人知的秘密。一般初学者掌握这个以后,使用命令就不会那么迷茫了。
Stage1 - init
1 | $ git init canai |
发生了什么呢?
- 创建了很多空目录,比如.git/objects/和.git/refs/
- 还没有索引(Index)文件
创建了符号索引文件HEAD
1
2$ cat HEAD
ref: refs/heads/master
Stage2 - add
1 | $ git add README |
发生了什么呢?
创建了索引(Index)文件,产生一个SHA1哈希值指向一个blob实体
1
2
3
4
5
6# 索引文件以二进制格式保存
$ cat .git/index
DIRCZM??$???ZM??$???q?????_???????e?8??V?README2?r??;V7?E???uA?ۣ
# 只能这种方式打开看到里面的内容
$ git ls-files --stage
100644 5f89c6f016cad2d419e865df380595e39b1256db 0 README创建了一个blob实体。README文件的内容存储在该blob中
1
2
3
4
5
6# blob文件以二进制格式保存
$ cat .git/objects/5f89c6f016cad2d419e865df380595e39b1256db
xK??OR02bpT(?/?THN?K?T((??JM.???? ?
# 只能这种方式打开看到里面的内容
$ git cat-file blob 5f89c6
A roti canai project.
Stage3 - commit
1 | $ git commit -m 'first commit' |
发生了什么呢?
创建了分支‘master’引用,指向‘master’分支中最新的commit实体
1
2$ cat .git/refs/heads/master
06fae2f981d13ea39253dce05ca2bb440009e74e创建了第一个commit实体(含有一个引用指向代码仓库根目录tree实体)
1
2
3
4
5
6$ git cat-file commit 06fae2f
tree 0ff699bbafc5d17d0637bf058c924ab405b5dcfe
author Li Li <allen.lili@hotmail.com> 1515037476 +1100
committer Li Li <allen.lili@hotmail.com> 1515037476 +1100
first commit创建了tree实体(含有一个引用指向该tree代表目录“canai”)
1
2$ git ls-tree 0ff699b
100644 blob 5f89c6f016cad2d419e865df380595e39b1256db README
Stage4 add modified files
1 | $ echo "Welcome everyone." >> README |
发生了什么呢?
更新了索引(Index)文件。注意到了吗?它记录了一个新blob
1
2$ git ls-files --stage
100644 1192db4c15e019da7fc053225d09dea14bc3ac07 0 README创建了一个新的blob实体(即是README)
1
2
3$ git cat-file blob 1192db4
A roti canai project.
Welcome everyone.
Stage5 add modified files into a new directory
1 | $ mkdir doc |
发生了什么呢?
更新了索引(Index)文件。注意到了吗?它记录了一个新blob,–stage暂存区有两个文件,包括前一步还没有commit的blob
1
2
3$ git ls-files --stage
100644 1192db4c15e019da7fc053225d09dea14bc3ac07 0 README
100644 ea283e4fb22719fad512405d41dffa050cd16f9a 0 doc/manual.txt创建了一个新的blob实体(即是manual.txt)
1
2
3
4
5
6
7
8
9
10
11
12$ git cat-file blob ea283
[[TBD]] manual toc
```
-------------------------
# Stage6 - **commit** modified files
```bash
$ git commit -m'second commit'
[master 5fd2aa8] second commit
2 files changed, 2 insertions(+)
create mode 100644 doc/manual.txt
发生了什么呢?
更新了分支“master”引用,指向该分支中最新的commit实体。
1
2$ cat .git/refs/heads/master
5fd2aa86e614e93d3beffb2b53ea43f2ebbf2c8f创建了第二个commit实体。注意它的“parent”是指向首个commit实体。这样形成了一个提交图谱。
1
2
3
4
5
6
7$ git cat-file commit 5fd2
tree 7729a8b15b747bce541a9752a8f10d57daf221b6
parent 06fae2f981d13ea39253dce05ca2bb440009e74e
author Li Li <allen.lili@hotmail.com> 1515043504 +1100
committer Li Li <allen.lili@hotmail.com> 1515043504 +1100
second commit创建了一个新的代码仓库根目录tree实体。
1
2
3$ git ls-tree 7729
100644 blob 1192db4c15e019da7fc053225d09dea14bc3ac07 README
040000 tree 6ff17d485bf857514f299f0bde0e2a5c932bd055 doc创建了一个新的子目录tree实体。
1
2
3
4
5$ git ls-tree 6ff1
100644 blob ea283e4fb22719fad512405d41dffa050cd16f9a manual.txt
$ git cat-file blob 1192
A roti canai project.
Welcome everyone.
Stage7 添加一个注释标签(annotated tag)
1 | $ git tag -a -m'this is annotated tag' v0.1 06fae |
发生了什么呢?
创建了一个标签引用,指向一个tag实体。
1
2$ cat .git/refs/tags/v0.1
aad34fe53bcbf0904ce9a1b1e4b1512d2556963e创建了一个tag实体。
1
2
3
4
5
6
7$ git cat-file tag aad34
object 06fae2f981d13ea39253dce05ca2bb440009e74e
type commit
tag v0.1
tagger Li Li <allen.lili@hotmail.com> 1515047016 +1100
this is annotated tag
Stage8 添加一个新的(轻量的)标签
1 | $ git tag root-commit 06fae2f |
- 发生了什么呢?
- 创建了一个标签引用,指向一个commit实体
1
2$ cat .git/refs/tags/root-commit
06fae2f981d13ea39253dce05ca2bb440009e74e
- 创建了一个标签引用,指向一个commit实体
结论
init, add, commit简单情况下的记忆线索:
HEAD -> master -> commit -> tree or blob
根目录 -> 引用目录 -> 实体目录
根目录包括HEAD等
引用目录包括master、tag等
实体目录包括commit、blob、tree、tag