借助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要底层和手动得多,但核心概念是一致的。

相关推荐
西岸行者6 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意6 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码6 天前
嵌入式学习路线
学习
毛小茛6 天前
计算机系统概论——校验码
学习
babe小鑫6 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms6 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下6 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。6 天前
2026.2.25监控学习
学习
im_AMBER6 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J6 天前
从“Hello World“ 开始 C++
c语言·c++·学习