三大对象:
blob数据对象git hash-objecttree树对象git update-index, git write-treecommit提交对象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 -w993dc4dfb4891ea9d1273309e9d8b57f8895552fPS D:\code\cs61B\repo_2> git cat-file -p 993dgit is awesomePS D:\code\cs61B\repo_2> git cat-file -t 993dblob
创建 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-8CFFD:.└─.git│ HEAD│ index│├─objects│ └─99│ 3dc4dfb4891ea9d1273309e9d8b57f8895552f│└─refs└─heads
此时执行git status
PS D:\code\cs61B\repo_2> git statusOn branch refs/head/mainNo commits yetChanges to be committed:(use "git rm --cached <file>..." to unstage)new file: my_file.txtChanges 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.txtPS D:\code\cs61B\repo_2> git statusOn branch refs/head/mainNo commits yetChanges 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-tree78a8dfda629abd530a17c4a0f01981d089f299e0PS D:\code\cs61B\repo_2> git cat-file -p 78a8100644 blob 993dc4dfb4891ea9d1273309e9d8b57f8895552f my_file.txtPS D:\code\cs61B\repo_2> git cat-file -t 78a8tree
用git commit-tree创建树对象的提交
PS D:\code\cs61B\repo_2> git commit-tree 78a8 -m "First message"f9313878c0b9c7e4befca627238fa0c7766e12d9PS D:\code\cs61B\repo_2> git cat-file -p f931tree 78a8dfda629abd530a17c4a0f01981d089f299e0author zdkk <1040893382@qq.com> 1666185896 +0800committer zdkk <1040893382@qq.com> 1666185896 +0800First messagePS D:\code\cs61B\repo_2> git cat-file -t f931commit
此时查看状态git status
PS D:\code\cs61B\repo_2> git statusOn branch refs/head/mainNo commits yetChanges 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/HEADref: 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 statusOn branch mainnothing to commit, working tree cleanPS D:\code\cs61B\repo_2> git logcommit f9313878c0b9c7e4befca627238fa0c7766e12d9 (HEAD -> main)Author: zdkk <1040893382@qq.com>Date: Wed Oct 19 21:24:56 2022 +0800First 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 testfatal: Refusing to point HEAD outside of refs/PS D:\code\cs61B\repo_2> git symbolic-ref HEAD refs/heads/testPS D:\code\cs61B\repo_2> git statusOn branch testnothing to commit, working tree cleanPS D:\code\cs61B\repo_2>

用类似的操作在test分支上进行一次提交
可以看到,新的提交并没有以之前的提交作为父提交,需要手动指定
但是执行git log后,最新提交仍显示之前的一次,需要手动更改

至此,手动创建分支,切换分支的目标也完成了。
