专栏名称: 前端早读课
我们关注前端,产品体验设计,更关注前端同行的成长。 每天清晨五点早读,四万+同行相伴成长。
目录
相关文章推荐
格斗迷  ·  70岁退役老拳手街头KO两个流氓! ·  10 小时前  
格斗迷  ·  70岁退役老拳手街头KO两个流氓! ·  10 小时前  
前端早读课  ·  【早阅】AI 编程工具如何改变开发者的时间分配 ·  2 天前  
前端大全  ·  15 分钟带你感受 CSS :has() ... ·  4 天前  
前端大全  ·  图解Nestjs - 适合中国宝宝的入门指导 ·  3 天前  
前端早读课  ·  【第3418期】HTML ... ·  6 天前  
51好读  ›  专栏  ›  前端早读课

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

前端早读课  · 公众号  · 前端  · 2024-10-31 08:00

正文

前言

介绍了 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

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