社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Git

【第3404期】git bisect:基于二分法快速找到有问题的提交

前端早读课 • 1 周前 • 24 次点击  

前言

介绍了 git bisect 命令的使用,通过二分查找法快速定位出现问题的提交点。今日前端早读课文章由 @jrainlau 投稿分享。

云原生构建:https://cnb.cool/

正文从这开始~~

今天偶然看到了一篇文章 Debugging Till Dawn: How Git Bisect Saved My Demo,既惊讶于 Git 竟然提供了一个如此强大的工具用于 debug,也对自己的孤陋寡闻感到羞愧。

【第3269期】不知道bug 躲在哪个commit 吗?来试试Git bisect 吧!

只要是有项目经验的人,一定会遇到过一个问题:项目运行情况之前明明都是好的,怎么突然就坏了?为了找到原因,除了实时 debug 以外,更流行的做法是把代码不停回滚,直到回滚到出问题之前的那次提交。

但是随着项目规模不断变大,很有可能在发现问题时,已经过去了无数次提交了。那么这个时候该如何快速准确地找到引发问题的那次提交呢?git bisect 提供了一个非常实用的解法。

顾名思义,该命令是使用二分查找的方式来找到出问题的提交的。假设我们有一个仓库,直到目前为止它一共经历过 7 次提交,而在最后一次提交后,我们才 “惊讶地” 发现它出错了!这个时候我们就要设法找到到底是什么时候引入的错误。

为了简单起见,这个仓库只有一个 README.md 文件,对于 “正确” 的情况,README.md 的内容里应该有且只有单词 “good”。如果什么时候出现了单词 “bad”,就证明它出错了。

 # README.md

good
good
good
bad
good
good
good

现在我们拥有了三个已知条件:

  • 第一次提交的时候,项目是好的,当时的标记为 1.0.0;

  • 最后一次提交的时候,项目是坏的,此时的标记为 HEAD;

  • 通过项目的 README.md 文件中是否存在 “bad” 字符串来判断好坏。

接下来,我们就可以使用 git bisect 指令,来快速找到出问题的那次提交了!

首先,在项目根目录中执行以下指令,把前两个已知条件添加进去:

注意,下面的示例代码中,“>” 后的内容为输入指令并回车后的系统输出。

 git bisect start

> 状态:正在等待好的和坏的提交

git bisect bad HEAD
> 状态:正在等待好的提交,已知坏的提交

git bisect good v1.0.0
> 二分查找中:在此之后,还剩 2 个版本待测试 (大概 2 步)
> [0abea12555d76d1cf57500198d1ff011ae0ae4f9] 1.0.3

此时,二分查找已经启动,查找的指针落到了第 4 次提交(v1.0.3)当中。这时候我们看下在第四次的提交中,README.md 都有哪些内容:

 cat README.md

>
good
good
good
bad%

可以看到,在这一次提交(v1.0.3)中,项目仍然是坏的,那么我们就可以更新已知条件的第二条了:

【第2934期】利用好 git bisect 这把利器,帮助你快速定位疑难 bug

最后一次提交的时候,项目是坏的,此时的标记为 HEAD;

第四次提交的时候,项目是坏的,此时的标记为 v1.0.3;

 git bisect bad v1.0.3

> 二分查找中:在此之后,还剩 0 个版本待测试 (大概 1 步)
> [af369bdbffad4496cff3bf520793cc6b5cfe62e6] 1.0.2

此时二分查找的指针来到了第三次提交(v1.0.2)里,看看此时的 README.md:

 cat README.md

>
good
good
good%

可以看到,此时的项目是好的,所以我们可以更新第一条已知条件了:

第一次提交的时候,项目是好的,当时的标记为 1.0.0;

第三次提交的时候,项目是好的,此时的标记为 v1.0.2

所以我们只需要把更新后的条件输入到 git bisect,它就能告诉我们答案了:

 git bisect good v1.0.2

>
0abea12555d76d1cf57500198d1ff011ae0ae4f9 is the first bad commit
commit 0abea12555d76d1cf57500198d1ff011ae0ae4f9
Author: jrainliu <jrainliu@tencent.com>
Date: Fri Oct 25 10:27:02 2024 +0800

1.0.3

README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

哦,原来出现问题的提交就是标记为 v1.0.3 的那一次!这时候我们已经找到了有问题的提交记录,这时候只需要输入

 git bisect reset

即可结束二分查找了。

这种通过肉眼判断项目代码是否出错的方式,实在是太不优雅。好在 git bisect 是支持执行脚本指令的。还是以上面这个示例项目为例,我们只需要写一个简单的 bash 脚本,判断 README.md 的内容是否包含单词”bad“,并通过” 结束码 “就可以自动让 git bisect 告诉我们最终的答案了。

关于所谓的结束码,约定返回 0 为” 正常退出 “,返回非 0 为” 异常退出 “。

 # test.sh

#!/usr/bin/env bash

# Check if README.md contains the word "bad"
if grep -q "bad" README.md; then
echo "README.md contains the word 'bad'"
exit 1
else
echo "README.md does not contain the word 'bad'"
exit 0
fi

准备好脚本后,步骤和之前一样,先输入已知的” 好提交 “和” 坏提交 “的标记,然后让 git bisect 自己去执行 test.sh 即可:

 git bisect start

git bisect bad HEAD

git bisect good v1.0.0

git bisect run ./test.sh

类似递归的原理,当 test.sh 的退出码为 0 时,会自动缩小二分查找的范围,直到退出码为非 0。

 >

正在执行 './test.sh'
README.md contains the word 'bad'
二分查找中:在此之后,还剩 0 个版本待测试 (大概 1 步)
[af369bdbffad4496cff3bf520793cc6b5cfe62e6] 1.0.2
正在执行 './test.sh'
README.md does not contain the word 'bad'
0abea12555d76d1cf57500198d1ff011ae0ae4f9 is the first bad commit
commit 0abea12555d76d1cf57500198d1ff011ae0ae4f9
Author: jrainliu <jrainliu@tencent.com>
Date: Fri Oct 25 10:27:02 2024 +0800

1.0.3

README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
二分查找找到了第一个坏的提交

在体会到 git bisect 的强大以后,更能意识到” 代码可测试性” 的重要。如果只靠肉眼 debug,即使是二分查找法也难以提升效率,最终还是得靠完善的测试脚本,通过程序自动化地完成项目好坏的判断,这才是值得我们真正思考和关心的内容。

Debugging Till Dawn: How Git Bisect Saved My Demo:https://www.mikebuss.com/posts/debugging-till-dawn

关于本文
作者:@jrainlau
原文:https://cnb.cool/jrainlau/blog/-/issues/1

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/175468
 
24 次点击