【Git教程】(十五)二分法排错 — 概述及使用要求,执行过程及其实现(用二分法人工排错或自动排错),替代解决方案 ~

Git教程 · 二分法排错

  • 1️⃣ 概述
  • 2️⃣ 使用要求
  • 3️⃣ 执行过程及其实现
      • 3.1 用二分法人工排错
      • 3.2 用二分法自动排错
  • 4️⃣ 替代解决方案

在这里插入图片描述

在开发过程中,我们经常会突然遇到一个错误,是之前早期版本在成功通过测试时没有出现过的。这时候,时下较被看好的调试策略是先搜索出我们第一次发现错误时所在的提交。 由于在使用 Git 开展工作时,我们往往会产生许多小型提交,因此可以通过分析其中的变化来快速查找错误的成因。

Git 支持用二分法来搜索引发问题的提交。
二分法是基于二分搜索的一种查找方法。查找的起点是已确认没问题的提交,终点是已明确有错误的提交,两者之间这段提交历史将会被“分半”,位于“中间”的提交会在工作区 中被激活。然后我们会对被激活的提交进行错误检查。接着,再根据是否在被激活提交中找到该错误的情况,再对错误必然会隐藏的那段剩余的提交历史进行重新“分半”,并检查新的 “中间”提交。如此反复,我们最终就会找到第一次出现该错误的提交。在该工作流中,我们会为你演示以下操作。

  • 如何有效地用二分法找出引发问题的提交。
  • 如何用二分法实现自动化排错。

1️⃣ 概述

在下图中,我们将会看到一段提交历史,其中有一个确认无误的提交和已明确出了问题的提交。虽然提交历史并不非得要线性发展,但在出了问题的提交到没有问题的提交之间必须要有一条路径,以说明它们之间的父系关系。

当二分查找进程被启动之后, Git 就会在相关的提交历史的中间位置选择一个合适的提交。该提交将会被执行某种人工测试或脚本测试,然后根据其结果被标记为“good”或“had”。 接着,该二分查找任务会去挑选另一个提交对象,对其进行测试并标记。这个进程会一直重复该动作,直至找到其直系父提交中没有错误的那次提交。

在这里插入图片描述


2️⃣ 使用要求

  • 可重现的错误检测:我们必须要证明相关错误行为的一致性。也就是说,我们要能清楚地识别一个版本是正确还是不正确。对于自动化错误,无论它采用的是测试用例还是脚本,它都必须要能检测到错误。
  • 误差检测的成本不能太高:误差检测必须即快速又便宜。使用二分法进行多故障检测的成本取决于我们要测验的提交数量。如果其需要的时间过长或成本过高,对错误的成因来一次分析性搜索显然会更有效率。

3️⃣ 执行过程及其实现

在开发过程中,我们经常会遇到之前版本中不曾出现过的错误。二分法可以帮助我们在提交历史中定位那个包含错误的提交。

为了演示接下来的这些操作,我们做了一个小型的示范性项目。在该项目中,我们实现了各种数学函数。其中值得一提的是一个计算阶乘的功能。该功能会以列表的形式返回从1到5所有数的阶乘。

> java FactorialMain
Factorial of 1 = 1
Factorial of 2 = 1
Factorial of 3 = 2
Factorial of 4 = 6
Factorial of 5 = 24

3.1 用二分法人工排错

