一、前言

  • 了解了管理或者维护 Git 仓库、实现代码控制所需的大多数日常命令和工作流程,尝试跟了踪和提交文件的基本操作,并且掌握了暂存区和轻量级地分支及合并的威力。如果想进一步对 Git 深入学习,可以学习一些 Git 更加强大的功能,这些功能可能并不会在日常操作中使用,但在某些时候可能还是会起到一定的关键性作用。
  • 如果还不清楚 Git 的基础使用流程、分支的管理、托管服务器的技术以及分布式工作流程等相关的技术和能力,请参考博客:
    • Git之深入解析Git的安装流程与初次运行Git前的环境配置;
    • Git之深入解析本地仓库的基本操作·仓库的获取更新和提交历史的查看撤销以及标签别名的使用;
    • Git之深入解析Git的杀手级特性·分支管理与变基的开发工作流以及远程分支的跟踪;
    • Git之深入解析如何运行自己的Git仓库托管服务器;
    • Git之深入解析如何使用Git的分布式工作流程与如何管理多人开发贡献的项目。
  • 除了主要作为版本控制工具外,Git 也提供了几个命令来辅助我们调试项目源码中的问题。由于 Git 被设计成适用于几乎所有类型的内容,这些工具也相当通用,但它们往往可以在出现问题时帮助我们找到 bug 或者原因。

二、文件标注

  • 如果在追踪代码中的一个 bug,并且想知道是什么时候以及为何会引入,文件标注通常是最好用的工具,它能显示任何文件中每行最后一次修改的提交记录。所以,如果在代码中看到一个有 bug 的方法,可以使用 git blame 标注这个文件,查看哪一次提交引入了这行。
  • 如下所示,用 git blame 确定了 Linux 内核源码顶层的 Makefile 中每一行分别来自哪个提交和提交者,此外用 -L 选项还可以将标注的输出限制为该文件中的第 69 行到第 82 行:
$ git blame -L 69,82 Makefile
b8b0618cf6fab (Cheng Renquan  2019-05-26 16:03:07 +0800 69) ifeq ("$(origin V)", "command line")
b8b0618cf6fab (Cheng Renquan  2019-05-26 16:03:07 +0800 70)   KBUILD_VERBOSE = $(V)
^1da177e4c3f4 (Linus Torvalds 2020-04-16 15:20:36 -0700 71) endif
^1da177e4c3f4 (Linus Torvalds 2020-04-16 15:20:36 -0700 72) ifndef KBUILD_VERBOSE
^1da177e4c3f4 (Linus Torvalds 2020-04-16 15:20:36 -0700 73)   KBUILD_VERBOSE = 0
^1da177e4c3f4 (Linus Torvalds 2020-04-16 15:20:36 -0700 74) endif
^1da177e4c3f4 (Linus Torvalds 2020-04-16 15:20:36 -0700 75)
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 76) ifeq ($(KBUILD_VERBOSE),1)
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 77)   quiet =
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 78)   Q =
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 79) else
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 80)   quiet=quiet_
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 81)   Q = @
066b7ed955808 (Michal Marek   2020-07-04 14:29:30 +0200 82) endif
  • 请注意,第一个字段是最后一次修改该行的提交的部分 SHA-1 值。接下来两个字段的值是从提交中提取出来的,作者的名字以及提交的时间,所以就可以很轻易地知道是谁在什么时候修改了那一行。然后就是行号和文件内容,注意一下 ^1da177e4c3f4 这个提交的几行,其中的前缀 ^ 指出了该文件自第一次提交后从未修改的那些行。这会带来小小的困惑,因为目前至少已经看到三种 Git 使用 ^ 来修饰一个提交的 SHA-1 值的不同含义,但这里确实就是这个意思。
  • 另一件比较酷的事情是 Git 不会显式地记录文件的重命名,它会记录快照,然后在事后尝试计算出重命名的动作,这其中有一个很有意思的特性就是可以让 Git 找出所有的代码移动,如果在 git blame 后面加上一个 -C,Git 会分析正在标注的文件,并且尝试找出文件中从别的地方复制过来的代码片段的原始出处。比如,将 GITServerHandler.m 这个文件拆分为数个文件,其中一个文件是 GITPackUpload.m,对 GITPackUpload.m 执行带 -C 参数的 blame 命令,就可以看到代码块的原始出处:
