TimothyQiu's Blog

keep it simple stupid

定位工具 Git Bisect

分类:技术

经过 @Neuron Teckid 童鞋的提点,发现了 git bisect 这个非常有意思的工具。

话说,我第一眼把 bisect 看成了 biscuit,以为 Git 也开始学 Android 卖萌了呢……结果一查字典,这个词是「等分」的意思……

假设某天你发现你编译出的程序里有个 Bug,该如何找出它是从哪个版本开始引入的呢?在版本历史中找出有 Bug 和无 Bug 两个版本,用简单的二分查找法就可以定位啦。git bisect 正是用来帮助你完成这种二分查找法的自动化的。

基本用法

git bisect start         # 初始化二分查找
git bisect bad           # 标记当前版本存在问题
git bisect good 38a63d9  # 标记 38a63d9 版本没有问题

至少标记了一个没有问题的版本(Good)和一个有问题的版本(Bad)后,Git 就会开始二分查找的过程,不断检出 Good 和 Bad 中间的版本等待你检查后作出标记。每次检出后 Git 都会提示你还剩多少文件、大致还剩余多少次比较:

Bisecting: 441 revisions left to test after this (roughly 9 steps)

比如上面这三步后,Git 检出了中间版本 b17ff03。你编译运行后发现这个版本没有问题,就可以用 git bisect good 将当前版本标记为没有问题。此时 Git 就会再把 b17ff03 和最初版本之间的区域二分,检出中间版本等待你的检查。

等一切完成以后,就可以用 git bisect reset 返回开始前的版本。

自动查找

手动标记 Good / Bad 可以帮助人类从挑选下一个合适的版本的工作中解放出来。(似乎可以理解为 C++ 从 forstd::for_each 的抽象过程。)但这还是远远不够的,因为测试某个版本是否正常的重任依旧需要人类的介入。

所幸你可以指定一个检测用的程序,让 git bisect 自动完成整个定位的过程。这个程序必须在当前版本没有问题时返回 0,而 1 到 127 之间的值则表示有问题(特殊值 125 表示没法确定)。

git bisect run <cmd>...

例如,让你从一个陌生的代码库里找到能够编译和不能编译的临界提交,我们可以通过传入 make 来实现自动化查找:

git bisect start HEAD 38a63d9  # 简单写法:初始化二分查找,HEAD 有问题,而 38a63d9 没有
git bisect run make            # 利用 make 来检测某个版本是否能够通过编译

而后,Git 就会自己用二分查找法不断检出中间版本,每次检出后都会运行 make,根据 make 的返回值来确定当前版本是否存在问题(是否能够通过编译)。

以上。

被遗忘的 Git Stash

分类:技术

在介绍 Git 的时候,大多数文章都会提到它在 Working Copy 和 Repository 之间新增的 Staging Area,它使得你可以只提交 Working Copy 中的一小部分。作为一个半路出家的 Git 山寨用户,我之前知道的也就只是这三个地方了,不过这两天发现了第四个区域:Stashing Area。

假设你刚把代码改得乱七八糟,忽然想要从修改前的某个版本里做一个小改动,马上出一个紧急修正版。此时理论上,你只需先提交当前所有改动,然后就可以马上切换到以前的版本/分支开始工作了。但是作为「每次一提交都要能够通过编译」原则的忠实粉丝,这种思路所可能产生的垃圾提交是完全无法忍受的。

一种比较山寨的做法就是,手动把已修改的文件复制出去,然后 git checkout 回修改前的版本,最后切换版本/分支开始工作。做完以后再切换回来、把之前复制出去的文件复制回来。

Stashing Area 直接翻译过来是储藏间,是 Git 中用来暂存已作出的修改的地方,可以避免这种手动做法的繁琐。

  1. git stash save 将当前 Working Copy 中的修改保存为 Stash 中的一条新的记录,Working Copy 则变成了修改前的样子。
  2. 切换到别的版本/分支干活。
  3. 切换回原先的版本/分支。
  4. git stash pop 将 Stash 中最新的记录取出,并应用到 Working Copy 上。(从名字上可以看出,Stash 是一个栈式结构。)

Stash 的另一个方便之处是 git stash branch,它可以直接从 Stash 上创建一个分支。比如在你刚把代码改得乱七八糟,忽然想起来自己忘了新建分支的时候很有用。

相关信息