首先,我们要对二分查找的基本过程有个交代,以说明在该测试中所要人工查找的错误成因。

  • 第1步:定义错误标志
    一般情况下,错误往往都是由开发者、测试者或者用户发现的。我们的第一步是要对该错误进行分析和理解,找出该错误的某种标志。
    下面我们来看几个错误标志的例子。

    • 当某个动作或函数调用引发某种异常时,该程序就会被取消执行或显示错误消息。
    • 某个函数返回了包含错误结果的信息项。
    • 某个测试用例执行失败。

    具体到我们这个例子中,3的阶乘可以被视为是一个标志,代表它出错了。
    如你所见,多数情况下我们用单凭分析就足以发现问题的成因了,无须进行二分查找。

  • 第2步:分别找出没问题的和有问题的提交
    该二分查找过程需要我们提供一个没问题的提交和一个出了错的提交。 一个不错的选择是我们可以用最新发行版或者最新历程碑来充当那个确认无误的提交。
    如果我们发现被选中来充当没有问题的提交中也包含了该错误,那就必须去回溯更久远的历史了。
    由于相关错误的信息已经被上报,我们要想找到一个问题提交并不难,但如果想要在一堆没有问题的提交中搜索更多问题提交,我们就务必要找出那个最古老的问题提交了。
    下面是上述例子的日志输出,我们来看看它的提交历史。

    > git log --oneline
    202d25d modulo finished
    e36fead multiply finished
    918ed2f sub finished
    ebe74ld add finished
    87ac59e ComputeFactorial finished
    39cbdc0 init
    

    分析结果表明,提交 87ac59e ComputerFactorial finished 应该是没有问题的,出错的应该是提交202d25d modulo finished

  • 第3步:执行二分法排错
    现在,既然我们已经将错误局限在了提交历史一个区间内,就可以开始用二分查找来进行实际的错误搜索了。
    我们可以通过bisect start 命令来开始二分查找。在这里,我们必须要将问题提交指定为第一个参数,而没有问题的提交则是第二个参数。

    > git bisect start 202d25d 87ac59e
    Bisecting: 1 revision left to test after this(roughly 1 step)
    [918ed2f29a44e468d690fb770aablad2dbaela5a]sub finished
    

    bisect start 命令会将第一个提交标志成 “bad” 提交,第二个则标志为 “good” 提交。 然后接下来,位于这两个提交之间的那个提交(具体到我们的例子中就是提交 918ed2f sub finished) 会被激活。
    现在,工作区中包含了来自某个提交的文件,我们还不不能确定它有没有出问题。由于我们之前已经找到了该错误的标志,该版本的状态目前是可以被测试的。

    > java FactorialMain
    Factorial of  1 =1
    Factorial of  2 =1
    Factorial of  3 =2
    Factorial of  4 =6
    Factorial of  5 =24
    

    但从在工作区中运行 FactorialMain 的结果表明,该错误仍然存在于其中,这意味着当前提交依然是有问题的。
    现在,我们用以下命令中的一个对当前提交进行标志。

    • bisect good: 错误不在其中,该提交确认无误。
    • bisect bad: 错误就在其中,该提交有问题。
    • bisect skip: 当前提交无法被测试。 一般是因为没有被编译或缺失了一些文件,这时 候二分查找进程就会去激活另一个提交来测试。
      在我们的例子中,由于错误还存在于该提交中,所以我们会将其标志为 “bad” 提交。
    >git bisect bad
    Bisecting: 0 revisions  left  to  test  after  this(roughly  0  steps) 
    [ebe741de3366a3fc08fbedfdfa408517dd172ca3]add finished
    

    在 Git 的响应报告中,我们看到目前被激活的是提交 ebe741d add finished。此外, Git 还报告说这是它必须要测试的最后一个提交。
    我们对FactorialComputer 的重新测试表明,该提交中是确认无误的,因此被标志为 “good”提交。

    > git bisect good
    commit 918ed2f29a44e468d690fb770aablad2dbaela5a
    Author:Rene Preissel <rp@eToSquare.de>
    Date: Fri Jun 2408:04:432011 +0200sub finished
    :040000 040000 0e5bfb07e859072a564eaca07346le4a12a0ed61  \
    329e7f864bac874c69be4531452c753cf56be794 M    src
    

    现在,Git 告诉我们提交918ed2f sub finished 才是该错误第一出现的地方。我们现在可以用Git 命令来分析该提交做了哪些修改了(例如git show 918ed2f)。
    最后,我们发现这个例子中阶乘计算只能计算到n-1。
    请注意,在我们启动排错过程之前,必须要将工作区重新设置到当前分支的HEAD 上。
    关于这一点我们将会在下一步骤中做说明。

  • 第4步:停止或取消二分查找
    在成功分析出错误根源,或者决定取消某个二分查找之后,我们还必须要用 bisect reset 命令将工作区中的内容重置回正常的开发版本。

    > git  bisect  reset
    Previous HEAD position was ebe74ld...add finished
    Switched to branch 'master'
    

