天天看点

Git源码调试

前言

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.           

具体的实现是:

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 $< $@           

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 },
        ... ...
}           

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

$ edit configure and Makefile , from -O2 to -O0

$ ./configure

$ make clean

$ make all