如何使用Git Bisect:使用单元测试确定错误提交?

10
我对git很陌生,刚刚发现了“git bisect”。当你可以使用新编写的单元测试(之前不存在)检查错误时,通常如何使用它?
假设我们有一个包含单元测试的代码库,但是 - 常常会这样 - 它们并不完整。在某个版本中,我们发现某个功能无法正常工作,但我们知道在之前的某个版本中它是可行的。不幸的是,该功能没有通过单元测试进行检查。现在我想做的是:
1.编写测试用例(当然一开始会失败)
2.使用 git bisect 使用此测试用例寻找引入错误的提交
3.纠正错误并提交修复(以及测试用例)
这种用例有一个问题。由于 git bisect 检出旧版本,所以刚插入的测试用例不会存在,因此我无法使用它来检查错误。我可以尝试不提交测试,而将其保留为本地更改。但是,如果在某个版本中更改了测试文件,那么我可能会遇到合并冲突。
那么该怎么办?git bisect 通常如何使用?
3个回答

13

我通常使用bisect来确定bug引入的时间,这样我就可以查看单个提交以查找错误的原因。当我知道某些东西曾经可以工作而现在不行时,这很有用。我首先选择或查找一个旧的可用提交,在其上标记git bisect good,在当前HEAD上标记git bisect bad,然后通过bisect进行操作,直到git告诉我引入问题的提交。有时我可以在开始此过程前编写单元测试,有时我只能等到看到引入bug的代码后再编写它。

所以,假设我有单元测试或其他需要在每个点上使用的代码或脚本,stash对于在进行git bisect过程中保存这些内容非常有用。因此,

git stash save blah
git bisect bad (and now I'm on a new commit)
git stash pop
mvn clean test

git stash save blah
git bisect good
git stash pop
mvn clean test

等等之类的。


3

首先,在尝试这个之前,请确保您的git status是干净的 - 我建议使用一个脚本来调用git reset --hard,这样任何未提交的更改都将丢失。

一种方法是首先将最近的测试源代码复制到从未在存储库历史记录中跟踪过的某个位置(或者在存储库之外的某个位置)。然后编写一个脚本:

  1. 将最近的测试覆盖到源代码树中
  2. 运行测试,保存返回码。
  3. 执行git reset --hard以清除步骤1中的更改
  4. 退出并带着从2中保存的返回码。

然后,在将两个提交标记为好和坏以便让git bisect有一个开始点之后,您可以使用git bisect run YOUR-SCRIPT来查找最近的单元测试将无法通过的第一个提交。

这种方法基本上是git bisect运行文档中建议的内容,其中说:

您可能经常发现,在bisect会话期间,您希望对正在测试的修订版本进行临时修改(例如在头文件中进行s /#define DEBUG 0 /#define DEBUG 1 /,或“需要此补丁才能解决此双分支不关心的另一个问题的修订版本”)。

为了应对这种情况,在内部git bisect找到要测试的下一个修订版之后,脚本可以在编译之前应用补丁,运行真正的测试,然后在回退树到原始状态之前决定修订版(可能需要该补丁)是否通过了测试。最后,脚本应退出并带有bisect会话的最终结果。


1

您没有提到您使用的技术,所以我将以我最熟悉的 Ruby 作为例子。不过,同样的原则也适用于其他技术。

  1. 将最新的测试文件放在项目目录之外。这里我假设它在 /tmp/my_test.rb

  2. 在您的代码库中,创建一个小的 shell 脚本,比如说,test_runner.sh:

    #!/usr/bin/env sh    
    cp -f /tmp/my_test.rb test/my_test.rb # 这可能会覆盖一些旧的测试文件
    ruby test/my_test.rb # 更改为您使用的任何测试运行器
    test_result=$?
    git checkout test/my_test.rb # 撤消可能已经进行的任何更改
    exit $test_result
    
  3. 像通常使用 bisect 一样标记提交为好/坏。

  4. 使用 git bisect run test_runner.sh,在 git 为您找到错误时去喝杯咖啡。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接