借助AI学习开源代码git0.7之编译和使用

如何学习优秀的开源代码?目前大部分的优秀开源代码,代码量都已经非常庞大,比如git。以git为例,git最新版本代码有279814行,

而git0.7版本已经大部分实现了现在git版本的基本功能,而代码量却只有4950行,

借助ai工具帮忙分析和整理,加上自己的代码阅读和学习验证,就可以从这些开源大神的代码中学到很多,从而提高自己。

学习源码之前,先编译和研究下现有编译的程序的使用。

编译

本人使用的笔记本是macbook,所以下面的是在macsos下编译,window和linux需自行验证。

执行make命令,报错如下:

"编译失败了,错误信息是 openssl/sha.h: No such file or directory。"

Makefile 默认使用 OpenSSL 的 SHA1 实现,但我的macos环境中没有安装OpenSSL的开发库,

不过项目本身在mozilla-sha1/和ppc/目录下提供了SHA1的实现。

可以修改Makefile来使用这些内置的实现。

修改Makefile

修改如下:

复制代码
diff --git a/cpp/git-0.7/Makefile b/cpp/git-0.7/Makefile
index a4987f3..aa52a05 100755
--- a/cpp/git-0.7/Makefile
+++ b/cpp/git-0.7/Makefile
@@ -39,7 +39,7 @@ LIB_H += diff.h
 LIB_OBJS += diff.o

 LIBS = $(LIB_FILE)
-LIBS += -lz -lcrypto
+LIBS += -lz

 ifdef MOZILLA_SHA1
   SHA1_HEADER="mozilla-sha1/sha1.h"
@@ -50,7 +50,7 @@ ifdef PPC_SHA1
   LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
 else
   SHA1_HEADER=<openssl/sha.h>
-  LIBS += -lssl
+  LIBS += -lssl -lcrypto
 endif
 endif

重新编译

make MOZILLA_SHA1=1

ok,编译成功了。

会在当前目录生成很多git-*的可执行程序。

0.7版本的git,命令都是以git-开头的,比如git-init-db,git-update-cache,git-write-tree,git-commit-tree等。不像现在的git,命令都是git开头的,比如git init,git add,git commit等。

学习使用

先使用,才能更好地去学习源码。把当前目录加入PATH中方便使用命令(后续命令都是按加入PATH中)。

根据 README 中的 "Workflow" 部分,一个基本的使用流程如下:

第一步:初始化一个新的 "git" 仓库

创建一个 .git 目录,里面包含了对象数据库 (.git/objects) 和其他必要的文件。

复制代码
mkdir ~/git_test
cd ~/git_test
git-init-db

第二步:将文件添加到暂存区 (index)

创建一个测试的新文件 hello.txt。

  1. touch hello.txt
  2. echo "hello world" > hello.txt
  3. git-update-cache --add hello.txt

其中git-update-cache命令会:

  1. 为 hello.txt 创建一个 blob 对象,并将其存入对象数据库。
  2. 在 index 文件中记录 hello.txt 的信息(文件名、权限、SHA1 等)。

第三步:创建一个 tree 对象

tree 对象代表了当前暂存区 (index) 的状态。

git-write-tree

这个命令会输出一个40个字符的SHA1哈希,这就是新创建的tree对象的 ID。需要记下这个ID。

第四步:创建一个 commit 对象

这个 commit 对象会将上一步创建的 tree 对象与一个提交信息和父提交(如果有的话)关联起来。

  1. 假设上一步得到的 tree SHA1 是 <tree_sha1>
  2. -p <parent_sha1> 是可选的,第一次提交没有父提交
  3. echo "Initial commit" | ./git-commit-tree <tree_sha1>

注意git0.7这个版本,tree_sha1是需要输入完整的字符的。

这个命令会输出一个新的 SHA1 哈希,这是 commit 对象的 ID。可以将这个ID保存到一个文件里,比如.git/HEAD,来跟踪当前的分支。

其他常用命令

  1. git-cat-file

    * 功能:

    1. 显示对象类型 (-t 选项):

    * 给定一个对象的 SHA1 哈希,它会告诉你这个对象是 blob (文件内容)、tree (目录结构) 还是 commit (提交记录)。

    1. 显示对象内容 (指定类型):

    * 给定一个对象的 SHA1 哈希和其类型(blob、tree 或 commit),它会打印出该对象的原始内容。

    * 用法:

    git-cat-file -t 查看对象类型。

    git-cat-file 查看对象内容

  2. git-ls-tree

    * 功能:

    1. 列出 tree 对象的内容: 它会解析一个 tree 对象的二进制数据,并以人类可读的格式显示其包含的条目。

    2. 显示文件和子目录: 对于 tree 对象中的每个条目,它会显示其模式(权限)、类型(blob 或 tree)、SHA1 哈希以及对应的文件名或目录名。

    3. 递归显示 (可能): 现代 Git 的 ls-tree 命令通常支持递归显示子目录内容,这个早期版本可能也有类似的功能.

* 用法: git-ls-tree <tree_sha1> 这会列出 tree 对象中的文件和目录。

  1. git-read-tree
    * 功能:
    1. 更新暂存区: 它的主要作用是用一个指定的 tree 对象所代表的目录结构和文件内容来完全替换或更新当前的暂存区(.git/index 文件)。
    2. 准备工作目录: 当你需要将仓库历史中的某个特定状态(由一个 tree 对象表示)恢复到暂存区时,git-read-tree
      是第一步。例如,在切换分支、合并或检出旧版本时,你首先会使用 git-read-tree 来更新暂存区,然后可能再使用 git-checkout-cache 将暂存区的内容写入工作目录。

