1. 仓库初始化 1.1 准备空文件夹 为了探索git,我们建一个新的文件夹,在这里,可以随便怎么搞
1 2 3 4 5 6 7 8 9 10 11 12 # 删除临时文件夹(如果存在的话),创建一个临时文件夹,并进入 ➜ rm -rf tmp && mkdir tmp && cd $_ # 显示当前文件夹的路径 ➜ pwd /Users/lewis/tmp # 目前,里面是空的,一个空文件夹准备好了 ➜ ls -al total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:47 . drwxr-xr-x+ 128 lewis staff 4096 3 4 09:48 ..
1.2 git初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # 在这个文件夹中,建立git仓库 ➜ git init Initialized empty Git repository in /Users/lewis/tmp/.git/ # 看到多了一个 .git 文件夹 ➜ ls -al total 0 drwxr-xr-x 3 lewis staff 96 3 4 09:41 . drwxr-xr-x+ 128 lewis staff 4096 3 4 09:44 .. drwxr-xr-x 9 lewis staff 288 3 4 09:43 .git # 看看这个文件夹里有什么,嗯,有3个文件 和 4个文件夹 ➜ ls -al .git total 24 drwxr-xr-x 9 lewis staff 288 3 4 10:10 . drwxr-xr-x 3 lewis staff 96 3 4 09:53 .. -rw-r--r-- 1 lewis staff 23 3 4 09:53 HEAD -rw-r--r-- 1 lewis staff 137 3 4 09:53 config -rw-r--r-- 1 lewis staff 73 3 4 09:53 description drwxr-xr-x 13 lewis staff 416 3 4 09:53 hooks drwxr-xr-x 3 lewis staff 96 3 4 09:53 info drwxr-xr-x 4 lewis staff 128 3 4 09:53 objects drwxr-xr-x 4 lewis staff 128 3 4 09:53 refs
1.3 .git文件夹初探 这些都是干嘛用的呢?通过文件名,有一些好猜的,和一些不太好理解的
好猜的,不妨先猜一下,
config:配置文件
description:描述文件,具体描述什么还不清楚,感觉不是核心
hooks:钩子文件夹,应该是做扩展功能用的,在主流程上加些钩子
info:存的是一些信息,什么信息要看一下
不好猜的
HEAD:头?你个大头鬼啊。。。
objects:存的是对象?什么是对象?
refs:references的简写?存的是对象的引用?
感觉好猜的部分,是辅助功能,不好猜的才是核心
1.3.1 辅助功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 # config里面存了什么? ➜ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true # 感觉就是些配置,能看懂一个 ignorecase,是忽略大小写,总之,这是配置文件 # description文件呢? ➜ cat .git/description Unnamed repository; edit this file 'description' to name the repository. # 看描述,是给仓库命名用的,先不管它 # 看看hooks文件夹 ➜ ls -al .git/hooks total 96 drwxr-xr-x 13 lewis staff 416 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 10:24 .. -rwxr-xr-x 1 lewis staff 478 3 4 09:53 applypatch-msg.sample -rwxr-xr-x 1 lewis staff 896 3 4 09:53 commit-msg.sample -rwxr-xr-x 1 lewis staff 3327 3 4 09:53 fsmonitor-watchman.sample -rwxr-xr-x 1 lewis staff 189 3 4 09:53 post-update.sample -rwxr-xr-x 1 lewis staff 424 3 4 09:53 pre-applypatch.sample -rwxr-xr-x 1 lewis staff 1638 3 4 09:53 pre-commit.sample -rwxr-xr-x 1 lewis staff 1348 3 4 09:53 pre-push.sample -rwxr-xr-x 1 lewis staff 4898 3 4 09:53 pre-rebase.sample -rwxr-xr-x 1 lewis staff 544 3 4 09:53 pre-receive.sample -rwxr-xr-x 1 lewis staff 1492 3 4 09:53 prepare-commit-msg.sample -rwxr-xr-x 1 lewis staff 3610 3 4 09:53 update.sample # 里面都是些示例文件,和猜测一样,是正常流程的钩子 # info文件夹下,只有一个文件 ➜ tmp git:(master) ls -al .git/info total 8 drwxr-xr-x 3 lewis staff 96 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 10:26 .. -rw-r--r-- 1 lewis staff 240 3 4 09:53 exclude # exclude文件里的内容,看不太懂,感觉是排除规则之类的 ➜ cat .git/info/exclude # git ls-files --others --exclude-from=.git/info/exclude # Lines that start with '#' are comments. # For a project mostly in C, the following would be a good set of # exclude patterns (uncomment them if you want to use them): # *.[oa] # *~
1.3.2 核心功能 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 # HEAD 文件,这意思,是指向refs文件夹吗? ➜ cat .git/HEAD ref: refs/heads/master # 那就先看refs里面有什么吧! ➜ tmp git:(master) ls -alR .git/refs total 0 drwxr-xr-x 4 lewis staff 128 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 10:34 .. drwxr-xr-x 2 lewis staff 64 3 4 09:53 heads drwxr-xr-x 2 lewis staff 64 3 4 09:53 tags .git/refs/heads: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. .git/refs/tags: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. # refs里面有两个子文件夹,heads 和 tags,目前都是空的 # 有个heads,看来HEAD很可能是指向这个里面的 # objects里面,也是两个空文件夹 ➜ tmp git:(master) ls -alR .git/objects total 0 drwxr-xr-x 4 lewis staff 128 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 10:37 .. drwxr-xr-x 2 lewis staff 64 3 4 09:53 info drwxr-xr-x 2 lewis staff 64 3 4 09:53 pack .git/objects/info: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. .git/objects/pack: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 ..
2. 初识git 2.1 创建文件 1 2 3 4 5 # 创建一个空文件,取名为 hello.txt ➜ touch hello.txt ➜ ll total 0 -rw-r--r-- 1 lewis staff 0B 3 4 10:46 hello.txt
2.2 交给git管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # 加到git中 ➜ git add hello.txt # 此时,refs 和 objects无变化,但多出了一个index文件 ➜ ls -al .git/ total 32 drwxr-xr-x 10 lewis staff 320 3 4 10:47 . drwxr-xr-x 4 lewis staff 128 3 4 10:46 .. -rw-r--r-- 1 lewis staff 23 3 4 09:53 HEAD -rw-r--r-- 1 lewis staff 137 3 4 09:53 config -rw-r--r-- 1 lewis staff 73 3 4 09:53 description drwxr-xr-x 13 lewis staff 416 3 4 09:53 hooks -rw-r--r-- 1 lewis staff 104 3 4 10:47 index drwxr-xr-x 3 lewis staff 96 3 4 09:53 info drwxr-xr-x 5 lewis staff 160 3 4 10:47 objects drwxr-xr-x 4 lewis staff 128 3 4 09:53 refs ➜ cat .git/index DIRC^_????^_????YI?????⛲??CK?)?wZ???S? hello.txt?kEO? ?Z.?!P?a?5e?8% # index这个文件中有乱码,看来存的是二进制 # 能看到hello.txt,说明git add后,改动是存到这个文件的
结论一:
git add 指令,改动了「.git/index」这个文件。
2.3 提交为一个版本 1 2 3 4 5 # 提交 ➜ git commit -m 'first file' [master (root-commit) 528022a] first file 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 hello.txt
2.4 初步分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 # 看看index,感觉有改动,但看不出来具体做了什么 ➜ tmp git:(master) cat .git/index DIRC^_????^_????YI?????⛲??CK?)?wZ???S? hello.txtTREE1 0 :1???[B??B???% # refs文件夹中,在heads里,多了一个master文件 ➜ tmp git:(master) ls -alR .git/refs total 0 drwxr-xr-x 4 lewis staff 128 3 4 09:53 . drwxr-xr-x 12 lewis staff 384 3 4 11:06 .. drwxr-xr-x 3 lewis staff 96 3 4 10:48 heads drwxr-xr-x 2 lewis staff 64 3 4 09:53 tags .git/refs/heads: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:48 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. -rw-r--r-- 1 lewis staff 41 3 4 10:48 master .git/refs/tags: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. # objects文件夹中,多了3个文件夹,每个文件夹里都出现了一个文件 ➜ tmp git:(master) ls -alR .git/objects total 0 drwxr-xr-x 7 lewis staff 224 3 4 10:48 . drwxr-xr-x 12 lewis staff 384 3 4 10:50 .. drwxr-xr-x 3 lewis staff 96 3 4 10:48 52 drwxr-xr-x 3 lewis staff 96 3 4 10:47 e6 drwxr-xr-x 3 lewis staff 96 3 4 10:48 fc drwxr-xr-x 2 lewis staff 64 3 4 09:53 info drwxr-xr-x 2 lewis staff 64 3 4 09:53 pack .git/objects/52: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:48 . drwxr-xr-x 7 lewis staff 224 3 4 10:48 .. -r--r--r-- 1 lewis staff 127 3 4 10:48 8022a97b413fae3f4a8cc0e308e5506a598ea3 .git/objects/e6: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:47 . drwxr-xr-x 7 lewis staff 224 3 4 10:48 .. -r--r--r-- 1 lewis staff 15 3 4 10:47 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 .git/objects/fc: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:48 . drwxr-xr-x 7 lewis staff 224 3 4 10:48 .. -r--r--r-- 1 lewis staff 54 3 4 10:48 b545d5746547a597811b7441ed8eba307be1ff .git/objects/info: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 7 lewis staff 224 3 4 10:48 .. .git/objects/pack: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 7 lewis staff 224 3 4 10:48 ..
结论二:
git commit时,对「.git/index」文件有改动;
git commit时,在「.git/objects」文件夹下,会增加文件;
2.5 引用分析 1 2 3 4 5 6 7 8 9 10 11 12 # 有没有发现,refs里面多出来的文件,正是HEAD文件所指向的? ➜ cat .git/HEAD ref: refs/heads/master ➜ ls -al .git/refs/heads/master -rw-r--r-- 1 lewis staff 41 3 4 10:48 .git/refs/heads/master # 那这个master文件里面又存了什么? ➜ tmp git:(master) cat .git/refs/heads/master 528022a97b413fae3f4a8cc0e308e5506a598ea3 # 看着有点眼熟,确认一下 ➜ tmp git:(master) ls -al .git/objects/52/8022a97b413fae3f4a8cc0e308e5506a598ea3 -r--r--r-- 1 lewis staff 127 3 4 10:48 .git/objects/52/8022a97b413fae3f4a8cc0e308e5506a598ea3
结论三:
「.git/HEAD」是一个指针文件,可以指向「.git/refs」中的文件;
「.git/refs/heads/master」文件也是一个指针,指向「.git/objects」里面的一个文件;
2.6 对象分析 1 2 3 4 5 6 7 # 用了个不熟悉的命令,它是查看这一串对象中存储内容的一个指令 ➜ git cat-file -p 528022a97b413fae3f4a8cc0e308e5506a598ea3 tree fcb545d5746547a597811b7441ed8eba307be1ff author Lewis <fangniude@gmail.com> 1583290125 +0800 committer Lewis <fangniude@gmail.com> 1583290125 +0800 first file
可以看到,文件中有committer
和first file
,说明这个对象存储的是commit的信息,就叫它commit对象
吧
还有一个tree
,指向了另一个对象,那就叫它tree对象
吧
1 2 3 # 看看 tree对象 中存了什么 ➜ git cat-file -p fcb545d5746547a597811b7441ed8eba307be1ff 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.txt
tree对象
指向了第3个对象,感觉就是我们刚才新建的hello.txt
文件
1 2 # 看看hello.txt 文件 ➜ git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
结论四:
「.git/objects」里面,会存储commit对象、tree对象 和 blob对象;
commit对象,对应的是一个commit,会指向一个tree对象;
tree对象对应的是文件夹,还存储了其中文件的名字 和 这些文件的指针;
blob对象存储文件的内容
2.7 第1次提交图 1 2 3 4 5 6 7 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 M((master)) -.-> C1 H((HEAD)) -.-> M
2.8 第2次提交 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 # 再建一个空的文件 ➜ touch hello.copy # 交给git管理 ➜ git add hello.copy # 提交 ➜ git commit -m 'add hello.copy' [master 9222323] add hello.copy 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 hello.copy # 继续分析,master文件指向的对象变了 ➜ cat .git/refs/heads/master 92223238a21c13bec2663fe349e8ea1dbfab97bb # 这是新的commit对象,除了指向tree对象之外,还指向了一个parent ➜ git cat-file -p 92223238a21c13bec2663fe349e8ea1dbfab97bb tree 598293c40ffff2b5d26ab7f9d78601e8d8d05d94 parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583295073 +0800 committer Lewis <fangniude@gmail.com> 1583295073 +0800 add hello.copy # parent对象就是上一次commit ➜ tmp git:(master) git cat-file -p 528022a97b413fae3f4a8cc0e308e5506a598ea3 tree fcb545d5746547a597811b7441ed8eba307be1ff author Lewis <fangniude@gmail.com> 1583290125 +0800 committer Lewis <fangniude@gmail.com> 1583290125 +0800 first file # tree对象里面,有了两个文件,两个文件指向了同一个blob对象 ➜ tmp git:(master) git cat-file -p 598293c40ffff2b5d26ab7f9d78601e8d8d05d94 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.copy 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.txt # 不妨看看此时的objects,变成5个对象,多了一个commit对象 和 一个tree对象 ➜ tmp git:(master) ls -alR .git/objects total 0 drwxr-xr-x 9 lewis staff 288 3 4 12:11 . drwxr-xr-x 12 lewis staff 384 3 4 12:29 .. drwxr-xr-x 3 lewis staff 96 3 4 10:48 52 drwxr-xr-x 3 lewis staff 96 3 4 12:11 59 drwxr-xr-x 3 lewis staff 96 3 4 12:11 92 drwxr-xr-x 3 lewis staff 96 3 4 10:47 e6 drwxr-xr-x 3 lewis staff 96 3 4 10:48 fc drwxr-xr-x 2 lewis staff 64 3 4 09:53 info drwxr-xr-x 2 lewis staff 64 3 4 09:53 pack .git/objects/52: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:48 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. -r--r--r-- 1 lewis staff 127 3 4 10:48 8022a97b413fae3f4a8cc0e308e5506a598ea3 .git/objects/59: total 8 drwxr-xr-x 3 lewis staff 96 3 4 12:11 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. -r--r--r-- 1 lewis staff 63 3 4 12:11 8293c40ffff2b5d26ab7f9d78601e8d8d05d94 .git/objects/92: total 8 drwxr-xr-x 3 lewis staff 96 3 4 12:11 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. -r--r--r-- 1 lewis staff 160 3 4 12:11 223238a21c13bec2663fe349e8ea1dbfab97bb .git/objects/e6: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:47 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. -r--r--r-- 1 lewis staff 15 3 4 12:11 9de29bb2d1d6434b8b29ae775ad8c2e48c5391 .git/objects/fc: total 8 drwxr-xr-x 3 lewis staff 96 3 4 10:48 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. -r--r--r-- 1 lewis staff 54 3 4 10:48 b545d5746547a597811b7441ed8eba307be1ff .git/objects/info: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 .. .git/objects/pack: total 0 drwxr-xr-x 2 lewis staff 64 3 4 09:53 . drwxr-xr-x 9 lewis staff 288 3 4 12:11 ..
结论五:
增加一个commit后,master这个指针会指向新的commit;
commit对象可以指向其parent,即上一次提交;
同一个文件(内容相同的对象)只存储一份;
2.9 第2次提交图 1 2 3 4 5 6 7 8 9 10 11 12 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 M((master)) -.-> C2 H((HEAD)) -.-> M
3. 分支branch 3.1 建dev分支 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 # 看看当前有哪些分支 ➜ git branch * master (END) # 看到只有一个master分支,前面有个`*`代表当前在这个分支 # 创建dev分支 ➜ git branch dev ➜ git branch dev * master (END) # 切换到dev分支 ➜ git checkout dev Switched to branch 'dev' ➜ git branch * dev master (END) # 看看现在HEAD在哪儿? ➜ cat .git/HEAD ref: refs/heads/dev # 多出来一个dev文件,其中的内容 和 master完成一样 ➜ cat .git/refs/heads/dev 92223238a21c13bec2663fe349e8ea1dbfab97bb ➜ cat .git/refs/heads/master 92223238a21c13bec2663fe349e8ea1dbfab97bb # 看看 .git/refs/heads 文件夹下的内容 ➜ ls -al .git/refs/heads total 16 drwxr-xr-x 4 lewis staff 128 3 4 14:31 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. -rw-r--r-- 1 lewis staff 41 3 4 14:31 dev -rw-r--r-- 1 lewis staff 41 3 4 12:11 master
1 2 3 4 5 6 7 8 9 10 11 12 13 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 M((master)) -.-> C2 D((dev)) -.-> C2 H((HEAD)) -.-> D
结论六:
分支是通过「refs/heads」下面的文件来管理,一个文件一个分支;
HEAD 指向哪儿,代表当前在哪个分支
3.2 dev分支提交 注意: 为了简化,我们在dev分支,先退回「第1次提交」,然后再做「第3次提交」
1 2 3 4 5 6 7 8 9 10 11 # 回到第1次提交 ➜ git reset --hard 528022a97b413fae3f4a8cc0e308e5506a598ea3 HEAD is now at 528022a first file # 验证一下,的确只有一个文件 ➜ tmp git:(dev) ls -al total 0 drwxr-xr-x 4 lewis staff 128 3 4 14:54 . drwxr-xr-x+ 128 lewis staff 4096 3 4 14:55 .. drwxr-xr-x 13 lewis staff 416 3 4 14:55 .git -rw-r--r-- 1 lewis staff 0 3 4 10:46 hello.txt
然后,增加一个文件夹,并在其中增加个文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 # 新建 testBranch文件夹 ➜ mkdir testBranch # 添加个有内容的文件 ➜ echo 'this is dev file' > testBranch/devAdd.txt # 确认下,文件添加成功了,其中有内容 ➜ cat testBranch/devAdd.txt this is dev file # 加到index中 ➜ git add testBranch/devAdd.txt # 第3次提交 ➜ git commit -m 'third commit' [dev 1616454] third commit 1 file changed, 1 insertion(+) create mode 100644 testBranch/devAdd.txt # 当前是怎么样的呢? # 先看HEAD,还是指向dev ➜ tmp git:(dev) cat .git/HEAD ref: refs/heads/dev # dev指向了第3次提交 ➜ tmp git:(dev) cat .git/refs/heads/dev 161645439e35c5db8f4755641ca98815c69a9d63 ➜ tmp git:(dev) git cat-file -p 161645439e35c5db8f4755641ca98815c69a9d63 tree fb54f679949f2593bb83d4179f8c7d058393235c parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583306810 +0800 committer Lewis <fangniude@gmail.com> 1583306810 +0800 third commit # 第3次提交的parent,是第1次提交,没毛病 ➜ tmp git:(dev) git cat-file -p 528022a97b413fae3f4a8cc0e308e5506a598ea3 tree fcb545d5746547a597811b7441ed8eba307be1ff author Lewis <fangniude@gmail.com> 1583290125 +0800 committer Lewis <fangniude@gmail.com> 1583290125 +0800 first file # 第3次提交的tree对象中,除了第1次提交的hello.txt外,还有一个tree对象,指向testBranch ➜ tmp git:(dev) git cat-file -p fb54f679949f2593bb83d4179f8c7d058393235c 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.txt 040000 tree ba015591b2652a669fc5892ff58023af8482e8c3 testBranch # testBranch这个对象,包含1个blob对象,即devAdd.txt这个文件 ➜ tmp git:(dev) git cat-file -p ba015591b2652a669fc5892ff58023af8482e8c3 100644 blob 101ff992f2995edf65ee71ebee38b7ba412555cf devAdd.txt # 这个文件中的内容,是刚才输入的文字 ➜ tmp git:(dev) git cat-file -p 101ff992f2995edf65ee71ebee38b7ba412555cf this is dev file
看看现在的图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 T3[/testBranch的tree/] -->F2(devAdd.txt) T4[/第3次提交tree/] -->|hello.txt| F1 T4 --> T3 C3[第3次提交] --> T4 M((master)) -.-> C2 D((dev)) -.-> C3 H((HEAD)) -.-> D
结论七:
分支就是个引用(或 指针),可以随便指向哪个对象;
在引用改变的时候,对象不用动;
每一次提交,都会生成一个新的「提交tree」;
文件夹是通过「tree对象」管理版本的,tree对象可以指向tree对象 和 blob对象
3.3 分支合并 将dev分支的,合并到master分支。
3.3.1 merge合并 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 # 切回master分支 ➜ git checkout master Switched to branch 'master' # 从dev分支merge过来 ➜ git merge dev Merge made by the 'recursive' strategy. testBranch/devAdd.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 testBranch/devAdd.txt # 来看现在是怎么样的,还是从HEAD开始 ➜ cat .git/HEAD ref: refs/heads/master # 看看master里面,指向了一个新的merge commit,它有2个parent ➜ cat .git/refs/heads/master bb6c11e29dcc8865f9c8eae2da89750fd29bf005 ➜ git cat-file -p bb6c11e29dcc8865f9c8eae2da89750fd29bf005 tree 202b85d575214f94ed494ee026e8b2cdb4fcab4f parent 92223238a21c13bec2663fe349e8ea1dbfab97bb parent 161645439e35c5db8f4755641ca98815c69a9d63 author Lewis <fangniude@gmail.com> 1583313790 +0800 committer Lewis <fangniude@gmail.com> 1583313790 +0800 Merge branch 'dev' # 第1个parent是 第2次提交 ➜ git cat-file -p 92223238a21c13bec2663fe349e8ea1dbfab97bb tree 598293c40ffff2b5d26ab7f9d78601e8d8d05d94 parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583295073 +0800 committer Lewis <fangniude@gmail.com> 1583295073 +0800 add hello.copy # 第2个parent是 第3次提交 ➜ git cat-file -p 161645439e35c5db8f4755641ca98815c69a9d63 tree fb54f679949f2593bb83d4179f8c7d058393235c parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583306810 +0800 committer Lewis <fangniude@gmail.com> 1583306810 +0800 third commit # 当然,它还指向了第4次提交的树,其中有原来master 和 dev所有的文件 ➜ git cat-file -p 202b85d575214f94ed494ee026e8b2cdb4fcab4f 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.copy 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.txt 040000 tree ba015591b2652a669fc5892ff58023af8482e8c3 testBranch
现在的图,是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 T3[/testBranch的tree/] -->F2(devAdd.txt) T4[/第3次提交tree/] -->|hello.txt| F1 T4 --> T3 C3[第3次提交] --> T4 T5[/第4次提交tree/] -->|hello.txt|F1 T5 -->|hello.copy|F1 T5 -->T3 C4[第4次提交]-->T5 C4 --> C2 C4 --> C3 M((master)) -.-> C4 D((dev)) -.-> C3 H((HEAD)) -.-> M
3.3.2 rebase合并 思路: dev基于master合并,开发中最常用的工作模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 # 需要先回滚刚才的操作 ➜ git reset --hard 92223238a21c13bec2663fe349e8ea1dbfab97bb HEAD is now at 9222323 add hello.copy # 切换到dev分支 ➜ git checkout dev Switched to branch 'dev' # 执行rebase ➜ git rebase master First, rewinding head to replay your work on top of it... Applying: third commit # 然后,一起来看效果吧,dev有了一个新的commit ➜ cat .git/refs/heads/dev 6b4df1e31ed4c652f790841f46f30c34abb65c8c ➜ tmp git:(dev) git cat-file -p 6b4df1e31ed4c652f790841f46f30c34abb65c8c tree 202b85d575214f94ed494ee026e8b2cdb4fcab4f parent 92223238a21c13bec2663fe349e8ea1dbfab97bb author Lewis <fangniude@gmail.com> 1583306810 +0800 committer Lewis <fangniude@gmail.com> 1583315190 +0800 third commit # 这个commit的parent,是master指向的那次提交,即第2次提交 ➜ tmp git:(dev) cat .git/refs/heads/master 92223238a21c13bec2663fe349e8ea1dbfab97bb ➜ tmp git:(dev) git cat-file -p 92223238a21c13bec2663fe349e8ea1dbfab97bb tree 598293c40ffff2b5d26ab7f9d78601e8d8d05d94 parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583295073 +0800 committer Lewis <fangniude@gmail.com> 1583295073 +0800 add hello.copy # 当然,它指向的树对象,居然是刚才merge时,第4次提交的树对象,因为内容一致,直接重用了 ➜ git cat-file -p 202b85d575214f94ed494ee026e8b2cdb4fcab4f 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.copy 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 hello.txt 040000 tree ba015591b2652a669fc5892ff58023af8482e8c3 testBranch
下面是现在的图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 graph LR T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 T3[/testBranch的tree/] -->F2(devAdd.txt) T5[/第5次提交tree/] -->|hello.txt| F1 T5[/第5次提交tree/] -->|hello.copy| F1 T5 --> T3 C5[第5次提交] --> T5 C5 --> C2 M((master)) -.-> C2 D((dev)) -.-> C5 H((HEAD)) -.-> D
4. 标签tag 我们给第2次提交,打个2.0标签,第5次提交打个3.0标签。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 当前在dev分支,即5次提交 ➜ git tag -a 3.0 -m 'this is 3.0' # 切换到master分支,即第2次提交 ➜ git checkout master Switched to branch 'master' # 这个偷个懒,不带什么参数 ➜ git tag 2.0 # 可以看到,两个tag打好了 ➜ git tag --list 2.0 3.0 (END) # 再看看refs/tags吧 ➜ ls -al .git/refs/tags total 16 drwxr-xr-x 4 lewis staff 128 3 4 18:17 . drwxr-xr-x 4 lewis staff 128 3 4 09:53 .. -rw-r--r-- 1 lewis staff 41 3 4 18:16 2.0 -rw-r--r-- 1 lewis staff 41 3 4 18:17 3.0
4.1 轻量的tag 我们先来看2.0这个tag。
1 2 3 4 5 6 7 8 9 10 11 12 # 和分支一样,2.0这个tag里面,也是存了一个引用 ➜ cat .git/refs/tags/2.0 92223238a21c13bec2663fe349e8ea1dbfab97bb # 指向的是第2次提交,就像现在的master一样 ➜ git cat-file -p 92223238a21c13bec2663fe349e8ea1dbfab97bb tree 598293c40ffff2b5d26ab7f9d78601e8d8d05d94 parent 528022a97b413fae3f4a8cc0e308e5506a598ea3 author Lewis <fangniude@gmail.com> 1583295073 +0800 committer Lewis <fangniude@gmail.com> 1583295073 +0800 add hello.copy
4.2 重量的tag 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # 这个也类似 ➜ cat .git/refs/tags/3.0 87c71f8bfbbb86ffae62f61f322084654932f85a # 但它指向了一个没有见过的对象,能看到刚才输入的信息,它指向了另一个object ➜ git cat-file -p 87c71f8bfbbb86ffae62f61f322084654932f85a object 6b4df1e31ed4c652f790841f46f30c34abb65c8c type commit tag 3.0 tagger Lewis <fangniude@gmail.com> 1583317040 +0800 this is 3.0 # 指向了谁呢?当然是第5次提交了 ➜ git cat-file -p 6b4df1e31ed4c652f790841f46f30c34abb65c8c tree 202b85d575214f94ed494ee026e8b2cdb4fcab4f parent 92223238a21c13bec2663fe349e8ea1dbfab97bb author Lewis <fangniude@gmail.com> 1583306810 +0800 committer Lewis <fangniude@gmail.com> 1583315190 +0800 third commit
4.3 有tag的图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 graph LR %% 第1次提交 T1[/第1次提交tree/] -->|hello.txt| F1(空文件) C1[第1次提交] -->T1 %% 第2次提交 T2[/第2次提交tree/] -->|hello.txt| F1 T2 -->|hell.copy| F1 C2[第2次提交] -->T2 C2 -->C1 %% 第5次提交 T3[/testBranch的tree/] -->F2(devAdd.txt) T5[/第5次提交tree/] -->|hello.txt| F1 T5[/第5次提交tree/] -->|hello.copy| F1 T5 --> T3 C5[第5次提交] --> T5 C5 --> C2 %% 分支 M((master)) -.-> C2 D((dev)) -.-> C5 H((HEAD)) -.-> M %% tag 2((2.0)) -.->C2 TAG>Tag对象]-->C5 3((3.0)) -.->TAG
5. 时光机 6. 远程remote 7. 总结