【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://xiahunao.cn/news/2978500.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Linux thermal框架介绍

RK3568温控 cat /sys/class/thermal/thermal_zone0/temp cat /sys/class/thermal/thermal_zone1/temp cat /sys/class/thermal/cooling_device0/cur_state cat /sys/class/thermal/cooling_device1/cur_state cat /sys/class/thermal/cooling_device2/cur_state thermal_zone…

负氧离子监测系统适合景区使用吗

TH-FZ4负氧离子监测系统适合景区使用吗&#xff1f;答案是毫无疑问的&#xff0c;负氧离子监测系统是一种专门用于监测空气中负氧离子浓度的设备&#xff0c;结合了防腐木的结构优势和负氧离子监测技术&#xff0c;广泛应用于旅游景区、生态园区、森林公园等地方。这种系统通过…

Axure糖尿病健康管理APP原型 (知识科普/病友社区/远程医生会诊/购物商城/血糖监测/饮食监测)

作品概况 页面数量&#xff1a;共 50 页 源文件格式&#xff1a;rp格式&#xff0c;兼容 Axure RP 9/10&#xff0c;非程序软件无源代码 应用领域&#xff1a;医疗健康、慢病管理、糖尿病管理 作品特色 本作品为Axure糖尿病健康管理APP端原型图&#xff0c;设计规范内容清晰…

SQL的基础语句

1、select语句 select colums from table_name 2、条件语句 #查询出查询出用户id为1和3的用户记录 IN 操作符允许我们在 WHERE 子句中规定多个值。 select * from student where id in (1,3) #查询出所有姓王的同学 模糊查询 like 通配符(% 任意多个字符 _单个字符) #下例…

达芬奇调色:色彩理论入门

写在前面 整理一些达芬奇调色的笔记博文内容涉及&#xff1a; 一级调色是什么&#xff0c;以及 调色素材格式 log&#xff0c;raw&#xff0c;rec709 简单认知理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#…

【剪映专业版】03立体自动翻页

【剪映专业版】立体自动翻页制作 1.导入素材&#xff0c;图片或视频均可 2.将素材2拖动至素材1的上方&#xff0c;点击蒙版&#xff0c;选择线性蒙版&#xff0c;并旋转为90度。 3.复制素材1&#xff0c;并拖动到素材2上方&#xff0c;分割并删除后半部分&#xff0c;点击蒙版…

Innodb之Doublewrite Buffer

Innodb 事件流程 Doublewrite Buffer InnoDB 存储引擎的 Doublewrite Buffer&#xff08;双写缓冲区&#xff09;是一种用于数据完整性和恢复的关键机制。它是为了在数据库发生崩溃时保护数据不受损坏设计的。下面将详细介绍 Doublewrite Buffer 的工作原理、目的以及其对性能…

echarts柱形图实现2.5D

思路&#xff1a;使用markpoint option {title: {text: Rainfall vs Evaporation,subtext: Fake Data},tooltip: {trigger: axis},legend: {data: [Rainfall, Evaporation]},toolbox: {show: true,feature: {dataView: { show: true, readOnly: false },magicType: { show: t…

一文了解什么是私有化部署

在当今数据驱动的商业环境中&#xff0c;企业对于数据的处理和传输需求日益增长&#xff0c;这使得私有化部署成为了一种受到青睐的数据管理策略。私有化部署不仅能够提供更高的数据安全性和隐私保护&#xff0c;还能让企业根据自身需求定制解决方案&#xff0c;从而更有效地控…

你们项目日志是如何处理的???

ELK日志采集系统 1.什么是ELK ELK 是一套流行的数据搜索、分析和可视化解决方案&#xff0c;由三个开源项目组成&#xff0c;每个项目的首字母合起来形成了“ELK”这一术语&#xff1a; Elasticsearch (ES): Elasticsearch 是一个基于 Apache Lucene 构建的分布式、实时搜索与…

RAG开山之作:结合参数化与非参数化记忆的知识密集型NLP任务新解法

20年RAG刚提出时的论文&#xff1a;Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks&#xff0c;也算是RAG的开山之作之一了。 摘要&#xff1a;检索增强生成&#xff08;RAG&#xff09;方法结合了预训练语言模型与基于检索的非参数化记忆&#xff0c;通过…

布局香港之零售小店篇 | 香港一人小企与连锁超市的竞争

近年来&#xff0c;内地品牌入驻香港市场开拓业务已成大势所趋。香港特区政府早前公布的「2023年有香港境外母公司的驻港公司按年统计调查」显示&#xff0c;2023年母公司在海外及内地的驻港公司数量高达9039家。内地品牌在香港的成功落地&#xff0c;不仅为香港市民带来了丰富…

rosdep一键修复

External Player - 哔哩哔哩嵌入式外链播放器 rosdep失败原因 通常在执行rosdep init操作时就会报错&#xff0c;问题的核心在于rosdep会访问raw.githubusercontent.com这个网址下的资源&#xff0c;例如https://raw.githubusercontent.com/ros/rosdistro/master/rosdep/sour…

Leetcode 119 杨辉三角 II

目录 一、问题描述二、示例及约束三、代码方法一&#xff1a;递推方法二&#xff1a;线性递推 四、总结 一、问题描述 给定一个非负索引 rowIndex&#xff0c;返回「杨辉三角」的第 rowIndex 行。   在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。   自我…

运行Java或Python的时候,Git是必要的吗?

在运行Java或Python代码时&#xff0c;Git并不是必需的&#xff0c;但它可以成为一个非常有用的工具&#xff0c;特别是在团队协作、版本控制和代码管理方面。 Git的作用和优势 版本控制&#xff1a; Git是一个分布式版本控制系统&#xff0c;可以跟踪文件的更改历史&#xff…

CodeGemma初探

什么是 CodeGemma CodeGemma是一系列强大而轻量级的模型的集合&#xff0c;可以执行各种编码任务&#xff0c;包括填充中间代码补全、代码生成、自然语言理解、数学推理和指令跟随。 版本&#xff1a; instruct&#xff1a;7B, 这个版本专门针对自然语言到代码聊天和指令跟随…

租房管理|基于SprinBoot+vue的租房管理系统(源码+数据库+文档)

租房管理目录 基于SprinBootvue的租房管理系统 一、前言 二、系统设计 三、系统功能设计 前台 后台 管理员 订单信息管理 屋主申诉管理 屋主权限 房源信息管理 订单信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获…

阿里云mysql8.0 this is incompatible withsql mode=only full group by

阿里云RDS中mysql5.6升级为8.0后&#xff0c;出现如下问题&#xff1a; ### Error querying database. Cause:java.sql.SQLSyntaxErrorException: Expression #1 of SELECT listis not in GROUP BY clause and contains nonaggregatedcolumn temp.product_id which is not fun…

陪诊小程序开发:守护健康,温暖陪伴每一步

在繁忙的都市生活中&#xff0c;每个人都可能面临就医的困扰。面对陌生的医院环境、复杂的就诊流程&#xff0c;很多人感到无助和迷茫。陪诊小程序的开发&#xff0c;旨在通过科技与服务的融合&#xff0c;为用户带来更加贴心、便捷的陪诊体验&#xff0c;守护健康&#xff0c;…

编译支持播放H265的cef控件

接着在上次编译的基础上增加h265支持编译支持视频播放的cef控件&#xff08;h264&#xff09; 测试页面&#xff0c;直接使用cef_enhancement,里边带着的那个html即可&#xff0c;h265视频去这个网站下载elecard,我修改的这个版本参考了里边的修改方式&#xff0c;不过我的这个…