三大对象:
blob
数据对象git hash-object
tree
树对象git update-index, git write-tree
commit
提交对象git commit-tree
手动实现git init``git add``git commit
自定义.git
下各种目录和文件
将HEAD
指向main
PS D:\code\cs61B\repo_2> echo "ref: refs/heads/main" > .git/HEAD
创建数据对象
PS D:\code\cs61B\repo_2> echo "git is awesome" | git hash-object --stdin -w
993dc4dfb4891ea9d1273309e9d8b57f8895552f
PS D:\code\cs61B\repo_2> git cat-file -p 993d
git is awesome
PS D:\code\cs61B\repo_2> git cat-file -t 993d
blob
创建 blob 这个过程通常发生在我们将一些东西添加到 暂存区 的时候——也就是我们使用 git add
的时候
跟踪这个文件——把它添加到 暂存区。为此,我们可以使用底层命令 git update-index
,例如:git update-index --add --cacheinfo 100644 <blob-hash> <filename>
。
:::danger
cacheinfo 是一个git 存储的十六位的文件模式,这个模式遵循 POSIX 类型和模式 的布局
:::
PS D:\code\cs61B\repo_2> git update-index --add --cacheinfo 10064 993dc4dfb4891ea9d1273309e9d8b57f8895552f my_file.txt
查看文件结构,多了一个名为index
的新文件,这就是著名的暂存区。
PS D:\code\cs61B\repo_2> tree /f
卷 Data 的文件夹 PATH 列表
卷序列号为 FA2A-8CFF
D:.
└─.git
│ HEAD
│ index
│
├─objects
│ └─99
│ 3dc4dfb4891ea9d1273309e9d8b57f8895552f
│
└─refs
└─heads
此时执行git status
PS D:\code\cs61B\repo_2> git status
On branch refs/head/main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: my_file.txt
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: my_file.txt
这里发生了两件事。
第一件事,我们可以在changes to be committed
中看到绿色的new file: my_file.txt
。这是因为 索引 中有了 new_file.txt
,它正等着被提交。
第二件事,我们可以看到红色的 deleted: my_file.txt
——因为 git 相信 my_file.txt
这个 文件 已经被删除了,并且它没有被暂存。
将那个 blob 的内容写入我们文件系统中名为 my_file.txt
的文件,我们可以很容易地解决这个问题:
PS D:\code\cs61B\repo_2> echo "git is awesome" > my_file.txt
PS D:\code\cs61B\repo_2> git status
On branch refs/head/main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: my_file.txt
执行 git status
后,它将不再出现在红色内容中
用git write-tree
将暂存区内容生成树对象
PS D:\code\cs61B\repo_2> git write-tree
78a8dfda629abd530a17c4a0f01981d089f299e0
PS D:\code\cs61B\repo_2> git cat-file -p 78a8
100644 blob 993dc4dfb4891ea9d1273309e9d8b57f8895552f my_file.txt
PS D:\code\cs61B\repo_2> git cat-file -t 78a8
tree
用git commit-tree
创建树对象的提交
PS D:\code\cs61B\repo_2> git commit-tree 78a8 -m "First message"
f9313878c0b9c7e4befca627238fa0c7766e12d9
PS D:\code\cs61B\repo_2> git cat-file -p f931
tree 78a8dfda629abd530a17c4a0f01981d089f299e0
author zdkk <1040893382@qq.com> 1666185896 +0800
committer zdkk <1040893382@qq.com> 1666185896 +0800
First message
PS D:\code\cs61B\repo_2> git cat-file -t f931
commit
此时查看状态git status
PS D:\code\cs61B\repo_2> git status
On branch refs/head/main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: my_file.txt
仍显示未提交,为什么呢?git
需要知道最近一次提交,才能知道文件已经被提交
也就是说需要将HEAD引用指向最近提交
PS D:\code\cs61B\repo_2> cat .git/HEAD
ref: refs/heads/main
当前HEAD指向main
引用,但是main
在哪里呢?我们还没有创建它
使用git update-ref
命令将main
指向最近的提交对象
PS D:\code\cs61B\repo_2> git update-ref refs/heads/main f9313878c0b9c7e4befca627238fa0c7766e12d9
再次查看git status
以及git log
PS D:\code\cs61B\repo_2> git status
On branch main
nothing to commit, working tree clean
PS D:\code\cs61B\repo_2> git log
commit f9313878c0b9c7e4befca627238fa0c7766e12d9 (HEAD -> main)
Author: zdkk <1040893382@qq.com>
Date: Wed Oct 19 21:24:56 2022 +0800
First message
至此,成功创建出了一个提交。
实现git branch
和git checkout
与创建main
类似,使用git update-ref
创建一个test
分支
PS D:\code\cs61B\repo_2> git update-ref refs/heads/test f9313878c0b9c7e4befca627238fa0c7766e12d9
可以看出,我们确实创建了一个分支,只不过此时与main
指向同一个提交对象
使用git symbolic-ref
查看,更改HEAD指向
PS D:\code\cs61B\repo_2> git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
PS D:\code\cs61B\repo_2> git symbolic-ref HEAD refs/heads/test
PS D:\code\cs61B\repo_2> git status
On branch test
nothing to commit, working tree clean
PS D:\code\cs61B\repo_2>
用类似的操作在test
分支上进行一次提交
可以看到,新的提交并没有以之前的提交作为父提交,需要手动指定
但是执行git log
后,最新提交仍显示之前的一次,需要手动更改
至此,手动创建分支,切换分支的目标也完成了。