$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2019-01-04 141)
f344f58d GITServerHandler.m (Scott 2019-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2019-01-04 143) {70befddd GITServerHandler.m (Scott 2019-03-22 144)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 145)
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 146)         NSString *parentSha;
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 147)         GITCommit *commit = [g
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 148)
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 149)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2019-03-24 150)
56ef2caf GITServerHandler.m (Scott 2019-01-05 151)         if(commit) {56ef2caf GITServerHandler.m (Scott 2019-01-05 152)                 [refDict setOb
56ef2caf GITServerHandler.m (Scott 2019-01-05 153)
  • 这个功能很有用,通常来说,我们会认为复制代码过来的那个提交是最原始的提交,因为那是第一次在这个文件中修改了这几行。但 Git 会告诉我们第一次写这几行代码的那个提交才是原始提交,即使这是在另外一个文件里写的。

三、二分查找

  • 当知道问题是在哪里引入的情况下文件标注可以查找问题,如果不知道哪里出了问题,并且自从上次可以正常运行到现在已经有数十个或者上百个提交,这个时候就可以使用 git bisect 来帮助查找。bisect 命令会对你的提交历史进行二分查找来帮助我们尽快找到是哪一个提交引入了问题。
  • 假设刚刚在线上环境部署了我们的代码,接着收到一些 bug 反馈,但这些 bug 在之前的开发环境里没有出现过,这就百思不得其解,我们重新查看了代码,发现这个问题是可以被重现的,但是不知道哪里出了问题。我们可以用“二分法”来找到这个问题。
  • 首先执行 git bisect start 来启动,接着执行 git bisect bad 来告诉系统当前所在的提交是有问题的,然后必须使用 git bisect good <good_commit>,告诉 bisect 已知的最后一次正常状态是哪次提交:
$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on repo
  • Git 发现在标记为正常的提交(v1.0)和当前的错误版本之间有大约 12 次提交,于是 Git 检出中间的那个提交。 现在可以执行测试,看看在这个提交下问题是不是还是存在,如果还存在,说明问题是在这个提交之前引入的;如果问题不存在,说明问题是在这个提交之后引入的。假设测试结果是没有问题的,可以通过 git bisect good 来告诉 Git,然后继续寻找:
$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] secure this thing
  • 现在在另一个提交上了,这个提交是刚刚那个测试通过的提交和有问题的提交的中点,我们再一次执行测试,发现这个提交下是有问题的,因此可以通过 git bisect bad 告诉 Git:
$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] drop exceptions table
  • 这个提交是正常的,现在 Git 拥有的信息已经可以确定引入问题的位置在哪里,它会告诉我们第一个错误提交的 SHA-1 值并显示一些提交说明,以及哪些文件在那次提交里被修改过,这样就可以找出引入 bug 的根源:
$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date:   Tue Jan 27 14:48:32 2009 -0800secure this thing:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M  config
  • 当完成这些操作之后,我们应该执行 git bisect reset 重置你的 HEAD 指针到最开始的位置,否则会停留在一个奇怪的状态:
$ git bisect reset
  • 这是一个可以帮助我们在几分钟内从数百个提交中找到 bug 的强大工具。事实上,如果有一个脚本在项目是正常的情况下返回 0,在不正常的情况下返回非 0,可以使 git bisect 自动化这些操作。首先,设定好项目正常以及不正常所在提交的二分查找范围,可以通过 bisect start 命令的参数来设定这两个提交,第一个参数是项目不正常的提交,第二个参数是项目正常的提交:
$ git bisect start HEAD v1.0
$ git bisect run test-error.sh
  • Git 会自动在每个被检出的提交里执行 test-error.sh,直到找到项目第一个不正常的提交,也可以执行 make 或者 make tests 或者其他东西来进行自动化测试。

