Git Repository(本地仓库)相关理解
原来虽然对Git已经有所了解,但是根据视频学到了一些新东西,尤其是Repository根据命令进行的变化,所以把新学到的知识记录一下,进一步加深理解。
项目初始化
git init
tree .git
# .git
# ├── HEAD
# ├── config
# ├── description
# ├── hooks
# │ ├── applypatch-msg.sample
# │ ├── ***略
# ├── info
# │ └── exclude
# ├── objects
# │ ├── info
# │ └── pack
# └── refs
# ├── heads
# └── tags
使用初始化命令会创建一个.git
的隐藏目录。
Git Add
vim readme.md
# write something in readme.md
tree .git
# 此时版本库没有变化
git add . # 添加所有新增文件
tree .git
# .git
# ├── ***略
# ├── index
# ├── info
# │ └── exclude
# ├── objects
# │ ├── e7
# │ │ └── 5454320df19c0f69c5f413288c3a2fa9ef4fba
# │ ├── info
# │ └── pack
# └── ***略
当我们将新增文件添加到git中,此时多出了两个文件:.git/index
,还有一个.git/objects/e7*
文件,检查两个文件。
git ls-files -s # 查看index
# 100644 e75454320df19c0f69c5f413288c3a2fa9ef4fba 0 readme.md
git cat-file -p e75454320df19c0f69c5f413288c3a2fa9ef4fba
# hello world! # 查看objects/e7
Git Commit
此时如果我们继续commit
git commit -m "add readme"
tree .git
# .git
# ├── ***略
# ├── logs
# │ ├── HEAD
# │ └── refs
# │ └── heads
# │ └── main
# ├── objects
# │ ├── 1f
# │ │ └── c820ea73032ae8202d026595e38f24b3e78e93
# │ ├── 6c
# │ │ └── 5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# │ ├── e7
# │ │ └── 5454320df19c0f69c5f413288c3a2fa9ef4fba
# │ ├── info
# │ └── pack
# └── refs
# ├── heads
# │ └── main
# └── tags
此时.git/objects/
添加了几个新的记录,同时创建了.git/logs/
文件夹,说明已经有日志信息了,我们通过git log
查看日志信息。
git log
# commit 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea (HEAD -> main)
# Author: yiowoc <499962540@qq.com>
# Date: Wed Aug 2 16:02:01 2023 +0800
# add readme
可以看出日志里面的CommitID包含在.git/objects
的三条记录中,那这三条记录都保存了什么呢?
git cat-file -p 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# tree 1fc820ea73032ae8202d026595e38f24b3e78e93
# author yiowoc <499962540@qq.com> 1690963321 +0800
# committer yiowoc <499962540@qq.com> 1690963321 +0800
# add readme
git cat-file -p 1fc820ea73032ae8202d026595e38f24b3e78e93
# 100644 blob e75454320df19c0f69c5f413288c3a2fa9ef4fba readme.md
git cat-file -p e75454320df19c0f69c5f413288c3a2fa9ef4fba
# hello world!
看出联系了吗,其实信息是commit
->tree
->blob
这样传递的。
- 通过CommitID寻找到
tree
信息,每个commit
都会存储对应的Tree ID。 - 通过
tree
存储的信息,获取到对应的目录树信息。 - 从
tree
中获得blob
的ID,通过BlobID获取对应的文件内容。
同时,tree
存储的信息即为暂存区保存的信息。
Git Tag
标签一般表示一个稳定版本,指向的Commit一般不会变更,通过git tag
可以生成tag。
git tag v0.0.1
tree .git
# .git
# ├── ***略
# └── refs
# ├── heads
# │ └── main
# └── tags
# └── v0.0.1
可以看到,refs/tags
多了一个标签。
同时介绍一种特殊的标签:附注标签,通过git tag -a
创建。
git tag -a v0.0.2 -m "version 0.0.2"
tree .git
# .git
# ├── ***略
# ├── objects
# │ ├── 11 ##这是新的
# │ │ └── e0a0fa7292dce43cde409e3a7e2c6e91a0ba0e
# │ ├── 1f
# │ │ └── c820ea73032ae8202d026595e38f24b3e78e93
# │ ├── 6c
# │ │ └── 5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# │ ├── e7
# │ │ └── 5454320df19c0f69c5f413288c3a2fa9ef4fba
# │ ├── info
# │ └── pack
# └── refs
# ├── heads
# │ └── main
# └── tags
# └── v0.0.1
# └── v0.0.2
可以看出,除了.git/tags
添加了标签外,.git/objects
也多了一条记录。
git cat-file -p 11e0a0fa7292dce43cde409e3a7e2c6e91a0ba0e
# object 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# type commit
# tag v0.0.2
# tagger yiowoc <499962540@qq.com> 1690964677 +0800
# version 0.0.2
git cat-file -p 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# tree 1fc820ea73032ae8202d026595e38f24b3e78e93
# author yiowoc <499962540@qq.com> 1690963321 +0800
# committer yiowoc <499962540@qq.com> 1690963321 +0800
# add readme
git log
# commit 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea (HEAD -> main, tag: v0.0.2, tag: v0.0.1)
# Author: yiowoc <499962540@qq.com>
# Date: Wed Aug 2 16:02:01 2023 +0800
# add readme
可以看出,附注标签在.git/object
创建了一条记录,保存当前的CommitID,同时git log
的记录不变,是原来的commit
。
信息串联:
tag记录获取CommitID->commit获取TreeID->tree获取BlobID->BlobID获取变更信息。
Git Checkout
git checkout -b test
tree .git
# .git
# ├── ***略
# └── refs
# ├── heads
# │ ├── main
# │ └── test
# └── ***略
当创建一个新的分支,可以发现.git/refs/heads
也创建了一个对应的记录。
cat .git/refs/heads/test
# 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
可知分支其实起到了一个指针的作用,指向了一个CommitID为当前版本。
vim readme.md # 做点更新
git add . # 同上文,此时index,objects都会变化
git commit -m "update readme"
git log
# commit b80fcfda9289817ecd933403a68a0a0b6823535f (HEAD -> test)
# Author: yiowoc <499962540@qq.com>
# Date: Wed Aug 2 16:48:40 2023 +0800
# update readme
# 略
git cat-file -p b80fcfda9289817ecd933403a68a0a0b6823535f
# tree a85ce7f4750c82ae9afc7f3623d4b7d618597064
# parent 6c5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# author yiowoc <499962540@qq.com> 1690966120 +0800
# committer yiowoc <499962540@qq.com> 1690966120 +0800
# update readme
当我们再次对文件进行修改,提交之后,这次的commit
存有一个parent
字段,通过commit串联获取历史版本代码。
tree .git
# .git
# ├── ***略
# ├── objects
# │ ├── 11
# │ │ └── e0a0fa7292dce43cde409e3a7e2c6e91a0ba0e
# │ ├── 1f
# │ │ └── c820ea73032ae8202d026595e38f24b3e78e93
# │ ├── 6c
# │ │ └── 5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# │ ├── 7c
# │ │ └── ce49e40884a8c8a89ca6db5977d2073d54ce61
# │ ├── a8
# │ │ └── 5ce7f4750c82ae9afc7f3623d4b7d618597064
# │ ├── b8
# │ │ └── 0fcfda9289817ecd933403a68a0a0b6823535f
# │ ├── e7
# │ │ └── 5454320df19c0f69c5f413288c3a2fa9ef4fba
# │ ├── info
# │ └── pack
# └── ***略
同时可以看出,相比于add/commit
前,commit
总过新增了三个文件(commit/tree/blob)。同时test指向新的commit。
Git Commit --amend
可以通过git commit --amend
修改上一个commit信息。
vim readme.md # 上次更新有误,进行修改
git commit --ammend
tree .git
# .git
# ├── ***略
# ├── objects
# │ ├── 11
# │ │ └── e0a0fa7292dce43cde409e3a7e2c6e91a0ba0e
# │ ├── 1f
# │ │ └── c820ea73032ae8202d026595e38f24b3e78e93
# │ ├── 6b
# │ │ └── eb650c3efe0382b375d5744820470f6b52bf76
# │ ├── 6c
# │ │ └── 5dd2fb7432a3d74e5aaf91d196a9310fbca6ea
# │ ├── 7c
# │ │ └── ce49e40884a8c8a89ca6db5977d2073d54ce61
# │ ├── a8
# │ │ └── 5ce7f4750c82ae9afc7f3623d4b7d618597064
# │ ├── b8
# │ │ └── 0fcfda9289817ecd933403a68a0a0b6823535f
# │ ├── e7
# │ │ └── 5454320df19c0f69c5f413288c3a2fa9ef4fba
# │ ├── info
# │ └── pack
# └── ***略
git log
# commit 6beb650c3efe0382b375d5744820470f6b52bf76 (HEAD -> test)
# Author: yiowoc <499962540@qq.com>
# Date: Wed Aug 2 16:48:40 2023 +0800
# fix the updating!
# 略
从上面的文件可知,git commit --amend
操作的确修改了上一次的commit,通过创建一个.git/objects
记录(前面的提交会创建三个记录),同时将上一次的commit指向新的记录的方式来修改了历史版本,旧的旧的commit记录并没有删除。
总结
更加细节的东西(比如Git GC/Git研发流程)这里就不赘述了。总结一下上面的内容。
我对工作区/暂存区/版本库的概念更加清晰了:
- 通过
git init
会创建隐藏目录.git
,即版本库。 - 通过
git add .
操作会创建/修改.git/index
文件,即暂存区,同时也会在.git/objects/
中保存信息。 - 工作区就是除了
.git
以外当前文件夹的空间。
在版本库中:
index
主要记录git add
的信息。objects
会记录git add/commit/tag
等多种信息。refs/heads
主要存储分支信息,每个分支指向一个CommitID。refs/tags
主要记录tags信息,每个标签指向一个CommitID。
我们的所有git
操作都仰仗版本库的记录,所以好好了解一下它的运作还是很有好处的。
临末附上原来写的git merge与git rebase的区别。如果有什么问题,希望大家能指出。