如何使用git对分?

如何使用git对分?,git,git-bisect,Git,Git Bisect,我读过一些文章说,git-bisect非常棒。然而,我不是以英语为母语的人,我不明白为什么它很棒 请有人用一些代码示例演示一下: 如何使用它 这就像是svn的过错吗 git-bisect背后的思想是在历史中执行二进制搜索以找到特定的回归。假设您有以下开发历史: ... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current 您知道您的程序在当前版本下工作不正常,并且在0版本下工作。因此,回归很可能是在一个提交中引入的1,2,3,4,5,current

我读过一些文章说,
git-bisect
非常棒。然而,我不是以英语为母语的人,我不明白为什么它很棒

请有人用一些代码示例演示一下:

  • 如何使用它
  • 这就像是svn的过错吗

  • git-bisect
    背后的思想是在历史中执行二进制搜索以找到特定的回归。假设您有以下开发历史:

    ... --- 0 --- 1 --- 2 --- 3 --- 4* --- 5 --- current
    
    您知道您的程序在
    当前
    版本下工作不正常,并且在
    0
    版本下工作。因此,回归很可能是在一个提交中引入的
    1
    2
    3
    4
    5
    current

    您可以尝试签出每个提交,构建它,检查回归是否存在。如果有大量提交,这可能需要很长时间。这是一个线性搜索。我们可以通过二进制搜索做得更好。这就是git bisect命令的作用。在每一步中,它都试图将可能不好的修订数量减少一半

    您将使用如下命令:

    $ git stash save
    $ git bisect start
    $ git bisect bad
    $ git bisect good 0
    Bisecting: 2 revisions left to test after this (roughly 2 steps)
    [< ... sha ... >] 3
    
    然后它将签出另一个提交。
    4
    5
    (因为只有两次提交)。假设它选择了
    5
    。构建之后,我们测试程序,并查看回归是否存在。然后我们告诉它到git:

    $ make
    $ make test
    ... ... ...
    $ git bisect bad
    Bisecting: 0 revisions left to test after this (roughly 0 steps)
    [< ... sha ... >] 4
    
    $ make
    $ make test
    ... ... ...
    $ git bisect bad
    < ... sha ... > is the first bad commit
    < ... commit message ... >
    
    在这个简单的情况下,我们只需要测试3个版本(
    3
    4
    5
    ),而不是4个版本(
    1
    2
    3
    4
    )。这是一场小小的胜利,但这是因为我们的历史太小了。如果搜索范围是N个提交,我们应该期望使用
    git-bisect
    测试1+log2n个提交,而不是使用线性搜索测试大约N/2个提交


    一旦找到了引入回归的提交,就可以研究它来发现问题。完成此操作后,在使用
    git bisect
    命令之前,您可以使用
    git bisect reset
    将所有内容恢复到原始状态。

    $git bisect..
    基本上是一个用于调试的git工具。”Git Bisect通过执行上次(已知)工作提交后的上一次提交进行调试。它使用二进制搜索遍历所有这些提交,以找到引入回归/错误的提交

    $git对分开始
    #开始对分

    $git bisect bad
    #说明当前提交(v1.5)具有回归/设置“bad”点

    $git bisect good v1.0
    #提到它是最后一次良好的工作提交(无回归)

    提到“坏”和“好”点将有助于git对分(二进制搜索)选择中间元素(commit v1.3)。如果在提交v1.3时存在回归,则将其设置为新的“坏”点,即(好->v1.0和坏->v1.3)

    或者类似地,如果commit v1.3没有bug,则将其设置为新的“Good point”,即(*Good->v1.3和Bad->v1.6)

    git对分运行
    自动对分 如果您有一个自动的
    /test
    脚本,如果测试正常,该脚本的退出状态为0,则您可以通过
    对分运行
    自动找到错误:

    git checkout KNOWN_BAD_COMMIT
    git bisect start
    
    # Confirm that our test script is correct, and fails on the bad commit.
    ./test
    # Should output != 0.
    echo $?
    # Tell Git that the current commit is bad.
    git bisect bad
    
    # Same for a known good commit in the past.
    git checkout KNOWN_GOOD_COMMIT
    ./test
    # Should output 0.
    echo $?
    # After this, git automatically checks out to the commit
    # in the middle of KNOWN_BAD_COMMIT and KNOWN_GOOD_COMMIT.
    git bisect good
    
    # Bisect automatically all the way to the first bad or last good rev.
    git bisect run ./test
    
    # End the bisect operation and checkout to master again.
    git bisect reset
    
    git bisect log
    
    当然,这假设如果测试脚本
    /test
    是git跟踪的,那么它不会在平分期间的某个早期提交中消失

    我发现,通常只需将树内脚本从树中复制出来,并可能使用类似于
    PATH
    的变量,然后从那里运行它,就可以摆脱这种情况

    当然,如果
    test
    所依赖的测试基础结构依赖于较旧的提交,则没有解决方案,您将不得不手动执行操作,决定如何逐个测试提交

    然而,我发现使用这种自动化通常是有效的,并且可以为积压的任务中较慢的测试节省大量时间,您可以让它在一夜之间运行,并且可能在第二天早上发现您的bug,这是值得尝试的

    更多提示 在对分后继续执行第一次失败的提交,而不是返回到
    master

    git bisect reset HEAD
    
    一次启动
    +初始
    错误
    良好

    git bisect start KNOWN_BAD_COMMIT KNOWN_GOOD_COMMIT~
    
    同:

    git checkout KNOWN_BAD_COMMIT
    git bisect start
    git bisect bad
    git bisect good KNOWN_GOOD_COMMIT
    
    查看到目前为止已测试的内容(通过手动
    良好
    不良
    运行
    ):

    样本输出:

    git bisect log
    git bisect start
    # bad: [00b9fcdbe7e7d2579f212b51342f4d605e53253d] 9
    git bisect bad 00b9fcdbe7e7d2579f212b51342f4d605e53253d
    # good: [db7ec3d602db2d994fe981c0da55b7b85ca62566] 0
    git bisect good db7ec3d602db2d994fe981c0da55b7b85ca62566
    # good: [2461cd8ce8d3d1367ddb036c8f715c7b896397a5] 4
    git bisect good 2461cd8ce8d3d1367ddb036c8f715c7b896397a5
    # good: [8fbab5a3b44fd469a2da3830dac5c4c1358a87a0] 6
    git bisect good 8fbab5a3b44fd469a2da3830dac5c4c1358a87a0
    # bad: [dd2c05e71c246f9bcbd2fbe81deabf826c54be23] 8
    git bisect bad dd2c05e71c246f9bcbd2fbe81deabf826c54be23
    # bad: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05] 7
    git bisect bad c536b1b7242d5fcf92cd87e9a534bedb1c0c9c05
    # first bad commit: [c536b1b7242d5fcf92cd87e9a534bedb1c0c9c0
    
    在git日志上显示好的和坏的引用,以更好地了解时间:

    git log --decorate --pretty=fuller --simplify-by-decoration master
    
    这仅显示具有相应ref的提交,这将灰色地减少噪波,但不包括以下类型的自动生成ref:

    refs/bisect/good*
    refs/bisect/bad*
    
    它告诉我们哪些承诺被标记为好的或坏的

    考虑是否要使用该命令

    失败是快的,成功是慢的 有时:

    • 故障发生得很快,例如,第一次测试中的一次中断
    • 成功需要一段时间,例如,失败的测试通过,而我们不关心的所有其他测试都会跟进
    对于这些情况,例如,假设故障总是在5秒钟内发生,并且如果我们懒得让测试更具体,我们可以使用
    timeout
    ,如下所示:

    #!/usr/bin/env bash
    timeout 5 test-command
    if [ $? -eq 1 ]; then
      exit 1
    fi
    
    这是因为
    timeout
    退出
    124
    ,而
    测试命令的失败退出
    1

    魔法退出状态
    git bisect run
    对退出状态有点挑剔:

    • 高于127的任何值都会导致平分失败,如下所示:

      git bisect run failed:
      exit code 134 from '../test -aa' is < 0 or >= 128
      
      #!/usr/bin/env bash
      set -eu
      ./build
      status=0
      ./actual-test-command || status=$?
      if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
        status=1
      fi
      exit "$status"
      

      在git 2.16.1上测试。

      只是为了补充一点:

      我们可以指定一个文件名或路径来
      git bisect start
      ,以防我们知道bug来自特定的文件。 例如 假设我们知道导致回归的更改在com/workingDir中 然后我们可以运行
      git bisect start com/workingDir
      这意味着 在…上
      #!/usr/bin/env bash
      timeout 5 test-command
      if [ $? -eq 1 ]; then
        exit 1
      fi
      
      git bisect run failed:
      exit code 134 from '../test -aa' is < 0 or >= 128
      
      #!/usr/bin/env bash
      set -eu
      ./build
      status=0
      ./actual-test-command || status=$?
      if [ "$status" -eq 125 ] || [ "$status" -gt 127 ]; then
        status=1
      fi
      exit "$status"
      
      $ git bisect start
      $ git bisect bad
      $ git bisect good <goodcommit>
      
      $ git bisect start
      $ git bisect good
      $ git bisect bad <badcommit>
      
      <abcdef> is the first bad commit
      
      git bisect reset
      
       git bisect start [--term-{old,good}=<term> --term-{new,bad}=<term>]
                        [--no-checkout] [<bad> [<good>...]] [--] [<paths>...]