Git之深入解析如何使用Git调试项目源码中的问题相关推荐

  1. vue操作dom_vue源码全面解析(四十六)源码中操作DOM的方法集合

    // 查找节点是否存在,如果不存在新建一个div元素返回function query (el) { if (typeof el === 'string') { var selected = docum ...

  2. Git之深入解析如何借助Git的配置方法和钩子机制来自定义Git需求

    一.前言 到目前为止,我们已经了解了 Git 基本的运作机制和使用方式,学习了许多 Git 提供的工具简单且有效地使用它,可以高效地帮助我们工作,提升我们的效率. 如果还不清楚 Git 的基础使用流程 ...

  3. Android逆向之旅---动态方式破解apk前奏篇(Eclipse动态调试smail源码)

    一.前言 今天我们开始apk破解的另外一种方式:动态代码调试破解,之前说的主要采用的是静态方式,步骤也很简单,首先使用apktool来反编译apk,得到smail源码,然后分析smail代码,采用代码 ...

  4. git bash here创建项目无法选择m_由GitLab用户切换引发的某程序员“暴动”,怒而开源项目源码...

    疯狂吐槽,咱也不知道为什么,原来GitHub用的好好的,我自己的项目也会上传到自己的码云,但是,谁想到,今天老大跟我说,让我把一个项目代码传到gitlab上,哎,又要切换账户了,所以,今天分享两部分内 ...

  5. build怎么调试 react_GitHub - bozhouyongqi/debug-react: 本地调试react源码环境

    [TOC] 工欲善其事,必先利其器. 在学习raect源码时,如果能够在浏览器中单步调试,势必会加深理解.其实可以借助webpack的resolve.alias将react等指向本地的目录,这样就不会 ...

  6. build怎么调试 react_React源码下载-本地环境搭建

    前几天有小伙伴和我聊天,谈到现在前端面试越来越难,动不动就是xxx原理,有没有看过xx源码之类的问题, 之后就问我应该怎么来学习现在主流框架的源码,于是有了这一篇文章. 说到使用react那很简单 r ...

  7. 找准切入点,调试看源码,事半功倍

    关注若川视野,回复"pdf" 领取资料,回复"加群",可加群长期交流学习 最近写了很多源码分析相关的文章,React.Vue 都有,想把我阅读源码的一些心得分享 ...

  8. Apache Spark源码走读(九)如何进行代码跟读使用Intellij idea调试Spark源码

    <一>如何进行代码跟读 概要 今天不谈Spark中什么复杂的技术实现,只稍为聊聊如何进行代码跟读.众所周知,Spark使用scala进行开发,由于scala有众多的语法糖,很多时候代码跟着 ...

  9. CLion调试redis6源码

    背景 clion使用cmake来管理编译redis源码,而redis源码本身使用原生的make,因此直接将redis源码导入clion无法直接运行,需要配置cmake. 写c程序大体步骤为: 1).用 ...

最新文章

  1. Windows10远程访问Jupyter notebook
  2. Garbage First
  3. 学习OpenGL:笔记一
  4. Product description search in opportunity line item
  5. Silverlight 动态调用 WebService
  6. vb访问mysql容易死机_VB访问MySQL
  7. Disruptor(无锁并发框架)-发布
  8. hdu1243----最长公共子序列
  9. java8 转 java7,spnego.jar从Java 7切换到Java 8强制转换异常
  10. Android--线程详解
  11. 个人简历小程序(附源码)
  12. 【干货】大学本科生零基础如何开始做发明类竞赛项目
  13. 综合布线干线子系统设计原则
  14. 黑群晖docker清理缓存_嘿群辉 篇五:群辉docker迁移磁盘
  15. 校友会2019中国大学计算机,校友会2019中国大学一流专业排名800强发布,北大清华复旦前三...
  16. Java女生后来_那些主动的女生后来怎么样了?
  17. 实用:常用PPT国内外不错的网站介绍
  18. rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
  19. FileStream与StreamWriter区别
  20. 【STM32】内部温度传感器示例

热门文章

  1. AspNetCore 多环境配置 以及注册 消费Consul
  2. 【app.json】配置说明,不断更新中
  3. 优化:更优雅的异步代码?
  4. 2017-2018-2 20179215 《密码与安全新技术》第5周作业
  5. 第一次作业:艰难的计算机之路
  6. Ruby Regexp
  7. 在线的IDE(compilr)支持图形界面,支持C,C++,JAVA
  8. magento 相关xml功能的介绍
  9. linux双网卡私网,linux双网卡路由配置私网专线
  10. linux如何生成so文件,新人问个问题,莫见笑:关于如何生成so文件,大家多多捧场啊...