三大对象:

    • blob数据对象 git hash-object
    • tree树对象 git update-index, git write-tree
    • commit提交对象 git commit-tree

    手动实现git init``git add``git commit
    自定义.git下各种目录和文件
    HEAD指向main

    1. PS D:\code\cs61B\repo_2> echo "ref: refs/heads/main" > .git/HEAD

    创建数据对象

    1. PS D:\code\cs61B\repo_2> echo "git is awesome" | git hash-object --stdin -w
    2. 993dc4dfb4891ea9d1273309e9d8b57f8895552f
    3. PS D:\code\cs61B\repo_2> git cat-file -p 993d
    4. git is awesome
    5. PS D:\code\cs61B\repo_2> git cat-file -t 993d
    6. blob

    创建 blob 这个过程通常发生在我们将一些东西添加到 暂存区 的时候——也就是我们使用 git add 的时候

    跟踪这个文件——把它添加到 暂存区。为此,我们可以使用底层命令 git update-index,例如:git update-index --add --cacheinfo 100644 <blob-hash> <filename>。 :::danger cacheinfo 是一个git 存储的十六位的文件模式,这个模式遵循 POSIX 类型和模式 的布局 :::

    1. PS D:\code\cs61B\repo_2> git update-index --add --cacheinfo 10064 993dc4dfb4891ea9d1273309e9d8b57f8895552f my_file.txt

    查看文件结构,多了一个名为index的新文件,这就是著名的暂存区。

    1. PS D:\code\cs61B\repo_2> tree /f
    2. Data 的文件夹 PATH 列表
    3. 卷序列号为 FA2A-8CFF
    4. D:.
    5. └─.git
    6. HEAD
    7. index
    8. ├─objects
    9. └─99
    10. 3dc4dfb4891ea9d1273309e9d8b57f8895552f
    11. └─refs
    12. └─heads

    此时执行git status

    1. PS D:\code\cs61B\repo_2> git status
    2. On branch refs/head/main
    3. No commits yet
    4. Changes to be committed:
    5. (use "git rm --cached <file>..." to unstage)
    6. new file: my_file.txt
    7. Changes not staged for commit:
    8. (use "git add/rm <file>..." to update what will be committed)
    9. (use "git restore <file>..." to discard changes in working directory)
    10. 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的文件,我们可以很容易地解决这个问题:

    1. PS D:\code\cs61B\repo_2> echo "git is awesome" > my_file.txt
    2. PS D:\code\cs61B\repo_2> git status
    3. On branch refs/head/main
    4. No commits yet
    5. Changes to be committed:
    6. (use "git rm --cached <file>..." to unstage)
    7. new file: my_file.txt

    执行 git status后,它将不再出现在红色内容中

    git write-tree将暂存区内容生成树对象

    1. PS D:\code\cs61B\repo_2> git write-tree
    2. 78a8dfda629abd530a17c4a0f01981d089f299e0
    3. PS D:\code\cs61B\repo_2> git cat-file -p 78a8
    4. 100644 blob 993dc4dfb4891ea9d1273309e9d8b57f8895552f my_file.txt
    5. PS D:\code\cs61B\repo_2> git cat-file -t 78a8
    6. tree

    git commit-tree创建树对象的提交

    1. PS D:\code\cs61B\repo_2> git commit-tree 78a8 -m "First message"
    2. f9313878c0b9c7e4befca627238fa0c7766e12d9
    3. PS D:\code\cs61B\repo_2> git cat-file -p f931
    4. tree 78a8dfda629abd530a17c4a0f01981d089f299e0
    5. author zdkk <1040893382@qq.com> 1666185896 +0800
    6. committer zdkk <1040893382@qq.com> 1666185896 +0800
    7. First message
    8. PS D:\code\cs61B\repo_2> git cat-file -t f931
    9. commit

    此时查看状态git status

    1. PS D:\code\cs61B\repo_2> git status
    2. On branch refs/head/main
    3. No commits yet
    4. Changes to be committed:
    5. (use "git rm --cached <file>..." to unstage)
    6. new file: my_file.txt

    仍显示未提交,为什么呢?
    git需要知道最近一次提交,才能知道文件已经被提交
    也就是说需要将HEAD引用指向最近提交

    1. PS D:\code\cs61B\repo_2> cat .git/HEAD
    2. ref: refs/heads/main

    当前HEAD指向main引用,但是main在哪里呢?我们还没有创建它
    使用git update-ref命令将main指向最近的提交对象

    1. PS D:\code\cs61B\repo_2> git update-ref refs/heads/main f9313878c0b9c7e4befca627238fa0c7766e12d9

    再次查看git status以及git log

    1. PS D:\code\cs61B\repo_2> git status
    2. On branch main
    3. nothing to commit, working tree clean
    4. PS D:\code\cs61B\repo_2> git log
    5. commit f9313878c0b9c7e4befca627238fa0c7766e12d9 (HEAD -> main)
    6. Author: zdkk <1040893382@qq.com>
    7. Date: Wed Oct 19 21:24:56 2022 +0800
    8. First message

    至此,成功创建出了一个提交。

    实现git branchgit checkout

    与创建main类似,使用git update-ref创建一个test分支

    1. PS D:\code\cs61B\repo_2> git update-ref refs/heads/test f9313878c0b9c7e4befca627238fa0c7766e12d9

    image.png
    可以看出,我们确实创建了一个分支,只不过此时与main指向同一个提交对象

    使用git symbolic-ref查看,更改HEAD指向

    1. PS D:\code\cs61B\repo_2> git symbolic-ref HEAD test
    2. fatal: Refusing to point HEAD outside of refs/
    3. PS D:\code\cs61B\repo_2> git symbolic-ref HEAD refs/heads/test
    4. PS D:\code\cs61B\repo_2> git status
    5. On branch test
    6. nothing to commit, working tree clean
    7. PS D:\code\cs61B\repo_2>

    image.png

    用类似的操作在test分支上进行一次提交
    image.png

    可以看到,新的提交并没有以之前的提交作为父提交,需要手动指定
    image.png

    但是执行git log后,最新提交仍显示之前的一次,需要手动更改

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