3.2 用二分法自动排错

在之前的操作序列中,我们测试的是某个提交中是否包含了某个错误,用的是人工测试。

如果我们连对的一个很长历史的区间或者人工测试的成本非常高昂,也可以通过一段脚本来进行自动化测试,让二分查找算法自己去完成它的工作。

  • 第1步:定义错误标志
    错误标志的的方法与人工的二分法排错一样,我们只要确保这些错误标志能被脚本自动检测到即可。

  • 第2步:准备好测试脚本
    如果我们想要进行自动化的二分法排错,就必须要提供一段 shell 脚本。为了能实现错误标志的自动检测,这段shell 脚就本必须要根据指定错误是否存在的情况返回以下不同的退出码。

    • Exit code 0: 表示没有找到错误,二分查找进程应该会将该提交标志为“good”。
    • Exit codes 1-124,126,127 : 表示错误被找到,二分查找进程应该会将该提交标志为“bad”。
    • Exit code 125: 表示测试由于程序可行性的原因没被执行。 一般情况下,是该版本无法被编译。二分查找过程会直接跳过该提交。

    在这里,我们的计算器应用是用Java 编写的。下面我们就将其作为一个例子来演示一下 如何在这类环境中对自动化二分查找进程进行调试。对于其他的开发环境,这段独立的脚本通常要做些相应的调整。

    事实上,我们这段自动化错误检验是通过 JUnit 测试来执行的 ( 你可以从 http://wwwjunit.org 网站上下载到JUnit) 。 它只负责检测3阶乘是否真的是6。如果返回结果为 false, 即视为测试失败。

    public class FactorialBisectTest {@Testpublic void testFactorial(){long result = Computer.factorial(3);Assert.assertEquals(6,result);}
    }
    

    特别提醒:不要忘记该测试要在一个新文件中实现,它不应该被 Git 纳入版本控制。在 二分查找进程中,工作区中会有不同的提交被激活,而且是一个接一个地进行。如果该测试文件也处于 Git 的控制之下,它在旧提交被激活时就不存在了。而且从另一方面来说,非版本文件也应该被抽离在工作区的修改之外。

    另外,自动化的二分查找进程需要我们提供一段 shell 脚本。该 shell 脚本首先必须能编 译我们的Java 源文件,然后再启动test.Ant, 将其用作本例中的构建系统。在该计算机项目中,

    我看可以通过一个名为 build.xml 的构建文件来执行一次纯净的构建过程 (ant clean compile)。另外为了执行二分查找测试,我们还需要另一个名为bisect-build.xml 的构建文件, 它只提供了一个用于启动测试的 target。再次提醒,该文件不能被 Git 纳入版本控制。

    <target name="test"><junit><classpath refid= "build.classpath" /><test name= "FakultaetsBisectTest" haltonerror="true" haltonfailure="true" /></junit> 
    </target>
    

    如果我们想访问不同的 Ant target, 就要有一个名为 bisect-test.sh 的 shell 脚本,这个脚本也不能被 Git 纳入版本控制。

    #!/bin/bash
    ant clean compile
    if [ $? -ne 0]; thenexit 125;
    fi
    ant -f bisect-build.xml
    if [ $? -ne 0]; thenexit 1;
    elseexit 0;
    fi
    

    该脚本会去调用构建文件中的各种构建 target,并检测 Ant 的退出码。测试失败时 Ant 会返回一个大于0的退出码。我们需要将其转换成二分查找进程所需要返回的代码。

    • 如果构建失败,就返回退出码125。
    • 如果测试成功,就返回退出码0。
    • 如果测试失败,就返回退出码1。
  • 第3步:分别找出没问题的和有问题的提交
    在对没问题和有问题提交的搜索方面,这里的流程和人工的过程并没有什么不同。但是, 你也可以用 JUnit 测试来检查错误。举例来说,我们选择提交 87ac59e FactorialCompute finished 来验证一下它确实是没有问题的。

    > git checkout 87ac59e
    > ant -f bisect-build.xml
    Buildfile:bisect-build.xml
    test:
    BUILD SUCCESSFUL
    Total    time:0    seconds
    

    特别提醒: 在完成上述过程之后,请不要忘记将master分支设置成当前活跃分支。

    > git  checkout  master
    
  • 第4步:执行二分法的自动化排错
    在使用自动化排错时,第一次二分查找进程也得要用bisect start 命令来启动。另外,我们还需要将有问题的提交指定为第一参数,没问题的提交为第二参数传递给该命令。

    > git bisect start 202d25d 87ac59e
    Bisecting:1 revision left to test  after this(Roughly 1 step)
    [918ed2f29a44e468d690fb770aablad2dbaela5a]sub finished
    

    然后在用 bisect run命令来执行名为 bisect-test.sh 的 shell 脚本。

    > git bisect run ./bisect-test.sh
    

    下面我们将输出截断,只显示bisect run 命令的最后几行内容。你会很高兴地看到该命令找到了 918ed2f sub finished 是第一个出错的提交。

    ..
    Buildfile:bisect-build.xml
    test:BUILD SUCCESSFUL
    Total time:0 seconds
    918ed2f29a44e468d690fb770aablad2dbaela5a is the first bad commit
    commit 918ed2f29a44e468d690fb770aablad2dbaela5a
    Author:Rene Preissel <rp@eToSquare.de>
    Date: Fri Jun 2408:04:432011 +0200sub finished
    :040000 040000 Oe5bfb07e859072a564eaca07346le4a12a0ed61 \
    329e7f864bac874c69be4531452c753cf56be794 M   src
    bisect run success
    
  • 第5步:完成二分查找操作
    在成功完成排错之后,我们还必须要用bisect reset 命令来结束整个二分查找进程。

    > git bisect reset
    Previous HEAD position was ebe741d...add finished
    Switched to branch 'master!
    

4️⃣ 替代解决方案

用合并操作将测试脚本添加到旧提交中去
上面这个过程的优势在于 Git 在激活新提交的时候将一些未被版本化的文件留在了工作区中。这样一来,我们在旧提交中也可以执行这些“新”的测试脚本了。
当然,我们也可以采用另一种解决方案,就是将测试脚本纳入到一个新分支中(见下图中的 bisect-test 分支)。

在该二分查找的 shell 脚本中,二分查找进程会在每次测试运行之前将bisect-test 分支合并到当前提交中。然后用--nocommit 选项防止其变成一个永久性的提交。

然后待测试完成之后,再用 reset 命令重置掉合并操作所带来的修改。这个操作序列和示例脚本可以在 bisect 命令的在线文档的 Example一节中找到。

这个使用 bisect-test 分支的解决方案不仅可以在我们拥有一个测试用例和新增一个新的测试脚本时发挥作用。也可以用于测试必须要适应现有代码的,例如可能是因为测试中某种审核需要访问的数据在旧提交是不可见的。
但在大多数情况下,我们之前所描述的非版本化文件的方案已经够用了,而且它实现起来相对要更容易一些。



温习回顾上一篇(点击跳转)
《【Git教程】(十四)基于特性分支的开发 — 概述及使用要求,执行过程及其实现,替代方案 ~》

继续阅读下一篇(点击跳转)
《》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/644082.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于spring boot学生综合测评系统

基于spring boot学生综合测评系统设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件…

主打国产算力 广州市通用人工智能公共算力中心项目签约

4月9日&#xff0c;第十届广州国际投资年会期间&#xff0c;企商在线&#xff08;北京&#xff09;数据技术股份有限公司与广州市增城区政府就“广州市通用人工智能公共算力中心”项目进行签约。 该项目由广州市增城区人民政府发起&#xff0c;企商在线承建。项目拟建成中国最…

程序员过了35岁没人要?“这行越老越香”

程序员35岁失业&#xff1f;参加完OceanBase开发者大会&#xff0c;我又悟了&#xff01; 周六参加了OceanBase2024 开发者大会的现场&#xff0c;来之前我其实挺忐忑的&#xff0c;我觉得一个数据库产品的发布会&#xff0c;能有什么新鲜的东西&#xff1f; 踏入酒店的那一刻&…

c++11 标准模板(STL)本地化库 - 平面类别(std::messages) - 实现从消息目录获取字符串(二)

本地化库 本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析&#xff0c;以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C 标准库的其他组件的行为。 平面类别 实现从消息目录获取字符串 std::messages template< class Ch…

智慧文旅:引领旅游产业智慧升级的创新模式

一、智慧文旅是什么&#xff1f; 智慧文旅是指以当地特色文化为核心&#xff0c;借助现代科技手段&#xff0c;实现旅游景区全面智慧升级的旅游模式。在智慧文旅中&#xff0c;新一代信息网络技术和装备得到充分运用&#xff0c;文化旅游基础设施得到新建和改善&#xff0c;特…

自动批量将阿里云盘文件发布成WordPress文章脚本源码(以RiPro主题为例含付费信息下载地址SEO等自动设置)源码

背景 很多资源下载站&#xff0c;付费资源下载站&#xff0c;付费内容查看等都可以用WordPress站点发布内容&#xff0c;这些站点一般会基于一个主题&#xff0c;付费信息作为文章附属的信息发布&#xff0c;底层存储在WP表里&#xff0c;比如日主题&#xff0c;子比主题等。 …

猫咪也能吃大餐!福派斯无麸质牛肉猫粮,让爱宠更健康

作为猫奴的你们&#xff0c;总是希望给自家的小猫咪提供最好的营养。那么&#xff0c;今天我就来给大家推荐一款我个人非常喜欢的营养猫粮——福派斯无麸质牛肉高脂猫粮。 首先&#xff0c;让我们聊聊为什么选择无麸质猫粮。有些猫咪对麸质成分敏感&#xff0c;吃了含有麸质的猫…

上海亚商投顾:沪指缩量调整 有色、煤炭等周期股集体大跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日缩量调整&#xff0c;午后一度跌近1%&#xff0c;黄白二线走势分化&#xff0c;微盘股指数涨超3%。军…

【C++】优先队列

优先队结构的不同物理结构与常用操作算法 优先队列是一种特殊的队列,队列中的元素具有优先级,每次弹出操作会弹出优先级最高的元素。 优先队列常用的物理结构有: 1. 数组:简单但不高效,插入和删除操作需要移动大量元素,时间复杂度高。 2. 二叉堆:是一种完全二叉树,通常用数…

Checkpoint机制和生产配置

1.前提 在将Checkpoint之前&#xff0c;先回顾一下flink处理数据的流程&#xff1a; 2. 概述 Checkpoint机制&#xff0c;又叫容错机制&#xff0c;可以保证流式任务中&#xff0c;不会因为异常时等原因&#xff0c;造成任务异常退出。可以保证任务正常运行。 &#xff08;1&…

MySQL库表占用空间排序

在进行数据库备份恢复时&#xff0c;经常会碰到耗时很长的问题。大概率是因为某些库表的占用空间太大。 以下语句按照库表占用空间大小&#xff0c;进行降序排序&#xff1a; SELECT table_schema AS Database,table_name AS Table,ROUND((data_length index_length) / 1024…

腾讯文档中目录的生成及级别设置

腾讯文档是一款可多人同时编辑的在线文档。腾讯文档支持在线Word、Excel、PPT、PDF、收集表、思维导图、流程图多种类型。 今天介绍在线Word的目录生成及级别设置。 文章目录 一、腾讯文档生成目录二、目录的级别设置 一、腾讯文档生成目录 首先需要设置好文章的标题级别 在…