* 用法: git-read-tree <tree_sha1>

<tree_sha1>: 你想要加载到暂存区中的 tree 对象的 40 位 SHA1 哈希值。git-read-tree<tree_sha1>这会用指定的tree对象更新 index。

  1. git-checkout-cache

* 功能:

  1. 检出 index 中的文件: 它会从 index 中检出文件到工作目录,类似于 git checkout。

  2. 检出 index 中的所有文件: 它会检出 index 中的所有文件到工作目录。

* 用法: git-checkout-cache -a 这会检出 index 中的所有文件到工作目录。

  1. git-diff-files

    * 功能: 比较工作目录中的文件与暂存区(index)中的对应文件之间的差异。

    * 用法: git-diff-files 这会显示工作目录中所有已修改但尚未添加到暂存区的文件差异。

  2. git-diff-tree

    * 功能: 比较两个 tree 对象之间的差异,或者一个 tree 对象与工作目录/暂存区之间的差异。

    * 用法:

    git-diff-tree <tree_sha1_1> <tree_sha1_2>

    比较两个 tree 对象

    git-diff-tree <tree_sha1>

    比较一个 tree 对象与当前暂存区/工作目录 (具体行为可能需要查看源码或帮助)

  3. git-rev-tree

    * 功能: 遍历一个 tree 对象及其所有子对象(包括 blob 和嵌套的 tree),并打印它们的 SHA1 哈希和路径。

    * 用法: git-rev-tree <tree_sha1> 这类似于 git ls-tree -r 的功能。

  4. git-show-files

    * 功能: 显示暂存区(index)中所有文件的信息,包括模式、SHA1 和文件名。

    * 用法: git-show-files 这类似于 git ls-files --stage。

  5. git-check-files

    * 功能: 检查工作目录中的文件是否与暂存区中的文件匹配。它会报告哪些文件在工作目录中被修改、删除或新增。

    * 用法: git-check-files

  6. git-merge-base

    * 功能: 查找两个或多个提交(commit)的最近共同祖先。这是进行三方合并(three-way merge)的基础。

    * 用法: git-merge-base <commit_sha1_1> <commit_sha1_2> 会输出共同祖先的 SHA1 哈希。

  7. git-merge-cache

    * 功能: 执行三方合并,将三个 tree 对象(通常是共同祖先、分支 A 和分支 B)合并到暂存区(index)中。

    * 用法: git-merge-cache <base_tree_sha1> <our_tree_sha1> <their_tree_sha1>

    这个命令会将合并结果写入暂存区。如果存在冲突,暂存区会包含冲突标记,需要手动解决。

  8. git-unpack-file

    * 功能: 从对象数据库中解压一个 blob 对象并将其内容写入标准输出。

    * 用法: git-unpack-file <blob_sha1> > output_file.txt

  9. git-export

    * 功能: 将一个 tree 对象的内容导出到指定目录。

    * 用法: git-export <tree_sha1> <output_directory>

  10. git-diff-cache

    * 功能: 比较暂存区(index)与一个 tree 对象之间的差异。

    * 用法: git-diff-cache <tree_sha1>

  11. git-rev-list

    * 功能: 遍历提交历史,并以逆序(从最新到最旧)打印提交的 SHA1 哈希。

    * 用法: git-rev-list <commit_sha1> 可以用来查看一个提交的所有祖先。

  12. git-mktag

    * 功能: 创建一个 tag 对象。在 Git 中,标签可以指向一个提交、一个树或一个 blob,通常用于标记重要的版本。

    * 用法: echo "My tag message" | ./git-mktag <object_sha1> <object_type> 它会输出新创建的 tag 对象的 SHA1 哈希。

  13. git-tar-tree

    * 功能: 将一个 tree 对象的内容打包成一个 tar 归档文件。

    * 用法: git-tar-tree <tree_sha1> > archive.tar

总结一下,一个完整的从无到有的提交流程是:(fish shell为例)

  1. git-init-db
  2. 创建或修改文件
  3. git-update-cache --add ...
  4. set -x TREE_ID $(git-write-tree)
  5. set -x COMMIT_ID (echo "My commit message" \| git-commit-tree TREE_ID)
  6. echo $COMMIT_ID > .git/HEAD

这就是这个早期 git 0.7版本的基本用法。它比现代的git要底层和手动得多,但核心概念是一致的。

相关推荐
2303_Alpha4 天前
SpringBoot
笔记·学习
萘柰奈4 天前
Unity学习----【进阶】TextMeshPro学习(三)--进阶知识点(TMP基础设置,材质球相关,两个辅助工具类)
学习·unity
沐矢羽4 天前
Tomcat PUT方法任意写文件漏洞学习
学习·tomcat
好奇龙猫4 天前
日语学习-日语知识点小记-进阶-JLPT-N1阶段蓝宝书,共120语法(10):91-100语法+考え方13
学习
向阳花开_miemie4 天前
Android音频学习(十八)——混音流程
学习·音视频
工大一只猿4 天前
51单片机学习
嵌入式硬件·学习·51单片机
c0d1ng4 天前
量子计算学习(第十四周周报)
学习·量子计算
Hello_Embed4 天前
STM32HAL 快速入门(二十):UART 中断改进 —— 环形缓冲区解决数据丢失
笔记·stm32·单片机·学习·嵌入式软件
咸甜适中4 天前
rust语言 (1.88) 学习笔记:客户端和服务器端同在一个项目中
笔记·学习·rust
Magnetic_h4 天前
【iOS】设计模式复习
笔记·学习·ios·设计模式·objective-c·cocoa