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

发布于:2025-07-17 ⋅ 阅读:(24) ⋅ 点赞:(0)

如何学习优秀的开源代码?目前大部分的优秀开源代码,代码量都已经非常庞大,比如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 (提交记录)。
          2. 显示对象内容 (指定类型):
           * 给定一个对象的 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。
   
4. 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要底层和手动得多,但核心概念是一致的。


网站公告

今日签到

点亮在社区的每一天
去签到