前言
Git作为目前最流行的代码版本管理工具,是DevOps工具链中的核心工具之一。DevOps工程师是Git的重度使用者,难免在使用中会碰到一些从文档层面不易理解或解决的问题,需要从源码层面进行分析。本小文旨在了解Git源码基础架构,能快速定位需要分析的代码模块,并通过IDE进行调试分析。
Git代码结构
common main
git源码中包含好多个git相关程序,他们的启动过程是一致的,可以复用一套代码。git为此设计了一个 common main结构,原文说明如下:
* There are certain house-keeping tasks that need to be performed at
the very beginning of any Git program, and programs that are not
built-in commands had to do them exactly the same way as "git"
potty does. It was easy to make mistakes in one-off standalone
programs (like test helpers). A common "main()" function that
calls cmd_main() of individual program has been introduced to
make it harder to make mistakes.
AI 代码解读
具体的实现是:
1、在common-main.c中定义通用的main函数,里面调用 cmd_main
2、各个git程序在编译时链接上面这个编译出来的cmd-main.o
3、各个git程序定义各自的cmd_main
builtin commands
使用过git的同学都知道,git有很多子命令,譬如 checkout, add, commit, status, push等等。执行 git xxx 和执行 git-xxx 的效果是一样的。
这些子命令在git源码里叫builtin,我们来看看 builtin 是怎么实现的。
首先看编译过程,从顶层的Makefile看到如下生成语句:
$(BUILT_INS): git$X
$(QUIET_BUILT_IN)$(RM) $@ && \
ln $< $@ 2>/dev/null || \
ln -s $< $@ 2>/dev/null || \
cp $< $@
AI 代码解读
builtin是git的链接或是拷贝而来的,实际是一个东西。
在代码层面,git.c 维护一个builtin的清单,
static struct cmd_struct commands[] = {
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "am", cmd_am, RUN_SETUP | NEED_WORK_TREE },
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
{ "archive", cmd_archive },
{ "bisect--helper", cmd_bisect__helper, RUN_SETUP },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP },
{ "bundle", cmd_bundle, RUN_SETUP_GENTLY },
{ "cat-file", cmd_cat_file, RUN_SETUP },
... ...
}
AI 代码解读
cmd_struct的第一个字段是子命令的名称,第二个字段是具体执行函数。get_builtin 函数根据名称找到结构,然后run_builtin执行结构里的命令。
所有的builtin的源码都在builtin子目录下,譬如builtin/add.c 对应 git add 子命令,里面定义cmd_add函数执行具体的操作
git代码调试
调试的前提是能编译通过,所以需要先安装依赖的包:
$ sudo apt-get install libssl-dev zlib1g-dev libcurl4-openssl-dev
还有个小细节,git的源码默认是按-O2编译的,会导致在Eclipse调试的时候查看变量值显示 optimized out, 很不方便,所以需要更改编译选项。
编译过程是通过Makefile组织的,我们需要修改Makefile。Makefile里有引入configure生成的configure.mak.autogen, 里面也有编译选项,所以需要同时改configure和Makefile
editconfigureandMakefile,from−O2to−O0 ./configure
makeclean make all