在某些情况下,在git bisect
会话期间,测试特定提交需要很长时间(例如,因为我必须构建一个完整的发布包并将其部署在一台特别奇怪的机器上)。事实上,测试一个构建需要很长时间,以至于我想在不知道当前测试是否成功的情况下已经开始构建接下来的两个提交。这样,我可以通过测试当前版本并并行构建接下来的两个版本来加速二等分。
git bisect
有没有人知道根据当前提交是好还是坏来显示下两个修订版的技巧?
在某些情况下,在git bisect
会话期间,测试特定提交需要很长时间(例如,因为我必须构建一个完整的发布包并将其部署在一台特别奇怪的机器上)。事实上,测试一个构建需要很长时间,以至于我想在不知道当前测试是否成功的情况下已经开始构建接下来的两个提交。这样,我可以通过测试当前版本并并行构建接下来的两个版本来加速二等分。
git bisect
有没有人知道根据当前提交是好还是坏来显示下两个修订版的技巧?
git bisect
在内部使用git rev-list --bisect
来找出哪个版本是两个版本之间的中点。您可以自己使用它来基本重新实现git bisect
. 它不应该那么难。
git bisect 在内部使用 git rev-list --bisect 来找出哪个版本是两个版本之间的中点。
Git 2.30(2021 年第一季度)改变了这种情况:“ git bisect start/next
” (man)在很长的历史中花了很多时间试图找出中间点;当我们看到一个足够接近中间点的提交时,可以通过停止来优化这一点。
请参阅SZEDER Gábor ( ) 的提交 0afcea7(2020 年 11 月 12 日)。(由Junio C Hamano 合并 -- --在提交 2557c11中,2020 年 11 月 25 日)szeder
gitster
bisect
: 放松halfway()
对大量提交的检查签字人:SZEDER Gábor
'
git bisect start ...
' ( man )和随后的 'git bisect (good|bad)
' ( man )命令可能需要相当长的时间,当好提交和坏提交之间的给定/剩余修订范围很大并且包含大量合并提交时,例如在git.git中:$ git rev-list --count v1.6.0..v2.28.0 44284 $ time git bisect start v2.28.0 v1.6.0 Bisecting: 22141 revisions left to test after this (roughly 15 steps) [e197c21807dacadc8305250baa0b9228819189d4] unable_to_lock_die(): rename function from unable_to_lock_index_die() real 0m15.472s user 0m15.220s sys 0m0.255s
运行时的大部分时间都花在
do_find_bisection()
,我们试图找到一个尽可能接近坏修订和好修订之间中点的提交,即在一个提交中,可到达的提交数量在好坏范围内是该范围内提交总数的一半。
因此,我们计算了该范围内的每个提交在好坏范围内可以达到多少次提交,这对于线性历史来说是快速和容易的,即使在我的机器上,线性范围内超过 300k 的提交也可以在大约 0.3 秒内处理。
唉,处理合并提交并非易事,而且相当昂贵,因为使用的算法似乎是二次的,导致上面显示的运行时间很长。有趣的是,看看一个额外的提交可以带来多大的不同:
$ git rev-list --count v1.6.0^..v2.28.0 44285 $ time git bisect start v2.28.0 v1.6.0^ Bisecting: 22142 revisions left to test after this (roughly 15 steps) [565301e41670825ceedf75220f2918ae76831240] Sync with 2.1.2 real 0m5.848s user 0m5.600s sys 0m0.252s
差异是由尝试减少1c4fea3a40中添加的运行时的优化之一引起的(“git-rev-list --bisect: optimization”,2007-03-21,Git v1.5.2-rc0 -- merge):
Another small optimization is whenever we find a half-way commit (that is, a commit that can reach exactly half of the commits), we stop giving counts to remaining commits, as we will not find any better commit than we just found.
在第二个 '
git bisect start
' ( man )命令中,我们碰巧在中途发现了一个提交并且可以提前返回,但是在第一种情况下没有这样的提交,所以我们不能提前返回并最终计算了来自好坏范围内的所有提交的可达提交。然而,当我们有数千个提交时,找到确切的中间点并不是那么重要,一些提交或多或少不会对二等分产生任何真正的影响。
因此,让我们放宽
halfway()
帮助程序中的检查,将提交在确切的中点的大约 0.1% 范围内也视为中途,并将函数重命名为approx_halfway()
相应的。
这将使我们能够在更大的好坏范围内尽早返回,即使在中途点没有提交,从而大大减少上述第一个命令的运行时间,从约 15 秒到 4.901 秒。此外,即使在中间点有一个提交,在找到确切的中间点之前,我们仍然可能会在 0.1% 范围内偶然发现一个提交,这使我们能够更早地返回,稍微减少第二个命令的运行时间5.848 秒到 5.058 秒。
请注意,此更改不会影响包含 ~2000 次或更少提交的好坏范围,因为整数运算导致 0.1% 的容差变为零;但是,如果范围那么小,那么计算所有提交的可达提交已经足够快了。
自然,这可能会改变在每个二等分步骤中选择哪些提交,并且反过来可能会改变找到第一个错误提交所需的二分步骤。
如果必要的二分步骤的数量经常增加,那么这种变化可能会适得其反,因为在每个步骤中构建和测试可能需要比节省的时间更长的时间。
OTOH,如果要减少步数,那将是双赢。因此,我进行了一些测试以查看这种情况发生的频率:在git.git中选择随机好的和坏的开始修订至少 50k 次提交和随机的第一次错误提交,并使用 '
git bisect git merge-base run --is-ancestor HEAD $first_bad_commit
' ( man )检查必要的数量平分步骤。
在使用和不使用此补丁的情况下重复所有这 1000 次后,我发现:
- 146 例比以前多一等分步,149 例少一步,而其余 705 例中步数没有变化。
因此,二分步数确实在不可忽略的情况下发生了变化,但从长远来看,平均步数似乎没有变化。- 在 456 个案例中,第一个 '
git bisect start
' ( man )命令的速度提高了 3 倍以上,因此这种“在中途没有提交”的案例似乎很常见,值得关注。