Table of Contents
[原文链接:Link] 转载请注明原作者
🔖Git学习路线
- 三个对象,三个区域,此外还有三个状态。
(并且通过它们来了解 git 系统的CURD操作)
🏔️3 Git Objects
Blob
=>Tree
=>Commit
(极其重要)
🏔️3 Git Areas
Working Directory
=>Stage \ Index
=>Commit History
Working Area
=>Staging Area
=>Git Directory \ Repository (Repo)
本地工作区
=>暂存区
=>历史记录区 \ 版本库
(以上所有叫法均可。但如上三个区域不包含本地文件工作目录,它和 git 的三个区域相互独立,是个沙箱环境)
- 👌三区域关系图:
2020年新版 git 已将撤销功能重命名为“$ git restore”
而不是 “$ git checkout” 和 “$ git reset”
详情见本文第四章
🏔️3 Git Status
unmodified (clear)
,modified
,staged
,committed
未修改 (干净的)
,已修改
,已暂存
,已提交
(主要是后三个状态常常被关注,clear 代表自上次 commit 后未做其它更改)
🏔️2 File Status
上部分中,4个状态仅属于 git 部分,是 git 对象的状态,而非本地工作目录(File Directory) 的文件状态。
在本地目录中,每个文件仅可有两种状态之一,已跟踪 tracked
,未跟踪 untracked
。
- 其中,已跟踪的本地文件才可以具有 Git 上述的状态之一。
- 查看文件跟踪状态的指令:
$ git status
如图,表示一个文件在 git 系统中的生命周期。 (Reference: Link)
- 额外内容
- .git 目录结构 (由 $ git init 创建,该目录中的文件不要手动更改或删除。要在 Git Bash 让 git 自己去处理,不然极易崩溃)
- hooks:
- info:
- logs:
- objects: 存对象 (hash-object) 的数据库 (也就是版本库,本地Repo)
- refs:
- COMMIT_EDITMSG:
- config:
- description:
- FETCH_HEAD:
- HEAD:
- index: 当前暂存区内容
🍻Git 三大对象:
✨blob 对象
-
🔑核心:就是个 hash-object 的 k-v 键值对数据库
-
🔒代表: 单文件的一个版本,及内容
-
📝存放:file的hash(作为数据库的key),存压缩的内容(作为数据库的value)
-
作用区域:
本地工作区
-
➖缺陷:
- 只有blob对象的话,仅通过它们无法知道项目总体轮廓(文件间关联) (
引出 tree 对象
) - 只通过hash来确定key,数据不足,无法确定版本的先后顺序 (
引出 commit 对象
)
- 只有blob对象的话,仅通过它们无法知道项目总体轮廓(文件间关联) (
-
🔧指令控制:
-
🧼在工作区(且在objects目录中)创建blob对象: (-w)
$ echo "test content v1" > ./file.txt
$ git hash-object -w ./file.txt
-
通过linux管道(pipeline)指令,在工作区直接创建blob对象(不常用):
$ echo 'test content' | git hash-object -w --stdin
(–stdin = STarDand INput from command) -
仅查看对象 hash (SHA1) 值:
$ git hash-object ./file.txt
-
-
➕补充:
-
(⚠️) 特性:blob对象不像SVN那样存差异或增量数据,而是压缩后存储全部数据。每次新增一个hash,数据库都会增大。
-
(⚠️) 自己修改完文件,若不输入
$ git hash-object -w ./file.txt
, Git是不会知道你版本有更新的。当然,这个功能被$ git add ./file.txt
封装了,但它还包含了其他功能,后续说明 [Link]。 -
(❌) 若想查看hash-object中的value,在linux命令中调用cat指令,如:
$ cat ./.git/objects/d6/5490dsn2ud3b2uf87f2b
该指令只能看到被压缩后的value (加密文件内容)
-
(✔️) 所以若想查看解压后(解码后)的object content,需要使用如下命令:
$ git cat-file -p d65490dsn2ud3b2uf87f2b
-
(✔️) 若想查看一个object的类型 (是blob,tree,还是commit类),则使用如下命令:
$ git cat-file -t d65490dsn2ud3b2uf87f2b
*(其中hash值并不需要写全部,也可以匹配到)*
-
✨tree 对象
-
🔑核心:用指针来关联各个相关objects (blobs, or sub-trees) 的key (SHA-1 hash),从而构建一个版本的轮廓
-
🔒代表: 该项目的一个版本 也就是项目的轮廓,或快照
-
📝存放:存tree的hash,存file的index
-
作用区域:
暂存区
-
➖缺陷:仅存下了项目轮廓及文件关系,单不知是谁,什么时候,因为什么,种的树(
引出 commit 对象
) -
➕补充:
- tree 对象可以指向(含有)另一个tree对象(sub-tree),或者说另一个目录。
-
🔧指令控制:
-
🧼查看暂存区状态
$ git ls-files -s
“s” stands for “Stage Index” Area -
🧼更新暂存区数据
$ git update-index --add --cacheinfo 100644 560a3d89bf36ea10794402f6664740c284d4ae3b ./test.txt
其中:
- 100644 = 普通文件类型
- 100755 = 可执行文件
- 120000 = 符号链接
此外,tree不同于blob在工作区的持续添加,暂存区的内容若已存在则直接覆写,如:
$ git update-index --add --cacheinfo 100644 e1d551f2a5c0d06def7edde8ffe66c6e06f8ca6d ./test.txt
它只会更改上述中同一条text.txt记录的hash值。
-
🧼将暂存区内容写为一个 Tree 对象
$ git write-tree
(且存入 objects 目录中,并返回 tree 对象的 hash)
-
🧼查看 Tree 对象内容
$ git cat-file -p 5f5087577ca62d5dbed59ffcaf5f4ad7bd5e1b3e
-
🧼读取一个 sub-tree 到暂存区
$ git read-tree 5f5087577ca62d5dbed59ffcaf5f4ad7bd5e1b3e
(从hash key读取一个 tree)
-
🧼从暂存区删除一个对象 (unstage)
$ git rm --cached test.txt
-
✨commit 对象
-
🔒代表: 对 tree 进行封装, 加入几条额外描述信息而已
-
📝存放:谁,什么时候,因为什么,是第几次,种了哪个树
-
🔧指令控制:
-
🧼初次创建提交对象
$ git commit-tree 5f50875 -m "first commit"
或
$ echo "first commit" | git commit-tree 5f50875
(它也会存入 objects 目录中,并返回 commit对象的 hash)
-
🧼非初次创建提交对象 [ 需指定父级commit对象 (-p) ]
$ git commit-tree 5f50875 -m "new commit" -p 77ca62d5d
-
🧼查看 commit 对象内容
$ git cat-file -p d592d5dbed59ffcaf5f4ad7bd5effcafe
(一般是一个 tree 的 hash 带上 作者信息)
-
🔮Git高层命令 add 与 commit 的底层拆解
🎀 git add
$ git add ./test.txt
其实只是组合了如下两条底层命令!!(上述三个对象的底层控制指令而已)$ git hash-object -w ./test.txt
$ git update-index --add --cacheinfo 100644 e1d551f2a5c0d06def7edde8ffe66c6e06f8ca6d ./test.txt
add 后,文件直接进入暂存区!从而等commit,注意这里是个组合拳!
但该操作会覆盖暂存区的旧内容!
🎀 git commit
$ git commit -m "new commit"
其实只是组合了如下两条底层命令!!(同理,也是个组合拳)$ git write-tree
$ git commit-tree <当前暂存区commit对象的hash> -m "new commit" -p <父commit的hash若存在>
commit 后,文件变回 tracked 的 unmodified 状态,等待下一个版本的修改
该操作不会删除暂存区内容!
🎀 git commit -a
$ git commit -a -m "new commit"
其实只是组合了如下命令!!$ git add <全部本地变动了但未被保存到暂存区的files>
(未被跟踪的不被包括在内)$ git commit -m "new commit"
🔮其他高层命令
🎀 git init
- 也算高层命令,初始化.
/.git/
目录
🎀 git status
- 用于检查 file 区域与 git 区域的更新
!!建议在每一次commit前输入一次来检查!!
🎀 git diff
- 用于检查 file 区域与 git 区域的更新(status的详情版,具体到文件内容)
- 单独检查那些更新还没被暂存:
$ git diff
- 检查暂存区待提交内容:
$ git diff --cached
或$ git diff --staged
🎀 git rm
- 多样化的删除操作(一般用不上)
- 删除文件,并更新暂存区(也是底层两条命令的组合拳)
$ git rm ./test.txt
- 不删除文件,只在暂存区删除记录
$ git rm --cached test.txt
- 删除文件,并更新暂存区(也是底层两条命令的组合拳)
🎀 git mv
- 用于文件改名,并置入暂存区
$ git mv ./README.txt ./README.md
相当于如下三条命令的组合拳!$ mv ./README.txt ./README.md
$ git rm README.txt
$ git add README.md
🎀 git log
- 用于查看 commit 历史记录 (这功能一般都被 IDEA 软件给实现完了)
$ git log
$ git log --oneline
简洁显示$ git log --pretty=oneline
另一种简洁显示而已
🔀Git额外笔记
-
Project snapshot is a Tree
-
File is a Blob from Tree
-
Blob is a “key-value” or “hash-object” data
-
Commit is an encapsulated Tree with author information
-
Tree can have sub-tree
-
“ls” stands for “List”
-
“cd” stands for “Change Directory”
💫Git换行格式 (Line Endings)
- LF: Line Feed (Windows 默认换行机制)
- LF样例: \n
- CRLF: Carriage Return Line Feed 包含回车的换行机制 (linux & git 默认换行机制)
- CRLF样例: \r\n
😄 望这篇笔记能对你也有所帮助,若是喜欢,也不妨点一下收藏,万分感谢。
如有错误,也尽请指出。