用git bisect寻找程序中引入change的位置
提前声明,本文可以说和Qt关系很大, 也可以说和Qt毫无关系,如果对git没兴趣的看官可自行绕过…
git是目前Qt及其相关项目开发官方使用的代码管控工具, 我们在前面的blog中已经介绍了如果用git访问Qt项目和QtCreator项目, 详细的信息可以在下面两篇帖子中找到:
从Qt仓库获取最新代码的新手指南
QtCreator官方Git上手指南
要说git确实是个不错的工具, 如果仅仅用它做代码版本管理真有点屈才。 本文就介绍一个git的好功能, 希望对大家有用。
Git bisect
bisect这个关键字应该写成bi-sect大概更好理解, 学过算法的人应该对这个“bi-”不陌生吧? 对了,就是“二分”的意思。 顾名思义, 这个bi-sect就是做代码的二分, 而且是在两个change之间做二分。 这种二分有什么用处呢? 聪明的同学应该已经想到了吧? 既然是在change之间做二分当然是为了定位某个change, 所以一般情况下这个bisect用于寻找某项对功能产生影响的修改, 如假设某个change给代码里引入了bug, 我们可以通过在好版本和坏版本之间做二分最终定位到引入bug的代码修改; 同理, 如果某个bug被修正了, 我们的当务之急是找到bugfix, 但是在每天几十几百个增加的修改中寻找一个change那无异于大浪淘沙大海捞针(举个例子, 笔者统计了一下, 从Qt4.5.3到Qt4.6.0之间的change数量是超过五千个…请大家闭上眼睛想象一下如果在这些change里找到你感兴趣的那个change还有什么好方法。), 这时二分定位就显得十分必要了。
Git bisect HowTo
刚才说到在Qt4.5.3和Qt4.6.0之间有超过五千个change, 大家可能觉得bisect应该是项非常庞大的工程, 其实也不尽然。 二分查找本质上就是不停的除以二, 即使是五千多这么个让人看着很心寒的数字,除个十来次也差不多了。
在开始bisect之前我们先要找出有差异的两个版本label, 这一步比较容易,在你发现差异的同时想必已经对有差异的两个版本号了然于胸了吧。 Qt的发布版本和git的分支label之间有对应的关系, 如Qt4.5.3就对应v4.5.3这个label。
下面展开bisect旅程, 假设在4.6.0里修正了4.5.3的一个bug, 我们要找到这个bug的fix。 进入项目下载目录运行下面的命令:
$ git bisect start
确认代码二分的起始点和结束点:
$ git bisect bad v4.5.3
$ git bisect good v4.6.0
这时git会自动显示出这两个label之间的change数, 需要做git bisect的次数,并自动二分, 然后下载二分后的代码。 然后我们要基于当前的git代码状态编译出一个版本,验证此版本是good还是bad。 验证之后只需要运行git bisect good/bad (根据实际情况给good或者bad), git就会继续自动二分的过程, 直至完全定位, 整个过程十分简单。
这里边只剩下验证的过程可以优化了, 有不少小技巧。 以验证Qt版本为例, 建议用shadow build的方法为git bisect单独建立一个编译目录。 全新的编译过程比较耗时,我们可以在configure的时候通过加一些参数去掉一部份module节省编译时间, 一般笔者不用这么麻烦的方法。 笔者用的方法是完全configure但有选择的编译:
$ cd build_dir
$ $QT_SRC_DIR/configure -debug -confirm-license -commercial
$ make -C src/tools/bootstrap;make -C src/tools/uic; make -C src/tools/moc; make -C src/tools/rcc
$ make -C src/corelib;make -C src/gui
$ cd src/corelib;sudo make install
$ cd ../gui;sudo make install
$ cp ../bin/qmake /usr/local/Trolltech/Qt-xxx/bin
$ cp -r ../mkspecs /usr/local/Trolltech/Qt-xxx/
一般诊断gui库中的问题,用上面的编译步骤就足够了,只需要编译出QtCore和QtGui两个库即可, 甚至多数情况下只需要重新编译Gui库。 当然大家要根据自己需要诊断的内容酌情添加其它的工具或模块。
如果是git bisect之后再次编译就更简单, 可以用Qt自带的脚本syncqt更新头文件, 然后只编译更改的部分:
$cd build_dir
$ bin/sycqt; make -C src/corelib; make -C src/gui
$ cd src/corelib; sudo make install
$ cd ../gui; sudo make install
偶尔还需要重新编译moc和uic等工具, 根据实际情况来。 通过这样的方法可以大幅度减少验证时间, 让你在很短的时间里就定位到具体的change上。
另外还有两点值得一提的地方, 一是Qt默认的安装目录用版本号来区分, 在我们上面的bisect过程中随时都有可能遇到版本号发生变化的情况,有可能进而影响到Qt默认的安装路径。 最好是在configure的时候加个-prefix选项, 以免造成不必要的问题。
另外一点是git bisect还有个很有用的选项叫 git bisect visual, 该命令是用可视化的方式显示出相关的change及其注释, 让我们能在众多change看到需要的内容, 这个功能在bisect到接近完成阶段的时候特别有用。 用数字说话大家就明白了, 我们可能经过bisect 5次就剩下十几个change需要验证, 但这十几个change却要用另外的4、5次bisect才能完成, 有点得不偿失, 这时我们可以直接运行git bisect visual, 看看这十几个change都关乎哪些文件,从它们的描述和涉及的文件往往很容易就看到哪个是我们要找的东西了, 这样可以节省4、5次bisect的时间。
在完成bisect之后运行git bisect reset, git会自动把代码reset到bisect开始之前的状态, 完全不用我们费多少脑筋。
Tags: bisect, git, Qt, syncqt
This entry was posted
on Monday, March 29th, 2010 at 7:07 PM and is filed under Linux技术, Qt技术, Windows技术.
You can follow any responses to this entry through the RSS 2.0 feed.
You can leave a response, or trackback from your own site.
今天又用了一下这个方法, 定位了一个bug